ionbase-ui 0.59.0 → 0.69.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/dist/components/AgentActivity.d.ts +2 -1
- package/dist/components/AgentActivity.d.ts.map +1 -1
- package/dist/components/AgentActivity.js +4 -17
- package/dist/components/AgentActivity.js.map +1 -1
- package/dist/components/Calendar.d.ts +20 -0
- package/dist/components/Calendar.d.ts.map +1 -0
- package/dist/components/Calendar.js +151 -0
- package/dist/components/Calendar.js.map +1 -0
- package/dist/components/CalendarPopover.d.ts +26 -0
- package/dist/components/CalendarPopover.d.ts.map +1 -0
- package/dist/components/CalendarPopover.js +45 -0
- package/dist/components/CalendarPopover.js.map +1 -0
- package/dist/components/DateField.d.ts +15 -0
- package/dist/components/DateField.d.ts.map +1 -0
- package/dist/components/DateField.js +74 -0
- package/dist/components/DateField.js.map +1 -0
- package/dist/components/DatePicker.d.ts +81 -0
- package/dist/components/DatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker.js +102 -0
- package/dist/components/DatePicker.js.map +1 -0
- package/dist/components/DateRangePicker.d.ts +117 -0
- package/dist/components/DateRangePicker.d.ts.map +1 -0
- package/dist/components/DateRangePicker.js +152 -0
- package/dist/components/DateRangePicker.js.map +1 -0
- package/dist/components/Header.d.ts +10 -0
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +18 -3
- package/dist/components/Header.js.map +1 -1
- package/dist/components/NumberInput.d.ts +63 -0
- package/dist/components/NumberInput.d.ts.map +1 -0
- package/dist/components/NumberInput.js +102 -0
- package/dist/components/NumberInput.js.map +1 -0
- package/dist/components/PromptInput.d.ts +89 -0
- package/dist/components/PromptInput.d.ts.map +1 -0
- package/dist/components/PromptInput.js +130 -0
- package/dist/components/PromptInput.js.map +1 -0
- package/dist/components/SegmentedControl.d.ts +63 -0
- package/dist/components/SegmentedControl.d.ts.map +1 -0
- package/dist/components/SegmentedControl.js +79 -0
- package/dist/components/SegmentedControl.js.map +1 -0
- package/dist/components/Sidebar.d.ts +109 -0
- package/dist/components/Sidebar.d.ts.map +1 -0
- package/dist/components/Sidebar.js +106 -0
- package/dist/components/Sidebar.js.map +1 -0
- package/dist/components/Stepper.d.ts +73 -0
- package/dist/components/Stepper.d.ts.map +1 -0
- package/dist/components/Stepper.js +82 -0
- package/dist/components/Stepper.js.map +1 -0
- package/dist/components/ToolCall.d.ts +66 -0
- package/dist/components/ToolCall.d.ts.map +1 -0
- package/dist/components/ToolCall.js +78 -0
- package/dist/components/ToolCall.js.map +1 -0
- package/dist/components/agent-status.d.ts +14 -0
- package/dist/components/agent-status.d.ts.map +1 -0
- package/dist/components/agent-status.js +16 -0
- package/dist/components/agent-status.js.map +1 -0
- package/dist/components/index.d.ts +17 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/iso-date.d.ts +53 -0
- package/dist/components/iso-date.d.ts.map +1 -0
- package/dist/components/iso-date.js +102 -0
- package/dist/components/iso-date.js.map +1 -0
- package/dist/figma-descriptions.json +107 -52
- package/dist/figma-map.json +735 -2
- package/dist/meta/AgentActivityStep.json +2 -2
- package/dist/meta/DatePicker.json +270 -0
- package/dist/meta/DateRangePicker.json +284 -0
- package/dist/meta/Header.json +32 -2
- package/dist/meta/NumberInput.json +407 -0
- package/dist/meta/PromptInput.json +212 -0
- package/dist/meta/SegmentedControl.json +217 -0
- package/dist/meta/SegmentedControlItem.json +122 -0
- package/dist/meta/Sidebar.json +150 -0
- package/dist/meta/SidebarItem.json +184 -0
- package/dist/meta/SidebarSection.json +131 -0
- package/dist/meta/Stepper.json +135 -0
- package/dist/meta/StepperStep.json +148 -0
- package/dist/meta/Tabs.json +5 -0
- package/dist/meta/ToolCall.json +192 -0
- package/dist/meta/components.json +5784 -3297
- package/dist/meta/contrast.json +7776 -2478
- package/dist/meta/index.json +139 -2
- package/dist/meta/patterns/AgentRun.json +27 -0
- package/dist/meta/patterns/Form.json +9 -0
- package/dist/meta/patterns/PageShell.json +43 -3
- package/dist/meta/patterns/Wizard.json +20 -1
- package/dist/meta/patterns/index.json +10 -1
- package/dist/styles/date-picker.css +420 -0
- package/dist/styles/date-range-picker.css +280 -0
- package/dist/styles/header.css +26 -0
- package/dist/styles/index.css +15 -0
- package/dist/styles/number-input.css +83 -0
- package/dist/styles/prompt-input.css +127 -0
- package/dist/styles/segmented-control.css +182 -0
- package/dist/styles/sidebar.css +307 -0
- package/dist/styles/stepper.css +250 -0
- package/dist/styles/tool-call.css +202 -0
- package/llms.txt +2 -2
- package/package.json +20 -19
- package/LICENSE +0 -21
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Sidebar
|
|
3
|
+
*
|
|
4
|
+
* Drawn in Figma as `Sidebar` (1396:502), `Sidebar Section` (1396:501) and
|
|
5
|
+
* `Sidebar Item` (1396:412), from this file. Rows take Menu Item's rhythm — 32px, 8px inset, `md`
|
|
6
|
+
* radius — because a sidebar row and a menu row are the same density of
|
|
7
|
+
* choice. The column is `surface/default` against the page's `surface/page`,
|
|
8
|
+
* the same step a card takes. Hover and current are fills (`surface/hover`,
|
|
9
|
+
* `surface/selected`),
|
|
10
|
+
* which is exactly where this parts company with NavItem: NavItem was measured
|
|
11
|
+
* as a header link that recolours and never fills.
|
|
12
|
+
*
|
|
13
|
+
* Written against the contrast gate's known limits (AGENTS.md, "How a
|
|
14
|
+
* stylesheet goes unmeasured"): state is BEM modifiers, the sidebar's surface
|
|
15
|
+
* is on the block so the translucent hover has a ground in this file, and there
|
|
16
|
+
* are no `:not()` lists.
|
|
17
|
+
*/
|
|
18
|
+
.ion-sidebar {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
inline-size: 100%;
|
|
22
|
+
block-size: 100%;
|
|
23
|
+
min-block-size: 0;
|
|
24
|
+
border-inline-end: var(--border-width-default) solid var(--border-subtle);
|
|
25
|
+
background-color: var(--surface-default);
|
|
26
|
+
color: var(--text-secondary);
|
|
27
|
+
font-family: var(--font-family-sans);
|
|
28
|
+
font-size: var(--type-body-sm);
|
|
29
|
+
line-height: var(--type-body-sm-line-height);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ion-sidebar__header,
|
|
33
|
+
.ion-sidebar__footer {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex: none;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
gap: var(--spacing-8);
|
|
38
|
+
padding: var(--spacing-12);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.ion-sidebar__header {
|
|
42
|
+
border-block-end: var(--border-width-default) solid var(--border-subtle);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ion-sidebar__footer {
|
|
46
|
+
border-block-start: var(--border-width-default) solid var(--border-subtle);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Only the middle scrolls, so the switcher and Invite stay put. */
|
|
50
|
+
.ion-sidebar__body {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex: 1 1 auto;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: var(--spacing-16);
|
|
55
|
+
min-block-size: 0;
|
|
56
|
+
padding: var(--spacing-12) var(--spacing-8);
|
|
57
|
+
overflow-y: auto;
|
|
58
|
+
overscroll-behavior: contain;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* ---------------------------------------------------------------- section */
|
|
62
|
+
|
|
63
|
+
.ion-sidebar__section {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
gap: var(--spacing-2);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.ion-sidebar__section-header {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: var(--spacing-4);
|
|
73
|
+
min-block-size: var(--spacing-24);
|
|
74
|
+
padding-inline: var(--spacing-8) var(--spacing-4);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ion-sidebar__section-title {
|
|
78
|
+
display: inline-flex;
|
|
79
|
+
flex: 1 1 auto;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: var(--spacing-4);
|
|
82
|
+
margin: 0;
|
|
83
|
+
padding: 0;
|
|
84
|
+
border: 0;
|
|
85
|
+
border-radius: var(--radius-xs);
|
|
86
|
+
background: none;
|
|
87
|
+
color: var(--text-tertiary);
|
|
88
|
+
font: inherit;
|
|
89
|
+
font-size: var(--type-caption);
|
|
90
|
+
line-height: var(--type-caption-line-height);
|
|
91
|
+
font-weight: var(--font-weight-medium);
|
|
92
|
+
text-align: start;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
button.ion-sidebar__section-title {
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.ion-sidebar__section-actions {
|
|
100
|
+
display: inline-flex;
|
|
101
|
+
flex: none;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: var(--spacing-2);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* -------------------------------------------------------------------- list */
|
|
107
|
+
|
|
108
|
+
.ion-sidebar__list {
|
|
109
|
+
display: flex;
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
gap: var(--spacing-2);
|
|
112
|
+
margin: 0;
|
|
113
|
+
padding: 0;
|
|
114
|
+
list-style: none;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
* Indentation accumulates by nesting, so depth needs no prop and no inline
|
|
119
|
+
* style: each level is one more padded list inside the last.
|
|
120
|
+
*/
|
|
121
|
+
.ion-sidebar__list--nested {
|
|
122
|
+
margin-block-start: var(--spacing-2);
|
|
123
|
+
padding-inline-start: var(--spacing-16);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* A hidden list is `hidden`; the display above must not override it. */
|
|
127
|
+
.ion-sidebar__list[hidden] {
|
|
128
|
+
display: none;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* --------------------------------------------------------------------- row */
|
|
132
|
+
|
|
133
|
+
.ion-sidebar__row {
|
|
134
|
+
position: relative;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: var(--spacing-2);
|
|
138
|
+
min-block-size: var(--spacing-32);
|
|
139
|
+
padding-inline-end: var(--spacing-4);
|
|
140
|
+
border-radius: var(--radius-md);
|
|
141
|
+
color: var(--text-secondary);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.ion-sidebar__link {
|
|
145
|
+
display: flex;
|
|
146
|
+
flex: 1 1 auto;
|
|
147
|
+
align-items: center;
|
|
148
|
+
gap: var(--spacing-8);
|
|
149
|
+
min-inline-size: 0;
|
|
150
|
+
min-block-size: var(--spacing-32);
|
|
151
|
+
margin: 0;
|
|
152
|
+
padding: 0 var(--spacing-8);
|
|
153
|
+
border: 0;
|
|
154
|
+
border-radius: var(--radius-md);
|
|
155
|
+
background: none;
|
|
156
|
+
color: inherit;
|
|
157
|
+
font: inherit;
|
|
158
|
+
text-align: start;
|
|
159
|
+
text-decoration: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
a.ion-sidebar__link,
|
|
163
|
+
button.ion-sidebar__link {
|
|
164
|
+
cursor: pointer;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ion-sidebar__icon {
|
|
168
|
+
display: inline-flex;
|
|
169
|
+
flex: none;
|
|
170
|
+
color: var(--icon-secondary);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.ion-sidebar__icon svg,
|
|
174
|
+
.ion-sidebar__chevron svg {
|
|
175
|
+
width: var(--icon-size-sm);
|
|
176
|
+
height: var(--icon-size-sm);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Long names truncate; the full text is still the link's accessible name. */
|
|
180
|
+
.ion-sidebar__label {
|
|
181
|
+
flex: 1 1 auto;
|
|
182
|
+
min-inline-size: 0;
|
|
183
|
+
overflow: hidden;
|
|
184
|
+
text-overflow: ellipsis;
|
|
185
|
+
white-space: nowrap;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.ion-sidebar__badge {
|
|
189
|
+
flex: none;
|
|
190
|
+
color: var(--text-tertiary);
|
|
191
|
+
font-size: var(--type-caption);
|
|
192
|
+
line-height: var(--type-caption-line-height);
|
|
193
|
+
font-variant-numeric: tabular-nums;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.ion-sidebar__chevron {
|
|
197
|
+
display: inline-flex;
|
|
198
|
+
flex: none;
|
|
199
|
+
color: var(--icon-tertiary);
|
|
200
|
+
transition: transform var(--ion-duration-base) var(--ion-ease-out);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.ion-sidebar__chevron--expanded,
|
|
204
|
+
.ion-sidebar__section-title--expanded .ion-sidebar__chevron {
|
|
205
|
+
transform: rotate(90deg);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* The separate expand button of a row that is also a link. */
|
|
209
|
+
.ion-sidebar__toggle {
|
|
210
|
+
display: inline-flex;
|
|
211
|
+
flex: none;
|
|
212
|
+
align-items: center;
|
|
213
|
+
justify-content: center;
|
|
214
|
+
width: var(--spacing-24);
|
|
215
|
+
height: var(--spacing-24);
|
|
216
|
+
margin: 0;
|
|
217
|
+
padding: 0;
|
|
218
|
+
border: 0;
|
|
219
|
+
border-radius: var(--radius-sm);
|
|
220
|
+
background: none;
|
|
221
|
+
color: inherit;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/*
|
|
226
|
+
* Row actions. Hidden until the row is hovered or holds focus — `opacity`,
|
|
227
|
+
* not `display` or `visibility`, so they stay in the tab order and appear the
|
|
228
|
+
* moment focus reaches them. Always shown where there is no hover to reveal
|
|
229
|
+
* them, or a touch user could never find them.
|
|
230
|
+
*/
|
|
231
|
+
.ion-sidebar__actions {
|
|
232
|
+
display: inline-flex;
|
|
233
|
+
flex: none;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: var(--spacing-2);
|
|
236
|
+
opacity: 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.ion-sidebar__row:hover .ion-sidebar__actions,
|
|
240
|
+
.ion-sidebar__row:focus-within .ion-sidebar__actions {
|
|
241
|
+
opacity: 1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@media (hover: none) {
|
|
245
|
+
.ion-sidebar__actions {
|
|
246
|
+
opacity: 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ------------------------------------------------------------------ states */
|
|
251
|
+
|
|
252
|
+
@media (hover: hover) {
|
|
253
|
+
.ion-sidebar__row:hover {
|
|
254
|
+
background-color: var(--surface-hover);
|
|
255
|
+
color: var(--text-default);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ion-sidebar__row--current {
|
|
260
|
+
background-color: var(--surface-selected);
|
|
261
|
+
color: var(--text-default);
|
|
262
|
+
font-weight: var(--font-weight-medium);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.ion-sidebar__row--current .ion-sidebar__icon {
|
|
266
|
+
color: var(--icon-primary);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
@media (hover: hover) {
|
|
270
|
+
.ion-sidebar__row--current:hover {
|
|
271
|
+
background-color: var(--surface-selected-hover);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/*
|
|
276
|
+
* Two classes, so a disabled row does not react to hover. The sidebar's surface
|
|
277
|
+
* is repeated rather than `transparent`, which the contrast gate would read as an
|
|
278
|
+
* inherited surface and drop — see the note in segmented-control.css.
|
|
279
|
+
*/
|
|
280
|
+
.ion-sidebar .ion-sidebar__row--disabled {
|
|
281
|
+
background-color: var(--surface-default);
|
|
282
|
+
color: var(--text-disabled);
|
|
283
|
+
cursor: not-allowed;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.ion-sidebar .ion-sidebar__row--disabled .ion-sidebar__icon {
|
|
287
|
+
color: var(--icon-disabled);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.ion-sidebar__link:focus-visible,
|
|
291
|
+
.ion-sidebar__toggle:focus-visible,
|
|
292
|
+
.ion-sidebar__section-title:focus-visible {
|
|
293
|
+
outline: var(--border-width-thick) solid var(--border-focus);
|
|
294
|
+
outline-offset: calc(-1 * var(--border-width-thick));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
@media (forced-colors: active) {
|
|
298
|
+
.ion-sidebar__row--current {
|
|
299
|
+
outline: var(--border-width-default) solid;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@media (prefers-reduced-motion: reduce) {
|
|
304
|
+
.ion-sidebar__chevron {
|
|
305
|
+
transition: none;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Stepper
|
|
3
|
+
*
|
|
4
|
+
* Drawn in Figma as `Stepper` (1391:431) and `Stepper Step` (1391:356), from
|
|
5
|
+
* this file. Built code-first, like Breadcrumb: the indicator is a circle at the
|
|
6
|
+
* `lg` icon rung, the label type is Breadcrumb's, and the colours are the primary
|
|
7
|
+
* and error roles every other status in the system uses.
|
|
8
|
+
*
|
|
9
|
+
* Status is never colour alone. `complete` draws a check and `error` an
|
|
10
|
+
* exclamation, and both carry their name as visually hidden text.
|
|
11
|
+
*
|
|
12
|
+
* Status and current are BEM modifiers, not `[data-*]` attributes, and that is
|
|
13
|
+
* load-bearing: the contrast gate keys contexts on `--modifier` classes. The
|
|
14
|
+
* first draft used `[data-status]`, and the filled current indicator and every
|
|
15
|
+
* error colour were silently unmeasured — no failure, no pass, just absent.
|
|
16
|
+
*/
|
|
17
|
+
.ion-stepper {
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: var(--spacing-8);
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
list-style: none;
|
|
23
|
+
font-family: var(--font-family-sans);
|
|
24
|
+
font-size: var(--type-body-sm);
|
|
25
|
+
line-height: var(--type-body-sm-line-height);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* Horizontal only: an inline-size container stops sizing to its content, which
|
|
30
|
+
* a vertical rail inside a flex parent needs to do.
|
|
31
|
+
*/
|
|
32
|
+
.ion-stepper--horizontal {
|
|
33
|
+
container-type: inline-size;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.ion-stepper--vertical {
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
gap: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.ion-stepper__label {
|
|
42
|
+
font-weight: var(--font-weight-medium);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ion-stepper__step {
|
|
46
|
+
position: relative;
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: var(--spacing-8);
|
|
50
|
+
min-width: 0;
|
|
51
|
+
color: var(--text-secondary);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.ion-stepper--vertical .ion-stepper__step {
|
|
55
|
+
align-items: flex-start;
|
|
56
|
+
padding-bottom: var(--spacing-24);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ion-stepper--horizontal .ion-stepper__step {
|
|
60
|
+
flex: 1 1 0;
|
|
61
|
+
align-items: flex-start;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ion-stepper--horizontal .ion-stepper__step:last-child {
|
|
65
|
+
flex: 0 0 auto;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ion-stepper--vertical .ion-stepper__step:last-child {
|
|
69
|
+
padding-bottom: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* The connector. Drawn by CSS after every step but the last, so it is
|
|
74
|
+
* decoration that never enters the accessibility tree. It turns primary once
|
|
75
|
+
* the step before it is complete, which is the "how far have I got" reading.
|
|
76
|
+
*
|
|
77
|
+
* A border, not a background: the contrast gate reads `background-color` on a
|
|
78
|
+
* `::after` as the ground for the whole step, and measured the check glyph
|
|
79
|
+
* against its own connector at 1:1. It is a line, so it is drawn as one.
|
|
80
|
+
*/
|
|
81
|
+
.ion-stepper--horizontal .ion-stepper__step:not(:last-child)::after {
|
|
82
|
+
content: '';
|
|
83
|
+
flex: 1 1 var(--spacing-16);
|
|
84
|
+
min-width: var(--spacing-16);
|
|
85
|
+
|
|
86
|
+
/* Centred on the indicator, not on a step that may carry a description. */
|
|
87
|
+
margin-top: calc((var(--icon-size-lg) - var(--border-width-thick)) / 2);
|
|
88
|
+
border-top: var(--border-width-thick) solid var(--border-default);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.ion-stepper--vertical .ion-stepper__step:not(:last-child)::after {
|
|
92
|
+
content: '';
|
|
93
|
+
position: absolute;
|
|
94
|
+
top: calc(var(--icon-size-lg) + var(--spacing-4));
|
|
95
|
+
bottom: var(--spacing-4);
|
|
96
|
+
|
|
97
|
+
/* Centred under the indicator. */
|
|
98
|
+
left: calc((var(--icon-size-lg) - var(--border-width-thick)) / 2);
|
|
99
|
+
border-left: var(--border-width-thick) solid var(--border-default);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ion-stepper__trigger {
|
|
103
|
+
display: inline-flex;
|
|
104
|
+
align-items: flex-start;
|
|
105
|
+
gap: var(--spacing-8);
|
|
106
|
+
min-width: 0;
|
|
107
|
+
margin: 0;
|
|
108
|
+
padding: 0;
|
|
109
|
+
border: 0;
|
|
110
|
+
border-radius: var(--radius-xs);
|
|
111
|
+
background: none;
|
|
112
|
+
color: inherit;
|
|
113
|
+
font: inherit;
|
|
114
|
+
text-align: start;
|
|
115
|
+
text-decoration: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
a.ion-stepper__trigger,
|
|
119
|
+
button.ion-stepper__trigger {
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
a.ion-stepper__trigger:focus-visible,
|
|
124
|
+
button.ion-stepper__trigger:focus-visible {
|
|
125
|
+
outline: var(--border-width-thick) solid var(--border-focus);
|
|
126
|
+
outline-offset: 2px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
a.ion-stepper__trigger:hover .ion-stepper__label,
|
|
130
|
+
button.ion-stepper__trigger:hover .ion-stepper__label {
|
|
131
|
+
color: var(--text-default);
|
|
132
|
+
text-decoration: underline;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.ion-stepper__indicator {
|
|
136
|
+
display: inline-flex;
|
|
137
|
+
flex: none;
|
|
138
|
+
align-items: center;
|
|
139
|
+
justify-content: center;
|
|
140
|
+
width: var(--icon-size-lg);
|
|
141
|
+
height: var(--icon-size-lg);
|
|
142
|
+
border: var(--border-width-thick) solid var(--border-strong);
|
|
143
|
+
border-radius: var(--radius-full);
|
|
144
|
+
color: var(--text-secondary);
|
|
145
|
+
font-size: var(--type-caption);
|
|
146
|
+
font-weight: var(--font-weight-semibold);
|
|
147
|
+
line-height: var(--type-caption-line-height);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ion-stepper__indicator svg {
|
|
151
|
+
width: var(--icon-size-sm);
|
|
152
|
+
height: var(--icon-size-sm);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.ion-stepper__text {
|
|
156
|
+
display: flex;
|
|
157
|
+
flex-direction: column;
|
|
158
|
+
gap: var(--spacing-2);
|
|
159
|
+
min-width: 0;
|
|
160
|
+
|
|
161
|
+
/* Aligns the label's first line with the 24px indicator. */
|
|
162
|
+
padding-top: var(--spacing-2);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.ion-stepper__description {
|
|
166
|
+
color: var(--text-tertiary);
|
|
167
|
+
font-size: var(--type-caption);
|
|
168
|
+
line-height: var(--type-caption-line-height);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* complete — a primary check in a primary ring, and a primary connector. */
|
|
172
|
+
.ion-stepper .ion-stepper__step--complete:not(:last-child)::after {
|
|
173
|
+
border-color: var(--border-primary);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.ion-stepper__step--complete .ion-stepper__indicator {
|
|
177
|
+
border-color: var(--border-primary);
|
|
178
|
+
color: var(--icon-primary);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* error — the same ring in error, with a different glyph. */
|
|
182
|
+
.ion-stepper__step--error {
|
|
183
|
+
color: var(--text-error);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.ion-stepper__step--error .ion-stepper__indicator {
|
|
187
|
+
border-color: var(--border-error);
|
|
188
|
+
color: var(--icon-error);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* current — the one filled indicator on the row, so the position reads at a
|
|
193
|
+
* glance. The label goes to the strongest text colour for the same reason
|
|
194
|
+
* Breadcrumb's current crumb does.
|
|
195
|
+
*/
|
|
196
|
+
.ion-stepper__step--current {
|
|
197
|
+
color: var(--text-default);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.ion-stepper__step--current .ion-stepper__indicator {
|
|
201
|
+
border-color: var(--surface-primary);
|
|
202
|
+
background-color: var(--surface-primary);
|
|
203
|
+
color: var(--text-on-color);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.ion-stepper__step--current.ion-stepper__step--error {
|
|
207
|
+
color: var(--text-error);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.ion-stepper__step--current.ion-stepper__step--error .ion-stepper__indicator {
|
|
211
|
+
border-color: var(--surface-error);
|
|
212
|
+
background-color: var(--surface-error);
|
|
213
|
+
color: var(--text-on-color);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/*
|
|
217
|
+
* Narrow containers: a horizontal stepper keeps every indicator and only the
|
|
218
|
+
* current step's label. The other labels are hidden visually, NOT removed, so
|
|
219
|
+
* "Step 2 of 5: Shipping, Completed" is still read for each of them.
|
|
220
|
+
*/
|
|
221
|
+
@container (max-width: 40rem) {
|
|
222
|
+
.ion-stepper--horizontal .ion-stepper__step--current {
|
|
223
|
+
flex: 0 1 auto;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.ion-stepper--horizontal
|
|
227
|
+
.ion-stepper__step:not(.ion-stepper__step--current)
|
|
228
|
+
.ion-stepper__text {
|
|
229
|
+
position: absolute;
|
|
230
|
+
width: 1px;
|
|
231
|
+
height: 1px;
|
|
232
|
+
padding: 0;
|
|
233
|
+
overflow: hidden;
|
|
234
|
+
clip-path: inset(50%);
|
|
235
|
+
white-space: nowrap;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/*
|
|
240
|
+
* Forced colours throw the primary fill away, which would leave the current
|
|
241
|
+
* step looking like every other. A heavier ring survives, because width is
|
|
242
|
+
* not a colour. (Not `Highlight` + `forced-color-adjust: none`: the contrast
|
|
243
|
+
* gate flattens at-rules, and a system colour here replaced the real fill in
|
|
244
|
+
* its model, so the white-on-primary pairing silently went unmeasured.)
|
|
245
|
+
*/
|
|
246
|
+
@media (forced-colors: active) {
|
|
247
|
+
.ion-stepper__step--current .ion-stepper__indicator {
|
|
248
|
+
border-width: var(--border-width-thicker);
|
|
249
|
+
}
|
|
250
|
+
}
|