@gtivr4/a1-design-system-react 0.4.0 → 0.5.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.
Files changed (57) hide show
  1. package/package.json +2 -1
  2. package/src/components/accordion/Accordion.d.ts +20 -0
  3. package/src/components/banner/Banner.d.ts +19 -0
  4. package/src/components/bleed/Bleed.d.ts +17 -0
  5. package/src/components/blockquote/Blockquote.d.ts +23 -0
  6. package/src/components/breadcrumb/Breadcrumb.d.ts +22 -0
  7. package/src/components/button/Button.d.ts +17 -0
  8. package/src/components/button-container/ButtonContainer.d.ts +11 -0
  9. package/src/components/calendar/Calendar.d.ts +75 -0
  10. package/src/components/calendar/Calendar.jsx +76 -13
  11. package/src/components/calendar/calendar.css +71 -0
  12. package/src/components/card/Card.d.ts +31 -0
  13. package/src/components/checkbox-group/CheckboxGroup.d.ts +37 -0
  14. package/src/components/choice-group/ChoiceGroup.d.ts +68 -0
  15. package/src/components/circular-progress/CircularProgress.d.ts +37 -0
  16. package/src/components/circular-progress/CircularProgress.jsx +85 -0
  17. package/src/components/circular-progress/circular-progress.css +104 -0
  18. package/src/components/cluster/Cluster.d.ts +21 -0
  19. package/src/components/code/Code.d.ts +15 -0
  20. package/src/components/data-table/DataTable.d.ts +83 -0
  21. package/src/components/dialog/Dialog.d.ts +15 -0
  22. package/src/components/dialog/dialog.css +7 -3
  23. package/src/components/divider/Divider.d.ts +22 -0
  24. package/src/components/field/SelectField.d.ts +22 -0
  25. package/src/components/field/TextField.d.ts +21 -0
  26. package/src/components/field/TextareaField.d.ts +28 -0
  27. package/src/components/field-row/FieldRow.d.ts +8 -0
  28. package/src/components/fieldset/Fieldset.d.ts +27 -0
  29. package/src/components/figure/Figure.d.ts +39 -0
  30. package/src/components/grid/Grid.d.ts +38 -0
  31. package/src/components/heading/Heading.d.ts +43 -0
  32. package/src/components/heading/Heading.jsx +2 -2
  33. package/src/components/icon/Icon.d.ts +25 -0
  34. package/src/components/icon-button/IconButton.d.ts +14 -0
  35. package/src/components/inset/Inset.d.ts +17 -0
  36. package/src/components/inverse/Inverse.d.ts +9 -0
  37. package/src/components/link/Link.d.ts +15 -0
  38. package/src/components/list/List.d.ts +40 -0
  39. package/src/components/menu/Menu.d.ts +41 -0
  40. package/src/components/message/Message.d.ts +34 -0
  41. package/src/components/notification/Notification.d.ts +23 -0
  42. package/src/components/page-layout/PageLayout.d.ts +24 -0
  43. package/src/components/page-nav/PageNav.d.ts +19 -0
  44. package/src/components/pagination/Pagination.d.ts +19 -0
  45. package/src/components/paragraph/Paragraph.d.ts +23 -0
  46. package/src/components/radio-group/RadioGroup.d.ts +37 -0
  47. package/src/components/section/Section.d.ts +33 -0
  48. package/src/components/segmented-control/SegmentedControl.d.ts +23 -0
  49. package/src/components/side-nav/SideNav.d.ts +62 -0
  50. package/src/components/spacer/Spacer.d.ts +16 -0
  51. package/src/components/stack/Stack.d.ts +38 -0
  52. package/src/components/status-bar/StatusBar.d.ts +42 -0
  53. package/src/components/switch/Switch.d.ts +27 -0
  54. package/src/components/system-banner/SystemBanner.d.ts +17 -0
  55. package/src/components/tabs/Tabs.d.ts +53 -0
  56. package/src/index.js +2 -0
  57. package/src/tokens.css +22 -0
