@gtivr4/a1-design-system-react 0.1.0 → 0.2.3
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/color-scheme.css +586 -24
- package/src/components/accordion/Accordion.jsx +80 -0
- package/src/components/accordion/accordion.css +118 -0
- package/src/components/banner/Banner.jsx +66 -0
- package/src/components/banner/banner.css +205 -0
- package/src/components/bleed/Bleed.jsx +27 -0
- package/src/components/bleed/bleed.css +5 -0
- package/src/components/blockquote/Blockquote.jsx +40 -0
- package/src/components/blockquote/blockquote.css +166 -0
- package/src/components/breadcrumb/Breadcrumb.jsx +82 -0
- package/src/components/breadcrumb/breadcrumb.css +133 -0
- package/src/components/button/button.css +42 -12
- package/src/components/button-container/ButtonContainer.jsx +20 -1
- package/src/components/button-container/button-container.css +19 -1
- package/src/components/calendar/Calendar.jsx +383 -0
- package/src/components/calendar/calendar.css +225 -0
- package/src/components/card/Card.jsx +50 -12
- package/src/components/card/card.css +178 -14
- package/src/components/checkbox-group/CheckboxGroup.jsx +120 -0
- package/src/components/checkbox-group/checkbox-group.css +304 -0
- package/src/components/cluster/Cluster.jsx +52 -0
- package/src/components/cluster/cluster.css +9 -0
- package/src/components/code/Code.jsx +135 -0
- package/src/components/code/code.css +60 -0
- package/src/components/data-table/DataTable.jsx +721 -0
- package/src/components/data-table/DataTableFilters.jsx +339 -0
- package/src/components/data-table/data-table-filters.css +259 -0
- package/src/components/data-table/data-table.css +425 -0
- package/src/components/dialog/Dialog.jsx +45 -2
- package/src/components/dialog/dialog.css +13 -4
- package/src/components/divider/Divider.jsx +64 -0
- package/src/components/divider/divider.css +170 -0
- package/src/components/field/CreditCardField.jsx +131 -0
- package/src/components/field/DateField.jsx +11 -0
- package/src/components/field/NumberField.jsx +11 -0
- package/src/components/field/PhoneField.jsx +107 -0
- package/src/components/field/SelectField.jsx +86 -0
- package/src/components/field/TextField.jsx +83 -0
- package/src/components/field/TextareaField.jsx +147 -0
- package/src/components/field/TimeField.jsx +11 -0
- package/src/components/field/ZipField.jsx +114 -0
- package/src/components/field/credit-card.css +30 -0
- package/src/components/field/field.css +380 -0
- package/src/components/field/textarea-field.css +185 -0
- package/src/components/field-row/FieldRow.jsx +23 -0
- package/src/components/field-row/field-row.css +51 -0
- package/src/components/fieldset/Fieldset.jsx +49 -0
- package/src/components/fieldset/fieldset.css +75 -0
- package/src/components/figure/Figure.jsx +63 -0
- package/src/components/figure/figure.css +97 -0
- package/src/components/grid/Grid.jsx +36 -2
- package/src/components/grid/grid.css +129 -4
- package/src/components/heading/Heading.jsx +41 -1
- package/src/components/heading/heading.css +65 -4
- package/src/components/icon/icon.css +1 -0
- package/src/components/icon-button/icon-button.css +1 -0
- package/src/components/inline/inline.css +51 -0
- package/src/components/inline-editable/InlineEditable.jsx +77 -0
- package/src/components/inline-editable/inline-editable.css +47 -0
- package/src/components/inset/Inset.jsx +27 -0
- package/src/components/inset/inset.css +6 -0
- package/src/components/labels/Labels.jsx +5 -5
- package/src/components/link/Link.jsx +2 -3
- package/src/components/link/link.css +30 -1
- package/src/components/list/List.jsx +92 -0
- package/src/components/list/list.css +178 -0
- package/src/components/menu/Menu.jsx +243 -10
- package/src/components/menu/menu.css +157 -17
- package/src/components/message/Message.jsx +25 -50
- package/src/components/message/message.css +50 -33
- package/src/components/notification/Notification.jsx +1 -1
- package/src/components/page-layout/PageLayout.jsx +16 -1
- package/src/components/page-layout/page-layout.css +97 -4
- package/src/components/page-nav/PageNav.jsx +110 -0
- package/src/components/page-nav/page-nav.css +167 -0
- package/src/components/paragraph/Paragraph.jsx +35 -2
- package/src/components/paragraph/paragraph.css +38 -1
- package/src/components/radio-group/RadioGroup.jsx +121 -0
- package/src/components/radio-group/radio-group.css +268 -0
- package/src/components/section/Section.jsx +108 -0
- package/src/components/section/section.css +280 -0
- package/src/components/segmented-control/SegmentedControl.jsx +4 -0
- package/src/components/segmented-control/segmented.css +13 -0
- package/src/components/side-nav/SideNav.jsx +29 -9
- package/src/components/side-nav/scrim.css +1 -1
- package/src/components/side-nav/side-nav.css +70 -32
- package/src/components/snackbar/Snackbar.jsx +56 -0
- package/src/components/snackbar/snackbar.css +113 -0
- package/src/components/spacer/Spacer.jsx +36 -0
- package/src/components/spacer/spacer.css +44 -0
- package/src/components/stack/Stack.jsx +100 -0
- package/src/components/stack/stack.css +37 -0
- package/src/components/switch/Switch.jsx +114 -0
- package/src/components/switch/switch.css +276 -0
- package/src/components/system-banner/SystemBanner.jsx +57 -0
- package/src/components/system-banner/system-banner.css +118 -0
- package/src/components/tabs/Tabs.jsx +96 -28
- package/src/components/tabs/tabs.css +352 -15
- package/src/components/token-select/TokenSelect.jsx +159 -0
- package/src/components/token-select/token-select.css +110 -0
- package/src/components/top-header/TopHeader.jsx +641 -0
- package/src/components/top-header/top-header.css +337 -0
- package/src/illustrations/ComponentThumbnails.jsx +227 -0
- package/src/index.js +41 -5
- package/src/themes.css +256 -5
- package/src/utilities/spacing.css +8 -0
- package/src/utilities/sr-only.css +16 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/* ─── TextareaField — size-specific padding ──────────────────────────────── */
|
|
2
|
+
|
|
3
|
+
.a1-field {
|
|
4
|
+
--a1-textarea-padding-block: var(--component-field-textarea-padding-block);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.a1-field--comfortable {
|
|
8
|
+
--a1-textarea-padding-block: var(--component-field-textarea-padding-block-comfortable);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.a1-field--compact {
|
|
12
|
+
--a1-textarea-padding-block: var(--component-field-textarea-padding-block-compact);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* ─── Textarea control ───────────────────────────────────────────────────── */
|
|
16
|
+
|
|
17
|
+
.a1-field__textarea {
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
display: block; /* removes inline gap below element */
|
|
20
|
+
width: 100%;
|
|
21
|
+
padding-inline: var(--a1-field-padding-inline);
|
|
22
|
+
padding-block: var(--a1-textarea-padding-block);
|
|
23
|
+
font-family: var(--component-paragraph-font-family);
|
|
24
|
+
font-size: var(--a1-field-font-size);
|
|
25
|
+
font-weight: var(--base-font-weight-regular);
|
|
26
|
+
line-height: var(--semantic-font-line-height-body);
|
|
27
|
+
color: var(--semantic-color-text-default);
|
|
28
|
+
background: var(--a1-field-background);
|
|
29
|
+
border: var(--component-field-border-width) solid var(--a1-field-border-color);
|
|
30
|
+
border-radius: var(--a1-field-border-radius);
|
|
31
|
+
transition:
|
|
32
|
+
border-color var(--semantic-motion-duration-fast),
|
|
33
|
+
background var(--semantic-motion-duration-fast);
|
|
34
|
+
-webkit-appearance: none;
|
|
35
|
+
appearance: none;
|
|
36
|
+
resize: vertical;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.a1-field__textarea::placeholder {
|
|
40
|
+
color: var(--semantic-color-text-muted);
|
|
41
|
+
font-weight: var(--base-font-weight-regular);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ─── Hover ──────────────────────────────────────────────────────────────── */
|
|
45
|
+
|
|
46
|
+
.a1-field__textarea:hover:not(:disabled):not(:focus) {
|
|
47
|
+
background: var(--a1-field-hover-background);
|
|
48
|
+
border-color: var(--a1-field-hover-border-color);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.a1-field__textarea:read-only:hover:not(:disabled):not(:focus) {
|
|
52
|
+
background: var(--a1-field-read-only-background);
|
|
53
|
+
border-color: var(--a1-field-read-only-border-color);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* ─── Active ─────────────────────────────────────────────────────────────── */
|
|
57
|
+
|
|
58
|
+
.a1-field__textarea:active:not(:disabled) {
|
|
59
|
+
background: var(--a1-field-active-background);
|
|
60
|
+
border-color: var(--a1-field-active-border-color);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.a1-field__textarea:read-only:active:not(:disabled) {
|
|
64
|
+
background: var(--a1-field-read-only-background);
|
|
65
|
+
border-color: var(--a1-field-read-only-border-color);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ─── Focus ──────────────────────────────────────────────────────────────── */
|
|
69
|
+
|
|
70
|
+
.a1-field__textarea:focus {
|
|
71
|
+
outline: var(--a1-field-focus-ring-width) solid var(--a1-field-focus-ring-color);
|
|
72
|
+
outline-offset: var(--a1-field-focus-ring-offset);
|
|
73
|
+
border-color: var(--semantic-color-action-background);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ─── Required ───────────────────────────────────────────────────────────── */
|
|
77
|
+
|
|
78
|
+
.a1-field--required .a1-field__textarea {
|
|
79
|
+
border-color: var(--semantic-color-status-info-border);
|
|
80
|
+
border-left-width: var(--a1-field-accent-border-width);
|
|
81
|
+
border-left-color: var(--semantic-color-status-info-background);
|
|
82
|
+
padding-left: calc(var(--a1-field-padding-inline) - var(--a1-field-accent-compensation));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.a1-field--required .a1-field__textarea:focus {
|
|
86
|
+
border-color: var(--semantic-color-status-info-background);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ─── Error ──────────────────────────────────────────────────────────────── */
|
|
90
|
+
|
|
91
|
+
.a1-field--error .a1-field__textarea {
|
|
92
|
+
border-width: var(--component-field-error-border-width);
|
|
93
|
+
border-color: var(--semantic-color-status-error-border);
|
|
94
|
+
border-left-width: var(--a1-field-accent-border-width);
|
|
95
|
+
border-left-color: var(--semantic-color-status-error-background);
|
|
96
|
+
padding-left: calc(var(--a1-field-padding-inline) - var(--a1-field-accent-compensation));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.a1-field--error .a1-field__textarea:focus {
|
|
100
|
+
border-color: var(--semantic-color-status-error-background);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ─── Disabled ───────────────────────────────────────────────────────────── */
|
|
104
|
+
|
|
105
|
+
.a1-field__textarea:disabled {
|
|
106
|
+
background: var(--semantic-color-surface-raised);
|
|
107
|
+
color: var(--semantic-color-text-muted);
|
|
108
|
+
border-color: var(--semantic-color-border-subtle);
|
|
109
|
+
cursor: not-allowed;
|
|
110
|
+
resize: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* ─── Read-only ──────────────────────────────────────────────────────────── */
|
|
114
|
+
|
|
115
|
+
.a1-field__textarea:read-only:not(:disabled) {
|
|
116
|
+
background: var(--a1-field-read-only-background);
|
|
117
|
+
color: var(--a1-field-read-only-text);
|
|
118
|
+
border-color: var(--a1-field-read-only-border-color);
|
|
119
|
+
cursor: text;
|
|
120
|
+
user-select: text;
|
|
121
|
+
resize: none;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ─── Footer (hint / error + char count row) ─────────────────────────────── */
|
|
125
|
+
|
|
126
|
+
.a1-field__footer {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: baseline;
|
|
129
|
+
gap: var(--base-spacing-8);
|
|
130
|
+
margin-top: var(--a1-field-gap);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.a1-field__footer-message {
|
|
134
|
+
flex: 1;
|
|
135
|
+
min-width: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.a1-field__footer .a1-field__message {
|
|
139
|
+
margin: 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ─── Character count ────────────────────────────────────────────────────── */
|
|
143
|
+
|
|
144
|
+
.a1-field__char-count {
|
|
145
|
+
font-family: var(--component-paragraph-font-family);
|
|
146
|
+
font-size: var(--a1-field-message-size);
|
|
147
|
+
line-height: var(--semantic-font-line-height-body);
|
|
148
|
+
color: var(--semantic-color-text-muted);
|
|
149
|
+
white-space: nowrap;
|
|
150
|
+
flex-shrink: 0;
|
|
151
|
+
font-variant-numeric: tabular-nums;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.a1-field__char-count--warning {
|
|
155
|
+
color: var(--semantic-color-status-warn-text);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.a1-field__char-count--over {
|
|
159
|
+
color: var(--semantic-color-status-error-text);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ─── Side label layout adjustments ─────────────────────────────────────── */
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
* Align label to the top of the textarea's first text line rather than
|
|
166
|
+
* centering it vertically as with single-line inputs.
|
|
167
|
+
*/
|
|
168
|
+
.a1-field--label-side:has(.a1-field__textarea) .a1-field__label {
|
|
169
|
+
padding-top: var(--a1-textarea-padding-block);
|
|
170
|
+
padding-bottom: 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Place the footer under the textarea (column 2) instead of under the label */
|
|
174
|
+
.a1-field--label-side .a1-field__footer {
|
|
175
|
+
grid-column: 2;
|
|
176
|
+
grid-row: 2;
|
|
177
|
+
margin-top: 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@media (--bp-sm-down) {
|
|
181
|
+
.a1-field--label-side:has(.a1-field__textarea) .a1-field__label {
|
|
182
|
+
padding-top: 0;
|
|
183
|
+
padding-bottom: var(--a1-field-gap);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { FieldsetContext } from "../fieldset/FieldsetContext.js";
|
|
3
|
+
import "./field-row.css";
|
|
4
|
+
|
|
5
|
+
export function FieldRow({ children, className = "", ...props }) {
|
|
6
|
+
const ctx = useContext(FieldsetContext);
|
|
7
|
+
|
|
8
|
+
// Side-label fields already use an internal two-column grid;
|
|
9
|
+
// stacking the row prevents layout conflicts.
|
|
10
|
+
const stacked = ctx?.labelPosition === "side";
|
|
11
|
+
|
|
12
|
+
const classes = [
|
|
13
|
+
"a1-field-row",
|
|
14
|
+
stacked && "a1-field-row--stacked",
|
|
15
|
+
className,
|
|
16
|
+
].filter(Boolean).join(" ");
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className={classes} {...props}>
|
|
20
|
+
{children}
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* ─── FieldRow ───────────────────────────────────────────────────────────── */
|
|
2
|
+
|
|
3
|
+
.a1-field-row {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: flex-start;
|
|
6
|
+
gap: var(--base-spacing-12);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* Every direct child fills an equal share of the available width */
|
|
10
|
+
.a1-field-row > * {
|
|
11
|
+
flex: 1 1 0;
|
|
12
|
+
min-width: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Fixed-width fields (ZipField, DateField) keep their natural fit-content width */
|
|
16
|
+
.a1-field-row > .a1-field--fit {
|
|
17
|
+
flex: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* ─── Stacked — used when side labels are active ─────────────────────────── */
|
|
21
|
+
|
|
22
|
+
.a1-field-row--stacked {
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.a1-field-row--stacked > * {
|
|
27
|
+
flex: none;
|
|
28
|
+
width: 100%;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Fit-content fields don't stretch to full width even when stacked */
|
|
32
|
+
.a1-field-row--stacked > .a1-field--fit {
|
|
33
|
+
width: fit-content;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* ─── Responsive — stack on xs / sm viewports ─────────────────────────────── */
|
|
37
|
+
|
|
38
|
+
@media (--bp-sm-down) {
|
|
39
|
+
.a1-field-row {
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.a1-field-row > * {
|
|
44
|
+
flex: none;
|
|
45
|
+
width: 100%;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.a1-field-row > .a1-field--fit {
|
|
49
|
+
width: fit-content;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FieldsetContext } from "./FieldsetContext.js";
|
|
2
|
+
import "./fieldset.css";
|
|
3
|
+
|
|
4
|
+
const SIZES = ["comfortable", "default", "compact"];
|
|
5
|
+
const LABEL_POSITIONS = ["above", "side"];
|
|
6
|
+
|
|
7
|
+
export function Fieldset({
|
|
8
|
+
legend,
|
|
9
|
+
size,
|
|
10
|
+
labelPosition,
|
|
11
|
+
markRequired = false,
|
|
12
|
+
surface = false,
|
|
13
|
+
children,
|
|
14
|
+
className = "",
|
|
15
|
+
...props
|
|
16
|
+
}) {
|
|
17
|
+
const resolvedSize = SIZES.includes(size) ? size : undefined;
|
|
18
|
+
const resolvedPosition = LABEL_POSITIONS.includes(labelPosition) ? labelPosition : undefined;
|
|
19
|
+
|
|
20
|
+
// Note appears for compact/default; comfortable fields already show a "Required" badge.
|
|
21
|
+
const showRequiredNote = markRequired && resolvedSize !== "comfortable";
|
|
22
|
+
|
|
23
|
+
const classes = [
|
|
24
|
+
"a1-fieldset",
|
|
25
|
+
surface && "a1-fieldset--surface",
|
|
26
|
+
className,
|
|
27
|
+
].filter(Boolean).join(" ");
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<FieldsetContext.Provider value={{ size: resolvedSize, labelPosition: resolvedPosition }}>
|
|
31
|
+
<fieldset className={classes} {...props}>
|
|
32
|
+
{legend && (
|
|
33
|
+
<legend className={`a1-fieldset__legend${showRequiredNote ? " a1-fieldset__legend--has-note" : ""}`}>
|
|
34
|
+
{legend}
|
|
35
|
+
</legend>
|
|
36
|
+
)}
|
|
37
|
+
{showRequiredNote && (
|
|
38
|
+
<p className="a1-fieldset__required-note">
|
|
39
|
+
<span className="a1-fieldset__required-note__asterisk">*</span>
|
|
40
|
+
{" "}Required field
|
|
41
|
+
</p>
|
|
42
|
+
)}
|
|
43
|
+
<div className="a1-fieldset__body">
|
|
44
|
+
{children}
|
|
45
|
+
</div>
|
|
46
|
+
</fieldset>
|
|
47
|
+
</FieldsetContext.Provider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* ─── Fieldset — reset browser defaults ──────────────────────────────────── */
|
|
2
|
+
|
|
3
|
+
.a1-fieldset {
|
|
4
|
+
border: none;
|
|
5
|
+
margin: 0;
|
|
6
|
+
padding: 0;
|
|
7
|
+
min-width: 0; /* prevents default overflow on narrow containers */
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* ─── Legend ─────────────────────────────────────────────────────────────── */
|
|
11
|
+
|
|
12
|
+
.a1-fieldset__legend {
|
|
13
|
+
display: block;
|
|
14
|
+
width: 100%;
|
|
15
|
+
padding: 0;
|
|
16
|
+
margin-bottom: var(--base-spacing-16);
|
|
17
|
+
font-family: var(--component-paragraph-font-family);
|
|
18
|
+
font-size: var(--semantic-font-size-body-lg);
|
|
19
|
+
font-weight: var(--component-field-label-font-weight);
|
|
20
|
+
color: var(--semantic-color-text-default);
|
|
21
|
+
line-height: var(--semantic-font-line-height-body);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Tighten bottom margin when the required note follows */
|
|
25
|
+
.a1-fieldset__legend--has-note {
|
|
26
|
+
margin-bottom: var(--base-spacing-4);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ─── Required note (* Required field) ───────────────────────────────────── */
|
|
30
|
+
|
|
31
|
+
.a1-fieldset__required-note {
|
|
32
|
+
margin: 0 0 var(--base-spacing-12);
|
|
33
|
+
font-family: var(--component-paragraph-font-family);
|
|
34
|
+
font-size: var(--semantic-font-size-body-xs);
|
|
35
|
+
color: var(--semantic-color-text-muted);
|
|
36
|
+
line-height: var(--semantic-font-line-height-body);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.a1-fieldset__required-note__asterisk {
|
|
40
|
+
color: var(--semantic-color-status-info-background);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* ─── Body ───────────────────────────────────────────────────────────────── */
|
|
44
|
+
|
|
45
|
+
.a1-fieldset__body {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
gap: var(--base-spacing-16);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* ─── Surface variant ────────────────────────────────────────────────────── */
|
|
52
|
+
|
|
53
|
+
.a1-fieldset--surface {
|
|
54
|
+
background: var(--semantic-color-surface-page);
|
|
55
|
+
border: var(--component-card-border-width) solid var(--semantic-color-border-subtle);
|
|
56
|
+
border-radius: var(--component-card-border-radius);
|
|
57
|
+
box-shadow: var(--component-card-shadow);
|
|
58
|
+
padding: var(--component-card-padding);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
* float: left is the standard hack to pull <legend> out of its special
|
|
63
|
+
* browser rendering (where it would otherwise sit on top of the border).
|
|
64
|
+
* With float the legend becomes a normal block at the top of the card.
|
|
65
|
+
*/
|
|
66
|
+
.a1-fieldset--surface > .a1-fieldset__legend {
|
|
67
|
+
float: left;
|
|
68
|
+
width: 100%;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Clear the legend float so subsequent content flows below it */
|
|
72
|
+
.a1-fieldset--surface > .a1-fieldset__required-note,
|
|
73
|
+
.a1-fieldset--surface > .a1-fieldset__body {
|
|
74
|
+
clear: left;
|
|
75
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import "./figure.css";
|
|
2
|
+
import { Bleed } from "../bleed/Bleed.jsx";
|
|
3
|
+
|
|
4
|
+
const rounded = ["none", "sm", "md", "lg"];
|
|
5
|
+
const captionPositions = ["start", "center"];
|
|
6
|
+
const spacings = ["sm", "md", "lg"];
|
|
7
|
+
const sizes = ["xs", "sm", "md", "lg"];
|
|
8
|
+
const alignments = ["start", "center", "end"];
|
|
9
|
+
|
|
10
|
+
export function Figure({
|
|
11
|
+
src,
|
|
12
|
+
alt = "",
|
|
13
|
+
caption,
|
|
14
|
+
captionSrOnly = false,
|
|
15
|
+
captionPosition = "start",
|
|
16
|
+
radius,
|
|
17
|
+
size,
|
|
18
|
+
align,
|
|
19
|
+
marginTop,
|
|
20
|
+
marginBottom,
|
|
21
|
+
bleed,
|
|
22
|
+
className = "",
|
|
23
|
+
imgClassName = "",
|
|
24
|
+
style,
|
|
25
|
+
imgStyle,
|
|
26
|
+
...props
|
|
27
|
+
}) {
|
|
28
|
+
const classes = [
|
|
29
|
+
"a1-figure",
|
|
30
|
+
radius != null && rounded.includes(radius) && `a1-figure--rounded-${radius}`,
|
|
31
|
+
captionPositions.includes(captionPosition) && captionPosition !== "start" && `a1-figure--caption-${captionPosition}`,
|
|
32
|
+
sizes.includes(size) && `a1-figure--${size}`,
|
|
33
|
+
alignments.includes(align) && align !== "start" && `a1-figure--align-${align}`,
|
|
34
|
+
spacings.includes(marginTop) && `a1-figure--mt-${marginTop}`,
|
|
35
|
+
spacings.includes(marginBottom) && `a1-figure--mb-${marginBottom}`,
|
|
36
|
+
className,
|
|
37
|
+
].filter(Boolean).join(" ");
|
|
38
|
+
|
|
39
|
+
const captionClasses = [
|
|
40
|
+
captionSrOnly ? "a1-sr-only" : "a1-figure__caption",
|
|
41
|
+
].join(" ");
|
|
42
|
+
|
|
43
|
+
const figure = (
|
|
44
|
+
<figure className={classes} style={style} {...props}>
|
|
45
|
+
<img
|
|
46
|
+
src={src}
|
|
47
|
+
alt={alt}
|
|
48
|
+
className={["a1-figure__img", imgClassName].filter(Boolean).join(" ")}
|
|
49
|
+
style={imgStyle}
|
|
50
|
+
/>
|
|
51
|
+
{caption && (
|
|
52
|
+
<figcaption className={captionClasses}>{caption}</figcaption>
|
|
53
|
+
)}
|
|
54
|
+
</figure>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (bleed) {
|
|
58
|
+
const inlineValue = bleed === true ? undefined : bleed;
|
|
59
|
+
return <Bleed inline={inlineValue}>{figure}</Bleed>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return figure;
|
|
63
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* ══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
Figure
|
|
3
|
+
══════════════════════════════════════════════════════════════════════════ */
|
|
4
|
+
|
|
5
|
+
@import "../../utilities/sr-only.css";
|
|
6
|
+
|
|
7
|
+
.a1-figure {
|
|
8
|
+
margin: 0;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
gap: var(--base-spacing-8);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.a1-figure__img {
|
|
15
|
+
display: block;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: auto;
|
|
18
|
+
border-radius: var(--base-radius-container);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.a1-figure__caption {
|
|
22
|
+
font-family: var(--component-paragraph-font-family);
|
|
23
|
+
font-size: var(--semantic-font-size-body-sm);
|
|
24
|
+
font-weight: var(--semantic-font-weight-body);
|
|
25
|
+
line-height: var(--semantic-font-line-height-body);
|
|
26
|
+
color: var(--semantic-color-text-muted);
|
|
27
|
+
font-style: italic;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* ── Rounded modifier ──────────────────────────────────────────────────────── */
|
|
31
|
+
|
|
32
|
+
.a1-figure--rounded .a1-figure__img {
|
|
33
|
+
border-radius: var(--base-radius-container);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.a1-figure--rounded-none .a1-figure__img {
|
|
37
|
+
border-radius: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.a1-figure--rounded-sm .a1-figure__img {
|
|
41
|
+
border-radius: var(--base-radius-sm);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.a1-figure--rounded-md .a1-figure__img {
|
|
45
|
+
border-radius: var(--base-radius-md);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.a1-figure--rounded-lg .a1-figure__img {
|
|
49
|
+
border-radius: var(--base-radius-lg);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ── Margin ──────────────────────────────────────────────────────────────── */
|
|
53
|
+
|
|
54
|
+
.a1-figure--mt-sm { margin-top: var(--base-spacing-8); }
|
|
55
|
+
.a1-figure--mt-md { margin-top: var(--base-spacing-16); }
|
|
56
|
+
.a1-figure--mt-lg { margin-top: var(--base-spacing-24); }
|
|
57
|
+
|
|
58
|
+
.a1-figure--mb-sm { margin-bottom: var(--base-spacing-8); }
|
|
59
|
+
.a1-figure--mb-md { margin-bottom: var(--base-spacing-16); }
|
|
60
|
+
.a1-figure--mb-lg { margin-bottom: var(--base-spacing-24); }
|
|
61
|
+
|
|
62
|
+
/* ── Alignment ───────────────────────────────────────────────────────────── */
|
|
63
|
+
|
|
64
|
+
/* start/end: constrain the figure itself and shift via margin */
|
|
65
|
+
.a1-figure--align-end { margin-inline-start: auto; }
|
|
66
|
+
|
|
67
|
+
/* center: figure stays full-width; size constrains img + caption */
|
|
68
|
+
.a1-figure--align-center { align-items: center; }
|
|
69
|
+
|
|
70
|
+
/* ── Size ────────────────────────────────────────────────────────────────── */
|
|
71
|
+
|
|
72
|
+
/* Default: constrain the figure element */
|
|
73
|
+
.a1-figure--xs { max-width: 12rem; }
|
|
74
|
+
.a1-figure--sm { max-width: 20rem; }
|
|
75
|
+
.a1-figure--md { max-width: 30rem; }
|
|
76
|
+
.a1-figure--lg { max-width: 40rem; }
|
|
77
|
+
|
|
78
|
+
/* Center override: transfer the constraint to img + caption instead */
|
|
79
|
+
.a1-figure--align-center { max-width: none; }
|
|
80
|
+
|
|
81
|
+
.a1-figure--align-center.a1-figure--xs .a1-figure__img,
|
|
82
|
+
.a1-figure--align-center.a1-figure--xs .a1-figure__caption { max-width: 12rem; }
|
|
83
|
+
|
|
84
|
+
.a1-figure--align-center.a1-figure--sm .a1-figure__img,
|
|
85
|
+
.a1-figure--align-center.a1-figure--sm .a1-figure__caption { max-width: 20rem; }
|
|
86
|
+
|
|
87
|
+
.a1-figure--align-center.a1-figure--md .a1-figure__img,
|
|
88
|
+
.a1-figure--align-center.a1-figure--md .a1-figure__caption { max-width: 30rem; }
|
|
89
|
+
|
|
90
|
+
.a1-figure--align-center.a1-figure--lg .a1-figure__img,
|
|
91
|
+
.a1-figure--align-center.a1-figure--lg .a1-figure__caption { max-width: 40rem; }
|
|
92
|
+
|
|
93
|
+
/* ── Caption position ──────────────────────────────────────────────────────── */
|
|
94
|
+
|
|
95
|
+
.a1-figure--caption-center .a1-figure__caption {
|
|
96
|
+
text-align: center;
|
|
97
|
+
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import "./grid.css";
|
|
2
2
|
|
|
3
3
|
const SPACING_KEYS = [1, 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 64, 96, 128];
|
|
4
|
+
const gapSizes = {
|
|
5
|
+
sm: "var(--base-spacing-8)",
|
|
6
|
+
md: "var(--base-spacing-16)",
|
|
7
|
+
lg: "var(--base-spacing-24)",
|
|
8
|
+
xl: "var(--base-spacing-32)",
|
|
9
|
+
xxl: "var(--base-spacing-64)",
|
|
10
|
+
};
|
|
11
|
+
const layouts = ["default", "bento"];
|
|
12
|
+
const breakpoints = ["xs", "sm", "md", "lg", "xl"];
|
|
4
13
|
|
|
5
14
|
function resolveGap(key) {
|
|
6
15
|
if (key == null) return undefined;
|
|
16
|
+
if (gapSizes[key]) return gapSizes[key];
|
|
17
|
+
|
|
7
18
|
const n = Number(key);
|
|
8
19
|
return SPACING_KEYS.includes(n) ? `var(--base-spacing-${n})` : undefined;
|
|
9
20
|
}
|
|
@@ -13,11 +24,18 @@ export function Grid({
|
|
|
13
24
|
gap,
|
|
14
25
|
rowGap,
|
|
15
26
|
columnGap,
|
|
27
|
+
layout = "default",
|
|
28
|
+
autoRows,
|
|
16
29
|
className = "",
|
|
17
30
|
children,
|
|
18
31
|
...props
|
|
19
32
|
}) {
|
|
20
33
|
const classes = ["a1-grid"];
|
|
34
|
+
const resolvedLayout = layouts.includes(layout) ? layout : "default";
|
|
35
|
+
|
|
36
|
+
if (resolvedLayout !== "default") {
|
|
37
|
+
classes.push(`a1-grid--${resolvedLayout}`);
|
|
38
|
+
}
|
|
21
39
|
|
|
22
40
|
let inlineCols;
|
|
23
41
|
if (typeof columns === "number") {
|
|
@@ -36,6 +54,7 @@ export function Grid({
|
|
|
36
54
|
|
|
37
55
|
const style = {
|
|
38
56
|
...(inlineCols != null ? { "--a1-grid-cols": inlineCols } : {}),
|
|
57
|
+
...(autoRows ? { "--a1-grid-auto-rows": autoRows } : {}),
|
|
39
58
|
...(rowGapVal ? { rowGap: rowGapVal } : {}),
|
|
40
59
|
...(colGapVal ? { columnGap: colGapVal } : {}),
|
|
41
60
|
...props.style,
|
|
@@ -57,13 +76,28 @@ export function GridItem({
|
|
|
57
76
|
}) {
|
|
58
77
|
const classes = ["a1-grid-item"];
|
|
59
78
|
|
|
60
|
-
if (span === "
|
|
79
|
+
if (span && typeof span === "object") {
|
|
80
|
+
for (const [bp, value] of Object.entries(span)) {
|
|
81
|
+
if (!breakpoints.includes(bp)) continue;
|
|
82
|
+
if (value === "full") {
|
|
83
|
+
classes.push(`a1-grid-item--${bp}-span-full`);
|
|
84
|
+
} else if (typeof value === "number") {
|
|
85
|
+
classes.push(`a1-grid-item--${bp}-span-${value}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} else if (span === "full") {
|
|
61
89
|
classes.push("a1-grid-item--span-full");
|
|
62
90
|
} else if (typeof span === "number") {
|
|
63
91
|
classes.push(`a1-grid-item--span-${span}`);
|
|
64
92
|
}
|
|
65
93
|
|
|
66
|
-
if (typeof rowSpan === "
|
|
94
|
+
if (rowSpan && typeof rowSpan === "object") {
|
|
95
|
+
for (const [bp, value] of Object.entries(rowSpan)) {
|
|
96
|
+
if (breakpoints.includes(bp) && typeof value === "number") {
|
|
97
|
+
classes.push(`a1-grid-item--${bp}-row-span-${value}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} else if (typeof rowSpan === "number") {
|
|
67
101
|
classes.push(`a1-grid-item--row-span-${rowSpan}`);
|
|
68
102
|
}
|
|
69
103
|
|