@gtivr4/a1-design-system-react 0.3.1 → 0.4.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/package.json +1 -1
- package/src/components/choice-group/ChoiceGroup.jsx +2 -0
- package/src/components/choice-group/choice-group.css +11 -0
- package/src/components/data-table/DataTable.jsx +5 -5
- package/src/components/field/SelectField.jsx +1 -1
- package/src/components/field/TextField.jsx +1 -1
- package/src/components/field/TextareaField.jsx +1 -1
- package/src/components/field/field.css +8 -8
- package/src/components/field-row/FieldRow.jsx +2 -2
- package/src/components/fieldset/Fieldset.jsx +1 -1
- package/src/components/grid/Grid.jsx +1 -0
- package/src/components/heading/Heading.jsx +1 -1
- package/src/components/heading/heading.css +2 -0
- package/src/components/notification/Notification.jsx +4 -4
- package/src/components/notification/notification.css +1 -1
- package/src/components/paragraph/Paragraph.jsx +1 -1
- package/src/components/paragraph/paragraph.css +2 -0
- package/src/components/section/Section.jsx +8 -8
- package/src/components/section/section.css +3 -2
- package/src/components/segmented-control/segmented.css +0 -1
- package/src/components/status-bar/StatusBar.jsx +92 -0
- package/src/components/status-bar/status-bar.css +146 -0
- package/src/index.js +1 -0
- package/src/themes.css +1 -0
- package/src/tokens.css +10 -0
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@ export function ChoiceGroup({
|
|
|
16
16
|
size = "default",
|
|
17
17
|
columns,
|
|
18
18
|
multiple = false,
|
|
19
|
+
inlineIcon = false,
|
|
19
20
|
required = false,
|
|
20
21
|
name,
|
|
21
22
|
options = [],
|
|
@@ -76,6 +77,7 @@ export function ChoiceGroup({
|
|
|
76
77
|
"a1-choice-group",
|
|
77
78
|
resolvedSize !== "default" && `a1-choice-group--${resolvedSize}`,
|
|
78
79
|
multiple ? "a1-choice-group--multiple" : "a1-choice-group--single",
|
|
80
|
+
inlineIcon && "a1-choice-group--inline-icon",
|
|
79
81
|
isFixedColumns && "a1-choice-group--fixed-columns",
|
|
80
82
|
responsiveClass,
|
|
81
83
|
error && "a1-choice-group--error",
|
|
@@ -317,6 +317,17 @@
|
|
|
317
317
|
background-size: 80%;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
/* ─── Inline icon layout ────────────────────────────────────────────────────── */
|
|
321
|
+
|
|
322
|
+
.a1-choice-group--inline-icon .a1-choice-item {
|
|
323
|
+
flex-direction: row;
|
|
324
|
+
align-items: center;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.a1-choice-group--inline-icon .a1-choice-item__icon {
|
|
328
|
+
flex-shrink: 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
320
331
|
/* ─── Error state ───────────────────────────────────────────────────────────── */
|
|
321
332
|
|
|
322
333
|
.a1-choice-group--error
|
|
@@ -22,8 +22,8 @@ import "./data-table.css";
|
|
|
22
22
|
* }>
|
|
23
23
|
* rows: Array<Record<string, any>>
|
|
24
24
|
* getRowId?: (row: Record<string, any>, index: number) => string | number
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* size?: "comfortable" | "default" | "compact"
|
|
26
|
+
* omit (default) — switches between densities automatically based on available container width
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
// Estimated minimum content width per column type at a "neutral" padding level
|
|
@@ -193,7 +193,7 @@ function SelectionCheckbox({ checked, indeterminate = false, label, onChange })
|
|
|
193
193
|
export function DataTable({
|
|
194
194
|
columns = [],
|
|
195
195
|
rows = [],
|
|
196
|
-
|
|
196
|
+
size,
|
|
197
197
|
zebra = false,
|
|
198
198
|
scrollable = false,
|
|
199
199
|
caption,
|
|
@@ -238,14 +238,14 @@ export function DataTable({
|
|
|
238
238
|
const [internalSearchColumn, setInternalSearchColumn] = useState(defaultSearchColumn);
|
|
239
239
|
const [internalSelectedRowIds, setInternalSelectedRowIds] = useState(() => normalizeRowIds(defaultSelectedRowIds));
|
|
240
240
|
|
|
241
|
-
const isAuto =
|
|
241
|
+
const isAuto = size === undefined;
|
|
242
242
|
const isSortControlled = sort !== undefined;
|
|
243
243
|
const isPageControlled = page !== undefined;
|
|
244
244
|
const isFilterControlled = filterValue !== undefined;
|
|
245
245
|
const isSearchControlled = searchValue !== undefined;
|
|
246
246
|
const isSearchColumnControlled = searchColumn !== undefined;
|
|
247
247
|
const isSelectionControlled = selectedRowIds !== undefined;
|
|
248
|
-
const activeDensity = isAuto ? autoDensity :
|
|
248
|
+
const activeDensity = isAuto ? autoDensity : size;
|
|
249
249
|
const activeSort = isSortControlled ? normalizeSort(sort) : internalSort;
|
|
250
250
|
const activePage = isPageControlled ? page : internalPage;
|
|
251
251
|
const activeFilterValue = isFilterControlled
|
|
@@ -6,7 +6,7 @@ import { FieldsetContext } from "../fieldset/FieldsetContext.js";
|
|
|
6
6
|
import "./field.css";
|
|
7
7
|
|
|
8
8
|
const SIZES = ["comfortable", "default", "compact"];
|
|
9
|
-
const LABEL_POSITIONS = ["above", "
|
|
9
|
+
const LABEL_POSITIONS = ["above", "before"];
|
|
10
10
|
|
|
11
11
|
export const SelectField = forwardRef(function SelectField({
|
|
12
12
|
label,
|
|
@@ -5,7 +5,7 @@ import { FieldsetContext } from "../fieldset/FieldsetContext.js";
|
|
|
5
5
|
import "./field.css";
|
|
6
6
|
|
|
7
7
|
const SIZES = ["comfortable", "default", "compact"];
|
|
8
|
-
const LABEL_POSITIONS = ["above", "
|
|
8
|
+
const LABEL_POSITIONS = ["above", "before"];
|
|
9
9
|
|
|
10
10
|
export const TextField = forwardRef(function TextField({
|
|
11
11
|
label,
|
|
@@ -6,7 +6,7 @@ import "./field.css";
|
|
|
6
6
|
import "./textarea-field.css";
|
|
7
7
|
|
|
8
8
|
const SIZES = ["comfortable", "default", "compact"];
|
|
9
|
-
const LABEL_POSITIONS = ["above", "
|
|
9
|
+
const LABEL_POSITIONS = ["above", "before"];
|
|
10
10
|
const ROW_SIZES = { sm: 2, md: 4, lg: 8, xl: 12 };
|
|
11
11
|
|
|
12
12
|
function resolveRows(rows) {
|
|
@@ -336,9 +336,9 @@
|
|
|
336
336
|
color: var(--semantic-color-status-error-background);
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
/* ───
|
|
339
|
+
/* ─── Before label layout ───────────────────────────────────────────────────── */
|
|
340
340
|
|
|
341
|
-
.a1-field--label-
|
|
341
|
+
.a1-field--label-before {
|
|
342
342
|
display: grid;
|
|
343
343
|
grid-template-columns: var(--a1-field-side-label-width) 1fr;
|
|
344
344
|
column-gap: var(--base-spacing-16);
|
|
@@ -346,12 +346,12 @@
|
|
|
346
346
|
align-items: start;
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
.a1-field--label-
|
|
349
|
+
.a1-field--label-before .a1-field__label {
|
|
350
350
|
padding-top: calc((var(--a1-field-height) - 1lh) / 2);
|
|
351
351
|
padding-bottom: 0;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
.a1-field--label-
|
|
354
|
+
.a1-field--label-before .a1-field__message {
|
|
355
355
|
grid-column: 1;
|
|
356
356
|
grid-row: 2;
|
|
357
357
|
/* Fine-tuned margin: overrides the base margin-top added for the above-label
|
|
@@ -359,22 +359,22 @@
|
|
|
359
359
|
margin-top: calc((var(--a1-field-label-size) * 1.5 - var(--a1-field-height)) / 2 + var(--base-spacing-2));
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
/* ───
|
|
362
|
+
/* ─── Before label → stacked on xs/sm ─────────────────────────────────────── */
|
|
363
363
|
|
|
364
364
|
@media (--bp-sm-down) {
|
|
365
|
-
.a1-field--label-
|
|
365
|
+
.a1-field--label-before {
|
|
366
366
|
display: flex;
|
|
367
367
|
flex-direction: column;
|
|
368
368
|
gap: var(--a1-field-gap); /* restore: grid overrode row-gap to base-spacing-4 */
|
|
369
369
|
align-items: stretch; /* restore: grid set align-items: start */
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
.a1-field--label-
|
|
372
|
+
.a1-field--label-before .a1-field__label {
|
|
373
373
|
padding-top: 0;
|
|
374
374
|
padding-bottom: var(--a1-field-gap);
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
-
.a1-field--label-
|
|
377
|
+
.a1-field--label-before .a1-field__message {
|
|
378
378
|
margin-top: var(--a1-field-gap);
|
|
379
379
|
}
|
|
380
380
|
}
|
|
@@ -5,9 +5,9 @@ import "./field-row.css";
|
|
|
5
5
|
export function FieldRow({ children, className = "", ...props }) {
|
|
6
6
|
const ctx = useContext(FieldsetContext);
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// Before-label fields already use an internal two-column grid;
|
|
9
9
|
// stacking the row prevents layout conflicts.
|
|
10
|
-
const stacked = ctx?.labelPosition === "
|
|
10
|
+
const stacked = ctx?.labelPosition === "before";
|
|
11
11
|
|
|
12
12
|
const classes = [
|
|
13
13
|
"a1-field-row",
|
|
@@ -2,7 +2,7 @@ import { FieldsetContext } from "./FieldsetContext.js";
|
|
|
2
2
|
import "./fieldset.css";
|
|
3
3
|
|
|
4
4
|
const SIZES = ["comfortable", "default", "compact"];
|
|
5
|
-
const LABEL_POSITIONS = ["above", "
|
|
5
|
+
const LABEL_POSITIONS = ["above", "before"];
|
|
6
6
|
|
|
7
7
|
export function Fieldset({
|
|
8
8
|
legend,
|
|
@@ -7,7 +7,7 @@ const margins = ["sm", "md", "lg"];
|
|
|
7
7
|
const levels = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
8
8
|
const breakpoints = ["xs", "sm", "md", "lg", "xl"];
|
|
9
9
|
const textWraps = ["balance"];
|
|
10
|
-
const aligns = ["left", "center", "right"];
|
|
10
|
+
const aligns = ["left", "center", "right", "start", "end"];
|
|
11
11
|
|
|
12
12
|
const levelDefaults = { h1: "xl", h2: "lg", h3: "md", h4: "sm", h5: "xs", h6: "xs" };
|
|
13
13
|
|
|
@@ -88,6 +88,8 @@
|
|
|
88
88
|
.a1-heading--align-left { text-align: start; }
|
|
89
89
|
.a1-heading--align-center { text-align: center; }
|
|
90
90
|
.a1-heading--align-right { text-align: end; }
|
|
91
|
+
.a1-heading--align-start { text-align: start; }
|
|
92
|
+
.a1-heading--align-end { text-align: end; }
|
|
91
93
|
|
|
92
94
|
/* Expressive marks */
|
|
93
95
|
.a1-heading-mark {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./notification.css";
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const statuses = ["neutral", "error", "success", "warn", "info"];
|
|
4
4
|
const positions = ["top-right", "top-left", "bottom-right", "bottom-left"];
|
|
5
5
|
|
|
6
6
|
function formatCount(n, max) {
|
|
@@ -15,11 +15,11 @@ export function Notification({
|
|
|
15
15
|
count,
|
|
16
16
|
label,
|
|
17
17
|
dot = false,
|
|
18
|
-
|
|
18
|
+
status = "neutral",
|
|
19
19
|
position = "top-right",
|
|
20
20
|
max = 99,
|
|
21
21
|
}) {
|
|
22
|
-
const
|
|
22
|
+
const resolvedStatus = statuses.includes(status) ? status : "neutral";
|
|
23
23
|
const resolvedPosition = positions.includes(position) ? position : "top-right";
|
|
24
24
|
|
|
25
25
|
const isDot = dot || (count === undefined && label === undefined);
|
|
@@ -35,7 +35,7 @@ export function Notification({
|
|
|
35
35
|
|
|
36
36
|
const classes = [
|
|
37
37
|
"a1-notification",
|
|
38
|
-
`a1-notification--${
|
|
38
|
+
`a1-notification--${resolvedStatus}`,
|
|
39
39
|
`a1-notification--${resolvedPosition}`,
|
|
40
40
|
isDot && "a1-notification--dot",
|
|
41
41
|
]
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
/* ── Variants ───────────────────────────────────────────────────────────── */
|
|
45
45
|
|
|
46
|
-
.a1-notification--
|
|
46
|
+
.a1-notification--neutral {
|
|
47
47
|
--a1-notification-background: var(--base-color-neutral-600);
|
|
48
48
|
--a1-notification-foreground: var(--base-color-neutral-0);
|
|
49
49
|
}
|
|
@@ -4,7 +4,7 @@ const sizes = ["xs", "sm", "md", "lg", "xl"];
|
|
|
4
4
|
const colors = ["default", "muted"];
|
|
5
5
|
const breakpoints = ["xs", "sm", "md", "lg", "xl"];
|
|
6
6
|
const textWraps = ["balance"];
|
|
7
|
-
const aligns = ["left", "center", "right"];
|
|
7
|
+
const aligns = ["left", "center", "right", "start", "end"];
|
|
8
8
|
|
|
9
9
|
function isResponsiveSize(size) {
|
|
10
10
|
return size && typeof size === "object" && !Array.isArray(size);
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
.a1-paragraph--align-left { text-align: start; }
|
|
47
47
|
.a1-paragraph--align-center { text-align: center; }
|
|
48
48
|
.a1-paragraph--align-right { text-align: end; }
|
|
49
|
+
.a1-paragraph--align-start { text-align: start; }
|
|
50
|
+
.a1-paragraph--align-end { text-align: end; }
|
|
49
51
|
|
|
50
52
|
.a1-paragraph + .a1-paragraph,
|
|
51
53
|
.a1-paragraph + .a1-heading {
|
|
@@ -31,7 +31,7 @@ export function Section({
|
|
|
31
31
|
inverse = false,
|
|
32
32
|
contentWidth,
|
|
33
33
|
height,
|
|
34
|
-
|
|
34
|
+
align,
|
|
35
35
|
className = "",
|
|
36
36
|
children,
|
|
37
37
|
...props
|
|
@@ -72,14 +72,14 @@ export function Section({
|
|
|
72
72
|
classes.push(`a1-section--height-${height}`);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
if (typeof
|
|
76
|
-
if (VALID_ALIGNMENTS.includes(
|
|
77
|
-
classes.push(`a1-section--align-${
|
|
75
|
+
if (typeof align === "string") {
|
|
76
|
+
if (VALID_ALIGNMENTS.includes(align)) {
|
|
77
|
+
classes.push(`a1-section--align-${align}`);
|
|
78
78
|
}
|
|
79
|
-
} else if (
|
|
80
|
-
for (const [bp,
|
|
81
|
-
if (VALID_ALIGNMENTS.includes(
|
|
82
|
-
classes.push(`a1-section--${bp}-align-${
|
|
79
|
+
} else if (align && typeof align === "object") {
|
|
80
|
+
for (const [bp, alignVal] of Object.entries(align)) {
|
|
81
|
+
if (VALID_ALIGNMENTS.includes(alignVal)) {
|
|
82
|
+
classes.push(`a1-section--${bp}-align-${alignVal}`);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
/* ── Alignment ─────────────────────────────────────────────────────────────── */
|
|
112
112
|
/*
|
|
113
113
|
* Aligns direct children as layout items.
|
|
114
|
-
* Use the object prop for responsive changes:
|
|
114
|
+
* Use the object prop for responsive changes: align={{ xs: "center", lg: "left" }}
|
|
115
115
|
*/
|
|
116
116
|
|
|
117
117
|
.a1-section[class*="-align-"] {
|
|
@@ -206,10 +206,11 @@
|
|
|
206
206
|
|
|
207
207
|
/* ── Padding — static (with built-in responsive scaling) ───────────────────── */
|
|
208
208
|
/*
|
|
209
|
-
*
|
|
209
|
+
* Four tiers scale across three breakpoints:
|
|
210
210
|
* lg 96/64 → 96/40 at ≤1024 → 64/24 at ≤640
|
|
211
211
|
* md 64/40 → 40/24 at ≤1024 → 32/16 at ≤640
|
|
212
212
|
* sm 32/24 → 24/16 at ≤1024 → 16/12 at ≤640
|
|
213
|
+
* xs 16/16 → 12/12 at ≤1024 → 8/8 at ≤640
|
|
213
214
|
* Block (top/bottom) / Inline (left/right)
|
|
214
215
|
*/
|
|
215
216
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useId, useState, useEffect } from "react";
|
|
2
|
+
import { Button } from "../button/Button.jsx";
|
|
3
|
+
import { useLabel } from "../labels/Labels.jsx";
|
|
4
|
+
import "./status-bar.css";
|
|
5
|
+
|
|
6
|
+
const SIZES = ["sm", "md", "lg"];
|
|
7
|
+
const POSITIONS = ["above", "below", "before", "after"];
|
|
8
|
+
|
|
9
|
+
export function StatusBar({
|
|
10
|
+
value = 0,
|
|
11
|
+
max = 100,
|
|
12
|
+
label,
|
|
13
|
+
labelPosition = "above",
|
|
14
|
+
size = "md",
|
|
15
|
+
indeterminate = false,
|
|
16
|
+
className = "",
|
|
17
|
+
...props
|
|
18
|
+
}) {
|
|
19
|
+
const labelId = useId();
|
|
20
|
+
|
|
21
|
+
const pauseLabel = useLabel("statusBar.pause", "Pause");
|
|
22
|
+
const playLabel = useLabel("statusBar.play", "Play");
|
|
23
|
+
|
|
24
|
+
const [paused, setPaused] = useState(false);
|
|
25
|
+
const [showPause, setShowPause] = useState(false);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (!indeterminate) {
|
|
29
|
+
setShowPause(false);
|
|
30
|
+
setPaused(false);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const t = setTimeout(() => setShowPause(true), 3000);
|
|
34
|
+
return () => clearTimeout(t);
|
|
35
|
+
}, [indeterminate]);
|
|
36
|
+
|
|
37
|
+
const resolvedSize = SIZES.includes(size) ? size : "md";
|
|
38
|
+
const resolvedPosition = POSITIONS.includes(labelPosition) ? labelPosition : "above";
|
|
39
|
+
|
|
40
|
+
const pct = Math.min(100, Math.max(0, max > 0 ? (value / max) * 100 : 0));
|
|
41
|
+
const isLabelFirst = resolvedPosition === "above" || resolvedPosition === "before";
|
|
42
|
+
|
|
43
|
+
const classes = [
|
|
44
|
+
"a1-status-bar",
|
|
45
|
+
resolvedSize !== "md" && `a1-status-bar--${resolvedSize}`,
|
|
46
|
+
`a1-status-bar--${resolvedPosition}`,
|
|
47
|
+
indeterminate && "a1-status-bar--indeterminate",
|
|
48
|
+
indeterminate && paused && "a1-status-bar--paused",
|
|
49
|
+
className,
|
|
50
|
+
].filter(Boolean).join(" ");
|
|
51
|
+
|
|
52
|
+
const labelEl = label ? (
|
|
53
|
+
<span id={labelId} className="a1-status-bar__label">{label}</span>
|
|
54
|
+
) : null;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className={classes}>
|
|
58
|
+
{isLabelFirst && labelEl}
|
|
59
|
+
<div className="a1-status-bar__bar-row">
|
|
60
|
+
<div
|
|
61
|
+
className="a1-status-bar__track"
|
|
62
|
+
role="progressbar"
|
|
63
|
+
aria-valuenow={indeterminate ? undefined : value}
|
|
64
|
+
aria-valuemin={0}
|
|
65
|
+
aria-valuemax={max}
|
|
66
|
+
aria-labelledby={label ? labelId : undefined}
|
|
67
|
+
{...props}
|
|
68
|
+
>
|
|
69
|
+
<div
|
|
70
|
+
className={[
|
|
71
|
+
"a1-status-bar__fill",
|
|
72
|
+
indeterminate && "a1-status-bar__fill--indeterminate",
|
|
73
|
+
].filter(Boolean).join(" ")}
|
|
74
|
+
style={indeterminate ? undefined : { inlineSize: `${pct}%` }}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
{showPause && (
|
|
78
|
+
<Button
|
|
79
|
+
size="sm"
|
|
80
|
+
variant="secondary"
|
|
81
|
+
icon={paused ? "play_arrow" : "pause"}
|
|
82
|
+
className="a1-status-bar__pause"
|
|
83
|
+
onClick={() => setPaused(p => !p)}
|
|
84
|
+
>
|
|
85
|
+
{paused ? playLabel : pauseLabel}
|
|
86
|
+
</Button>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
{!isLabelFirst && labelEl}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/* ─── StatusBar ─────────────────────────────────────────────────────────────── */
|
|
2
|
+
|
|
3
|
+
.a1-status-bar {
|
|
4
|
+
--a1-sb-height: var(--component-status-bar-md-height);
|
|
5
|
+
--a1-sb-track-bg: var(--component-status-bar-track-background);
|
|
6
|
+
--a1-sb-fill-bg: var(--component-status-bar-fill-background);
|
|
7
|
+
--a1-sb-radius: var(--component-status-bar-border-radius);
|
|
8
|
+
--a1-sb-border-width: var(--component-status-bar-border-width);
|
|
9
|
+
--a1-sb-border-color: var(--component-status-bar-border-color);
|
|
10
|
+
--a1-sb-label-gap: var(--component-status-bar-label-gap);
|
|
11
|
+
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: var(--a1-sb-label-gap);
|
|
15
|
+
inline-size: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* ─── Sizes ─────────────────────────────────────────────────────────────────── */
|
|
19
|
+
|
|
20
|
+
.a1-status-bar--sm { --a1-sb-height: var(--component-status-bar-sm-height); }
|
|
21
|
+
.a1-status-bar--lg { --a1-sb-height: var(--component-status-bar-lg-height); }
|
|
22
|
+
|
|
23
|
+
/* ─── Label positions ───────────────────────────────────────────────────────── */
|
|
24
|
+
|
|
25
|
+
/* below: column layout, DOM order is [bar-row, label] so no CSS change needed */
|
|
26
|
+
|
|
27
|
+
.a1-status-bar--before,
|
|
28
|
+
.a1-status-bar--after {
|
|
29
|
+
flex-direction: row;
|
|
30
|
+
align-items: center;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.a1-status-bar--before .a1-status-bar__bar-row,
|
|
34
|
+
.a1-status-bar--after .a1-status-bar__bar-row {
|
|
35
|
+
flex: 1;
|
|
36
|
+
min-inline-size: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.a1-status-bar--before .a1-status-bar__label,
|
|
40
|
+
.a1-status-bar--after .a1-status-bar__label {
|
|
41
|
+
flex-shrink: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ─── Bar row (track + optional pause button) ───────────────────────────────── */
|
|
45
|
+
|
|
46
|
+
.a1-status-bar__bar-row {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: row;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: var(--base-spacing-8);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.a1-status-bar__bar-row .a1-status-bar__track {
|
|
54
|
+
flex: 1;
|
|
55
|
+
min-inline-size: 0;
|
|
56
|
+
inline-size: auto;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ─── Label ─────────────────────────────────────────────────────────────────── */
|
|
60
|
+
|
|
61
|
+
.a1-status-bar__label {
|
|
62
|
+
display: block;
|
|
63
|
+
font-family: var(--component-paragraph-font-family);
|
|
64
|
+
font-size: var(--semantic-font-size-body-sm);
|
|
65
|
+
font-weight: var(--base-font-weight-regular);
|
|
66
|
+
color: var(--semantic-color-text-default);
|
|
67
|
+
line-height: var(--semantic-font-line-height-body);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ─── Track ─────────────────────────────────────────────────────────────────── */
|
|
71
|
+
|
|
72
|
+
.a1-status-bar__track {
|
|
73
|
+
position: relative;
|
|
74
|
+
display: flex; /* flex direction inherits writing mode — fills from inline-start in RTL */
|
|
75
|
+
block-size: var(--a1-sb-height);
|
|
76
|
+
inline-size: 100%;
|
|
77
|
+
background-color: var(--a1-sb-track-bg);
|
|
78
|
+
border-radius: var(--a1-sb-radius);
|
|
79
|
+
border: var(--a1-sb-border-width) solid var(--a1-sb-border-color);
|
|
80
|
+
overflow: hidden;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ─── Fill ──────────────────────────────────────────────────────────────────── */
|
|
84
|
+
|
|
85
|
+
/* Flex child — grows from inline-start, which in RTL means it grows from the right */
|
|
86
|
+
.a1-status-bar__fill {
|
|
87
|
+
flex-shrink: 0;
|
|
88
|
+
block-size: 100%;
|
|
89
|
+
inline-size: 0;
|
|
90
|
+
background-color: var(--a1-sb-fill-bg);
|
|
91
|
+
border-radius: inherit;
|
|
92
|
+
transition: inline-size var(--semantic-motion-duration-normal) var(--semantic-motion-easing-standard);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* ─── Indeterminate (loading) ───────────────────────────────────────────────── */
|
|
96
|
+
|
|
97
|
+
/* Absolute positioning takes the fill out of flex flow for the sweep animation */
|
|
98
|
+
.a1-status-bar__fill--indeterminate {
|
|
99
|
+
position: absolute;
|
|
100
|
+
inset-block: 0;
|
|
101
|
+
left: 0;
|
|
102
|
+
inline-size: 35%;
|
|
103
|
+
animation: a1-sb-indeterminate var(--component-status-bar-indeterminate-duration) ease-in-out infinite;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* RTL: anchor to the physical right and reverse the sweep direction */
|
|
107
|
+
[dir="rtl"] .a1-status-bar__fill--indeterminate {
|
|
108
|
+
left: auto;
|
|
109
|
+
right: 0;
|
|
110
|
+
animation-direction: reverse;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.a1-status-bar--paused .a1-status-bar__fill--indeterminate {
|
|
114
|
+
animation-play-state: paused;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@keyframes a1-sb-indeterminate {
|
|
118
|
+
0% { transform: translateX(-115%); }
|
|
119
|
+
100% { transform: translateX(300%); }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@media (prefers-reduced-motion: reduce) {
|
|
123
|
+
.a1-status-bar__fill--indeterminate {
|
|
124
|
+
animation: none;
|
|
125
|
+
inline-size: 100%;
|
|
126
|
+
opacity: 0.4;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ─── Pause / play button ────────────────────────────────────────────────────── */
|
|
131
|
+
|
|
132
|
+
.a1-status-bar__pause {
|
|
133
|
+
flex-shrink: 0;
|
|
134
|
+
animation: a1-sb-pause-appear var(--semantic-motion-duration-normal) var(--semantic-motion-easing-enter);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@keyframes a1-sb-pause-appear {
|
|
138
|
+
from { opacity: 0; transform: scale(0.75); }
|
|
139
|
+
to { opacity: 1; transform: scale(1); }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@media (prefers-reduced-motion: reduce) {
|
|
143
|
+
.a1-status-bar__pause {
|
|
144
|
+
animation: none;
|
|
145
|
+
}
|
|
146
|
+
}
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { Blockquote } from "./components/blockquote/Blockquote.jsx";
|
|
|
5
5
|
export { Breadcrumb } from "./components/breadcrumb/Breadcrumb.jsx";
|
|
6
6
|
export { Notification } from "./components/notification/Notification.jsx";
|
|
7
7
|
export { Snackbar } from "./components/snackbar/Snackbar.jsx";
|
|
8
|
+
export { StatusBar } from "./components/status-bar/StatusBar.jsx";
|
|
8
9
|
export { Bleed } from "./components/bleed/Bleed.jsx";
|
|
9
10
|
export { IconButton } from "./components/icon-button/IconButton.jsx";
|
|
10
11
|
export { Button } from "./components/button/Button.jsx";export { ButtonContainer } from "./components/button-container/ButtonContainer.jsx";
|
package/src/themes.css
CHANGED
|
@@ -52,6 +52,7 @@ html.a1-theme-accessible {
|
|
|
52
52
|
--component-side-nav-border-width: 2px;
|
|
53
53
|
--component-tab-border-width: 2px;
|
|
54
54
|
--component-top-header-border-width: 2px;
|
|
55
|
+
--component-status-bar-border-width: 2px;
|
|
55
56
|
--component-button-font-family: var(--theme-a1-accessible-font-family-body);
|
|
56
57
|
--component-paragraph-font-family: var(--theme-a1-accessible-font-family-body);
|
|
57
58
|
--component-heading-font-family-heading: var(--theme-a1-accessible-font-family-heading);
|
package/src/tokens.css
CHANGED
|
@@ -646,6 +646,16 @@
|
|
|
646
646
|
--component-side-nav-item-font-line-height: 1.5;
|
|
647
647
|
--component-side-nav-item-active-font-weight: 500;
|
|
648
648
|
--component-side-nav-item-chevron-size: 1.125rem;
|
|
649
|
+
--component-status-bar-sm-height: 0.25rem;
|
|
650
|
+
--component-status-bar-md-height: 0.5rem;
|
|
651
|
+
--component-status-bar-lg-height: 0.75rem;
|
|
652
|
+
--component-status-bar-border-radius: 624.9375rem;
|
|
653
|
+
--component-status-bar-border-width: 0;
|
|
654
|
+
--component-status-bar-border-color: #a6b2c4;
|
|
655
|
+
--component-status-bar-track-background: #e1e8f3;
|
|
656
|
+
--component-status-bar-fill-background: #7c3aed;
|
|
657
|
+
--component-status-bar-label-gap: 0.5rem;
|
|
658
|
+
--component-status-bar-indeterminate-duration: 1400ms;
|
|
649
659
|
--component-switch-track-width: 2.5rem;
|
|
650
660
|
--component-switch-track-height: 1.375rem;
|
|
651
661
|
--component-switch-thumb-size: 1rem;
|