@vectoriox/iox-ui 5.85.0 → 5.86.0
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 +215 -8
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +1261 -67
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/forms-core/index.d.ts +23 -4
- package/index.d.ts +422 -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/styles/iox-design.css +199 -0
- 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",
|
package/styles/iox-design.css
CHANGED
|
@@ -705,3 +705,202 @@ span.iox-video__play { pointer-events: none; }
|
|
|
705
705
|
}
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
+
/* ── The floating family (premium components M5 — N3 toast · N4 tooltip and popover) ──────────────────────────────
|
|
709
|
+
ONE motion grammar for all three: they come FROM where they belong — a tooltip and a popover grow from their trigger
|
|
710
|
+
(the transform-origin placeFloating writes, Emil 47), a toast slides from its edge and back to it (Emil 129–130) —
|
|
711
|
+
and leave faster than they came (Emil 30). A neighbour tooltip, a keyboard open and Esc have no motion at all
|
|
712
|
+
(`data-iox-instant`, Emil 2/125). On a page that wears the design system the look's tokens time them (a look whose
|
|
713
|
+
motion is Off: 0ms); under reduced motion they keep the fade and drop the movement (Emil 192). The element styles'
|
|
714
|
+
colours and type are the contract's floating baseline, verbatim (`.iox-es-tooltip` / `.iox-es-toast`, pinned by the
|
|
715
|
+
token-names spec); a legacy page keeps the neutral literals of the unmarked rules. */
|
|
716
|
+
|
|
717
|
+
/* 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
|
|
718
|
+
nav's backdrop-filter cannot hold them), the page frame on the canvas (fixed inside the zoomed frame). */
|
|
719
|
+
.iox-float-layer {
|
|
720
|
+
position: fixed;
|
|
721
|
+
inset: 0;
|
|
722
|
+
width: auto;
|
|
723
|
+
height: auto;
|
|
724
|
+
max-width: none;
|
|
725
|
+
max-height: none;
|
|
726
|
+
margin: 0;
|
|
727
|
+
padding: 0;
|
|
728
|
+
border: 0;
|
|
729
|
+
background: transparent;
|
|
730
|
+
color: inherit;
|
|
731
|
+
overflow: visible;
|
|
732
|
+
pointer-events: none;
|
|
733
|
+
z-index: 60;
|
|
734
|
+
}
|
|
735
|
+
.iox-float-layer[popover]:not(:popover-open) { display: none; }
|
|
736
|
+
|
|
737
|
+
/* The tooltip. */
|
|
738
|
+
.iox-tooltip {
|
|
739
|
+
--tip-scale: 0.97;
|
|
740
|
+
position: absolute;
|
|
741
|
+
top: 0;
|
|
742
|
+
left: 0;
|
|
743
|
+
box-sizing: border-box;
|
|
744
|
+
max-width: min(280px, calc(100% - 24px));
|
|
745
|
+
padding: 6px 10px;
|
|
746
|
+
font: 500 13px/1.35 system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
747
|
+
background-color: #1f2328;
|
|
748
|
+
color: #ffffff;
|
|
749
|
+
border-radius: 6px;
|
|
750
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
|
|
751
|
+
overflow-wrap: anywhere;
|
|
752
|
+
text-align: start;
|
|
753
|
+
pointer-events: auto;
|
|
754
|
+
transition: opacity 125ms cubic-bezier(0.23, 1, 0.32, 1), scale 125ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
755
|
+
}
|
|
756
|
+
.iox-tooltip[hidden] { display: none; }
|
|
757
|
+
@starting-style { .iox-tooltip:not([hidden]) { opacity: 0; scale: var(--tip-scale); } }
|
|
758
|
+
.iox-tooltip[data-iox-closing] { opacity: 0; scale: var(--tip-scale); transition-duration: 80ms; }
|
|
759
|
+
.iox-es-tooltip {
|
|
760
|
+
background-color: var(--iox-tooltip-bg);
|
|
761
|
+
color: var(--iox-tooltip-ink);
|
|
762
|
+
border-radius: var(--iox-tooltip-radius);
|
|
763
|
+
box-shadow: var(--iox-tooltip-shadow);
|
|
764
|
+
font-family: var(--iox-font-body);
|
|
765
|
+
font-size: var(--iox-tooltip-size);
|
|
766
|
+
font-weight: var(--iox-weight-strong);
|
|
767
|
+
}
|
|
768
|
+
.iox-tooltip.iox-es-tooltip {
|
|
769
|
+
--tip-scale: var(--iox-tooltip-scale);
|
|
770
|
+
transition: opacity var(--iox-tooltip-dur-in) var(--iox-tooltip-ease), scale var(--iox-tooltip-dur-in) var(--iox-tooltip-ease);
|
|
771
|
+
}
|
|
772
|
+
.iox-tooltip.iox-es-tooltip[data-iox-closing] { transition-duration: var(--iox-tooltip-dur-out); }
|
|
773
|
+
.iox-tooltip[data-iox-instant],
|
|
774
|
+
.iox-tooltip.iox-es-tooltip[data-iox-instant] { transition: none; }
|
|
775
|
+
|
|
776
|
+
/* The toast stack, at its edge — above the home indicator (M7) and above a bottom tab bar (CC1's reserve). */
|
|
777
|
+
.iox-toasts {
|
|
778
|
+
position: absolute;
|
|
779
|
+
inset-inline: 0;
|
|
780
|
+
display: flex;
|
|
781
|
+
flex-direction: column;
|
|
782
|
+
align-items: center;
|
|
783
|
+
gap: 8px;
|
|
784
|
+
padding-inline: 16px;
|
|
785
|
+
box-sizing: border-box;
|
|
786
|
+
pointer-events: none;
|
|
787
|
+
}
|
|
788
|
+
.iox-toasts[data-iox-edge='bottom'] { bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
|
|
789
|
+
.iox-toasts[data-iox-edge='top'] { top: calc(16px + env(safe-area-inset-top, 0px)); flex-direction: column-reverse; }
|
|
790
|
+
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)); }
|
|
791
|
+
.iox-toast {
|
|
792
|
+
--toast-from: translateY(100%);
|
|
793
|
+
pointer-events: auto;
|
|
794
|
+
box-sizing: border-box;
|
|
795
|
+
display: flex;
|
|
796
|
+
align-items: center;
|
|
797
|
+
gap: 8px;
|
|
798
|
+
max-width: min(440px, 100%);
|
|
799
|
+
padding-block: 10px;
|
|
800
|
+
padding-inline: 16px 6px;
|
|
801
|
+
font: 500 15px/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
802
|
+
background-color: #1f2328;
|
|
803
|
+
color: #ffffff;
|
|
804
|
+
border-radius: 10px;
|
|
805
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
|
|
806
|
+
transition: transform 400ms ease, opacity 400ms ease;
|
|
807
|
+
}
|
|
808
|
+
.iox-toasts[data-iox-edge='top'] .iox-toast { --toast-from: translateY(-100%); }
|
|
809
|
+
@starting-style { .iox-toast { opacity: 0; transform: var(--toast-from); } }
|
|
810
|
+
.iox-toast[data-iox-closing] { opacity: 0; transform: var(--toast-from); transition-duration: 220ms; }
|
|
811
|
+
.iox-es-toast {
|
|
812
|
+
background-color: var(--iox-toast-bg);
|
|
813
|
+
color: var(--iox-toast-ink);
|
|
814
|
+
border-radius: var(--iox-toast-radius);
|
|
815
|
+
box-shadow: var(--iox-toast-shadow);
|
|
816
|
+
font-family: var(--iox-font-body);
|
|
817
|
+
font-size: var(--iox-size-body);
|
|
818
|
+
font-weight: var(--iox-weight-strong);
|
|
819
|
+
}
|
|
820
|
+
.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); }
|
|
821
|
+
.iox-toast.iox-es-toast[data-iox-closing] { transition-duration: var(--iox-toast-dur-out); }
|
|
822
|
+
.iox-toast__text { margin: 0; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
|
|
823
|
+
/* The close control: a 44px target (M2) drawn in the toast's own ink, whatever the look — its ring too (currentColor
|
|
824
|
+
on the toast's fill is the pair the toast already clears). */
|
|
825
|
+
.iox-toast__close {
|
|
826
|
+
flex: none;
|
|
827
|
+
display: inline-grid;
|
|
828
|
+
place-items: center;
|
|
829
|
+
inline-size: 44px;
|
|
830
|
+
block-size: 44px;
|
|
831
|
+
margin-block: -8px;
|
|
832
|
+
padding: 0;
|
|
833
|
+
border: 0;
|
|
834
|
+
border-radius: 999px;
|
|
835
|
+
background: transparent;
|
|
836
|
+
color: inherit;
|
|
837
|
+
cursor: pointer;
|
|
838
|
+
opacity: 0.8;
|
|
839
|
+
touch-action: manipulation;
|
|
840
|
+
transition: opacity 150ms ease-out, background-color 150ms ease-out;
|
|
841
|
+
}
|
|
842
|
+
.iox-toast__close:focus-visible { outline: 2px solid currentColor; outline-offset: -4px; opacity: 1; }
|
|
843
|
+
@media (hover: hover) and (pointer: fine) {
|
|
844
|
+
.iox-toast__close:hover { opacity: 1; background-color: color-mix(in srgb, currentColor 14%, transparent); }
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/* The popover — the node itself, in the top layer beside its opener (placeFloating writes top / left / the origin).
|
|
848
|
+
Closed it is the browser's hidden popover; the panel takes focus on open and draws no ring (its controls do). */
|
|
849
|
+
[data-iox-popover] { box-sizing: border-box; }
|
|
850
|
+
[data-iox-popover][popover] {
|
|
851
|
+
--pop-scale: 0.95;
|
|
852
|
+
position: fixed;
|
|
853
|
+
inset: auto;
|
|
854
|
+
margin: 0;
|
|
855
|
+
max-width: calc(100vw - 24px);
|
|
856
|
+
max-height: calc(100dvh - 24px);
|
|
857
|
+
overflow: auto;
|
|
858
|
+
overscroll-behavior: contain;
|
|
859
|
+
outline: none;
|
|
860
|
+
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;
|
|
861
|
+
}
|
|
862
|
+
@starting-style { [data-iox-popover][popover]:popover-open { opacity: 0; scale: var(--pop-scale); } }
|
|
863
|
+
[data-iox-popover][popover][data-iox-closing] { opacity: 0; scale: var(--pop-scale); transition-duration: 140ms; }
|
|
864
|
+
.iox-es-popover[data-iox-popover][popover] {
|
|
865
|
+
--pop-scale: var(--iox-popover-scale);
|
|
866
|
+
transition: opacity var(--iox-popover-dur-in) var(--iox-popover-ease), scale var(--iox-popover-dur-in) var(--iox-popover-ease),
|
|
867
|
+
overlay var(--iox-popover-dur-in) allow-discrete, display var(--iox-popover-dur-in) allow-discrete;
|
|
868
|
+
}
|
|
869
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-closing] { transition-duration: var(--iox-popover-dur-out); }
|
|
870
|
+
/* On a phone: a bottom sheet over the scrim, the safe area kept (the date picker's decision, FLOATING_SHEET_QUERY). */
|
|
871
|
+
[data-iox-popover][popover][data-iox-sheet] {
|
|
872
|
+
inset: auto 0 0 0;
|
|
873
|
+
width: 100%;
|
|
874
|
+
max-width: none;
|
|
875
|
+
max-height: 85dvh;
|
|
876
|
+
border-end-start-radius: 0;
|
|
877
|
+
border-end-end-radius: 0;
|
|
878
|
+
padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
|
|
879
|
+
transition: translate 500ms cubic-bezier(0.32, 0.72, 0, 1), overlay 500ms allow-discrete, display 500ms allow-discrete;
|
|
880
|
+
}
|
|
881
|
+
@starting-style { [data-iox-popover][popover][data-iox-sheet]:popover-open { opacity: 1; scale: 1; translate: 0 100%; } }
|
|
882
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-closing] { opacity: 1; scale: 1; translate: 0 100%; transition-duration: 280ms; }
|
|
883
|
+
[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); }
|
|
884
|
+
@starting-style { [data-iox-popover][popover][data-iox-sheet]:popover-open::backdrop { opacity: 0; } }
|
|
885
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-closing]::backdrop { opacity: 0; transition-duration: 280ms; }
|
|
886
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet] {
|
|
887
|
+
padding-bottom: calc(var(--iox-popover-pad) + env(safe-area-inset-bottom, 0px));
|
|
888
|
+
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;
|
|
889
|
+
}
|
|
890
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet][data-iox-closing] { transition-duration: var(--iox-sheet-dur-out); }
|
|
891
|
+
.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); }
|
|
892
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-sheet][data-iox-closing]::backdrop { transition-duration: var(--iox-sheet-dur-out); }
|
|
893
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-instant],
|
|
894
|
+
.iox-es-popover[data-iox-popover][popover][data-iox-instant]::backdrop,
|
|
895
|
+
[data-iox-popover][popover][data-iox-instant],
|
|
896
|
+
[data-iox-popover][popover][data-iox-instant]::backdrop { transition: none; }
|
|
897
|
+
|
|
898
|
+
/* Reduced motion: each of them fades — gentler, not zero; nothing scales or slides. */
|
|
899
|
+
@media (prefers-reduced-motion: reduce) {
|
|
900
|
+
.iox-tooltip.iox-tooltip,
|
|
901
|
+
[data-iox-popover][popover][popover] { --tip-scale: 1; --pop-scale: 1; }
|
|
902
|
+
.iox-toasts[data-iox-edge] .iox-toast.iox-toast { --toast-from: none; }
|
|
903
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-sheet] { transition-property: opacity, overlay, display; }
|
|
904
|
+
@starting-style { [data-iox-popover][popover][data-iox-sheet][data-iox-sheet]:popover-open { opacity: 0; translate: none; } }
|
|
905
|
+
[data-iox-popover][popover][data-iox-sheet][data-iox-sheet][data-iox-closing] { opacity: 0; translate: none; }
|
|
906
|
+
}
|
package/styles/iox-forms.css
CHANGED
|
@@ -36,8 +36,11 @@
|
|
|
36
36
|
has to be able to fix and retry. The submit button STAYS (premium N2: it reads "Sent" with its check,
|
|
37
37
|
disabled — the success in place), and so does the row holding it or the second channel (the WhatsApp
|
|
38
38
|
button beside Send is how a visitor reaches you AFTER sending too). */
|
|
39
|
-
.iox-form[data-iox-state="success"] .iox-field,
|
|
40
|
-
.iox-form[data-iox-state="success"] .iox-field-group:not(:has(.iox-submit, .iox-role-form-channel)) { display: none !important; }
|
|
39
|
+
.iox-form[data-iox-state="success"]:not([data-iox-after-send="toast"]) .iox-field,
|
|
40
|
+
.iox-form[data-iox-state="success"]:not([data-iox-after-send="toast"]) .iox-field-group:not(:has(.iox-submit, .iox-role-form-channel)) { display: none !important; }
|
|
41
|
+
/* A form that KEEPS its fields after sending (premium M5 — After sending ▸ "Keep the fields and show a toast") never
|
|
42
|
+
shows its Success block: a toast says the Sent words and the fields stay, cleared for the next answer. */
|
|
43
|
+
.iox-form[data-iox-after-send="toast"] .iox-form-success { display: none !important; }
|
|
41
44
|
|
|
42
45
|
/* The Success and Error blocks ENTER (premium N2 — Emil 139/30): opacity and a 4px rise over 200ms, out in 120ms,
|
|
43
46
|
transitions (a fast retry interrupts from the live value, never a restart). `display` is discrete, so the exit
|
|
@@ -240,6 +243,25 @@ dialog.iox-cal::backdrop { background: transparent; }
|
|
|
240
243
|
@starting-style { dialog.iox-cal[open] { opacity: 0; transform: none; } }
|
|
241
244
|
dialog.iox-cal[data-iox-closing] { opacity: 0; transition-duration: 120ms; }
|
|
242
245
|
}
|
|
246
|
+
/* A Date field that wears the design system is timed by the LOOK (premium M5 — the calendar is a popover, and a sheet on
|
|
247
|
+
a phone): the popover tokens on a laptop, the sheet's on a phone, so a look whose motion is Off opens it with no motion
|
|
248
|
+
at all (vectoriox/iox-ui#44). Reduced motion keeps the fade (the tokens survive it) and drops the movement. */
|
|
249
|
+
.iox-es-field dialog.iox-cal {
|
|
250
|
+
transition: opacity var(--iox-popover-dur-in) var(--iox-popover-ease), transform var(--iox-popover-dur-in) var(--iox-popover-ease);
|
|
251
|
+
}
|
|
252
|
+
@starting-style { .iox-es-field dialog.iox-cal[open] { transform: scale(var(--iox-popover-scale)); } }
|
|
253
|
+
.iox-es-field dialog.iox-cal[data-iox-closing] { transform: scale(var(--iox-popover-scale)); transition-duration: var(--iox-popover-dur-out); }
|
|
254
|
+
@media (max-width: 767px) {
|
|
255
|
+
.iox-es-field dialog.iox-cal { transform: none; transition: transform var(--iox-sheet-dur-in) var(--iox-sheet-ease); }
|
|
256
|
+
@starting-style { .iox-es-field dialog.iox-cal[open] { transform: translateY(100%); } }
|
|
257
|
+
.iox-es-field dialog.iox-cal[data-iox-closing] { transform: translateY(100%); transition-duration: var(--iox-sheet-dur-out); transition-timing-function: var(--iox-sheet-ease); }
|
|
258
|
+
.iox-es-field dialog.iox-cal::backdrop { transition: opacity var(--iox-sheet-dur-in) var(--iox-sheet-ease); }
|
|
259
|
+
.iox-es-field dialog.iox-cal[data-iox-closing]::backdrop { transition-duration: var(--iox-sheet-dur-out); }
|
|
260
|
+
}
|
|
261
|
+
@media (prefers-reduced-motion: reduce) {
|
|
262
|
+
.iox-es-field dialog.iox-cal, .iox-es-field dialog.iox-cal[data-iox-closing] { transform: none !important; transition: opacity var(--iox-popover-dur-in) var(--iox-popover-ease); }
|
|
263
|
+
.iox-es-field dialog.iox-cal[data-iox-closing] { transition-duration: var(--iox-popover-dur-out); }
|
|
264
|
+
}
|
|
243
265
|
/* Opened from the KEYBOARD (Enter / Space on the date button): it simply appears, and Esc or Enter on a day closes it
|
|
244
266
|
at once — keyboard-initiated actions never animate (Emil 2). The pointer gets the motion above. */
|
|
245
267
|
dialog.iox-cal[data-iox-instant],
|