@vectoriox/iox-ui 5.85.0 → 5.86.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions-core/index.d.ts +30 -2
- package/design-core/index.d.ts +1488 -224
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs +136 -70
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +1751 -279
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs +27 -4
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +223 -12
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs +3 -4
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +1272 -69
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/forms-core/index.d.ts +23 -4
- package/generation-core/index.d.ts +5 -1
- package/index.d.ts +426 -22
- package/package.json +1 -1
- package/src/actions-core/action.model.ts +1 -1
- package/src/actions-core/dialog-opener.ts +9 -3
- package/src/actions-core/element-actions.ts +25 -1
- package/src/actions-core/popover-opener.ts +50 -0
- package/src/actions-core/public-api.ts +1 -0
- package/src/design-core/flavor-spec.generated.ts +1750 -277
- package/src/forms-core/submit-lifecycle.ts +30 -3
- package/src/generation-core/baseline-roles.ts +1 -0
- package/src/generation-core/node-baselines.generated.ts +214 -8
- package/src/generation-core/pictures.ts +8 -4
- package/src/scene-core/scroll-driver.ts +2 -1
- package/styles/iox-design.css +216 -14
- package/styles/iox-forms.css +24 -2
|
@@ -24,6 +24,27 @@ export enum FormRenderState {
|
|
|
24
24
|
/** The attribute every renderer writes a form's state on (the canvas switcher, both live paths). */
|
|
25
25
|
export const FORM_STATE_ATTRIBUTE = 'data-iox-state';
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* What a form shows once it has sent (premium M5, N3) — the Form's "After sending" choice:
|
|
29
|
+
* - `message`: the success in place (M3): the fields leave, the Success block shows, Send reads "Sent" and stays so;
|
|
30
|
+
* - `toast`: the fields STAY, cleared for the next answer, and a toast says the form's Sent words — a newsletter in a
|
|
31
|
+
* footer, a form someone may send again.
|
|
32
|
+
*/
|
|
33
|
+
export enum FormAfterSend {
|
|
34
|
+
Message = 'message',
|
|
35
|
+
Toast = 'toast',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The Form trait holding the choice. */
|
|
39
|
+
export const FORM_AFTER_SEND_TRAIT = 'afterSend';
|
|
40
|
+
/** The attribute every renderer writes it on (only when it is `toast` — `message` is what a form always did). */
|
|
41
|
+
export const FORM_AFTER_SEND_ATTRIBUTE = 'data-iox-after-send';
|
|
42
|
+
|
|
43
|
+
/** The choice a stored value names (`message` unless it says `toast`). */
|
|
44
|
+
export function formAfterSend(value: unknown): FormAfterSend {
|
|
45
|
+
return value === FormAfterSend.Toast ? FormAfterSend.Toast : FormAfterSend.Message;
|
|
46
|
+
}
|
|
47
|
+
|
|
27
48
|
/** What the form does once the server has answered. */
|
|
28
49
|
export interface SubmitOutcome {
|
|
29
50
|
state: FormRenderState;
|
|
@@ -32,13 +53,19 @@ export interface SubmitOutcome {
|
|
|
32
53
|
/** A success clears the answers, so they cannot be sent twice. */
|
|
33
54
|
reset: boolean;
|
|
34
55
|
redirect?: string;
|
|
56
|
+
/** Say it in a toast (the form keeps its fields and goes back to Idle). */
|
|
57
|
+
toast?: boolean;
|
|
35
58
|
}
|
|
36
59
|
|
|
37
60
|
/**
|
|
38
|
-
* The server's answer → what the visitor sees. Only a confirmed success is Success
|
|
39
|
-
* land on the fields; anything else (a dropped network included)
|
|
61
|
+
* The server's answer → what the visitor sees. Only a confirmed success is Success (or, for a form that keeps its
|
|
62
|
+
* fields, Idle again with a toast); per-field verdicts land on the fields; anything else (a dropped network included)
|
|
63
|
+
* is the designed Error block.
|
|
40
64
|
*/
|
|
41
|
-
export function submitOutcome(response: SubmitResponse | null | undefined): SubmitOutcome {
|
|
65
|
+
export function submitOutcome(response: SubmitResponse | null | undefined, afterSend: FormAfterSend | string | null = FormAfterSend.Message): SubmitOutcome {
|
|
66
|
+
if (response?.ok && formAfterSend(afterSend) === FormAfterSend.Toast) {
|
|
67
|
+
return { state: FormRenderState.Idle, reset: true, toast: true, ...(response.redirect ? { redirect: response.redirect } : {}) };
|
|
68
|
+
}
|
|
42
69
|
if (response?.ok) return { state: FormRenderState.Success, reset: true, ...(response.redirect ? { redirect: response.redirect } : {}) };
|
|
43
70
|
if (response?.errors && Object.keys(response.errors).length) return { state: FormRenderState.Idle, errors: response.errors, reset: false };
|
|
44
71
|
return { state: FormRenderState.Error, reset: false };
|
|
@@ -61,6 +61,7 @@ export const BASELINE_ROLES: Readonly<Record<string, Readonly<Record<string, Bas
|
|
|
61
61
|
FormSuccess: { width: Behaviour, color: Look, padding: Look, borderRadius: Look, backgroundColor: Look },
|
|
62
62
|
FormError: { width: Behaviour, color: Look, padding: Look, borderRadius: Look, backgroundColor: Look },
|
|
63
63
|
Dialog: { width: Behaviour, padding: Look, borderRadius: Look, backgroundColor: Look, boxShadow: Look },
|
|
64
|
+
Popover: { width: Behaviour, padding: Look, borderRadius: Look, backgroundColor: Look, boxShadow: Look },
|
|
64
65
|
// CC3: a Video fills its column at 16 / 9 — the shape the poster and the player take.
|
|
65
66
|
Video: { width: Behaviour, aspectRatio: Behaviour },
|
|
66
67
|
};
|
|
@@ -206,7 +206,9 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
206
206
|
"pageRoute": "",
|
|
207
207
|
"target": "_self",
|
|
208
208
|
"type": "button",
|
|
209
|
-
"ariaLabel": ""
|
|
209
|
+
"ariaLabel": "",
|
|
210
|
+
"tooltip": "",
|
|
211
|
+
"tooltipPlacement": "above"
|
|
210
212
|
},
|
|
211
213
|
"styleProps": {
|
|
212
214
|
"position": "static",
|
|
@@ -302,7 +304,9 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
302
304
|
"target",
|
|
303
305
|
"type",
|
|
304
306
|
"__accessibilityLabel",
|
|
305
|
-
"ariaLabel"
|
|
307
|
+
"ariaLabel",
|
|
308
|
+
"tooltip",
|
|
309
|
+
"tooltipPlacement"
|
|
306
310
|
],
|
|
307
311
|
"styleTraits": [
|
|
308
312
|
"position",
|
|
@@ -1383,7 +1387,9 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
1383
1387
|
"url": "https://",
|
|
1384
1388
|
"pageRoute": "",
|
|
1385
1389
|
"target": "_self",
|
|
1386
|
-
"ariaLabel": ""
|
|
1390
|
+
"ariaLabel": "",
|
|
1391
|
+
"tooltip": "",
|
|
1392
|
+
"tooltipPlacement": "above"
|
|
1387
1393
|
},
|
|
1388
1394
|
"styleProps": {
|
|
1389
1395
|
"position": "static",
|
|
@@ -1478,7 +1484,9 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
1478
1484
|
"pageRoute",
|
|
1479
1485
|
"target",
|
|
1480
1486
|
"__accessibilityLabel",
|
|
1481
|
-
"ariaLabel"
|
|
1487
|
+
"ariaLabel",
|
|
1488
|
+
"tooltip",
|
|
1489
|
+
"tooltipPlacement"
|
|
1482
1490
|
],
|
|
1483
1491
|
"styleTraits": [
|
|
1484
1492
|
"position",
|
|
@@ -1583,7 +1591,9 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
1583
1591
|
"pageRoute": "",
|
|
1584
1592
|
"target": "_self",
|
|
1585
1593
|
"colorScheme": "default",
|
|
1586
|
-
"ariaLabel": ""
|
|
1594
|
+
"ariaLabel": "",
|
|
1595
|
+
"tooltip": "",
|
|
1596
|
+
"tooltipPlacement": "above"
|
|
1587
1597
|
},
|
|
1588
1598
|
"styleProps": {
|
|
1589
1599
|
"position": "static",
|
|
@@ -1678,7 +1688,9 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
1678
1688
|
"target",
|
|
1679
1689
|
"colorScheme",
|
|
1680
1690
|
"__accessibilityLabel",
|
|
1681
|
-
"ariaLabel"
|
|
1691
|
+
"ariaLabel",
|
|
1692
|
+
"tooltip",
|
|
1693
|
+
"tooltipPlacement"
|
|
1682
1694
|
],
|
|
1683
1695
|
"styleTraits": [
|
|
1684
1696
|
"position",
|
|
@@ -3649,7 +3661,7 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
3649
3661
|
"name": "Contact form",
|
|
3650
3662
|
"formId": "",
|
|
3651
3663
|
"feedback": "smart",
|
|
3652
|
-
"
|
|
3664
|
+
"afterSend": "message",
|
|
3653
3665
|
"focusFirstProblem": true,
|
|
3654
3666
|
"announceFailure": true,
|
|
3655
3667
|
"honeypot": true,
|
|
@@ -3745,7 +3757,7 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
3745
3757
|
"name",
|
|
3746
3758
|
"formId",
|
|
3747
3759
|
"feedback",
|
|
3748
|
-
"
|
|
3760
|
+
"afterSend",
|
|
3749
3761
|
"focusFirstProblem",
|
|
3750
3762
|
"announceFailure",
|
|
3751
3763
|
"__spamLabel",
|
|
@@ -5035,6 +5047,200 @@ export const NODE_BASELINES: Readonly<Record<string, NodeBaseline>> = {
|
|
|
5035
5047
|
],
|
|
5036
5048
|
"container": true
|
|
5037
5049
|
},
|
|
5050
|
+
"Popover": {
|
|
5051
|
+
"props": {
|
|
5052
|
+
"placement": "below",
|
|
5053
|
+
"ariaLabel": "",
|
|
5054
|
+
"colorScheme": "default"
|
|
5055
|
+
},
|
|
5056
|
+
"styleProps": {
|
|
5057
|
+
"position": "static",
|
|
5058
|
+
"top": "auto",
|
|
5059
|
+
"right": "auto",
|
|
5060
|
+
"bottom": "auto",
|
|
5061
|
+
"left": "auto",
|
|
5062
|
+
"zIndex": "0",
|
|
5063
|
+
"display": "block",
|
|
5064
|
+
"flexDirection": "row",
|
|
5065
|
+
"flexWrap": "nowrap",
|
|
5066
|
+
"justifyContent": "flex-start",
|
|
5067
|
+
"alignItems": "stretch",
|
|
5068
|
+
"gap": "0px",
|
|
5069
|
+
"gridTemplateColumns": "1fr",
|
|
5070
|
+
"gridTemplateRows": "auto",
|
|
5071
|
+
"justifyItems": "stretch",
|
|
5072
|
+
"alignContent": "stretch",
|
|
5073
|
+
"alignSelf": "auto",
|
|
5074
|
+
"order": "0",
|
|
5075
|
+
"flexGrow": "0",
|
|
5076
|
+
"flexShrink": "1",
|
|
5077
|
+
"flexBasis": "auto",
|
|
5078
|
+
"justifySelf": "auto",
|
|
5079
|
+
"gridColumn": "auto",
|
|
5080
|
+
"gridRow": "auto",
|
|
5081
|
+
"width": "320px",
|
|
5082
|
+
"height": "auto",
|
|
5083
|
+
"minWidth": "auto",
|
|
5084
|
+
"minHeight": "auto",
|
|
5085
|
+
"maxWidth": "auto",
|
|
5086
|
+
"maxHeight": "auto",
|
|
5087
|
+
"aspectRatio": "auto",
|
|
5088
|
+
"objectFit": "cover",
|
|
5089
|
+
"overflow": "visible",
|
|
5090
|
+
"fontFamily": "Poppins, sans-serif",
|
|
5091
|
+
"fontSize": "16px",
|
|
5092
|
+
"fontWeight": "400",
|
|
5093
|
+
"color": "#000000",
|
|
5094
|
+
"lineHeight": "1.5",
|
|
5095
|
+
"letterSpacing": "0px",
|
|
5096
|
+
"textTransform": "none",
|
|
5097
|
+
"textAlign": "start",
|
|
5098
|
+
"fontStyle": "normal",
|
|
5099
|
+
"textDecoration": "none",
|
|
5100
|
+
"fontVariantNumeric": "normal",
|
|
5101
|
+
"WebkitTextStrokeWidth": "0px",
|
|
5102
|
+
"WebkitTextStrokeColor": "transparent",
|
|
5103
|
+
"margin": "0px 0px 0px 0px",
|
|
5104
|
+
"padding": "16px",
|
|
5105
|
+
"borderWidth": "0px",
|
|
5106
|
+
"borderStyle": "solid",
|
|
5107
|
+
"borderColor": "#CCCCCC",
|
|
5108
|
+
"borderRadius": "12px",
|
|
5109
|
+
"backgroundColor": "#ffffff",
|
|
5110
|
+
"opacity": "1",
|
|
5111
|
+
"mixBlendMode": "normal",
|
|
5112
|
+
"cursor": "auto",
|
|
5113
|
+
"boxShadow": "0 12px 32px rgba(0, 0, 0, 0.18)",
|
|
5114
|
+
"textShadow": "",
|
|
5115
|
+
"translateX": "0px",
|
|
5116
|
+
"translateY": "0px",
|
|
5117
|
+
"scaleX": "1",
|
|
5118
|
+
"scaleY": "1",
|
|
5119
|
+
"rotate": "0deg",
|
|
5120
|
+
"skewX": "0deg",
|
|
5121
|
+
"skewY": "0deg",
|
|
5122
|
+
"transformOrigin": "center",
|
|
5123
|
+
"filterBlur": "0px",
|
|
5124
|
+
"filterHueRotate": "0deg",
|
|
5125
|
+
"filterBrightness": "1",
|
|
5126
|
+
"filterContrast": "1",
|
|
5127
|
+
"filterSaturate": "1",
|
|
5128
|
+
"filterGrayscale": "0",
|
|
5129
|
+
"filterSepia": "0",
|
|
5130
|
+
"filterInvert": "0",
|
|
5131
|
+
"backdropFilter": "none",
|
|
5132
|
+
"backdropBlur": "0px",
|
|
5133
|
+
"backdropBrightness": "1",
|
|
5134
|
+
"backdropContrast": "1",
|
|
5135
|
+
"backdropSaturate": "1",
|
|
5136
|
+
"clipPath": "none",
|
|
5137
|
+
"transitionProperty": "",
|
|
5138
|
+
"transitionDuration": "0ms",
|
|
5139
|
+
"transitionDelay": "0ms",
|
|
5140
|
+
"transitionTimingFunction": "ease"
|
|
5141
|
+
},
|
|
5142
|
+
"traits": [
|
|
5143
|
+
"placement",
|
|
5144
|
+
"__accessibilityLabel",
|
|
5145
|
+
"ariaLabel",
|
|
5146
|
+
"colorScheme"
|
|
5147
|
+
],
|
|
5148
|
+
"styleTraits": [
|
|
5149
|
+
"position",
|
|
5150
|
+
"top",
|
|
5151
|
+
"right",
|
|
5152
|
+
"bottom",
|
|
5153
|
+
"left",
|
|
5154
|
+
"zIndex",
|
|
5155
|
+
"display",
|
|
5156
|
+
"flexDirection",
|
|
5157
|
+
"flexWrap",
|
|
5158
|
+
"justifyContent",
|
|
5159
|
+
"alignItems",
|
|
5160
|
+
"gap",
|
|
5161
|
+
"gridTemplateColumns",
|
|
5162
|
+
"gridTemplateRows",
|
|
5163
|
+
"justifyItems",
|
|
5164
|
+
"alignContent",
|
|
5165
|
+
"textDirection",
|
|
5166
|
+
"alignSelf",
|
|
5167
|
+
"order",
|
|
5168
|
+
"flexGrow",
|
|
5169
|
+
"flexShrink",
|
|
5170
|
+
"flexBasis",
|
|
5171
|
+
"justifySelf",
|
|
5172
|
+
"gridColumn",
|
|
5173
|
+
"gridRow",
|
|
5174
|
+
"width",
|
|
5175
|
+
"height",
|
|
5176
|
+
"minWidth",
|
|
5177
|
+
"minHeight",
|
|
5178
|
+
"maxWidth",
|
|
5179
|
+
"maxHeight",
|
|
5180
|
+
"aspectRatio",
|
|
5181
|
+
"objectFit",
|
|
5182
|
+
"overflow",
|
|
5183
|
+
"fontFamily",
|
|
5184
|
+
"fontSize",
|
|
5185
|
+
"fontWeight",
|
|
5186
|
+
"color",
|
|
5187
|
+
"lineHeight",
|
|
5188
|
+
"letterSpacing",
|
|
5189
|
+
"textTransform",
|
|
5190
|
+
"textAlign",
|
|
5191
|
+
"fontStyle",
|
|
5192
|
+
"textDecoration",
|
|
5193
|
+
"fontVariantNumeric",
|
|
5194
|
+
"_sep_stroke",
|
|
5195
|
+
"WebkitTextStrokeWidth",
|
|
5196
|
+
"WebkitTextStrokeColor",
|
|
5197
|
+
"margin",
|
|
5198
|
+
"padding",
|
|
5199
|
+
"borderWidth",
|
|
5200
|
+
"borderStyle",
|
|
5201
|
+
"borderColor",
|
|
5202
|
+
"borderRadius",
|
|
5203
|
+
"backgroundColor",
|
|
5204
|
+
"opacity",
|
|
5205
|
+
"mixBlendMode",
|
|
5206
|
+
"cursor",
|
|
5207
|
+
"_sep_shadow",
|
|
5208
|
+
"boxShadow",
|
|
5209
|
+
"textShadow",
|
|
5210
|
+
"_sep_transform",
|
|
5211
|
+
"translateX",
|
|
5212
|
+
"translateY",
|
|
5213
|
+
"scaleX",
|
|
5214
|
+
"scaleY",
|
|
5215
|
+
"rotate",
|
|
5216
|
+
"skewX",
|
|
5217
|
+
"skewY",
|
|
5218
|
+
"transformOrigin",
|
|
5219
|
+
"_sep_filter",
|
|
5220
|
+
"filterBlur",
|
|
5221
|
+
"filterHueRotate",
|
|
5222
|
+
"filterBrightness",
|
|
5223
|
+
"filterContrast",
|
|
5224
|
+
"filterSaturate",
|
|
5225
|
+
"filterGrayscale",
|
|
5226
|
+
"filterSepia",
|
|
5227
|
+
"filterInvert",
|
|
5228
|
+
"_sep_backdrop",
|
|
5229
|
+
"backdropFilter",
|
|
5230
|
+
"backdropBlur",
|
|
5231
|
+
"backdropBrightness",
|
|
5232
|
+
"backdropContrast",
|
|
5233
|
+
"backdropSaturate",
|
|
5234
|
+
"_sep_clip",
|
|
5235
|
+
"clipPath",
|
|
5236
|
+
"_sep_transition",
|
|
5237
|
+
"transitionProperty",
|
|
5238
|
+
"transitionDuration",
|
|
5239
|
+
"transitionDelay",
|
|
5240
|
+
"transitionTimingFunction"
|
|
5241
|
+
],
|
|
5242
|
+
"container": true
|
|
5243
|
+
},
|
|
5038
5244
|
"Video": {
|
|
5039
5245
|
"props": {
|
|
5040
5246
|
"videoSource": "youtube",
|
|
@@ -351,14 +351,18 @@ export const SCRIM_LEVELS: ReadonlyArray<ScrimLevel> = [ScrimLevel.Soft, ScrimLe
|
|
|
351
351
|
/** What each level writes on the scrim node (`backgroundColor`, token references only) — `null`: the style's own. */
|
|
352
352
|
export const SCRIM_BACKGROUND: Readonly<Record<ScrimLevel, string | null>> = {
|
|
353
353
|
[ScrimLevel.Soft]: null,
|
|
354
|
-
[ScrimLevel.Firm]: 'linear-gradient(180deg, transparent 0%, var(--iox-media-scrim)
|
|
354
|
+
[ScrimLevel.Firm]: 'linear-gradient(180deg, color-mix(in srgb, var(--iox-media-scrim) 75%, transparent) 0%, var(--iox-media-scrim) 35%)',
|
|
355
355
|
[ScrimLevel.Full]: 'var(--iox-media-scrim)',
|
|
356
356
|
};
|
|
357
357
|
|
|
358
|
-
/**
|
|
358
|
+
/**
|
|
359
|
+
* The least share of the scrim's own strength under the FIRST line of words, at each level — read from where the words
|
|
360
|
+
* start in the box (its top padding) against the gradient's ramp, on a phone (the tallest box): the element style's own
|
|
361
|
+
* ramp (`transparent 0%` → full at 45%) has only about a quarter of its strength there; Firm starts at three quarters.
|
|
362
|
+
*/
|
|
359
363
|
export const SCRIM_COVER: Readonly<Record<ScrimLevel, number>> = {
|
|
360
|
-
[ScrimLevel.Soft]: 0.
|
|
361
|
-
[ScrimLevel.Firm]: 0.
|
|
364
|
+
[ScrimLevel.Soft]: 0.25,
|
|
365
|
+
[ScrimLevel.Firm]: 0.75,
|
|
362
366
|
[ScrimLevel.Full]: 1,
|
|
363
367
|
};
|
|
364
368
|
|
|
@@ -131,8 +131,9 @@ export class ScrollDriver {
|
|
|
131
131
|
private lastTime = 0;
|
|
132
132
|
private readonly wakeUp = (): void => this.wake();
|
|
133
133
|
private readonly onWakeEvent = (e: Event): void => {
|
|
134
|
+
// What arrived may be the stage itself (a played slider marks its stage when it boots): read the root again.
|
|
134
135
|
const scene = [...this.scenes.values()].find(s => s.root.contains(e.target as Node));
|
|
135
|
-
if (scene)
|
|
136
|
+
if (scene) this.readScene(scene);
|
|
136
137
|
};
|
|
137
138
|
|
|
138
139
|
constructor(private readonly options: ScrollDriverOptions = {}) {
|
package/styles/iox-design.css
CHANGED
|
@@ -142,7 +142,7 @@ iox-gallery.iox-es-media[data-iox-empty] > .iox-gallery {
|
|
|
142
142
|
--iox-image-hover-scale: 1;
|
|
143
143
|
}
|
|
144
144
|
.iox-es-card .iox-es-media {
|
|
145
|
-
transition: transform var(--iox-dur-ui) var(--iox-ease-standard), scale var(--iox-dur-ui) var(--iox-ease-standard);
|
|
145
|
+
transition: transform var(--iox-dur-ui, 200ms) var(--iox-ease-standard), scale var(--iox-dur-ui, 200ms) var(--iox-ease-standard);
|
|
146
146
|
}
|
|
147
147
|
@media (hover: hover) and (pointer: fine) {
|
|
148
148
|
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link)):hover .iox-es-media {
|
|
@@ -157,7 +157,7 @@ iox-gallery.iox-es-media[data-iox-empty] > .iox-gallery {
|
|
|
157
157
|
forces its own), so the pseudo sits under the card's content and its shadow outside the card's edge. */
|
|
158
158
|
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link)) {
|
|
159
159
|
--iox-card-shadow-hover: var(--iox-card-shadow);
|
|
160
|
-
--iox-dur-base: var(--iox-dur-ui);
|
|
160
|
+
--iox-dur-base: var(--iox-dur-ui, 200ms);
|
|
161
161
|
translate: 0px;
|
|
162
162
|
}
|
|
163
163
|
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link))::before {
|
|
@@ -165,11 +165,11 @@ iox-gallery.iox-es-media[data-iox-empty] > .iox-gallery {
|
|
|
165
165
|
position: absolute;
|
|
166
166
|
inset: calc(var(--iox-card-border-width, 0px) * -1);
|
|
167
167
|
border-radius: inherit;
|
|
168
|
-
box-shadow: var(--iox-card-shadow-raise);
|
|
168
|
+
box-shadow: var(--iox-card-shadow-raise, var(--iox-shadow-md, none));
|
|
169
169
|
opacity: 0;
|
|
170
170
|
pointer-events: none;
|
|
171
171
|
z-index: -1;
|
|
172
|
-
transition: opacity var(--iox-dur-ui) var(--iox-ease-standard);
|
|
172
|
+
transition: opacity var(--iox-dur-ui, 200ms) var(--iox-ease-standard);
|
|
173
173
|
}
|
|
174
174
|
@media (hover: hover) and (pointer: fine) {
|
|
175
175
|
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link)):hover::before {
|
|
@@ -495,12 +495,15 @@ span.iox-video__play { pointer-events: none; }
|
|
|
495
495
|
display: inline-grid; place-items: center; width: 24px; height: 24px; margin: 0; padding: 0; border: 0; border-radius: var(--iox-radius-pill, 999px);
|
|
496
496
|
background: none; opacity: 1; cursor: pointer; color: inherit;
|
|
497
497
|
}
|
|
498
|
+
/* The dot grows into the pill by its CLIP (premium M4 — Emil 41: never an animated width): the pill is always 26px wide,
|
|
499
|
+
clipped to an 8px dot at rest and opened whole when current — a compositor property, the dot's round ends kept. */
|
|
498
500
|
.iox-role-slider-pagination .swiper-pagination-bullet::after {
|
|
499
|
-
content: ''; display: block; width:
|
|
500
|
-
|
|
501
|
+
content: ''; display: block; width: 26px; height: 8px; border-radius: var(--iox-radius-pill, 999px); background: var(--iox-line-strong);
|
|
502
|
+
clip-path: inset(0 9px round var(--iox-radius-pill, 999px));
|
|
503
|
+
transition: clip-path var(--iox-dur-fast) var(--iox-ease-standard), background-color var(--iox-dur-fast) var(--iox-ease-standard);
|
|
501
504
|
}
|
|
502
505
|
.iox-role-slider-pagination .swiper-pagination-bullet-active { width: 34px; }
|
|
503
|
-
.iox-role-slider-pagination .swiper-pagination-bullet-active::after {
|
|
506
|
+
.iox-role-slider-pagination .swiper-pagination-bullet-active::after { clip-path: inset(0 0 round var(--iox-radius-pill, 999px)); background: currentColor; }
|
|
504
507
|
.iox-role-slider-pagination .swiper-pagination-bullet:focus-visible { outline: none; box-shadow: var(--iox-focus-ring); }
|
|
505
508
|
|
|
506
509
|
/* ── The date picker's sheet (premium components N8) ────────────────────────────────────────────────
|
|
@@ -545,7 +548,7 @@ span.iox-video__play { pointer-events: none; }
|
|
|
545
548
|
block-size: 16px;
|
|
546
549
|
pointer-events: none;
|
|
547
550
|
opacity: 0;
|
|
548
|
-
transition: opacity var(--iox-dur-ui) var(--iox-ease-standard);
|
|
551
|
+
transition: opacity var(--iox-dur-ui, 200ms) var(--iox-ease-standard);
|
|
549
552
|
}
|
|
550
553
|
[data-iox-header][data-iox-header-edge='fade']::after {
|
|
551
554
|
background: linear-gradient(to bottom,
|
|
@@ -595,8 +598,8 @@ span.iox-video__play { pointer-events: none; }
|
|
|
595
598
|
.iox-es-link {
|
|
596
599
|
--iox-link-decoration: none;
|
|
597
600
|
--iox-link-current-decoration: none;
|
|
598
|
-
--iox-dur-fast: var(--iox-dur-hover);
|
|
599
|
-
--iox-ease-standard: var(--iox-ease-hover);
|
|
601
|
+
--iox-dur-fast: var(--iox-dur-hover, 150ms);
|
|
602
|
+
--iox-ease-standard: var(--iox-ease-hover, ease);
|
|
600
603
|
background-image: linear-gradient(currentColor, currentColor);
|
|
601
604
|
background-repeat: no-repeat;
|
|
602
605
|
background-position: 0% calc(100% - var(--iox-link-underline-offset, 0px));
|
|
@@ -627,14 +630,14 @@ span.iox-video__play { pointer-events: none; }
|
|
|
627
630
|
}
|
|
628
631
|
/* A chip's colour moves on the hover timing too (Emil 92 — M3's review). */
|
|
629
632
|
.iox-es-chip {
|
|
630
|
-
--iox-dur-fast: var(--iox-dur-hover);
|
|
631
|
-
--iox-ease-standard: var(--iox-ease-hover);
|
|
633
|
+
--iox-dur-fast: var(--iox-dur-hover, 150ms);
|
|
634
|
+
--iox-ease-standard: var(--iox-ease-hover, ease);
|
|
632
635
|
}
|
|
633
636
|
|
|
634
637
|
/* ── Premium components M4 (Emil 55/85): a press lands faster than its release ──────────────────────────────────────
|
|
635
638
|
While pressed, every pressable's transition runs on dur-press; it releases on its own (slower) dur-fast. */
|
|
636
639
|
:is(.iox-es-button-primary, .iox-es-button-secondary, .iox-es-button-ghost, .iox-es-bottom-bar-item):active {
|
|
637
|
-
transition-duration: var(--iox-dur-press);
|
|
640
|
+
transition-duration: var(--iox-dur-press, 100ms);
|
|
638
641
|
}
|
|
639
642
|
|
|
640
643
|
/* ── Premium components M4 (T3): the Slider's feel, its bar and the slider the scroll plays ─────────────────────────
|
|
@@ -664,7 +667,7 @@ span.iox-video__play { pointer-events: none; }
|
|
|
664
667
|
}
|
|
665
668
|
/* The caption follows the slide in view: it changes behind a short fade (the runtime holds it at 0 for a frame). */
|
|
666
669
|
.iox-role-slider-caption {
|
|
667
|
-
transition: opacity var(--iox-dur-hover) var(--iox-ease-hover);
|
|
670
|
+
transition: opacity var(--iox-dur-hover, 150ms) var(--iox-ease-hover, ease);
|
|
668
671
|
}
|
|
669
672
|
.iox-role-slider-caption[data-iox-swapping] {
|
|
670
673
|
opacity: 0;
|
|
@@ -705,3 +708,202 @@ span.iox-video__play { pointer-events: none; }
|
|
|
705
708
|
}
|
|
706
709
|
}
|
|
707
710
|
|
|
711
|
+
/* ── The floating family (premium components M5 — N3 toast · N4 tooltip and popover) ──────────────────────────────
|
|
712
|
+
ONE motion grammar for all three: they come FROM where they belong — a tooltip and a popover grow from their trigger
|
|
713
|
+
(the transform-origin placeFloating writes, Emil 47), a toast slides from its edge and back to it (Emil 129–130) —
|
|
714
|
+
and leave faster than they came (Emil 30). A neighbour tooltip, a keyboard open and Esc have no motion at all
|
|
715
|
+
(`data-iox-instant`, Emil 2/125). On a page that wears the design system the look's tokens time them (a look whose
|
|
716
|
+
motion is Off: 0ms); under reduced motion they keep the fade and drop the movement (Emil 192). The element styles'
|
|
717
|
+
colours and type are the contract's floating baseline, verbatim (`.iox-es-tooltip` / `.iox-es-toast`, pinned by the
|
|
718
|
+
token-names spec); a legacy page keeps the neutral literals of the unmarked rules. */
|
|
719
|
+
|
|
720
|
+
/* The layer they are placed in: the viewport on the site (a top-layer popover, so a fixed header, a slider's clip or a
|
|
721
|
+
nav's backdrop-filter cannot hold them), the page frame on the canvas (fixed inside the zoomed frame). */
|
|
722
|
+
.iox-float-layer {
|
|
723
|
+
position: fixed;
|
|
724
|
+
inset: 0;
|
|
725
|
+
width: auto;
|
|
726
|
+
height: auto;
|
|
727
|
+
max-width: none;
|
|
728
|
+
max-height: none;
|
|
729
|
+
margin: 0;
|
|
730
|
+
padding: 0;
|
|
731
|
+
border: 0;
|
|
732
|
+
background: transparent;
|
|
733
|
+
color: inherit;
|
|
734
|
+
overflow: visible;
|
|
735
|
+
pointer-events: none;
|
|
736
|
+
z-index: 60;
|
|
737
|
+
}
|
|
738
|
+
.iox-float-layer[popover]:not(:popover-open) { display: none; }
|
|
739
|
+
|
|
740
|
+
/* The tooltip. */
|
|
741
|
+
.iox-tooltip {
|
|
742
|
+
--tip-scale: 0.97;
|
|
743
|
+
position: absolute;
|
|
744
|
+
top: 0;
|
|
745
|
+
left: 0;
|
|
746
|
+
box-sizing: border-box;
|
|
747
|
+
max-width: min(280px, calc(100% - 24px));
|
|
748
|
+
padding: 6px 10px;
|
|
749
|
+
font: 500 13px/1.35 system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
750
|
+
background-color: #1f2328;
|
|
751
|
+
color: #ffffff;
|
|
752
|
+
border-radius: 6px;
|
|
753
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
|
|
754
|
+
overflow-wrap: anywhere;
|
|
755
|
+
text-align: start;
|
|
756
|
+
pointer-events: auto;
|
|
757
|
+
transition: opacity 125ms cubic-bezier(0.23, 1, 0.32, 1), scale 125ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
758
|
+
}
|
|
759
|
+
.iox-tooltip[hidden] { display: none; }
|
|
760
|
+
@starting-style { .iox-tooltip:not([hidden]) { opacity: 0; scale: var(--tip-scale); } }
|
|
761
|
+
.iox-tooltip[data-iox-closing] { opacity: 0; scale: var(--tip-scale); transition-duration: 80ms; }
|
|
762
|
+
.iox-es-tooltip {
|
|
763
|
+
background-color: var(--iox-tooltip-bg);
|
|
764
|
+
color: var(--iox-tooltip-ink);
|
|
765
|
+
border-radius: var(--iox-tooltip-radius);
|
|
766
|
+
box-shadow: var(--iox-tooltip-shadow);
|
|
767
|
+
font-family: var(--iox-font-body);
|
|
768
|
+
font-size: var(--iox-tooltip-size);
|
|
769
|
+
font-weight: var(--iox-weight-strong);
|
|
770
|
+
}
|
|
771
|
+
.iox-tooltip.iox-es-tooltip {
|
|
772
|
+
--tip-scale: var(--iox-tooltip-scale);
|
|
773
|
+
transition: opacity var(--iox-tooltip-dur-in) var(--iox-tooltip-ease), scale var(--iox-tooltip-dur-in) var(--iox-tooltip-ease);
|
|
774
|
+
}
|
|
775
|
+
.iox-tooltip.iox-es-tooltip[data-iox-closing] { transition-duration: var(--iox-tooltip-dur-out); }
|
|
776
|
+
.iox-tooltip[data-iox-instant],
|
|
777
|
+
.iox-tooltip.iox-es-tooltip[data-iox-instant] { transition: none; }
|
|
778
|
+
|
|
779
|
+
/* The toast stack, at its edge — above the home indicator (M7) and above a bottom tab bar (CC1's reserve). */
|
|
780
|
+
.iox-toasts {
|
|
781
|
+
position: absolute;
|
|
782
|
+
inset-inline: 0;
|
|
783
|
+
display: flex;
|
|
784
|
+
flex-direction: column;
|
|
785
|
+
align-items: center;
|
|
786
|
+
gap: 8px;
|
|
787
|
+
padding-inline: 16px;
|
|
788
|
+
box-sizing: border-box;
|
|
789
|
+
pointer-events: none;
|
|
790
|
+
}
|
|
791
|
+
.iox-toasts[data-iox-edge='bottom'] { bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
|
|
792
|
+
.iox-toasts[data-iox-edge='top'] { top: calc(16px + env(safe-area-inset-top, 0px)); flex-direction: column-reverse; }
|
|
793
|
+
html:has(.iox-bar-reserve) .iox-toasts[data-iox-edge='bottom'] { bottom: calc(16px + var(--iox-tabbar-height, 64px) + env(safe-area-inset-bottom, 0px)); }
|
|
794
|
+
.iox-toast {
|
|
795
|
+
--toast-from: translateY(100%);
|
|
796
|
+
pointer-events: auto;
|
|
797
|
+
box-sizing: border-box;
|
|
798
|
+
display: flex;
|
|
799
|
+
align-items: center;
|
|
800
|
+
gap: 8px;
|
|
801
|
+
max-width: min(440px, 100%);
|
|
802
|
+
padding-block: 10px;
|
|
803
|
+
padding-inline: 16px 6px;
|
|
804
|
+
font: 500 15px/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
805
|
+
background-color: #1f2328;
|
|
806
|
+
color: #ffffff;
|
|
807
|
+
border-radius: 10px;
|
|
808
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
|
|
809
|
+
transition: transform 400ms ease, opacity 400ms ease;
|
|
810
|
+
}
|
|
811
|
+
.iox-toasts[data-iox-edge='top'] .iox-toast { --toast-from: translateY(-100%); }
|
|
812
|
+
@starting-style { .iox-toast { opacity: 0; transform: var(--toast-from); } }
|
|
813
|
+
.iox-toast[data-iox-closing] { opacity: 0; transform: var(--toast-from); transition-duration: 220ms; }
|
|
814
|
+
.iox-es-toast {
|
|
815
|
+
background-color: var(--iox-toast-bg);
|
|
816
|
+
color: var(--iox-toast-ink);
|
|
817
|
+
border-radius: var(--iox-toast-radius);
|
|
818
|
+
box-shadow: var(--iox-toast-shadow);
|
|
819
|
+
font-family: var(--iox-font-body);
|
|
820
|
+
font-size: var(--iox-size-body);
|
|
821
|
+
font-weight: var(--iox-weight-strong);
|
|
822
|
+
}
|
|
823
|
+
.iox-toast.iox-es-toast { transition: transform var(--iox-toast-dur-in) var(--iox-toast-ease), opacity var(--iox-toast-dur-in) var(--iox-toast-ease); }
|
|
824
|
+
.iox-toast.iox-es-toast[data-iox-closing] { transition-duration: var(--iox-toast-dur-out); }
|
|
825
|
+
.iox-toast__text { margin: 0; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
|
|
826
|
+
/* The close control: a 44px target (M2) drawn in the toast's own ink, whatever the look — its ring too (currentColor
|
|
827
|
+
on the toast's fill is the pair the toast already clears). */
|
|
828
|
+
.iox-toast__close {
|
|
829
|
+
flex: none;
|
|
830
|
+
display: inline-grid;
|
|
831
|
+
place-items: center;
|
|
832
|
+
inline-size: 44px;
|
|
833
|
+
block-size: 44px;
|
|
834
|
+
margin-block: -8px;
|
|
835
|
+
padding: 0;
|
|
836
|
+
border: 0;
|
|
837
|
+
border-radius: 999px;
|
|
838
|
+
background: transparent;
|
|
839
|
+
color: inherit;
|
|
840
|
+
cursor: pointer;
|
|
841
|
+
opacity: 0.8;
|
|
842
|
+
touch-action: manipulation;
|
|
843
|
+
transition: opacity 150ms ease-out, background-color 150ms ease-out;
|
|
844
|
+
}
|
|
845
|
+
.iox-toast__close:focus-visible { outline: 2px solid currentColor; outline-offset: -4px; opacity: 1; }
|
|
846
|
+
@media (hover: hover) and (pointer: fine) {
|
|
847
|
+
.iox-toast__close:hover { opacity: 1; background-color: color-mix(in srgb, currentColor 14%, transparent); }
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/* The popover — the node itself, in the top layer beside its opener (placeFloating writes top / left / the origin).
|
|
851
|
+
Closed it is the browser's hidden popover; the panel takes focus on open and draws no ring (its controls do). */
|
|
852
|
+
[data-iox-popover] { box-sizing: border-box; }
|
|
853
|
+
[data-iox-popover][popover] {
|
|
854
|
+
--pop-scale: 0.95;
|
|
855
|
+
position: fixed;
|
|
856
|
+
inset: auto;
|
|
857
|
+
margin: 0;
|
|
858
|
+
max-width: calc(100vw - 24px);
|
|
859
|
+
max-height: calc(100dvh - 24px);
|
|
860
|
+
overflow: auto;
|
|
861
|
+
overscroll-behavior: contain;
|
|
862
|
+
outline: none;
|
|
863
|
+
transition: opacity 200ms cubic-bezier(0.23, 1, 0.32, 1), scale 200ms cubic-bezier(0.23, 1, 0.32, 1), overlay 200ms allow-discrete, display 200ms allow-discrete;
|
|
864
|
+
}
|
|
865
|
+
@starting-style { [data-iox-popover][popover]:popover-open { opacity: 0; scale: var(--pop-scale); } }
|
|
866
|
+
[data-iox-popover][popover][data-iox-closing] { opacity: 0; scale: var(--pop-scale); transition-duration: 140ms; }
|
|
867
|
+
.iox-es-popover[data-iox-popover][popover] {
|
|
868
|
+
--pop-scale: var(--iox-popover-scale);
|
|
869
|
+
transition: opacity var(--iox-popover-dur-in) var(--iox-popover-ease), scale var(--iox-popover-dur-in) var(--iox-popover-ease),
|
|
870
|
+
overlay var(--iox-popover-dur-in) allow-discrete, display var(--iox-popover-dur-in) allow-discrete;
|
|
871
|
+
}
|
|
872
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-closing] { transition-duration: var(--iox-popover-dur-out); }
|
|
873
|
+
/* On a phone: a bottom sheet over the scrim, the safe area kept (the date picker's decision, FLOATING_SHEET_QUERY). */
|
|
874
|
+
[data-iox-popover][popover][data-iox-sheet] {
|
|
875
|
+
inset: auto 0 0 0;
|
|
876
|
+
width: 100%;
|
|
877
|
+
max-width: none;
|
|
878
|
+
max-height: 85dvh;
|
|
879
|
+
border-end-start-radius: 0;
|
|
880
|
+
border-end-end-radius: 0;
|
|
881
|
+
padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
|
|
882
|
+
transition: translate 500ms cubic-bezier(0.32, 0.72, 0, 1), overlay 500ms allow-discrete, display 500ms allow-discrete;
|
|
883
|
+
}
|
|
884
|
+
@starting-style { [data-iox-popover][popover][data-iox-sheet]:popover-open { opacity: 1; scale: 1; translate: 0 100%; } }
|
|
885
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-closing] { opacity: 1; scale: 1; translate: 0 100%; transition-duration: 280ms; }
|
|
886
|
+
[data-iox-popover][popover][data-iox-sheet]::backdrop { background: rgba(0, 0, 0, 0.45); transition: opacity 500ms cubic-bezier(0.32, 0.72, 0, 1); }
|
|
887
|
+
@starting-style { [data-iox-popover][popover][data-iox-sheet]:popover-open::backdrop { opacity: 0; } }
|
|
888
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-closing]::backdrop { opacity: 0; transition-duration: 280ms; }
|
|
889
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet] {
|
|
890
|
+
padding-bottom: calc(var(--iox-popover-pad) + env(safe-area-inset-bottom, 0px));
|
|
891
|
+
transition: translate var(--iox-sheet-dur-in) var(--iox-sheet-ease), overlay var(--iox-sheet-dur-in) allow-discrete, display var(--iox-sheet-dur-in) allow-discrete;
|
|
892
|
+
}
|
|
893
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet][data-iox-closing] { transition-duration: var(--iox-sheet-dur-out); }
|
|
894
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet]::backdrop { background: var(--iox-scrim); transition: opacity var(--iox-sheet-dur-in) var(--iox-sheet-ease); }
|
|
895
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet][data-iox-closing]::backdrop { transition-duration: var(--iox-sheet-dur-out); }
|
|
896
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-instant],
|
|
897
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-instant]::backdrop,
|
|
898
|
+
[data-iox-popover][popover][data-iox-instant],
|
|
899
|
+
[data-iox-popover][popover][data-iox-instant]::backdrop { transition: none; }
|
|
900
|
+
|
|
901
|
+
/* Reduced motion: each of them fades — gentler, not zero; nothing scales or slides. */
|
|
902
|
+
@media (prefers-reduced-motion: reduce) {
|
|
903
|
+
.iox-tooltip.iox-tooltip,
|
|
904
|
+
[data-iox-popover][popover][popover] { --tip-scale: 1; --pop-scale: 1; }
|
|
905
|
+
.iox-toasts[data-iox-edge] .iox-toast.iox-toast { --toast-from: none; }
|
|
906
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-sheet] { transition-property: opacity, overlay, display; }
|
|
907
|
+
@starting-style { [data-iox-popover][popover][data-iox-sheet][data-iox-sheet]:popover-open { opacity: 0; translate: none; } }
|
|
908
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-sheet][data-iox-closing] { opacity: 0; translate: none; }
|
|
909
|
+
}
|