Skip to content

Commit 89f3b1f

Browse files
fix(datetime): remove ion-buttons to fix CSP violations (#30770)
Issue number: N/A --------- ## What is the current behavior? The Datetime component breaks CSP rules due to the following: 1. Datetime is using `ion-buttons` which uses `scoped` encapsulation. 2. When using the `ionic` theme, it imports Phosphor icons as data URIs, which are blocked by `connect-src 'self' blob:`. ## What is the new behavior? - Remove all usages of `ion-buttons`, removing the dependency on a scoped component - Updates the styling to account for the removal of `ion-buttons` - Updates `ion-button` to change its styles based on being inside of an `ion-datetime` Phosphor icons have not been removed because there is a workaround for it and we will remove its usage across all components in future work. ## Does this introduce a breaking change? - [x] Yes - [ ] No This shouldn't cause breaking changes but because we are no longer recommending users use `ion-buttons` with custom buttons I am marking it as a breaking change. BREAKING CHANGE: The `ion-buttons` component has been removed from the internal implementation of `ion-datetime` and is no longer required when passing custom buttons to the `slot="buttons"`. When providing custom buttons, use a `div` element instead of `ion-buttons`. While existing code using `ion-buttons` may continue to work visually, future updates to the `ion-buttons` component may cause any styles you rely on to break. --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
1 parent 4aaece0 commit 89f3b1f

140 files changed

Lines changed: 277 additions & 91 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

BREAKING.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
1818
- [Button](#version-9x-button)
1919
- [Card](#version-9x-card)
2020
- [Chip](#version-9x-chip)
21+
- [Datetime](#version-9x-datetime)
2122
- [Grid](#version-9x-grid)
2223

2324
<h2 id="version-9x-components">Components</h2>
@@ -62,6 +63,10 @@ This is a comprehensive list of the breaking changes introduced in the major ver
6263

6364
- The `border-radius` of the `ios` and `md` chip now defaults to `10px` and `8px`, respectively, instead of `16px` in accordance with the iOS and Material Design 3 guidelines. To revert to the previous appearance, set the `shape` to `"round"`, or override the `--border-radius` CSS variable to specify a different value.
6465

66+
<h4 id="version-9x-datetime">Datetime</h4>
67+
68+
- The `ion-buttons` component has been removed from the internal implementation of `ion-datetime` and is no longer required when passing custom buttons to the `slot="buttons"`. When providing custom buttons, use a `div` element instead of `ion-buttons`. While existing code using `ion-buttons` may continue to work visually, future updates to the `ion-buttons` component may cause any styles you rely on to break.
69+
6570
<h4 id="version-9x-grid">Grid</h4>
6671

6772
- The properties `pull` and `push` have been deprecated and no longer work. A similar look can be achieved with the newly added property `order`.

core/src/components.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ export namespace Components {
600600
*/
601601
"expand"?: 'full' | 'block';
602602
/**
603-
* Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"` for a transparent button with a border, or to `"solid"` for a button with a filled background. The default fill is `"solid"` except inside of a toolbar, where the default is `"clear"`.
603+
* Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"` for a transparent button with a border, or to `"solid"` for a button with a filled background. The default fill is `"solid"` except when inside of a buttons or datetime component, where the default fill is `"clear"`.
604604
*/
605605
"fill"?: 'clear' | 'outline' | 'solid' | 'default';
606606
/**
@@ -6555,7 +6555,7 @@ declare namespace LocalJSX {
65556555
*/
65566556
"expand"?: 'full' | 'block';
65576557
/**
6558-
* Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"` for a transparent button with a border, or to `"solid"` for a button with a filled background. The default fill is `"solid"` except inside of a toolbar, where the default is `"clear"`.
6558+
* Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"` for a transparent button with a border, or to `"solid"` for a button with a filled background. The default fill is `"solid"` except when inside of a buttons or datetime component, where the default fill is `"clear"`.
65596559
*/
65606560
"fill"?: 'clear' | 'outline' | 'solid' | 'default';
65616561
/**

core/src/components/button/button.ionic.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,12 @@
334334
@include globals.position(null, globals.$ion-space-200, globals.$ion-space-200, null);
335335
}
336336
}
337+
338+
// Button in Datetime
339+
// --------------------------------------------------
340+
341+
:host(.in-datetime) {
342+
@include globals.typography(globals.$ion-body-action-md);
343+
344+
min-height: globals.$ion-space-1200;
345+
}

core/src/components/button/button.ios.scss

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,16 @@
293293
background: var(--ion-toolbar-color, var(--color));
294294
color: #{var(--ion-toolbar-background, var(--background), ion-color(primary, contrast))};
295295
}
296+
297+
// Button in Datetime
298+
// --------------------------------------------------
299+
300+
:host(.in-datetime) {
301+
--padding-top: 3px;
302+
--padding-bottom: 3px;
303+
--padding-start: 5px;
304+
--padding-end: 5px;
305+
306+
font-size: dynamic-font-clamp(1, 17px, 1.24);
307+
font-weight: 400;
308+
}

core/src/components/button/button.md.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,20 @@
243243
background: var(--ion-toolbar-background, var(--color));
244244
color: #{var(--ion-toolbar-color, var(--background), ion-color(primary, contrast))};
245245
}
246+
247+
// Button in Datetime
248+
// --------------------------------------------------
249+
250+
:host(.in-datetime) {
251+
--padding-top: 3px;
252+
--padding-bottom: 3px;
253+
--padding-start: 8px;
254+
--padding-end: 8px;
255+
--box-shadow: none;
256+
}
257+
258+
:host(.in-datetime.button-clear) {
259+
--background-activated: transparent;
260+
--background-focused: currentColor;
261+
--background-hover: currentColor;
262+
}

core/src/components/button/button.native.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,12 @@
5959
:host ::slotted(ion-badge[vertical]:not(:empty)) {
6060
@include globals.padding(2px);
6161
}
62+
63+
// Button in Datetime
64+
// --------------------------------------------------
65+
66+
:host(.in-datetime) {
67+
@include globals.margin(0px, 2px, 0px, 2px);
68+
69+
min-height: 32px;
70+
}

core/src/components/button/button.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ import type { RouterDirection } from '../router/utils/interface';
3131
shadow: true,
3232
})
3333
export class Button implements ComponentInterface, AnchorInterface, ButtonInterface {
34+
private inDatetime = false;
3435
private inItem = false;
3536
private inListHeader = false;
36-
private inToolbar = false;
37+
private inButtons = false;
3738
private formButtonEl: HTMLButtonElement | null = null;
3839
private formEl: HTMLFormElement | null = null;
3940
private inheritedAttributes: Attributes = {};
@@ -78,7 +79,8 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
7879
/**
7980
* Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"`
8081
* for a transparent button with a border, or to `"solid"` for a button with a filled background.
81-
* The default fill is `"solid"` except inside of a toolbar, where the default is `"clear"`.
82+
* The default fill is `"solid"` except when inside of a buttons or datetime component, where
83+
* the default fill is `"clear"`.
8284
*/
8385
@Prop({ reflect: true, mutable: true }) fill?: 'clear' | 'outline' | 'solid' | 'default';
8486

@@ -217,9 +219,10 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
217219
}
218220

219221
componentWillLoad() {
220-
this.inToolbar = !!this.el.closest('ion-buttons');
221-
this.inListHeader = !!this.el.closest('ion-list-header');
222-
this.inItem = !!this.el.closest('ion-item') || !!this.el.closest('ion-item-divider');
222+
this.inDatetime = hostContext('ion-datetime', this.el);
223+
this.inButtons = hostContext('ion-buttons', this.el);
224+
this.inListHeader = hostContext('ion-list-header', this.el);
225+
this.inItem = hostContext('ion-item', this.el) || hostContext('ion-item-divider', this.el);
223226
this.inheritedAttributes = inheritAriaAttributes(this.el);
224227
}
225228

@@ -234,9 +237,11 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
234237
private get rippleType() {
235238
const hasClearFill = this.fill === undefined || this.fill === 'clear';
236239

237-
// If the button is in a toolbar, has a clear fill (which is the default)
238-
// and only has an icon we use the unbounded "circular" ripple effect
239-
if (hasClearFill && this.hasIconOnly && this.inToolbar) {
240+
// Use the unbounded "circular" ripple effect if it:
241+
// - Has a clear fill (the default)
242+
// - Only has an icon and
243+
// - Is inside of buttons (used in a toolbar) or a datetime
244+
if (hasClearFill && this.hasIconOnly && (this.inButtons || this.inDatetime)) {
240245
return 'unbounded';
241246
}
242247

@@ -401,7 +406,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
401406
};
402407
let fill = this.fill;
403408
if (fill === undefined) {
404-
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
409+
fill = this.inDatetime || this.inButtons || this.inListHeader ? 'clear' : 'solid';
405410
}
406411

407412
/**
@@ -427,9 +432,10 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
427432
[`${buttonType}-${shape}`]: true,
428433
[`${buttonType}-${fill}`]: true,
429434
[`${buttonType}-strong`]: strong,
435+
'in-datetime': this.inDatetime,
430436
'in-toolbar': hostContext('ion-toolbar', this.el),
431437
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
432-
'in-buttons': hostContext('ion-buttons', this.el),
438+
'in-buttons': this.inButtons,
433439
'button-has-icon-only': hasIconOnly,
434440
'button-has-badge': hasBadge,
435441
'button-disabled': disabled,
Loading
-1008 Bytes
Loading

core/src/components/datetime/datetime.common.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@
149149
width: 100%;
150150
}
151151

152-
:host .datetime-action-buttons ion-buttons,
152+
:host .datetime-action-buttons,
153+
::slotted([slot="buttons"]),
153154
/**
154155
* The confirm and clear buttons are grouped in a
155156
* container so that they appear on the end opposite

0 commit comments

Comments
 (0)