@@ -0,0 +1,85 @@
1
+ import "./circular-progress.css";
2
+
3
+ const SIZES = ["xs", "sm", "md", "lg"];
4
+
5
+ // SVG uses a 100×100 viewBox with a 10-unit stroke so the ring scales
6
+ // proportionally when the container size changes via CSS.
7
+ const VIEWBOX = 100;
8
+ const STROKE = 10;
9
+ const R = (VIEWBOX - STROKE) / 2; // 45
10
+ const CIRC = 2 * Math.PI * R; // ≈ 282.74
11
+ const ARC = CIRC * 0.25; // 25% arc for indeterminate
12
+
13
+ export function CircularProgress({
14
+ value = 0,
15
+ max = 100,
16
+ size = "md",
17
+ indeterminate = false,
18
+ children,
19
+ className = "",
20
+ ...props
21
+ }) {
22
+ const resolvedSize = SIZES.includes(size) ? size : "md";
23
+ const hasInner = resolvedSize !== "xs";
24
+
25
+ const pct = Math.min(1, Math.max(0, max > 0 ? value / max : 0));
26
+ const dashArray = indeterminate ? `${ARC} ${CIRC - ARC}` : CIRC;
27
+ const dashOffset = indeterminate ? 0 : CIRC * (1 - pct);
28
+
29
+ const classes = [
30
+ "a1-circular-progress",
31
+ resolvedSize !== "md" && `a1-circular-progress--${resolvedSize}`,
32
+ indeterminate && "a1-circular-progress--indeterminate",
33
+ className,
34
+ ].filter(Boolean).join(" ");
35
+
36
+ return (
37
+ <div
38
+ className={classes}
39
+ role="progressbar"
40
+ aria-valuenow={indeterminate ? undefined : value}
41
+ aria-valuemin={0}
42
+ aria-valuemax={max}
43
+ {...props}
44
+ >
45
+ <div className="a1-circular-progress__ring">
46
+ <svg
47
+ className="a1-circular-progress__svg"
48
+ viewBox={`0 0 ${VIEWBOX} ${VIEWBOX}`}
49
+ aria-hidden="true"
50
+ >
51
+ <circle
52
+ className="a1-circular-progress__track"
53
+ cx={VIEWBOX / 2}
54
+ cy={VIEWBOX / 2}
55
+ r={R}
56
+ fill="none"
57
+ strokeWidth={STROKE}
58
+ />
59
+ <circle
60
+ className="a1-circular-progress__fill"
61
+ cx={VIEWBOX / 2}
62
+ cy={VIEWBOX / 2}
63
+ r={R}
64
+ fill="none"
65
+ strokeWidth={STROKE}
66
+ strokeDasharray={dashArray}
67
+ strokeDashoffset={dashOffset}
68
+ strokeLinecap="round"
69
+ transform={`rotate(-90 ${VIEWBOX / 2} ${VIEWBOX / 2})`}
70
+ />
71
+ </svg>
72
+ {hasInner && children && (
73
+ <div className="a1-circular-progress__inner" aria-hidden="true">
74
+ {children}
75
+ </div>
76
+ )}
77
+ </div>
78
+ {!hasInner && children && (
79
+ <div className="a1-circular-progress__after">
80
+ {children}
81
+ </div>
82
+ )}
83
+ </div>
84
+ );
85
+ }
@@ -0,0 +1,104 @@
1
+ /* ─── CircularProgress ───────────────────────────────────────────────────────── */
2
+
3
+ .a1-circular-progress {
4
+ --a1-cp-size: var(--component-circular-progress-md-size);
5
+ --a1-cp-track: var(--component-circular-progress-track-color);
6
+ --a1-cp-fill: var(--component-circular-progress-fill-color);
7
+ --a1-cp-gap: var(--component-circular-progress-gap);
8
+
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: var(--a1-cp-gap);
12
+ }
13
+
14
+ /* ─── Sizes ──────────────────────────────────────────────────────────────────── */
15
+
16
+ .a1-circular-progress--xs { --a1-cp-size: var(--component-circular-progress-xs-size); }
17
+ .a1-circular-progress--sm { --a1-cp-size: var(--component-circular-progress-sm-size); }
18
+ /* md is the default — no modifier needed */
19
+ .a1-circular-progress--lg { --a1-cp-size: var(--component-circular-progress-lg-size); }
20
+
21
+ /* ─── Ring (SVG + optional inner content) ────────────────────────────────────── */
22
+
23
+ .a1-circular-progress__ring {
24
+ flex-shrink: 0;
25
+ position: relative;
26
+ width: var(--a1-cp-size);
27
+ height: var(--a1-cp-size);
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ }
32
+
33
+ /* ─── SVG ────────────────────────────────────────────────────────────────────── */
34
+
35
+ .a1-circular-progress__svg {
36
+ position: absolute;
37
+ inset: 0;
38
+ width: 100%;
39
+ height: 100%;
40
+ overflow: visible;
41
+ }
42
+
43
+ /* ─── Track ──────────────────────────────────────────────────────────────────── */
44
+
45
+ .a1-circular-progress__track {
46
+ stroke: var(--a1-cp-track);
47
+ }
48
+
49
+ /* ─── Fill ───────────────────────────────────────────────────────────────────── */
50
+
51
+ .a1-circular-progress__fill {
52
+ stroke: var(--a1-cp-fill);
53
+ transition: stroke-dashoffset var(--semantic-motion-duration-normal) var(--semantic-motion-easing-standard);
54
+ }
55
+
56
+ /* ─── Inner content (sm / md / lg) ──────────────────────────────────────────── */
57
+
58
+ /* position: relative sits above the absolute SVG inside the flex __ring */
59
+ .a1-circular-progress__inner {
60
+ position: relative;
61
+ display: flex;
62
+ flex-direction: column;
63
+ align-items: center;
64
+ justify-content: center;
65
+ text-align: center;
66
+ /* 80% keeps content within the inner edge of the 10 %-wide viewBox stroke */
67
+ max-width: 80%;
68
+ overflow: hidden;
69
+ }
70
+
71
+ /* ─── After content (xs only, rendered after the ring in DOM order) ─────────── */
72
+
73
+ .a1-circular-progress__after {
74
+ font-family: var(--component-paragraph-font-family);
75
+ font-size: var(--semantic-font-size-body-sm);
76
+ color: var(--semantic-color-text-default);
77
+ line-height: var(--semantic-font-line-height-body);
78
+ }
79
+
80
+ /* ─── Indeterminate (spin) ───────────────────────────────────────────────────── */
81
+
82
+ .a1-circular-progress--indeterminate .a1-circular-progress__svg {
83
+ animation: a1-cp-spin var(--component-circular-progress-indeterminate-duration) linear infinite;
84
+ transform-origin: center;
85
+ }
86
+
87
+ .a1-circular-progress--indeterminate .a1-circular-progress__fill {
88
+ transition: none;
89
+ }
90
+
91
+ @keyframes a1-cp-spin {
92
+ to { transform: rotate(360deg); }
93
+ }
94
+
95
+ /* ─── Reduced motion ─────────────────────────────────────────────────────────── */
96
+
97
+ @media (prefers-reduced-motion: reduce) {
98
+ .a1-circular-progress--indeterminate .a1-circular-progress__svg {
99
+ animation: none;
100
+ }
101
+ .a1-circular-progress__fill {
102
+ transition: none;
103
+ }
104
+ }
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+
3
+ type SpacingToken = 1 | 2 | 4 | 6 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 64 | 96 | 128;
4
+
5
+ export interface ClusterProps extends React.HTMLAttributes<HTMLElement> {
6
+ /** Underlying element. Default: "div" */
7
+ as?: React.ElementType;
8
+ /** Gap applied to both row and column. Default: 8 */
9
+ gap?: SpacingToken;
10
+ /** Row gap override */
11
+ rowGap?: SpacingToken;
12
+ /** Column gap override */
13
+ columnGap?: SpacingToken;
14
+ /** Align-items. Default: "center" */
15
+ align?: "start" | "center" | "end" | "stretch" | "baseline";
16
+ /** Justify-content. Default: "start" */
17
+ justify?: "start" | "center" | "end" | "between" | "around" | "evenly";
18
+ children?: React.ReactNode;
19
+ }
20
+
21
+ export declare function Cluster(props: ClusterProps): React.ReactElement;
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+
3
+ export interface CodeProps extends React.HTMLAttributes<HTMLElement> {
4
+ /** Code presentation. Inline keeps minimal padding for prose; block renders a preformatted block. Default: "inline" */
5
+ variant?: "inline" | "block";
6
+ /** Allow long inline snippets or block code to wrap. Default: false */
7
+ wrapping?: boolean;
8
+ /** Show a small tertiary copy button at the bottom-left of the code block. Default: false */
9
+ copyCode?: boolean;
10
+ /** Text copied to the clipboard. Defaults to the rendered text children. */
11
+ copyText?: string;
12
+ children?: React.ReactNode;
13
+ }
14
+
15
+ export declare function Code(props: CodeProps): React.ReactElement;
@@ -0,0 +1,83 @@
1
+ import * as React from "react";
2
+
3
+ export interface DataTableColumn {
4
+ key: string;
5
+ label: string;
6
+ type?: "text" | "number" | "currency" | "date" | "badge" | "avatar" | "link" | "actions";
7
+ align?: "start" | "center" | "end";
8
+ width?: string;
9
+ sortable?: boolean;
10
+ sortAccessor?: (row: Record<string, unknown>) => unknown;
11
+ searchAccessor?: (row: Record<string, unknown>) => unknown;
12
+ statusMap?: Record<string, "neutral" | "info" | "success" | "warn" | "error">;
13
+ currencySymbol?: string;
14
+ }
15
+
16
+ export interface DataTableSortState {
17
+ key: string;
18
+ direction: "asc" | "desc";
19
+ }
20
+
21
+ export interface DataTableFilter {
22
+ key: string;
23
+ label: string;
24
+ type?: "single" | "multi";
25
+ options: Array<{ value: string; label: string }>;
26
+ }
27
+
28
+ export interface DataTableProps extends React.HTMLAttributes<HTMLDivElement> {
29
+ columns?: DataTableColumn[];
30
+ rows?: Record<string, unknown>[];
31
+ /**
32
+ * Cell spacing density.
33
+ * Omit (default) to auto-select density based on the available container width.
34
+ */
35
+ size?: "comfortable" | "default" | "compact";
36
+ /** Alternate row shading. Default: false */
37
+ zebra?: boolean;
38
+ /** Enable horizontal scroll on the table. Default: false */
39
+ scrollable?: boolean;
40
+ /** Accessible caption for the table */
41
+ caption?: string;
42
+ /** Controlled current page (1-based) */
43
+ page?: number;
44
+ /** Uncontrolled initial page. Default: 1 */
45
+ defaultPage?: number;
46
+ /** Number of rows per page for built-in pagination */
47
+ pageSize?: number;
48
+ /** Total page count for server-side pagination */
49
+ totalPages?: number;
50
+ /** Total row count for server-side row counter */
51
+ totalRows?: number;
52
+ /** Called when the active page changes */
53
+ onPageChange?: (page: number) => void;
54
+ /** Controlled sort state */
55
+ sort?: DataTableSortState | null;
56
+ /** Uncontrolled initial sort state */
57
+ defaultSort?: DataTableSortState;
58
+ /** Called when sort changes */
59
+ onSortChange?: (sort: DataTableSortState | null) => void;
60
+ filters?: DataTableFilter[];
61
+ filterValue?: Record<string, unknown>;
62
+ defaultFilterValue?: Record<string, unknown>;
63
+ onFilterChange?: (value: Record<string, unknown>) => void;
64
+ searchValue?: string;
65
+ defaultSearchValue?: string;
66
+ onSearchChange?: (value: string) => void;
67
+ searchColumn?: string;
68
+ defaultSearchColumn?: string;
69
+ onSearchColumnChange?: (column: string) => void;
70
+ searchableColumns?: Array<{ key: string; label: string }>;
71
+ /** Enable row selection. Default: false */
72
+ selectable?: boolean;
73
+ selectedRowIds?: (string | number)[];
74
+ defaultSelectedRowIds?: (string | number)[];
75
+ onSelectedRowIdsChange?: (ids: string[]) => void;
76
+ onDeleteSelected?: (rows: Record<string, unknown>[], ids: string[]) => void;
77
+ getRowId?: (row: Record<string, unknown>, index: number) => string | number;
78
+ emptyTitle?: string;
79
+ emptyDescription?: string;
80
+ emptyIcon?: string;
81
+ }
82
+
83
+ export declare function DataTable(props: DataTableProps): React.ReactElement;
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+
3
+ export interface DialogProps extends React.DialogHTMLAttributes<HTMLDialogElement> {
4
+ /** Whether the dialog is visible. Default: false */
5
+ open?: boolean;
6
+ /** Called when the user closes the dialog (Escape, close button, or backdrop click) */
7
+ onClose?: () => void;
8
+ /** Dialog title shown in the header */
9
+ title?: string;
10
+ /** Footer content — wrapped in a right-aligned `ButtonContainer` */
11
+ footer?: React.ReactNode;
12
+ children?: React.ReactNode;
13
+ }
14
+
15
+ export declare function Dialog(props: DialogProps): React.ReactElement;
@@ -12,8 +12,12 @@
12
12
  }
