@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.
- package/package.json +2 -1
- package/src/components/accordion/Accordion.d.ts +20 -0
- package/src/components/banner/Banner.d.ts +19 -0
- package/src/components/bleed/Bleed.d.ts +17 -0
- package/src/components/blockquote/Blockquote.d.ts +23 -0
- package/src/components/breadcrumb/Breadcrumb.d.ts +22 -0
- package/src/components/button/Button.d.ts +17 -0
- package/src/components/button-container/ButtonContainer.d.ts +11 -0
- package/src/components/calendar/Calendar.d.ts +75 -0
- package/src/components/calendar/Calendar.jsx +76 -13
- package/src/components/calendar/calendar.css +71 -0
- package/src/components/card/Card.d.ts +31 -0
- package/src/components/checkbox-group/CheckboxGroup.d.ts +37 -0
- package/src/components/choice-group/ChoiceGroup.d.ts +68 -0
- package/src/components/circular-progress/CircularProgress.d.ts +37 -0
- package/src/components/circular-progress/CircularProgress.jsx +85 -0
- package/src/components/circular-progress/circular-progress.css +104 -0
- package/src/components/cluster/Cluster.d.ts +21 -0
- package/src/components/code/Code.d.ts +15 -0
- package/src/components/data-table/DataTable.d.ts +83 -0
- package/src/components/dialog/Dialog.d.ts +15 -0
- package/src/components/dialog/dialog.css +7 -3
- package/src/components/divider/Divider.d.ts +22 -0
- package/src/components/field/SelectField.d.ts +22 -0
- package/src/components/field/TextField.d.ts +21 -0
- package/src/components/field/TextareaField.d.ts +28 -0
- package/src/components/field-row/FieldRow.d.ts +8 -0
- package/src/components/fieldset/Fieldset.d.ts +27 -0
- package/src/components/figure/Figure.d.ts +39 -0
- package/src/components/grid/Grid.d.ts +38 -0
- package/src/components/heading/Heading.d.ts +43 -0
- package/src/components/heading/Heading.jsx +2 -2
- package/src/components/icon/Icon.d.ts +25 -0
- package/src/components/icon-button/IconButton.d.ts +14 -0
- package/src/components/inset/Inset.d.ts +17 -0
- package/src/components/inverse/Inverse.d.ts +9 -0
- package/src/components/link/Link.d.ts +15 -0
- package/src/components/list/List.d.ts +40 -0
- package/src/components/menu/Menu.d.ts +41 -0
- package/src/components/message/Message.d.ts +34 -0
- package/src/components/notification/Notification.d.ts +23 -0
- package/src/components/page-layout/PageLayout.d.ts +24 -0
- package/src/components/page-nav/PageNav.d.ts +19 -0
- package/src/components/pagination/Pagination.d.ts +19 -0
- package/src/components/paragraph/Paragraph.d.ts +23 -0
- package/src/components/radio-group/RadioGroup.d.ts +37 -0
- package/src/components/section/Section.d.ts +33 -0
- package/src/components/segmented-control/SegmentedControl.d.ts +23 -0
- package/src/components/side-nav/SideNav.d.ts +62 -0
- package/src/components/spacer/Spacer.d.ts +16 -0
- package/src/components/stack/Stack.d.ts +38 -0
- package/src/components/status-bar/StatusBar.d.ts +42 -0
- package/src/components/switch/Switch.d.ts +27 -0
- package/src/components/system-banner/SystemBanner.d.ts +17 -0
- package/src/components/tabs/Tabs.d.ts +53 -0
- package/src/index.js +2 -0
- package/src/tokens.css +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtivr4/a1-design-system-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "React components for the A1 token-driven design system.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"README.md",
|
|
18
18
|
"guidelines/**/*.md",
|
|
19
19
|
"src/**/*.css",
|
|
20
|
+
"src/**/*.d.ts",
|
|
20
21
|
"src/**/*.jsx",
|
|
21
22
|
"src/index.js",
|
|
22
23
|
"!src/**/*.stories.jsx",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface AccordionProps {
|
|
4
|
+
/** Trigger label text */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Controlled open state */
|
|
7
|
+
open?: boolean;
|
|
8
|
+
/** Initial open state (uncontrolled). Default: false */
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
/** Called with the next boolean when the trigger is clicked */
|
|
11
|
+
onChange?: (open: boolean) => void;
|
|
12
|
+
/** Size — affects trigger text size and padding. Default: "md" */
|
|
13
|
+
size?: "sm" | "md" | "lg";
|
|
14
|
+
/** Prevent the accordion from being toggled. Default: false */
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export declare function Accordion(props: AccordionProps): React.ReactElement;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface BannerProps {
|
|
4
|
+
/** Layout style. "inline" sits within content; "system" spans full width. Default: "inline" */
|
|
5
|
+
variant?: "inline" | "system";
|
|
6
|
+
/** Semantic status colour. Default: "neutral" */
|
|
7
|
+
status?: "neutral" | "info" | "success" | "warn" | "error";
|
|
8
|
+
/** Bold title text shown before the body */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Override the default status icon with any Material Symbols name */
|
|
11
|
+
icon?: string;
|
|
12
|
+
/** Action element (e.g. a Button) rendered at the trailing end */
|
|
13
|
+
action?: React.ReactNode;
|
|
14
|
+
/** Called when the dismiss button is clicked. Omit to hide the dismiss button. */
|
|
15
|
+
onDismiss?: () => void;
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export declare function Banner(props: BannerProps): React.ReactElement;
|
|
@@ -0,0 +1,17 @@
|
|
|
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 BleedProps extends React.HTMLAttributes<HTMLElement> {
|
|
6
|
+
/** Underlying element. Default: "div" */
|
|
7
|
+
as?: React.ElementType;
|
|
8
|
+
/** Base bleed amount applied to all axes when no axis-specific value is set. Default: 16 */
|
|
9
|
+
space?: SpacingToken | "none";
|
|
10
|
+
/** Block-axis (top/bottom) bleed override. Default: "none" */
|
|
11
|
+
block?: SpacingToken | "none";
|
|
12
|
+
/** Inline-axis (left/right) bleed override. Falls back to `space`. */
|
|
13
|
+
inline?: SpacingToken;
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare function Bleed(props: BleedProps): React.ReactElement;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface BlockquoteProps extends React.HTMLAttributes<HTMLElement> {
|
|
4
|
+
/**
|
|
5
|
+
* Visual style variant. Default: "border"
|
|
6
|
+
*
|
|
7
|
+
* border — left accent border, subtle background
|
|
8
|
+
* filled — filled neutral surface
|
|
9
|
+
* feature — large centered text with accent bar, for pullquotes
|
|
10
|
+
* minimal — no decoration, plain text
|
|
11
|
+
* accent — filled action-colour background with inverse text
|
|
12
|
+
* pull — centred editorial with curly quotes
|
|
13
|
+
* ruled — top + bottom horizontal rules, centred
|
|
14
|
+
*/
|
|
15
|
+
variant?: "border" | "filled" | "feature" | "minimal" | "accent" | "pull" | "ruled";
|
|
16
|
+
/** Attribution text rendered as a `<figcaption>` */
|
|
17
|
+
cite?: string;
|
|
18
|
+
/** URL that the cite text links to */
|
|
19
|
+
citeUrl?: string;
|
|
20
|
+
children?: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare function Blockquote(props: BlockquoteProps): React.ReactElement;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface BreadcrumbItem {
|
|
4
|
+
label: string;
|
|
5
|
+
href?: string;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface BreadcrumbProps extends React.HTMLAttributes<HTMLElement> {
|
|
10
|
+
/**
|
|
11
|
+
* Ordered list of breadcrumb items.
|
|
12
|
+
* The last item is treated as the current page (non-interactive).
|
|
13
|
+
* All previous items render as links or buttons.
|
|
14
|
+
*/
|
|
15
|
+
items?: BreadcrumbItem[];
|
|
16
|
+
/**
|
|
17
|
+
* Label for the back link shown in narrow containers. Defaults to "Back".
|
|
18
|
+
*/
|
|
19
|
+
backLabel?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export declare function Breadcrumb(props: BreadcrumbProps): React.ReactElement;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
4
|
+
/** Underlying element or component to render. Default: "button" */
|
|
5
|
+
as?: React.ElementType;
|
|
6
|
+
/** Visual style. Default: "primary" */
|
|
7
|
+
variant?: "primary" | "secondary" | "tertiary" | "destructive" | "success";
|
|
8
|
+
/** Size. Default: "md" */
|
|
9
|
+
size?: "sm" | "md" | "lg";
|
|
10
|
+
/** Material Symbols icon name to show alongside the label */
|
|
11
|
+
icon?: string;
|
|
12
|
+
/** Whether the icon appears before or after the label. Default: "start" */
|
|
13
|
+
iconPosition?: "start" | "end";
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare function Button(props: ButtonProps): React.ReactElement;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ButtonContainerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Horizontal alignment of buttons. Default: "start" */
|
|
5
|
+
align?: "start" | "center" | "end";
|
|
6
|
+
/** Default size passed to child Button elements that do not set their own size. */
|
|
7
|
+
size?: "sm" | "md" | "lg";
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export declare function ButtonContainer(props: ButtonContainerProps): React.ReactElement;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface CalendarMonth {
|
|
4
|
+
/** Full calendar year, e.g. 2026 */
|
|
5
|
+
year: number;
|
|
6
|
+
/** 1-indexed month: 1 = January … 12 = December */
|
|
7
|
+
month: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface CalendarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
/**
|
|
12
|
+
* Display mode.
|
|
13
|
+
* - `"scroll"` — renders all months vertically; parent container controls scrolling (default).
|
|
14
|
+
* - `"paginated"` — shows one month at a time with prev/next buttons and month/year selects.
|
|
15
|
+
*/
|
|
16
|
+
variant?: "scroll" | "paginated";
|
|
17
|
+
/**
|
|
18
|
+
* Month to centre the scroll position on at mount (scroll) or the initial month shown (paginated).
|
|
19
|
+
* Accepts a `Date` object or `{ year, month }` (month is 1-indexed).
|
|
20
|
+
* Defaults to the current month.
|
|
21
|
+
*/
|
|
22
|
+
initialMonth?: Date | CalendarMonth;
|
|
23
|
+
/**
|
|
24
|
+
* Total number of months to render. Only applies to `variant="scroll"`.
|
|
25
|
+
* Default: 13
|
|
26
|
+
*/
|
|
27
|
+
monthsToShow?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Highlight today's date with the action colour.
|
|
30
|
+
* Default: true
|
|
31
|
+
*/
|
|
32
|
+
highlightToday?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Apply a background tint to dates before today.
|
|
35
|
+
* Default: true
|
|
36
|
+
*/
|
|
37
|
+
dimPast?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Show a "Today" button in the paginated nav bar that jumps to the current month.
|
|
40
|
+
* Disabled automatically when already on the current month.
|
|
41
|
+
* Only applies to `variant="paginated"`.
|
|
42
|
+
* Default: false
|
|
43
|
+
*/
|
|
44
|
+
todayButton?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Enables date selection. When false (default), the calendar is display-only —
|
|
47
|
+
* no click handlers, hover effects, or keyboard interaction on day cells.
|
|
48
|
+
* Pass `selectedDate` or `defaultSelectedDate` alongside this prop.
|
|
49
|
+
* Default: false
|
|
50
|
+
*/
|
|
51
|
+
selectable?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The currently selected date (controlled). Pass `null` to clear the selection.
|
|
54
|
+
* Omit entirely to use uncontrolled mode with `defaultSelectedDate`.
|
|
55
|
+
*/
|
|
56
|
+
selectedDate?: Date | null;
|
|
57
|
+
/**
|
|
58
|
+
* Initial selected date for uncontrolled mode. Ignored when `selectedDate` is provided.
|
|
59
|
+
*/
|
|
60
|
+
defaultSelectedDate?: Date | null;
|
|
61
|
+
/**
|
|
62
|
+
* Called with the new `Date` whenever the user clicks a selectable day.
|
|
63
|
+
*/
|
|
64
|
+
onChange?: (date: Date) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Earliest selectable date (inclusive). Days before this are disabled.
|
|
67
|
+
*/
|
|
68
|
+
minDate?: Date;
|
|
69
|
+
/**
|
|
70
|
+
* Latest selectable date (inclusive). Days after this are disabled.
|
|
71
|
+
*/
|
|
72
|
+
maxDate?: Date;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export declare function Calendar(props: CalendarProps): React.ReactElement;
|
|
@@ -42,6 +42,12 @@ export function Calendar({
|
|
|
42
42
|
dimPast = true,
|
|
43
43
|
variant = "scroll",
|
|
44
44
|
todayButton = false,
|
|
45
|
+
selectable = false,
|
|
46
|
+
selectedDate,
|
|
47
|
+
defaultSelectedDate,
|
|
48
|
+
onChange,
|
|
49
|
+
minDate,
|
|
50
|
+
maxDate,
|
|
45
51
|
className = "",
|
|
46
52
|
...props
|
|
47
53
|
}) {
|
|
@@ -63,6 +69,35 @@ export function Calendar({
|
|
|
63
69
|
const [viewMonth, setViewMonth] = useState(centerMonth);
|
|
64
70
|
const currentMonthRef = useRef(null);
|
|
65
71
|
|
|
72
|
+
// Selection — controlled when selectedDate is provided, otherwise internal state
|
|
73
|
+
const isControlled = selectedDate !== undefined;
|
|
74
|
+
const [internalSelected, setInternalSelected] = useState(defaultSelectedDate ?? null);
|
|
75
|
+
const selected = isControlled ? selectedDate : internalSelected;
|
|
76
|
+
|
|
77
|
+
function isSameDay(d, y, m, day) {
|
|
78
|
+
return d instanceof Date && d.getFullYear() === y && d.getMonth() === m && d.getDate() === day;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isDayDisabled(y, m, day) {
|
|
82
|
+
const date = new Date(y, m, day);
|
|
83
|
+
if (minDate) {
|
|
84
|
+
const min = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
|
|
85
|
+
if (date < min) return true;
|
|
86
|
+
}
|
|
87
|
+
if (maxDate) {
|
|
88
|
+
const max = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate());
|
|
89
|
+
if (date > max) return true;
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function handleDayClick(y, m, day) {
|
|
95
|
+
if (isDayDisabled(y, m, day)) return;
|
|
96
|
+
const date = new Date(y, m, day);
|
|
97
|
+
if (!isControlled) setInternalSelected(date);
|
|
98
|
+
onChange?.(date);
|
|
99
|
+
}
|
|
100
|
+
|
|
66
101
|
// ── Localised strings ─────────────────────────────────────────
|
|
67
102
|
|
|
68
103
|
// Month names
|
|
@@ -210,15 +245,30 @@ export function Calendar({
|
|
|
210
245
|
dimPast &&
|
|
211
246
|
new Date(year, month, day) < new Date(todayYear, todayMonth, todayDay);
|
|
212
247
|
|
|
248
|
+
const isSelected = isSameDay(selected, year, month, day);
|
|
249
|
+
const isDisabled = isDayDisabled(year, month, day);
|
|
250
|
+
|
|
213
251
|
return (
|
|
214
252
|
<td
|
|
215
253
|
key={di}
|
|
216
254
|
className={[
|
|
217
255
|
"a1-calendar__day",
|
|
218
|
-
isToday
|
|
219
|
-
isPast
|
|
256
|
+
isToday && "a1-calendar__day--today",
|
|
257
|
+
isPast && "a1-calendar__day--past",
|
|
258
|
+
isSelected && "a1-calendar__day--selected",
|
|
259
|
+
isDisabled && "a1-calendar__day--disabled",
|
|
220
260
|
].filter(Boolean).join(" ")}
|
|
221
261
|
aria-current={isToday ? "date" : undefined}
|
|
262
|
+
aria-selected={isSelected ? true : undefined}
|
|
263
|
+
aria-disabled={isDisabled ? true : undefined}
|
|
264
|
+
tabIndex={selectable && !isDisabled ? 0 : undefined}
|
|
265
|
+
onClick={selectable && !isDisabled ? () => handleDayClick(year, month, day) : undefined}
|
|
266
|
+
onKeyDown={selectable && !isDisabled ? (e) => {
|
|
267
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
268
|
+
e.preventDefault();
|
|
269
|
+
handleDayClick(year, month, day);
|
|
270
|
+
}
|
|
271
|
+
} : undefined}
|
|
222
272
|
>
|
|
223
273
|
<span className="a1-calendar__day-number" aria-hidden="true">
|
|
224
274
|
{day}
|
|
@@ -235,17 +285,27 @@ export function Calendar({
|
|
|
235
285
|
|
|
236
286
|
// ── Paginated variant ─────────────────────────────────────────
|
|
237
287
|
if (variant === "paginated") {
|
|
238
|
-
const
|
|
239
|
-
const
|
|
288
|
+
const minYear = minDate ? minDate.getFullYear() : todayYear - 10;
|
|
289
|
+
const minMon = minDate ? minDate.getMonth() : 0;
|
|
290
|
+
const maxYear = maxDate ? maxDate.getFullYear() : todayYear + 15;
|
|
291
|
+
const maxMon = maxDate ? maxDate.getMonth() : 11;
|
|
292
|
+
|
|
293
|
+
const yearStart = minDate ? minDate.getFullYear() : todayYear - 10;
|
|
294
|
+
const yearEnd = maxDate ? maxDate.getFullYear() : todayYear + 15;
|
|
240
295
|
const years = Array.from({ length: yearEnd - yearStart + 1 }, (_, i) => yearStart + i);
|
|
241
296
|
|
|
297
|
+
const prevAtMin = viewYear === minYear && viewMonth === minMon;
|
|
298
|
+
const nextAtMax = viewYear === maxYear && viewMonth === maxMon;
|
|
299
|
+
|
|
242
300
|
const goPrev = () => {
|
|
301
|
+
if (prevAtMin) return;
|
|
243
302
|
const p = addMonths(viewYear, viewMonth, -1);
|
|
244
303
|
setViewYear(p.year);
|
|
245
304
|
setViewMonth(p.month);
|
|
246
305
|
};
|
|
247
306
|
|
|
248
307
|
const goNext = () => {
|
|
308
|
+
if (nextAtMax) return;
|
|
249
309
|
const n = addMonths(viewYear, viewMonth, 1);
|
|
250
310
|
setViewYear(n.year);
|
|
251
311
|
setViewMonth(n.month);
|
|
@@ -263,19 +323,19 @@ export function Calendar({
|
|
|
263
323
|
|
|
264
324
|
return (
|
|
265
325
|
<div
|
|
266
|
-
className={["a1-calendar", "a1-calendar--paginated", className].filter(Boolean).join(" ")}
|
|
326
|
+
className={["a1-calendar", "a1-calendar--paginated", selectable && "a1-calendar--selectable", className].filter(Boolean).join(" ")}
|
|
267
327
|
{...props}
|
|
268
328
|
>
|
|
269
329
|
<div className="a1-calendar__inner">
|
|
270
330
|
<div className="a1-calendar__nav">
|
|
271
331
|
|
|
272
332
|
<span className="a1-calendar__nav-wide">
|
|
273
|
-
<Button variant="tertiary" size="sm" icon={isRtl ? "chevron_right" : "chevron_left"} iconPosition="start" onClick={goPrev}>
|
|
333
|
+
<Button variant="tertiary" size="sm" icon={isRtl ? "chevron_right" : "chevron_left"} iconPosition="start" onClick={goPrev} disabled={prevAtMin}>
|
|
274
334
|
{prevMonthLabel}
|
|
275
335
|
</Button>
|
|
276
336
|
</span>
|
|
277
337
|
<span className="a1-calendar__nav-narrow">
|
|
278
|
-
<IconButton icon={isRtl ? "chevron_right" : "chevron_left"} label={prevMonthLabel} variant="tertiary" onClick={goPrev} />
|
|
338
|
+
<IconButton icon={isRtl ? "chevron_right" : "chevron_left"} label={prevMonthLabel} variant="tertiary" onClick={goPrev} disabled={prevAtMin} />
|
|
279
339
|
</span>
|
|
280
340
|
|
|
281
341
|
<div className="a1-calendar__nav-label">
|
|
@@ -286,9 +346,12 @@ export function Calendar({
|
|
|
286
346
|
value={viewMonth}
|
|
287
347
|
onChange={e => setViewMonth(Number(e.target.value))}
|
|
288
348
|
>
|
|
289
|
-
{MONTHS.map((name, i) =>
|
|
290
|
-
|
|
291
|
-
|
|
349
|
+
{MONTHS.map((name, i) => {
|
|
350
|
+
const disabled =
|
|
351
|
+
(viewYear === minYear && i < minMon) ||
|
|
352
|
+
(viewYear === maxYear && i > maxMon);
|
|
353
|
+
return <option key={i} value={i} disabled={disabled}>{name}</option>;
|
|
354
|
+
})}
|
|
292
355
|
</SelectField>
|
|
293
356
|
<SelectField
|
|
294
357
|
className="a1-calendar__nav-field"
|
|
@@ -327,12 +390,12 @@ export function Calendar({
|
|
|
327
390
|
</div>
|
|
328
391
|
|
|
329
392
|
<span className="a1-calendar__nav-wide">
|
|
330
|
-
<Button variant="tertiary" size="sm" icon={isRtl ? "chevron_left" : "chevron_right"} iconPosition="end" onClick={goNext}>
|
|
393
|
+
<Button variant="tertiary" size="sm" icon={isRtl ? "chevron_left" : "chevron_right"} iconPosition="end" onClick={goNext} disabled={nextAtMax}>
|
|
331
394
|
{nextMonthLabel}
|
|
332
395
|
</Button>
|
|
333
396
|
</span>
|
|
334
397
|
<span className="a1-calendar__nav-narrow">
|
|
335
|
-
<IconButton icon={isRtl ? "chevron_left" : "chevron_right"} label={nextMonthLabel} variant="tertiary" onClick={goNext} />
|
|
398
|
+
<IconButton icon={isRtl ? "chevron_left" : "chevron_right"} label={nextMonthLabel} variant="tertiary" onClick={goNext} disabled={nextAtMax} />
|
|
336
399
|
</span>
|
|
337
400
|
|
|
338
401
|
</div>
|
|
@@ -351,7 +414,7 @@ export function Calendar({
|
|
|
351
414
|
|
|
352
415
|
return (
|
|
353
416
|
<div
|
|
354
|
-
className={["a1-calendar", className].filter(Boolean).join(" ")}
|
|
417
|
+
className={["a1-calendar", selectable && "a1-calendar--selectable", className].filter(Boolean).join(" ")}
|
|
355
418
|
{...props}
|
|
356
419
|
>
|
|
357
420
|
<div className="a1-calendar__inner">
|
|
@@ -110,6 +110,50 @@
|
|
|
110
110
|
background: var(--semantic-color-surface-raised);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/* ── Selected — full-cell fill (display and selectable modes) ─── */
|
|
114
|
+
|
|
115
|
+
.a1-calendar__day--selected {
|
|
116
|
+
background: var(--semantic-color-action-background);
|
|
117
|
+
color: var(--semantic-color-text-inverse);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ── Disabled (out of range) — same surface as past dates ──────── */
|
|
121
|
+
|
|
122
|
+
.a1-calendar__day--disabled {
|
|
123
|
+
background: var(--semantic-color-surface-raised);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* ── Selectable mode (opt-in via selectable prop) ──────────────── */
|
|
127
|
+
|
|
128
|
+
.a1-calendar--selectable .a1-calendar__day:not(.a1-calendar__day--empty):not(.a1-calendar__day--disabled) {
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
}
|
|
131
|
+
.a1-calendar--selectable .a1-calendar__day--disabled {
|
|
132
|
+
cursor: not-allowed;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Today — neutral ring instead of action fill (yields to selected) */
|
|
136
|
+
.a1-calendar--selectable .a1-calendar__day--today:not(.a1-calendar__day--selected) {
|
|
137
|
+
background: transparent;
|
|
138
|
+
color: var(--semantic-color-text-default);
|
|
139
|
+
}
|
|
140
|
+
.a1-calendar--selectable .a1-calendar__day--today:not(.a1-calendar__day--selected) .a1-calendar__day-number {
|
|
141
|
+
outline: 2px solid var(--semantic-color-text-default);
|
|
142
|
+
outline-offset: -1px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Full-cell hover for non-selected, non-disabled days */
|
|
146
|
+
.a1-calendar--selectable .a1-calendar__day:not(.a1-calendar__day--empty):not(.a1-calendar__day--disabled):not(.a1-calendar__day--selected):hover {
|
|
147
|
+
background: var(--semantic-color-surface-panel);
|
|
148
|
+
color: var(--semantic-color-text-default);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Focus ring */
|
|
152
|
+
.a1-calendar--selectable .a1-calendar__day:focus-visible {
|
|
153
|
+
outline: var(--component-field-focus-ring-width) solid var(--component-field-focus-ring-color);
|
|
154
|
+
outline-offset: -2px;
|
|
155
|
+
}
|
|
156
|
+
|
|
113
157
|
/* ── Paginated variant — nav bar ─────────────────────────── */
|
|
114
158
|
|
|
115
159
|
.a1-calendar__nav {
|
|
@@ -178,6 +222,33 @@
|
|
|
178
222
|
color: var(--semantic-color-text-inverse);
|
|
179
223
|
}
|
|
180
224
|
|
|
225
|
+
/* Selected: revert to circle in narrow view */
|
|
226
|
+
.a1-calendar__day--selected {
|
|
227
|
+
background: transparent;
|
|
228
|
+
color: var(--semantic-color-text-default);
|
|
229
|
+
}
|
|
230
|
+
.a1-calendar__day--selected .a1-calendar__day-number {
|
|
231
|
+
background: var(--semantic-color-action-background);
|
|
232
|
+
color: var(--semantic-color-text-inverse);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Selectable: today ring (suppress action-bg circle from non-selectable narrow rule) */
|
|
236
|
+
.a1-calendar--selectable .a1-calendar__day--today:not(.a1-calendar__day--selected) .a1-calendar__day-number {
|
|
237
|
+
background: transparent;
|
|
238
|
+
color: var(--semantic-color-text-default);
|
|
239
|
+
outline: 2px solid var(--semantic-color-text-default);
|
|
240
|
+
outline-offset: -1px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* Selectable: hover as circle in narrow */
|
|
244
|
+
.a1-calendar--selectable .a1-calendar__day:not(.a1-calendar__day--empty):not(.a1-calendar__day--disabled):not(.a1-calendar__day--selected):hover {
|
|
245
|
+
background: transparent;
|
|
246
|
+
color: var(--semantic-color-text-default);
|
|
247
|
+
}
|
|
248
|
+
.a1-calendar--selectable .a1-calendar__day:not(.a1-calendar__day--empty):not(.a1-calendar__day--disabled):not(.a1-calendar__day--selected):hover .a1-calendar__day-number {
|
|
249
|
+
background: var(--semantic-color-surface-panel);
|
|
250
|
+
}
|
|
251
|
+
|
|
181
252
|
.a1-calendar__nav {
|
|
182
253
|
padding-block: var(--component-calendar-heading-padding-block-compact);
|
|
183
254
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface CardProps extends React.HTMLAttributes<HTMLElement> {
|
|
4
|
+
/** Underlying element. Default: "div" */
|
|
5
|
+
as?: React.ElementType;
|
|
6
|
+
/** Visual and semantic card variant. Navigation cards make the entire card interactive. Default: "default" */
|
|
7
|
+
variant?: "default" | "navigation";
|
|
8
|
+
/** Destination for navigation cards. When `variant="navigation"` is set, the card renders as an anchor by default. */
|
|
9
|
+
href?: string;
|
|
10
|
+
/** Remove the card border and background. Default: false */
|
|
11
|
+
bare?: boolean;
|
|
12
|
+
/** Material Symbols icon name. Used by `iconDisplay` to render the icon. */
|
|
13
|
+
icon?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Controls how the icon is displayed.
|
|
16
|
+
* - `"default"` — small tokenised icon block above card content; scales with the card container (sm/md/lg).
|
|
17
|
+
* - `"hero"` — full-bleed coloured header area at the top of the card.
|
|
18
|
+
* - `"none"` — icon is not rendered.
|
|
19
|
+
* Default: `"default"` (when `icon` is provided).
|
|
20
|
+
*/
|
|
21
|
+
iconDisplay?: "none" | "default" | "hero";
|
|
22
|
+
/**
|
|
23
|
+
* Background colour of the hero block when `iconDisplay="hero"`.
|
|
24
|
+
* Accepts a semantic colour role or any valid CSS colour value.
|
|
25
|
+
* Default: "action"
|
|
26
|
+
*/
|
|
27
|
+
heroColor?: "action" | "neutral" | "info" | "success" | "warn" | "error" | (string & {});
|
|
28
|
+
children?: React.ReactNode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare function Card(props: CardProps): React.ReactElement;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface CheckboxOption {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
hint?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface CheckboxGroupProps {
|
|
11
|
+
/** Group legend */
|
|
12
|
+
label?: string;
|
|
13
|
+
/** Helper text */
|
|
14
|
+
hint?: string;
|
|
15
|
+
/** Error message */
|
|
16
|
+
error?: string;
|
|
17
|
+
/** Size density. Inherits from parent `Fieldset` when omitted. Default: "default" */
|
|
18
|
+
size?: "comfortable" | "default" | "compact";
|
|
19
|
+
required?: boolean;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Render checkboxes side by side. Default: false */
|
|
22
|
+
inline?: boolean;
|
|
23
|
+
/** Input name attribute shared by all checkboxes */
|
|
24
|
+
name?: string;
|
|
25
|
+
/** Array of checkbox options */
|
|
26
|
+
options?: CheckboxOption[];
|
|
27
|
+
/** Controlled selected values */
|
|
28
|
+
value?: string[];
|
|
29
|
+
/** Default selected values (uncontrolled) */
|
|
30
|
+
defaultValue?: string[];
|
|
31
|
+
/** Called with the full updated array of selected values on change */
|
|
32
|
+
onChange?: (value: string[]) => void;
|
|
33
|
+
id?: string;
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export declare function CheckboxGroup(props: CheckboxGroupProps): React.ReactElement;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ChoiceGroupSection {
|
|
4
|
+
/** Section heading displayed above the section's tiles */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Options in this section */
|
|
7
|
+
options: ChoiceOption[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ChoiceOption {
|
|
11
|
+
value: string;
|
|
12
|
+
label: string;
|
|
13
|
+
subtext?: string;
|
|
14
|
+
icon?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ChoiceGroupProps {
|
|
19
|
+
/** Group legend */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Helper text — hidden when error or success is present */
|
|
22
|
+
hint?: string;
|
|
23
|
+
/** Error message */
|
|
24
|
+
error?: string;
|
|
25
|
+
/** Success message — shown instead of hint when present, hidden if error is also present */
|
|
26
|
+
success?: string;
|
|
27
|
+
/** Tile size density — affects only padding and child element sizes. Default: "default" */
|
|
28
|
+
size?: "compact" | "default" | "comfortable";
|
|
29
|
+
/**
|
|
30
|
+
* Column count. Pass a number for a fixed count at all breakpoints, or a
|
|
31
|
+
* breakpoint object for responsive behaviour, e.g. `{ xs: 1, sm: 2, md: 3 }`.
|
|
32
|
+
* Omit (default) for automatic fill based on tile min-width.
|
|
33
|
+
*/
|
|
34
|
+
columns?: number | Partial<Record<"xs" | "sm" | "md" | "lg" | "xl", number>>;
|
|
35
|
+
/**
|
|
36
|
+
* Allow multiple selections (checkbox semantics). When false, only one
|
|
37
|
+
* option may be selected at a time (radio semantics). Default: false
|
|
38
|
+
*/
|
|
39
|
+
multiple?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Place each tile's icon to the left of the label and subtext instead of
|
|
42
|
+
* above the content block. Has no effect on tiles with no icon. Default: false
|
|
43
|
+
*/
|
|
44
|
+
inlineIcon?: boolean;
|
|
45
|
+
required?: boolean;
|
|
46
|
+
/** Input name attribute. Defaults to the group id. */
|
|
47
|
+
name?: string;
|
|
48
|
+
/** Flat list of options. Use sections instead for grouped options with headings. */
|
|
49
|
+
options?: ChoiceOption[];
|
|
50
|
+
/**
|
|
51
|
+
* Options divided into labeled sections with a divider between each group.
|
|
52
|
+
* When provided, options is ignored.
|
|
53
|
+
*/
|
|
54
|
+
sections?: ChoiceGroupSection[];
|
|
55
|
+
/**
|
|
56
|
+
* Controlled value. String for single-select; string[] for multi-select.
|
|
57
|
+
* Pass undefined to use uncontrolled mode.
|
|
58
|
+
*/
|
|
59
|
+
value?: string | string[] | null;
|
|
60
|
+
/** Default value for uncontrolled mode. Default: null / [] */
|
|
61
|
+
defaultValue?: string | string[] | null;
|
|
62
|
+
/** Called with the selected value (string or string[]) on change */
|
|
63
|
+
onChange?: (value: string | string[]) => void;
|
|
64
|
+
id?: string;
|
|
65
|
+
className?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export declare function ChoiceGroup(props: ChoiceGroupProps): React.ReactElement;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface CircularProgressProps {
|
|
4
|
+
/**
|
|
5
|
+
* Current value. Combined with max to compute the filled arc length.
|
|
6
|
+
* Ignored when indeterminate is true. Default: 0
|
|
7
|
+
*/
|
|
8
|
+
value?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Maximum value. Default: 100
|
|
11
|
+
*/
|
|
12
|
+
max?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Circle diameter. xs renders the smallest ring (no inner content — children
|
|
15
|
+
* are placed inline after the ring instead). Default: "md"
|
|
16
|
+
*/
|
|
17
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
18
|
+
/**
|
|
19
|
+
* Shows a continuously rotating arc instead of a value-based fill.
|
|
20
|
+
* Removes aria-valuenow so assistive technology announces an indeterminate
|
|
21
|
+
* state. Default: false
|
|
22
|
+
*/
|
|
23
|
+
indeterminate?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Content centered inside the ring for sm / md / lg sizes.
|
|
26
|
+
* For xs, children are rendered inline after the ring.
|
|
27
|
+
* Always pass aria-label on the root element for an accessible name since
|
|
28
|
+
* this content receives aria-hidden="true".
|
|
29
|
+
*/
|
|
30
|
+
children?: React.ReactNode;
|
|
31
|
+
/** Additional CSS class names applied to the root element. */
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export declare function CircularProgress(
|
|
36
|
+
props: CircularProgressProps & React.HTMLAttributes<HTMLDivElement>
|
|
37
|
+
): React.ReactElement;
|