13
13
 
14
14
  .a1-dialog[open] {
15
- display: flex;
16
- flex-direction: column;
15
+ /* CSS Grid instead of Flex: Safari collapses flex: 1 children when the
16
+ container has only max-height but no explicit height. Grid resolves
17
+ track sizes against the constrained container first, so 1fr works. */
18
+ display: grid;
19
+ grid-template-rows: auto minmax(0, 1fr);
20
+ grid-auto-rows: auto;
17
21
  gap: var(--base-spacing-16);
18
22
  }
19
23
 
@@ -45,8 +49,8 @@
45
49
  }
46
50
 
47
51
  .a1-dialog__body {
48
- flex: 1;
49
52
  overflow-y: auto;
53
+ min-height: 0;
50
54
  }
51
55
 
52
56
  .a1-dialog__footer {
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+
3
+ type Breakpoints = "xs" | "sm" | "md" | "lg" | "xl";
4
+ type Orientation = "horizontal" | "vertical";
5
+
6
+ export interface DividerProps extends React.HTMLAttributes<HTMLHRElement> {
7
+ /**
8
+ * Line orientation. Responsive object syntax supported. Default: "horizontal"
9
+ * @example orientation={{ xs: "horizontal", md: "vertical" }}
10
+ */
11
+ orientation?: Orientation | Partial<Record<Breakpoints, Orientation>>;
12
+ /** Visual style. Default: "subtle" */
13
+ variant?: "subtle" | "strong" | "accent" | "dashed" | "dotted";
14
+ /** Line thickness. Default: "xs" */
15
+ size?: "xs" | "sm" | "md" | "lg";
16
+ /** Block-axis margin (space above and below for horizontal, left/right for vertical). Default: "sm" */
17
+ space?: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "xxl";
18
+ /** Whether this divider is purely decorative (no semantic role). Default: true */
19
+ decorative?: boolean;
20
+ }
21
+
22
+ export declare function Divider(props: DividerProps): React.ReactElement;
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+
3
+ export interface SelectFieldProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "size"> {
4
+ /** Visible label text */
5
+ label?: string;
6
+ /** Helper text shown below the field */
7
+ hint?: string;
8
+ /** Error message — replaces hint and marks the field invalid */
9
+ error?: string;
10
+ /** Size density. Inherits from parent `Fieldset` when omitted. Default: "default" */
11
+ size?: "comfortable" | "default" | "compact";
12
+ /** Label position. Inherits from parent `Fieldset` when omitted. Default: "above" */
13
+ labelPosition?: "above" | "before";
14
+ required?: boolean;
15
+ disabled?: boolean;
16
+ /** Element rendered inside the field control */
17
+ inputOverlay?: React.ReactNode;
18
+ /** `<option>` elements */
19
+ children?: React.ReactNode;
20
+ }
21
+
22
+ export declare const SelectField: React.ForwardRefExoticComponent<SelectFieldProps & React.RefAttributes<HTMLSelectElement>>;
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+
3
+ export interface TextFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "placeholder"> {
4
+ /** Visible label text */
5
+ label?: string;
6
+ /** Helper text shown below the field */
7
+ hint?: string;
8
+ /** Error message — replaces hint and marks the field invalid */
9
+ error?: string;
10
+ /** Size density. Inherits from parent `Fieldset` when omitted. Default: "default" */
11
+ size?: "comfortable" | "default" | "compact";
12
+ /** Label position. Inherits from parent `Fieldset` when omitted. Default: "above" */
13
+ labelPosition?: "above" | "before";
14
+ required?: boolean;
15
+ disabled?: boolean;
16
+ readOnly?: boolean;
17
+ /** Element rendered inside the field control (e.g. a unit suffix) */
18
+ inputOverlay?: React.ReactNode;
19
+ }
20
+
21
+ export declare const TextField: React.ForwardRefExoticComponent<TextFieldProps & React.RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+
3
+ export interface TextareaFieldProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "size" | "rows"> {
4
+ /** Visible label text */
5
+ label?: string;
6
+ /** Helper text shown below the field */
7
+ hint?: string;
8
+ /** Error message — replaces hint and marks the field invalid */
9
+ error?: string;
10
+ /** Size density. Inherits from parent `Fieldset` when omitted. Default: "default" */
11
+ size?: "comfortable" | "default" | "compact";
12
+ /** Label position. Inherits from parent `Fieldset` when omitted. Default: "above" */
13
+ labelPosition?: "above" | "before";
14
+ required?: boolean;
15
+ disabled?: boolean;
16
+ readOnly?: boolean;
17
+ /**
18
+ * Initial visible row height. Pass a number for exact rows or a size token.
19
+ * sm=2 · md=4 · lg=8 · xl=12. Default: "md"
20
+ */
21
+ rows?: "sm" | "md" | "lg" | "xl" | number;
22
+ /** Maximum character count */
23
+ maxLength?: number;
24
+ /** Show a character counter. Auto-enabled when `maxLength` is set. Default: false */
25
+ showCount?: boolean;
26
+ }
27
+
28
+ export declare const TextareaField: React.ForwardRefExoticComponent<TextareaFieldProps & React.RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+
3
+ export interface FieldRowProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ /** Lays out multiple field components side by side in a single row. */
5
+ children?: React.ReactNode;
6
+ }
7
+
8
+ export declare function FieldRow(props: FieldRowProps): React.ReactElement;
@@ -0,0 +1,27 @@
1
+ import * as React from "react";
2
+
3
+ export interface FieldsetProps extends React.FieldsetHTMLAttributes<HTMLFieldSetElement> {
4
+ /** `<legend>` text for the field group */
5
+ legend?: string;
6
+ /**
7
+ * Size density applied to all child fields via context.
8
+ * Individual fields can override this.
9
+ */
10
+ size?: "comfortable" | "default" | "compact";
11
+ /**
12
+ * Label position applied to all child fields via context.
13
+ * Individual fields can override this.
14
+ */
15
+ labelPosition?: "above" | "before";
16
+ /**
17
+ * Show a "* Required field" note below the legend.
18
+ * Only shown for "default" and "compact" sizes (comfortable fields show inline badges).
19
+ * Default: false
20
+ */
21
+ markRequired?: boolean;
22
+ /** Add a subtle surface background to the fieldset. Default: false */
23
+ surface?: boolean;
24
+ children?: React.ReactNode;
25
+ }
26
+
27
+ export declare function Fieldset(props: FieldsetProps): React.ReactElement;
@@ -0,0 +1,39 @@
1
+ import * as React from "react";
2
+
3
+ type SpacingToken = 1 | 2 | 4 | 6 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 64 | 96 | 128;
4
+
5
+ export interface FigureProps extends React.HTMLAttributes<HTMLElement> {
6
+ /** Image source URL */
7
+ src: string;
8
+ /** Image alt text. Pass "" for decorative images. */
9
+ alt?: string;
10
+ /** Caption text or React node rendered as `<figcaption>` */
11
+ caption?: React.ReactNode;
12
+ /** Render caption visually hidden (screen-reader only). Default: false */
13
+ captionSrOnly?: boolean;
14
+ /** Caption alignment. Default: "start" */
15
+ captionPosition?: "start" | "center";
16
+ /** Border radius on the image. */
17
+ radius?: "none" | "sm" | "md" | "lg";
18
+ /** Constrain figure width. */
19
+ size?: "xs" | "sm" | "md" | "lg";
20
+ /** Horizontal alignment of the figure. Default: "start" */
21
+ align?: "start" | "center" | "end";
22
+ /** Top margin. */
23
+ marginTop?: "sm" | "md" | "lg";
24
+ /** Bottom margin. */
25
+ marginBottom?: "sm" | "md" | "lg";
26
+ /**
27
+ * Pull the figure outside its container padding using `Bleed`.
28
+ * Pass `true` for symmetric bleed or a numeric spacing token for inline-only.
29
+ */
30
+ bleed?: boolean | SpacingToken;
31
+ /** Extra class names on the `<figure>` element */
32
+ className?: string;
33
+ /** Extra class names on the `<img>` element */
34
+ imgClassName?: string;
35
+ /** Inline styles for the `<img>` element */
36
+ imgStyle?: React.CSSProperties;
37
+ }
38
+
39
+ export declare function Figure(props: FigureProps): React.ReactElement;
@@ -0,0 +1,38 @@
1
+ import * as React from "react";
2
+
3
+ type Breakpoints = "xs" | "sm" | "md" | "lg" | "xl";
4
+ type GapKey = "xs" | "sm" | "md" | "lg" | "xl" | "xxl" | 1 | 2 | 4 | 6 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 64 | 96 | 128;
5
+ type ColSpan = number | "full";
6
+
7
+ export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ /**
9
+ * Number of columns. Pass a number for a fixed count, or a responsive object.
10
+ * @example columns={{ xs: 1, md: 2, lg: 3 }}
11
+ */
12
+ columns?: number | Partial<Record<Breakpoints, number>>;
13
+ /** Gap applied to both row and column. Semantic token ("sm"–"xxl") or numeric spacing value. */
14
+ gap?: GapKey;
15
+ /** Row gap override. Falls back to `gap`. */
16
+ rowGap?: GapKey;
17
+ /** Column gap override. Falls back to `gap`. */
18
+ columnGap?: GapKey;
19
+ /** Grid layout preset. Default: "default" */
20
+ layout?: "default" | "bento";
21
+ /** CSS value for `grid-auto-rows` */
22
+ autoRows?: string;
23
+ children?: React.ReactNode;
24
+ }
25
+
26
+ export interface GridItemProps extends React.HTMLAttributes<HTMLDivElement> {
27
+ /**
28
+ * Column span. Pass a number, "full", or a responsive object.
29
+ * @example span={{ xs: "full", md: 2 }}
30
+ */
31
+ span?: ColSpan | Partial<Record<Breakpoints, ColSpan>>;
32
+ /** Row span. Pass a number or a responsive object. */
33
+ rowSpan?: number | Partial<Record<Breakpoints, number>>;
34
+ children?: React.ReactNode;
35
+ }
36
+
37
+ export declare function Grid(props: GridProps): React.ReactElement;
38
+ export declare function GridItem(props: GridItemProps): React.ReactElement;
@@ -0,0 +1,43 @@
1
+ import * as React from "react";
2
+
3
+ type Breakpoints = "xs" | "sm" | "md" | "lg" | "xl";
4
+ type HeadingSize = "xxl" | "xl" | "lg" | "md" | "sm" | "xs";
5
+ type DisplaySize = "sm" | "md" | "lg" | "xl" | "xxl" | "jumbo" | "xJumbo";
6
+
7
+ export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
8
+ /** HTML heading level. Default: "h2" */
9
+ as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span";
10
+ /**
11
+ * Typography type — drives the available size scale.
12
+ * "heading" uses the text hierarchy scale; "display" uses the larger editorial scale.
13
+ * Default: "heading"
14
+ */
15
+ type?: "heading" | "display";
16
+ /**
17
+ * Size within the active type scale. Responsive object syntax supported.
18
+ * Heading sizes: xs | sm | md | lg | xl | xxl
19
+ * Display sizes: sm | md | lg | xl | xxl | jumbo | xJumbo
20
+ * @example size={{ xs: "lg", md: "xl" }}
21
+ */
22
+ size?: HeadingSize | DisplaySize | Partial<Record<Breakpoints, HeadingSize | DisplaySize>>;
23
+ /** Text colour. Default: "default" */
24
+ color?: "default" | "muted" | "accent";
25
+ /** Add bottom margin. Useful when followed by body text. */
26
+ margin?: "sm" | "md" | "lg";
27
+ /** Apply text-wrap. "balance" distributes line lengths evenly — best for short headings. */
28
+ textWrap?: "balance";
29
+ /** Horizontal text alignment. "start"/"end" are logical aliases for LTR/RTL-safe alignment. */
30
+ align?: "left" | "center" | "right" | "start" | "end";
31
+ children?: React.ReactNode;
32
+ }
33
+
34
+ export interface HeadingMarkProps extends React.HTMLAttributes<HTMLSpanElement> {
35
+ /** Visual decoration style. Default: "highlight" */
36
+ variant?: "highlight" | "underline";
37
+ /** Underline style (only applies when variant="underline"). Default: "swoop" */
38
+ underlineStyle?: "swoop" | "wave" | "sketch";
39
+ children?: React.ReactNode;
40
+ }
41
+
42
+ export declare function Heading(props: HeadingProps): React.ReactElement;
43
+ export declare function HeadingMark(props: HeadingMarkProps): React.ReactElement;
@@ -4,7 +4,7 @@ const headingSizes = ["xxl", "xl", "lg", "md", "sm", "xs"];
4
4
  const displaySizes = ["sm", "md", "lg", "xl", "xxl", "jumbo", "xJumbo"];
5
5
  const colors = ["default", "muted", "accent"];
6
6
  const margins = ["sm", "md", "lg"];
7
- const levels = ["h1", "h2", "h3", "h4", "h5", "h6"];
7
+ const elements = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "span"];
8
8
  const breakpoints = ["xs", "sm", "md", "lg", "xl"];
9
9
  const textWraps = ["balance"];
10
10
  const aligns = ["left", "center", "right", "start", "end"];
@@ -50,7 +50,7 @@ export function Heading({
50
50
  style,
51
51
  ...props
52
52
  }) {
53
- const resolvedAs = levels.includes(Component) ? Component : "h2";
53
+ const resolvedAs = elements.includes(Component) ? Component : "h2";
54
54
  const isDisplay = type === "display";
55
55
  const validSizes = isDisplay ? displaySizes : headingSizes;
56
56
  const defaultSize = isDisplay ? "md" : (levelDefaults[resolvedAs] ?? "md");
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+
3
+ export interface IconProps extends React.HTMLAttributes<HTMLSpanElement> {
4
+ /** Material Symbols icon name (e.g. "check_circle", "home", "arrow_back") */
5
+ name: string;
6
+ /**
7
+ * Variable font weight axis (100–700).
8
+ * Default is set via CSS token `--a1-icon-weight`.
9
+ */
10
+ weight?: number;
11
+ /**
12
+ * Grade axis — adjusts visual weight without changing size (-25–200).
13
+ * Default is set via CSS token `--a1-icon-grade`.
14
+ */
15
+ grade?: number;
16
+ /**
17
+ * Optical size axis — adjusts detail level (20, 24, 40, 48).
18
+ * Default is set via CSS token `--a1-icon-opsz`.
19
+ */
20
+ opticalSize?: 20 | 24 | 40 | 48;
21
+ /** Fill the icon shape. Default: false */
22
+ fill?: boolean;
23
+ }
24
+
25
+ export declare function Icon(props: IconProps): React.ReactElement;