@instruments/materia-ui 0.4.1 → 0.4.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/README.md +2 -4
- package/agent-docs.md +9 -9
- package/dist/components/accordion/accordion-root.d.ts +1 -0
- package/dist/components/accordion/accordion-root.js +1 -0
- package/dist/components/alert/alert-root.d.ts +1 -0
- package/dist/components/alert/alert-root.js +1 -0
- package/dist/components/alert-dialog/alert-dialog-root.d.ts +1 -0
- package/dist/components/alert-dialog/alert-dialog-root.js +1 -0
- package/dist/components/avatar/avatar-root.d.ts +1 -0
- package/dist/components/avatar/avatar-root.js +1 -0
- package/dist/components/badge/badge-root.d.ts +1 -0
- package/dist/components/badge/badge-root.js +1 -0
- package/dist/components/calendar/calendar-root.js +1 -0
- package/dist/components/carousel/carousel-root.d.ts +1 -0
- package/dist/components/carousel/carousel-root.js +1 -0
- package/dist/components/chart/chart-root.d.ts +1 -0
- package/dist/components/chart/chart-root.js +1 -0
- package/dist/components/collapsible/collapsible-root.d.ts +1 -0
- package/dist/components/collapsible/collapsible-root.js +1 -0
- package/dist/components/combobox/combobox-root.d.ts +1 -0
- package/dist/components/combobox/combobox-root.js +1 -0
- package/dist/components/command/command-root.d.ts +1 -0
- package/dist/components/command/command-root.js +1 -0
- package/dist/components/dialog/dialog-content.d.ts +2 -0
- package/dist/components/dialog/dialog-content.js +3 -2
- package/dist/components/dialog/dialog-footer.d.ts +2 -0
- package/dist/components/dialog/dialog-footer.js +8 -8
- package/dist/components/dialog/dialog-root.d.ts +1 -0
- package/dist/components/dialog/dialog-root.js +1 -0
- package/dist/components/dialog/dialog-title.d.ts +2 -0
- package/dist/components/dialog/dialog-title.js +3 -1
- package/dist/components/drawer/drawer-root.d.ts +1 -0
- package/dist/components/drawer/drawer-root.js +1 -0
- package/dist/components/heading/heading-root.d.ts +1 -0
- package/dist/components/heading/heading-root.js +1 -0
- package/dist/components/input/input-root.d.ts +1 -0
- package/dist/components/input/input-root.js +1 -0
- package/dist/components/kbd/kbd-root.d.ts +1 -0
- package/dist/components/kbd/kbd-root.js +1 -0
- package/dist/components/logo/logo-mark.d.ts +1 -1
- package/dist/components/logo/logo-mark.js +1 -1
- package/dist/components/logotype/logotype-paths.d.ts +1 -1
- package/dist/components/logotype/logotype-paths.js +1 -1
- package/dist/components/month-year-picker/month-year-picker-root.d.ts +1 -0
- package/dist/components/month-year-picker/month-year-picker-root.js +1 -0
- package/dist/components/native-select/native-select-root.d.ts +1 -0
- package/dist/components/native-select/native-select-root.js +1 -0
- package/dist/components/pill/pill-root.d.ts +1 -0
- package/dist/components/pill/pill-root.js +1 -0
- package/dist/components/popover/popover-root.d.ts +1 -0
- package/dist/components/popover/popover-root.js +1 -0
- package/dist/components/quantity-control/quantity-control-root.d.ts +1 -0
- package/dist/components/quantity-control/quantity-control-root.js +1 -0
- package/dist/components/select/select-root.d.ts +1 -0
- package/dist/components/select/select-root.js +1 -0
- package/dist/components/separator/separator-root.d.ts +1 -0
- package/dist/components/separator/separator-root.js +1 -0
- package/dist/components/sheet/sheet-root.d.ts +1 -0
- package/dist/components/sheet/sheet-root.js +1 -0
- package/dist/components/spinner/spinner-root.d.ts +1 -0
- package/dist/components/spinner/spinner-root.js +1 -0
- package/dist/components/stepper/stepper-root.d.ts +1 -0
- package/dist/components/stepper/stepper-root.js +1 -0
- package/dist/components/success-tick-ripple/success-tick-ripple-root.d.ts +1 -0
- package/dist/components/success-tick-ripple/success-tick-ripple-root.js +1 -0
- package/dist/components/switch/switch-root.d.ts +1 -0
- package/dist/components/switch/switch-root.js +1 -0
- package/dist/components/tag/tag-root.d.ts +1 -0
- package/dist/components/tag/tag-root.js +1 -0
- package/dist/components/textarea/textarea-root.d.ts +1 -0
- package/dist/components/textarea/textarea-root.js +1 -0
- package/dist/components/time-slot-picker/time-slot-picker-root.d.ts +1 -0
- package/dist/components/time-slot-picker/time-slot-picker-root.js +1 -0
- package/dist/components/toast/toast-root.d.ts +1 -0
- package/dist/components/toast/toast-root.js +1 -0
- package/dist/components/tooltip/tooltip-root.d.ts +1 -0
- package/dist/components/tooltip/tooltip-root.js +1 -0
- package/dist/compositions/empty-state/empty-state-root.d.ts +1 -0
- package/dist/compositions/empty-state/empty-state-root.js +1 -0
- package/dist/compositions/file-upload/file-upload-dropzone.d.ts +1 -0
- package/dist/compositions/file-upload/file-upload-dropzone.js +1 -0
- package/dist/compositions/product-card/product-card-caption.js +4 -2
- package/dist/compositions/product-card/product-card-content-types.d.ts +8 -0
- package/dist/compositions/product-card/product-card-meta.js +2 -2
- package/dist/compositions/product-card/product-card-provider-types.d.ts +3 -0
- package/dist/compositions/product-card/product-card-provider.js +4 -1
- package/dist/compositions/product-card/product-card-root.d.ts +1 -1
- package/dist/compositions/product-card/product-card-root.js +2 -1
- package/dist/compositions/product-card/product-card-skeleton.d.ts +14 -5
- package/dist/compositions/product-card/product-card-skeleton.js +6 -5
- package/dist/data/decision-trees.d.ts +1 -1
- package/dist/data/decision-trees.js +1 -1
- package/dist/data/docs-manifest.d.ts +2 -0
- package/dist/data/docs-manifest.js +257 -67
- package/dist/styles/index.css +0 -1
- package/dist/utils/cn-theme.js +1 -1
- package/lint/README.md +6 -2
- package/lint/doctrine-rules.mjs +4 -4
- package/lint/oxlint/index.d.mts +13 -5
- package/lint/oxlint/index.mjs +26 -0
- package/lint/oxlint/no-naked-element.mjs +123 -65
- package/lint/oxlint/no-render-layout-as.mjs +61 -56
- package/lint/scan-classes.d.mts +58 -5
- package/lint/scan-classes.mjs +274 -38
- package/lint/tokens.d.mts +16 -8
- package/lint/tokens.mjs +13 -3
- package/lint/type-case.d.mts +16 -8
- package/lint/type-case.mjs +17 -0
- package/package.json +27 -14
- package/lint/oxlint/fixtures/allowed.tsx +0 -12
- package/lint/oxlint/fixtures/fixture.config.mjs +0 -29
- package/lint/oxlint/fixtures/invalid.tsx +0 -24
- package/lint/oxlint/fixtures/layout-only.tsx +0 -26
- package/lint/oxlint/fixtures/render-as-invalid.tsx +0 -11
- package/lint/oxlint/fixtures/render-as-valid.tsx +0 -14
- package/lint/oxlint/fixtures/valid.tsx +0 -18
- package/lint/oxlint/no-naked-element.test.ts +0 -155
- package/lint/oxlint/no-render-layout-as.test.ts +0 -81
package/README.md
CHANGED
|
@@ -127,10 +127,8 @@ Point your agent at the guidance from your own `AGENTS.md` or `CLAUDE.md`:
|
|
|
127
127
|
|
|
128
128
|
```md
|
|
129
129
|
## UI
|
|
130
|
-
|
|
131
|
-
node_modules/@instruments/materia-ui/agent-docs.md and follow its rules.
|
|
132
|
-
Never invent a prop; if a component can't do what you need, say so.
|
|
133
|
-
Run `materia-ui-lint --all <dirs>` on what you changed.
|
|
130
|
+
|
|
131
|
+
Build UI with @instruments/materia-ui. Before writing any UI, read node_modules/@instruments/materia-ui/agent-docs.md and follow its rules. Never invent a prop; if a component can't do what you need, say so. Run `materia-ui-lint --all <dirs>` on what you changed.
|
|
134
132
|
```
|
|
135
133
|
|
|
136
134
|
## Build an app
|
package/agent-docs.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @instruments/materia-ui - agent guidance
|
|
2
2
|
|
|
3
|
-
<!-- GENERATED by scripts/generate-agent-docs.
|
|
3
|
+
<!-- GENERATED by scripts/generate-agent-docs.ts - DO NOT EDIT.
|
|
4
4
|
Author `@bestPractice` JSDoc tags on public exports; regenerate with
|
|
5
5
|
`pnpm generate:agent-docs`. -->
|
|
6
6
|
|
|
@@ -133,7 +133,7 @@ Honours `prefers-reduced-motion` (renders nothing - a static ring would be loude
|
|
|
133
133
|
|
|
134
134
|
`@instruments/materia-ui/components/box`
|
|
135
135
|
|
|
136
|
-
The escape hatch: a raw host element with a `className`, still checked for tokens-only classes. Box renders the chosen
|
|
136
|
+
The escape hatch: a raw host element with a `className`, still checked for tokens-only classes. Box renders the chosen `LayoutElement` with no layout opinions of its own (no margin, width, or padding, unlike Container), so it suits decorative wrappers that a styled primitive would visually break. Reach for it only when no styled primitive fits; the `className` you pass is governed by the same tokens-only scan as everything else. RSC-safe.
|
|
137
137
|
|
|
138
138
|
- `Box` renders the chosen element with no layout opinions (no margin/width/padding, unlike `Container`); use it as a neutral wrapper when a styled primitive would interfere.
|
|
139
139
|
- Use `as="span"` for a decorative inline wrapper; reach for `Box` only when no styled primitive fits - its `className` is still checked for tokens-only classes.
|
|
@@ -1514,7 +1514,7 @@ A generic section header: an optional eyebrow label, a `Heading` title, an optio
|
|
|
1514
1514
|
|
|
1515
1515
|
A single-select, always-one-selected control that switches between a small set of visible options - a view or mode switcher rendered as a pill of segments. Built on Base UI ToggleGroup (single-select) but kept permanently selected: re-clicking the active segment never clears it.
|
|
1516
1516
|
|
|
1517
|
-
Compose it from
|
|
1517
|
+
Compose it from `SegmentedControlItem`s; shared `size` / `fullWidth` / active state flow to them through context. Controlled via `value`, or uncontrolled via `defaultValue`. Items scroll horizontally with a trailing fade hint when they overflow.
|
|
1518
1518
|
|
|
1519
1519
|
- One value is always selected - the active segment cannot be deselected; for deselectable or multi-select sets reach for ToggleGroup.
|
|
1520
1520
|
- Switching visible content panels is Tabs; navigating URLs is TabNavigation - SegmentedControl is an input that selects a value or mode.
|
|
@@ -1606,7 +1606,7 @@ Honours `prefers-reduced-motion` - renders nothing when motion is reduced (a sta
|
|
|
1606
1606
|
|
|
1607
1607
|
`@instruments/materia-ui/compositions/sidebar`
|
|
1608
1608
|
|
|
1609
|
-
The sidebar shell. Reads open/collapsed state from
|
|
1609
|
+
The sidebar shell. Reads open/collapsed state from `useSidebar`, so it must render inside a `SidebarProvider`.
|
|
1610
1610
|
|
|
1611
1611
|
Adapts by viewport and `collapsible`: an animated docked shell on desktop, a slide-in `Sheet` on mobile, or a static column when `collapsible="none"`.
|
|
1612
1612
|
|
|
@@ -1641,7 +1641,7 @@ The desktop (md+) top header beside the sidebar. Fixed by default, its left offs
|
|
|
1641
1641
|
|
|
1642
1642
|
The primary interactive row of a sidebar menu - a leading icon plus label, optional suffix icon and keyboard-shortcut hint.
|
|
1643
1643
|
|
|
1644
|
-
Collapses to icon-only when the sidebar collapses (swapping in `collapsedIcon` /`collapsedContent` and revealing the `tooltip`), unless `forceExpanded`. Reads collapsed state from
|
|
1644
|
+
Collapses to icon-only when the sidebar collapses (swapping in `collapsedIcon` /`collapsedContent` and revealing the `tooltip`), unless `forceExpanded`. Reads collapsed state from `useSidebar`; pass `render` to render a `<Link>` or other element as the button.
|
|
1645
1645
|
|
|
1646
1646
|
- In an icon-collapsible sidebar use `size="xl"`: the icon rail is sized for an `xl` row, so its collapsed square centres on the rail and the icon stays put as the sidebar folds.
|
|
1647
1647
|
|
|
@@ -1798,7 +1798,7 @@ Progressive streaming answer with settle-gated chrome.
|
|
|
1798
1798
|
|
|
1799
1799
|
`@instruments/materia-ui/components/sub-navigation`
|
|
1800
1800
|
|
|
1801
|
-
Vertical secondary navigation for page subsections and settings-like layouts; the `<nav>` landmark wrapping a
|
|
1801
|
+
Vertical secondary navigation for page subsections and settings-like layouts; the `<nav>` landmark wrapping a `SubNavigationList` of links.
|
|
1802
1802
|
|
|
1803
1803
|
- Reach for `SubNavigation` for a vertical in-page section/settings menu; horizontal router tabs are `TabNavigation`, the app-chrome shell is `Sidebar`.
|
|
1804
1804
|
- Fill it with a `SubNavigationList` of links - it already renders the `<nav>` landmark, so don't nest it inside another `<nav>`.
|
|
@@ -1838,7 +1838,7 @@ Chips paint the darkening overlay on every fill and draw the double-ring selecti
|
|
|
1838
1838
|
|
|
1839
1839
|
`@instruments/materia-ui/compositions/swatch-fan`
|
|
1840
1840
|
|
|
1841
|
-
A fanned stack of
|
|
1841
|
+
A fanned stack of `Swatch` tiles: a fixed three-card editorial fan or an interactive N-tile splay.
|
|
1842
1842
|
|
|
1843
1843
|
Pass 3 `items` with `interaction="breathe"` for the editorial fan (Figma geometry, `variant` spread/stack, white 3px mount via `bordered`); pass N `items` with `interaction="hover-fan"` for the interactive splay-on-hover with pointer tilt. `bordered={false}` swaps the white mount for the 1px hairline tile.
|
|
1844
1844
|
|
|
@@ -1862,7 +1862,7 @@ Row of selectable circular color/image swatches with single-select behaviour, bu
|
|
|
1862
1862
|
|
|
1863
1863
|
Row of selectable color/image swatches with controlled single selection, built on Base UI ToggleGroup: the row is one tab stop and the arrow keys move between swatches.
|
|
1864
1864
|
|
|
1865
|
-
Shares the selected `value`, `onValueChange`, and `size` with its
|
|
1865
|
+
Shares the selected `value`, `onValueChange`, and `size` with its `SwatchSelectorItem` children through context.
|
|
1866
1866
|
|
|
1867
1867
|
- Pair `SwatchSelector` with `SwatchSelectorItem` children - it shares `value`/`onValueChange`/`size` through context, so items need no individual wiring.
|
|
1868
1868
|
- Prefer `SwatchGroup` when the row is a single-choice form control needing radio roles and form submission; `SwatchSelector` is a row of pressed-state toggle buttons.
|
|
@@ -2030,7 +2030,7 @@ Inside a `ToggleGroup` it is the group's item, as in Base UI: give it a `value`,
|
|
|
2030
2030
|
|
|
2031
2031
|
`@instruments/materia-ui/components/toggle-group`
|
|
2032
2032
|
|
|
2033
|
-
A literal group of
|
|
2033
|
+
A literal group of `Toggle`s: several two-state pressable buttons that share one selection, laid out `joined` (a seamless segmented row), `separated`, or `wrap`ped. Built on Base UI ToggleGroup - by default one item is pressed at a time (radio-like), `multiple` makes it checkbox-like; `value` is always an array. The `Toggle`s inside take `size` / `radius` / `variant` from the group through context.
|
|
2034
2034
|
|
|
2035
2035
|
- An always-one-selected mode switcher is `SegmentedControl`, not `ToggleGroup` - reach here for multi-select toolbars and deselectable choice chips.
|
|
2036
2036
|
- `layout="wrap"` + `required` (without `multiple`) is the wizard choice-chip recipe.
|
|
@@ -10,6 +10,7 @@ import { accordionRootVariants } from "../accordion/accordion-variants.js";
|
|
|
10
10
|
* @bestPractice Leave `multiple` off for one-at-a-time panels or set it to allow several open at once; `value`/`defaultValue` are arrays either way, and an open item can always be closed again.
|
|
11
11
|
* @bestPractice Reach for `Collapsible` instead when there is a single expandable region - `Accordion` is for a set of grouped items keyed by `value`.
|
|
12
12
|
* @bestPractice Children must be `AccordionItem`s (each with `AccordionTrigger`/`AccordionContent`); the item's `value` is what `value`/`defaultValue` match against.
|
|
13
|
+
* @keywords disclosure, faq, expander
|
|
13
14
|
* @category data
|
|
14
15
|
*/
|
|
15
16
|
declare const AccordionRoot: <Value = string>({ className, variant, indicator, children, ...rest }: Omit<AccordionPrimitive.Root.Props<Value>, "className"> & VariantProps<typeof accordionRootVariants> & {
|
|
@@ -14,6 +14,7 @@ import { accordionRootVariants } from "../accordion/accordion-variants.js";
|
|
|
14
14
|
* @bestPractice Leave `multiple` off for one-at-a-time panels or set it to allow several open at once; `value`/`defaultValue` are arrays either way, and an open item can always be closed again.
|
|
15
15
|
* @bestPractice Reach for `Collapsible` instead when there is a single expandable region - `Accordion` is for a set of grouped items keyed by `value`.
|
|
16
16
|
* @bestPractice Children must be `AccordionItem`s (each with `AccordionTrigger`/`AccordionContent`); the item's `value` is what `value`/`defaultValue` match against.
|
|
17
|
+
* @keywords disclosure, faq, expander
|
|
17
18
|
* @category data
|
|
18
19
|
*/
|
|
19
20
|
const AccordionRoot = ({ className, variant = "default", indicator = "arrow", children, ...rest }) => {
|
|
@@ -15,6 +15,7 @@ declare const alertVariants: (props?: ({
|
|
|
15
15
|
* @bestPractice Use `Alert` for a persistent inline message block; a transient, auto-dismissing notification is a toast (`Toaster` and `toast()` from `components/toast`).
|
|
16
16
|
* @bestPractice Compose `AlertTitle` / `AlertDescription` as children and render a direct-child `<svg>` for the auto-detected icon column; `tone="danger"` recolours for errors.
|
|
17
17
|
* @bestPractice It renders `role="alert"`, so AT announces it on mount - keep it a notice, not a container for heavy interactive UI.
|
|
18
|
+
* @keywords callout, notice, banner, message
|
|
18
19
|
* @category feedback
|
|
19
20
|
*/
|
|
20
21
|
declare const Alert: ({ className, tone, ...props }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) => React.JSX.Element;
|
|
@@ -25,6 +25,7 @@ const alertVariants = cva("text-paragraph-sm relative grid w-full grid-cols-[0_1
|
|
|
25
25
|
* @bestPractice Use `Alert` for a persistent inline message block; a transient, auto-dismissing notification is a toast (`Toaster` and `toast()` from `components/toast`).
|
|
26
26
|
* @bestPractice Compose `AlertTitle` / `AlertDescription` as children and render a direct-child `<svg>` for the auto-detected icon column; `tone="danger"` recolours for errors.
|
|
27
27
|
* @bestPractice It renders `role="alert"`, so AT announces it on mount - keep it a notice, not a container for heavy interactive UI.
|
|
28
|
+
* @keywords callout, notice, banner, message
|
|
28
29
|
* @category feedback
|
|
29
30
|
*/
|
|
30
31
|
const Alert = ({ className, tone, ...props }) => (_jsx("div", { className: cn(alertVariants({ tone }), className), "data-component": "alert", "data-slot": "alert", role: "alert", ...props }));
|
|
@@ -9,6 +9,7 @@ import type * as React from "react";
|
|
|
9
9
|
* @bestPractice Use `AlertDialog` only for a confirm / warn / destructive decision (Cancel + Action); a general modal form or details view is a `Dialog`.
|
|
10
10
|
* @bestPractice Route every destructive confirmation here, never a plain `Dialog` - unlike `Dialog` it won't dismiss on outside-click / Esc, so the choice stays deliberate.
|
|
11
11
|
* @bestPractice Give the destructive `AlertDialogAction` `tone="danger"` and keep the safe escape as `AlertDialogCancel`.
|
|
12
|
+
* @keywords confirm, confirmation, modal
|
|
12
13
|
* @category overlays
|
|
13
14
|
*/
|
|
14
15
|
declare const AlertDialog: ({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) => React.JSX.Element;
|
|
@@ -10,6 +10,7 @@ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog
|
|
|
10
10
|
* @bestPractice Use `AlertDialog` only for a confirm / warn / destructive decision (Cancel + Action); a general modal form or details view is a `Dialog`.
|
|
11
11
|
* @bestPractice Route every destructive confirmation here, never a plain `Dialog` - unlike `Dialog` it won't dismiss on outside-click / Esc, so the choice stays deliberate.
|
|
12
12
|
* @bestPractice Give the destructive `AlertDialogAction` `tone="danger"` and keep the safe escape as `AlertDialogCancel`.
|
|
13
|
+
* @keywords confirm, confirmation, modal
|
|
13
14
|
* @category overlays
|
|
14
15
|
*/
|
|
15
16
|
const AlertDialog = ({ ...props }) => (_jsx(AlertDialogPrimitive.Root, { "data-component": "alert-dialog", "data-slot": "alert-dialog", ...props }));
|
|
@@ -34,6 +34,7 @@ export type AvatarRootProps = AvatarPrimitive.Root.Props & {
|
|
|
34
34
|
* @bestPractice Always render an `AvatarFallback` child - it is what shows while the image loads and when `src` is missing or errors; an image-only avatar renders empty on failure.
|
|
35
35
|
* @bestPractice Give `AvatarImage` a meaningful `alt`; the visual is decorative only when the fallback initials already convey the identity.
|
|
36
36
|
* @bestPractice Keep the default `radius="full"` for people; use a squared `radius` for brand/entity logos so they read as objects, not users.
|
|
37
|
+
* @keywords profile picture, user, initials
|
|
37
38
|
* @category data
|
|
38
39
|
*/
|
|
39
40
|
export declare const AvatarRoot: ({ className, size: sizeProp, radius, withRing, ringColor, ...props }: AvatarRootProps) => import("react").JSX.Element;
|
|
@@ -46,6 +46,7 @@ const RADIUS_CLASS = {
|
|
|
46
46
|
* @bestPractice Always render an `AvatarFallback` child - it is what shows while the image loads and when `src` is missing or errors; an image-only avatar renders empty on failure.
|
|
47
47
|
* @bestPractice Give `AvatarImage` a meaningful `alt`; the visual is decorative only when the fallback initials already convey the identity.
|
|
48
48
|
* @bestPractice Keep the default `radius="full"` for people; use a squared `radius` for brand/entity logos so they read as objects, not users.
|
|
49
|
+
* @keywords profile picture, user, initials
|
|
49
50
|
* @category data
|
|
50
51
|
*/
|
|
51
52
|
export const AvatarRoot = ({ className, size: sizeProp = "base", radius = "full", withRing = false, ringColor, ...props }) => {
|
|
@@ -65,6 +65,7 @@ export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, Omit<V
|
|
|
65
65
|
* @bestPractice For a notification count use `mode="count"` (circular, tabular figures), not `radius="full"` + manual classes.
|
|
66
66
|
* @bestPractice A standalone count needs an `accessibleLabel` ("3 unread"); inside an icon-only trigger, mark the badge `aria-hidden` and fold the count into the trigger's `aria-label`.
|
|
67
67
|
* @bestPractice A badge overlapping a corner of another surface takes `ring` so a 2px `background`-coloured ring separates it from what's beneath; set it only where the badge truly overlaps, and the page surface should be `background`.
|
|
68
|
+
* @keywords chip, status, label
|
|
68
69
|
* @category feedback
|
|
69
70
|
*/
|
|
70
71
|
export declare const Badge: ({ className, tone, size, emphasis, radius, asInput, render, disabled, testid, label, value, icon, iconPlacement, focused, hovered, loading, loadingLabel, mode, accessibleLabel, ring, children, ...props }: BadgeProps) => React.JSX.Element;
|
|
@@ -69,6 +69,7 @@ const getOptionalPillProps = ({ asInput, disabled, emphasis, tone, }) => {
|
|
|
69
69
|
* @bestPractice For a notification count use `mode="count"` (circular, tabular figures), not `radius="full"` + manual classes.
|
|
70
70
|
* @bestPractice A standalone count needs an `accessibleLabel` ("3 unread"); inside an icon-only trigger, mark the badge `aria-hidden` and fold the count into the trigger's `aria-label`.
|
|
71
71
|
* @bestPractice A badge overlapping a corner of another surface takes `ring` so a 2px `background`-coloured ring separates it from what's beneath; set it only where the badge truly overlaps, and the page surface should be `background`.
|
|
72
|
+
* @keywords chip, status, label
|
|
72
73
|
* @category feedback
|
|
73
74
|
*/
|
|
74
75
|
export const Badge = ({ className, tone, size, emphasis, radius = "rounded", asInput, render, disabled, testid, label, value, icon, iconPlacement = "start", focused, hovered, loading = false, loadingLabel, mode = "default", accessibleLabel, ring = false, children, ...props }) => {
|
|
@@ -46,6 +46,7 @@ const CalendarDayButton = ({ modifiers, ...props }) => {
|
|
|
46
46
|
* @bestPractice Set `mode` explicitly (`single` | `multiple` | `range`) - the selection value shape and `onSelect` signature change with it; a `range` handler never fires in `single` mode.
|
|
47
47
|
* @bestPractice Restrict selectable dates with react-day-picker matchers (`disabled`/`hidden`/`startMonth`/`endMonth`), not by filtering after the user clicks.
|
|
48
48
|
* @bestPractice Use `Calendar` for an inline date grid; for a compact click-to-open date field, wrap it in a `Popover` behind a `Button`/`Input` trigger.
|
|
49
|
+
* @keywords date picker, datepicker, date
|
|
49
50
|
* @category forms
|
|
50
51
|
*/
|
|
51
52
|
const Calendar = ({ className, classNames, showOutsideDays = true, ...props }) => (_jsx(DayPicker, { className: cn("w-fit p-3", className), classNames: {
|
|
@@ -50,6 +50,7 @@ interface CarouselProps {
|
|
|
50
50
|
* @bestPractice Set `slidesToShow` to show multiple items at once (it drives each item's `flex-basis`); don't fake a multi-item view with CSS widths on `CarouselItem`.
|
|
51
51
|
* @bestPractice Tune scroll behaviour via `opts` (Embla options like `loop`/`align`) and enable `wheelScroll`/`freeScroll` deliberately - free-scroll drops snap points, so pass `slideCount` if the dots miscount.
|
|
52
52
|
* @bestPractice Give a descriptive `aria-label` when the region isn't self-evidently "Carousel" (e.g. `"Product images"`).
|
|
53
|
+
* @keywords slideshow, gallery, swiper
|
|
53
54
|
* @category data
|
|
54
55
|
*/
|
|
55
56
|
declare const Carousel: ({ "aria-label": ariaLabel, opts, plugins, orientation, slidesToShow, slideCount, freeScroll, wheelScroll, className, children, }: CarouselProps) => import("react").JSX.Element;
|
|
@@ -29,6 +29,7 @@ const useCarousel = () => {
|
|
|
29
29
|
* @bestPractice Set `slidesToShow` to show multiple items at once (it drives each item's `flex-basis`); don't fake a multi-item view with CSS widths on `CarouselItem`.
|
|
30
30
|
* @bestPractice Tune scroll behaviour via `opts` (Embla options like `loop`/`align`) and enable `wheelScroll`/`freeScroll` deliberately - free-scroll drops snap points, so pass `slideCount` if the dots miscount.
|
|
31
31
|
* @bestPractice Give a descriptive `aria-label` when the region isn't self-evidently "Carousel" (e.g. `"Product images"`).
|
|
32
|
+
* @keywords slideshow, gallery, swiper
|
|
32
33
|
* @category data
|
|
33
34
|
*/
|
|
34
35
|
const Carousel = ({ "aria-label": ariaLabel = "Carousel", opts, plugins, orientation = "horizontal", slidesToShow = 1, slideCount, freeScroll = false, wheelScroll = false, className, children, }) => {
|
|
@@ -12,6 +12,7 @@ import type { ChartConfig } from "./chart-context.js";
|
|
|
12
12
|
*
|
|
13
13
|
* @bestPractice Colour every series through `config` (`{ desktop: { label, color } }`) and reference `var(--color-<key>)` on the marks - never hardcode a hex on a `Bar` / `Line`; that keeps light/dark theming and the legend/tooltip swatches in sync.
|
|
14
14
|
* @bestPractice Reach for `Chart` only to render a recharts data visualization; for a static value + delta use `Stat`, and for a progress bar use `Progress`.
|
|
15
|
+
* @keywords graph, plot, visualisation, visualization
|
|
15
16
|
* @category data
|
|
16
17
|
*/
|
|
17
18
|
export declare const Chart: ({ id, className, children, config, initialDimension, ...props }: React.ComponentProps<"div"> & {
|
|
@@ -19,6 +19,7 @@ const INITIAL_DIMENSION = { width: 320, height: 200 };
|
|
|
19
19
|
*
|
|
20
20
|
* @bestPractice Colour every series through `config` (`{ desktop: { label, color } }`) and reference `var(--color-<key>)` on the marks - never hardcode a hex on a `Bar` / `Line`; that keeps light/dark theming and the legend/tooltip swatches in sync.
|
|
21
21
|
* @bestPractice Reach for `Chart` only to render a recharts data visualization; for a static value + delta use `Stat`, and for a progress bar use `Progress`.
|
|
22
|
+
* @keywords graph, plot, visualisation, visualization
|
|
22
23
|
* @category data
|
|
23
24
|
*/
|
|
24
25
|
export const Chart = ({ id, className, children, config, initialDimension = INITIAL_DIMENSION, ...props }) => {
|
|
@@ -6,6 +6,7 @@ import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible"
|
|
|
6
6
|
* @bestPractice Use `Collapsible` for a single expand/collapse region; reach for `Accordion` when you have a set of grouped items where selecting one can close the others.
|
|
7
7
|
* @bestPractice Compose `CollapsibleTrigger` + `CollapsibleContent` inside it - a bare child won't expand.
|
|
8
8
|
* @bestPractice Drive it uncontrolled with `defaultOpen`; only lift to `open`/`onOpenChange` when external state must sync (e.g. persisting the open panel).
|
|
9
|
+
* @keywords disclosure, show more, expander
|
|
9
10
|
* @category data
|
|
10
11
|
*/
|
|
11
12
|
export declare const Collapsible: ({ ...props }: CollapsiblePrimitive.Root.Props) => import("react").JSX.Element;
|
|
@@ -8,6 +8,7 @@ import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible"
|
|
|
8
8
|
* @bestPractice Use `Collapsible` for a single expand/collapse region; reach for `Accordion` when you have a set of grouped items where selecting one can close the others.
|
|
9
9
|
* @bestPractice Compose `CollapsibleTrigger` + `CollapsibleContent` inside it - a bare child won't expand.
|
|
10
10
|
* @bestPractice Drive it uncontrolled with `defaultOpen`; only lift to `open`/`onOpenChange` when external state must sync (e.g. persisting the open panel).
|
|
11
|
+
* @keywords disclosure, show more, expander
|
|
11
12
|
* @category data
|
|
12
13
|
*/
|
|
13
14
|
export const Collapsible = ({ ...props }) => (_jsx(CollapsiblePrimitive.Root, { "data-component": "collapsible", "data-slot": "collapsible", ...props }));
|
|
@@ -48,6 +48,7 @@ export interface ComboboxProps {
|
|
|
48
48
|
* @bestPractice `onValueChange` fires with `""` when the current selection is toggled off - treat empty string as "cleared", not as a real value.
|
|
49
49
|
* @bestPractice For lists in the hundreds+, pass `virtualization={{ enabled: true }}` so only visible rows mount instead of every option.
|
|
50
50
|
* @bestPractice Provide `items` as `{ label, value }[]` - the visible text comes from `label` while selection is tracked by `value`.
|
|
51
|
+
* @keywords autocomplete, typeahead, searchable select
|
|
51
52
|
* @category forms
|
|
52
53
|
*/
|
|
53
54
|
export declare const Combobox: ({ items, value, onValueChange, placeholder, buttonClassName, contentClassName, disabled, size, virtualization, "data-testid": dataTestId, }: ComboboxProps) => React.JSX.Element;
|
|
@@ -80,6 +80,7 @@ const scrollHighlightIntoView = (virtualizer, item, { reason, index }) => {
|
|
|
80
80
|
* @bestPractice `onValueChange` fires with `""` when the current selection is toggled off - treat empty string as "cleared", not as a real value.
|
|
81
81
|
* @bestPractice For lists in the hundreds+, pass `virtualization={{ enabled: true }}` so only visible rows mount instead of every option.
|
|
82
82
|
* @bestPractice Provide `items` as `{ label, value }[]` - the visible text comes from `label` while selection is tracked by `value`.
|
|
83
|
+
* @keywords autocomplete, typeahead, searchable select
|
|
83
84
|
* @category forms
|
|
84
85
|
*/
|
|
85
86
|
export const Combobox = ({ items, value, onValueChange, placeholder = "Select…", buttonClassName, contentClassName, disabled, size = "xl", virtualization, "data-testid": dataTestId, }) => {
|
|
@@ -35,6 +35,7 @@ export type CommandProps<Item> = Omit<AutocompletePrimitive.Root.Props<Item>, "c
|
|
|
35
35
|
* @bestPractice Pass the entries as `items`, or as titled `groups`, and render them with a function child of `CommandList`; filtering only sees those entries, so items written as static JSX are not filtered.
|
|
36
36
|
* @bestPractice Act on a choice with `CommandItem`'s `onClick`, which fires for a pointer click and for `Enter` on the highlighted item.
|
|
37
37
|
* @bestPractice A plain click-triggered action menu is `DropdownMenu`; a remembered selection is `Combobox`.
|
|
38
|
+
* @keywords command palette, spotlight, cmd+k, quick search
|
|
38
39
|
* @category navigation
|
|
39
40
|
*/
|
|
40
41
|
export declare const Command: <Item>(props: CommandProps<Item>) => React.JSX.Element;
|
|
@@ -14,6 +14,7 @@ import { cn } from "@instruments/materia-ui/utils/cn";
|
|
|
14
14
|
* @bestPractice Pass the entries as `items`, or as titled `groups`, and render them with a function child of `CommandList`; filtering only sees those entries, so items written as static JSX are not filtered.
|
|
15
15
|
* @bestPractice Act on a choice with `CommandItem`'s `onClick`, which fires for a pointer click and for `Enter` on the highlighted item.
|
|
16
16
|
* @bestPractice A plain click-triggered action menu is `DropdownMenu`; a remembered selection is `Combobox`.
|
|
17
|
+
* @keywords command palette, spotlight, cmd+k, quick search
|
|
17
18
|
* @category navigation
|
|
18
19
|
*/
|
|
19
20
|
export const Command = (props) => {
|
|
@@ -10,6 +10,8 @@ type DialogContentProps = Omit<React.ComponentProps<typeof DialogPrimitive.Popup
|
|
|
10
10
|
* such as a product's quick view.
|
|
11
11
|
*/
|
|
12
12
|
export type DialogContentSize = "default" | "viewport";
|
|
13
|
+
/** Panel geometry per size. Exported for the Figma generator in `figma/`. */
|
|
14
|
+
export declare const DIALOG_SIZE_CLASSES: Record<DialogContentSize, string | undefined>;
|
|
13
15
|
export interface DialogContentExtras {
|
|
14
16
|
/** Extra classes for the overlay behind the dialog. */
|
|
15
17
|
overlayClassName?: string;
|
|
@@ -6,7 +6,8 @@ import { OVERLAY_PANEL_ANIMATION, OVERLAY_PANEL_CENTERED, } from "../../tokens/o
|
|
|
6
6
|
import { Button } from "../button.js";
|
|
7
7
|
import { DialogOverlay } from "../dialog/dialog-overlay.js";
|
|
8
8
|
import { DialogPortal } from "../dialog/dialog-portal.js";
|
|
9
|
-
|
|
9
|
+
/** Panel geometry per size. Exported for the Figma generator in `figma/`. */
|
|
10
|
+
export const DIALOG_SIZE_CLASSES = {
|
|
10
11
|
default: undefined,
|
|
11
12
|
viewport: "h-dialog-viewport w-dialog-viewport max-w-dialog-viewport sm:max-w-dialog-viewport md:h-dialog-viewport-md md:max-h-dialog-viewport md:w-dialog-viewport-md",
|
|
12
13
|
};
|
|
@@ -20,4 +21,4 @@ const SIZE_CLASSES = {
|
|
|
20
21
|
*
|
|
21
22
|
* @bestPractice Use `size="viewport"` for a dialog that holds a whole view (a product quick view, a large preview); it sets only the geometry, so lay the panel out as a column with a scrolling body yourself or compose `QuickView`.
|
|
22
23
|
*/
|
|
23
|
-
export const DialogContent = ({ className, children, showCloseButton = true, overlayClassName, size = "default", ...props }) => (_jsxs(DialogPortal, { "data-component": "dialog-portal", "data-slot": "dialog-portal", children: [_jsx(DialogOverlay, { className: overlayClassName }), _jsxs(DialogPrimitive.Popup, { className: cn(OVERLAY_PANEL_ANIMATION, OVERLAY_PANEL_CENTERED,
|
|
24
|
+
export const DialogContent = ({ className, children, showCloseButton = true, overlayClassName, size = "default", ...props }) => (_jsxs(DialogPortal, { "data-component": "dialog-portal", "data-slot": "dialog-portal", children: [_jsx(DialogOverlay, { className: overlayClassName }), _jsxs(DialogPrimitive.Popup, { className: cn(OVERLAY_PANEL_ANIMATION, OVERLAY_PANEL_CENTERED, DIALOG_SIZE_CLASSES[size], className), "data-component": "dialog-content", "data-size": size, "data-slot": "dialog-content", ...props, children: [children, showCloseButton ? (_jsx(DialogPrimitive.Close, { render: _jsx(Button, { "aria-label": "Close", className: "absolute top-5 right-5", "data-component": "dialog-close", "data-slot": "dialog-close", emphasis: "soft", icon: XIcon, size: "icon-sm", tone: "neutral" }) })) : null] })] }));
|
|
@@ -3,6 +3,8 @@ interface DialogFooterProps extends React.ComponentProps<"div"> {
|
|
|
3
3
|
/** Button alignment within the footer. @default "end" */
|
|
4
4
|
justify?: "end" | "between";
|
|
5
5
|
}
|
|
6
|
+
/** Footer classes for a `justify`. Exported for the Figma generator in `figma/`. */
|
|
7
|
+
export declare const dialogFooterClasses: (justify: NonNullable<DialogFooterProps["justify"]>) => string;
|
|
6
8
|
/**
|
|
7
9
|
* Action row at the bottom of the panel; stacks buttons vertically on mobile and
|
|
8
10
|
* lays them out horizontally from `sm` up. Render inside `<DialogContent>`.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "@instruments/materia-ui/utils/cn";
|
|
3
3
|
import { Flex } from "../flex.js";
|
|
4
|
+
/** Footer classes for a `justify`. Exported for the Figma generator in `figma/`. */
|
|
5
|
+
export const dialogFooterClasses = (justify) => cn("mt-2 flex-col-reverse gap-2 sm:flex-row", justify === "between" ? "sm:-ml-1.5 sm:justify-between" : "sm:justify-end",
|
|
6
|
+
// Concentric nesting: pull the actions 6px onto the trailing edges so a
|
|
7
|
+
// default pill button (h-9, r 18px) sits 18px from the rounded-modal (36px)
|
|
8
|
+
// corner - 36−18 - its curve parallel to the boundary.
|
|
9
|
+
// `between` also pulls the leading edge so the left action nestles too.
|
|
10
|
+
"sm:-mr-1.5 sm:-mb-1.5");
|
|
4
11
|
/**
|
|
5
12
|
* Action row at the bottom of the panel; stacks buttons vertically on mobile and
|
|
6
13
|
* lays them out horizontally from `sm` up. Render inside `<DialogContent>`.
|
|
7
14
|
* Import from "@instruments/materia-ui/components/dialog".
|
|
8
15
|
*/
|
|
9
|
-
export const DialogFooter = ({ className, justify = "end", ...props }) => (_jsx(Flex, { className: cn("
|
|
10
|
-
? "sm:-ml-1.5 sm:justify-between"
|
|
11
|
-
: "sm:justify-end",
|
|
12
|
-
// Concentric nesting: pull the actions 6px onto the trailing edges so a
|
|
13
|
-
// default pill button (h-9, r 18px) sits 18px from the rounded-modal (36px)
|
|
14
|
-
// corner - 36−18 - its curve parallel to the boundary.
|
|
15
|
-
// `between` also pulls the leading edge so the left action nestles too.
|
|
16
|
-
"sm:-mr-1.5 sm:-mb-1.5", className), "data-component": "dialog-footer", "data-slot": "dialog-footer", ...props }));
|
|
16
|
+
export const DialogFooter = ({ className, justify = "end", ...props }) => (_jsx(Flex, { className: cn(dialogFooterClasses(justify), className), "data-component": "dialog-footer", "data-slot": "dialog-footer", ...props }));
|
|
@@ -6,6 +6,7 @@ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
|
6
6
|
* @bestPractice Use `Dialog` for a centred blocking modal (form, details, footer actions); a destructive confirm is `AlertDialog`, an anchored non-blocking panel is `Popover`.
|
|
7
7
|
* @bestPractice A panel that slides in from a screen edge is a `Sheet` (or `Drawer` for a drag-to-dismiss bottom sheet), not a `Dialog`.
|
|
8
8
|
* @bestPractice Always render a `DialogTitle` (wrap in `sr-only` if visually hidden) so the modal is announced; `DialogContent` uses the 36px `--radius-modal` corner.
|
|
9
|
+
* @keywords modal, popup, lightbox
|
|
9
10
|
* @category overlays
|
|
10
11
|
*/
|
|
11
12
|
export declare const Dialog: (props: DialogPrimitive.Root.Props<unknown>) => import("react").ReactElement;
|
|
@@ -7,6 +7,7 @@ import { makeOverlayRoot } from "../overlay-primitives.js";
|
|
|
7
7
|
* @bestPractice Use `Dialog` for a centred blocking modal (form, details, footer actions); a destructive confirm is `AlertDialog`, an anchored non-blocking panel is `Popover`.
|
|
8
8
|
* @bestPractice A panel that slides in from a screen edge is a `Sheet` (or `Drawer` for a drag-to-dismiss bottom sheet), not a `Dialog`.
|
|
9
9
|
* @bestPractice Always render a `DialogTitle` (wrap in `sr-only` if visually hidden) so the modal is announced; `DialogContent` uses the 36px `--radius-modal` corner.
|
|
10
|
+
* @keywords modal, popup, lightbox
|
|
10
11
|
* @category overlays
|
|
11
12
|
*/
|
|
12
13
|
export const Dialog = makeOverlayRoot(DialogPrimitive.Root, {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2
2
|
import type * as React from "react";
|
|
3
|
+
/** Title classes. Exported for the Figma generator in `figma/`. */
|
|
4
|
+
export declare const DIALOG_TITLE_CLASSES = "text-subheading font-semibold text-balance";
|
|
3
5
|
/**
|
|
4
6
|
* Accessible heading that labels the dialog (wired to the panel's
|
|
5
7
|
* `aria-labelledby`). Render inside `<DialogHeader>`.
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
3
3
|
import { cn } from "@instruments/materia-ui/utils/cn";
|
|
4
|
+
/** Title classes. Exported for the Figma generator in `figma/`. */
|
|
5
|
+
export const DIALOG_TITLE_CLASSES = "text-subheading font-semibold text-balance";
|
|
4
6
|
/**
|
|
5
7
|
* Accessible heading that labels the dialog (wired to the panel's
|
|
6
8
|
* `aria-labelledby`). Render inside `<DialogHeader>`.
|
|
7
9
|
* Import from "@instruments/materia-ui/components/dialog".
|
|
8
10
|
*/
|
|
9
|
-
export const DialogTitle = ({ className, ...props }) => (_jsx(DialogPrimitive.Title, { className: cn(
|
|
11
|
+
export const DialogTitle = ({ className, ...props }) => (_jsx(DialogPrimitive.Title, { className: cn(DIALOG_TITLE_CLASSES, className), "data-component": "dialog-title", "data-slot": "dialog-title", ...props }));
|
|
@@ -16,6 +16,7 @@ export declare const DrawerContext: import("react").Context<DrawerContextValue>;
|
|
|
16
16
|
* @bestPractice Drawer is the touch-first slide-up panel - reach for `Sheet` for desktop side panels and `Dialog` for centred modals.
|
|
17
17
|
* @bestPractice Always render a `DrawerTitle` inside `DrawerContent` (sr-only if visually hidden) - the underlying primitive uses it for `aria-labelledby`.
|
|
18
18
|
* @bestPractice Pass `container` to scope the drawer and its scrim to a bounded element instead of the viewport (the mobile-nav overlay pattern).
|
|
19
|
+
* @keywords bottom sheet
|
|
19
20
|
* @category overlays
|
|
20
21
|
*/
|
|
21
22
|
export declare const Drawer: ({ container, ...props }: ComponentProps<typeof DrawerPrimitive.Root> & {
|
|
@@ -15,6 +15,7 @@ export const DrawerContext = createContext({});
|
|
|
15
15
|
* @bestPractice Drawer is the touch-first slide-up panel - reach for `Sheet` for desktop side panels and `Dialog` for centred modals.
|
|
16
16
|
* @bestPractice Always render a `DrawerTitle` inside `DrawerContent` (sr-only if visually hidden) - the underlying primitive uses it for `aria-labelledby`.
|
|
17
17
|
* @bestPractice Pass `container` to scope the drawer and its scrim to a bounded element instead of the viewport (the mobile-nav overlay pattern).
|
|
18
|
+
* @keywords bottom sheet
|
|
18
19
|
* @category overlays
|
|
19
20
|
*/
|
|
20
21
|
export const Drawer = ({ container, ...props }) => {
|
|
@@ -30,6 +30,7 @@ type HeadingProps = Omit<React.ComponentProps<"h1">, "size"> & {
|
|
|
30
30
|
*
|
|
31
31
|
* @bestPractice Set `level` (`h1`–`h6`) for the document outline and `size` for visual scale independently - don't pick a tag just to get a size; a small-looking heading can still be an `h2`.
|
|
32
32
|
* @bestPractice Keep one `h1` per page and don't skip levels for styling; use `size` (responsive-capable) to make a lower-level heading look larger.
|
|
33
|
+
* @keywords title, headline
|
|
33
34
|
* @category typography
|
|
34
35
|
*/
|
|
35
36
|
declare const Heading: ({ level, size, className, ...props }: HeadingProps) => React.JSX.Element;
|
|
@@ -41,6 +41,7 @@ const SIZE_CLASSES = {
|
|
|
41
41
|
*
|
|
42
42
|
* @bestPractice Set `level` (`h1`–`h6`) for the document outline and `size` for visual scale independently - don't pick a tag just to get a size; a small-looking heading can still be an `h2`.
|
|
43
43
|
* @bestPractice Keep one `h1` per page and don't skip levels for styling; use `size` (responsive-capable) to make a lower-level heading look larger.
|
|
44
|
+
* @keywords title, headline
|
|
44
45
|
* @category typography
|
|
45
46
|
*/
|
|
46
47
|
const Heading = ({ level = "2", size, className, ...props }) => {
|
|
@@ -32,6 +32,7 @@ export type InputProps = WithTestId<Omit<React.ComponentProps<"input">, "size">>
|
|
|
32
32
|
* @bestPractice Inside a `Field`, let invalid state cascade - omit `hasError`; pass `hasError` only to force error styling on a standalone `Input`. An invalid `Field` keeps `aria-invalid` on its control even with `hasError={false}`.
|
|
33
33
|
* @bestPractice Give every `Input` an associated label - inside a `Field` a `FieldLabel` targets it with no ids to wire; standalone, point a `Label`'s `htmlFor` at its `id`. A placeholder is not an accessible name.
|
|
34
34
|
* @bestPractice `size` defaults to `"xl"` (48px); pass a responsive object like `{ base: "sm", md: "xl" }` rather than swapping components per breakpoint.
|
|
35
|
+
* @keywords text field, textbox, text input
|
|
35
36
|
* @category forms
|
|
36
37
|
*/
|
|
37
38
|
export declare const Input: ({ className, testId, size, radius, hasError, focused, ...props }: InputProps) => React.JSX.Element;
|
|
@@ -25,6 +25,7 @@ import { DEFAULT_INPUT_SIZE, INPUT_SIZE_CLASSES, standaloneInputVariants, } from
|
|
|
25
25
|
* @bestPractice Inside a `Field`, let invalid state cascade - omit `hasError`; pass `hasError` only to force error styling on a standalone `Input`. An invalid `Field` keeps `aria-invalid` on its control even with `hasError={false}`.
|
|
26
26
|
* @bestPractice Give every `Input` an associated label - inside a `Field` a `FieldLabel` targets it with no ids to wire; standalone, point a `Label`'s `htmlFor` at its `id`. A placeholder is not an accessible name.
|
|
27
27
|
* @bestPractice `size` defaults to `"xl"` (48px); pass a responsive object like `{ base: "sm", md: "xl" }` rather than swapping components per breakpoint.
|
|
28
|
+
* @keywords text field, textbox, text input
|
|
28
29
|
* @category forms
|
|
29
30
|
*/
|
|
30
31
|
export const Input = ({ className, testId, size, radius, hasError, focused, ...props }) => {
|
|
@@ -65,6 +65,7 @@ type KbdProps = Omit<React.ComponentProps<"kbd">, "size"> & VariantProps<typeof
|
|
|
65
65
|
*
|
|
66
66
|
* @bestPractice Wrap multi-key chords in `KbdGroup` and set `size` on the group - children inherit it via context, so you size the combo once.
|
|
67
67
|
* @bestPractice It renders a semantic `<kbd>`; reserve it for keyboard keys/shortcuts, not as a generic small-label chip (that's `Badge`).
|
|
68
|
+
* @keywords keyboard shortcut, hotkey
|
|
68
69
|
* @category typography
|
|
69
70
|
*/
|
|
70
71
|
declare const Kbd: ({ className, size, tone, emphasis, ...props }: KbdProps) => import("react").JSX.Element;
|
|
@@ -124,6 +124,7 @@ const kbdVariants = cva("pointer-events-none inline-flex w-fit items-center just
|
|
|
124
124
|
*
|
|
125
125
|
* @bestPractice Wrap multi-key chords in `KbdGroup` and set `size` on the group - children inherit it via context, so you size the combo once.
|
|
126
126
|
* @bestPractice It renders a semantic `<kbd>`; reserve it for keyboard keys/shortcuts, not as a generic small-label chip (that's `Badge`).
|
|
127
|
+
* @keywords keyboard shortcut, hotkey
|
|
127
128
|
* @category typography
|
|
128
129
|
*/
|
|
129
130
|
const Kbd = ({ className, size, tone, emphasis, ...props }) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Material Bank mark's geometry, in one place: `Logo` draws it and
|
|
3
|
-
* `scripts/generate-brand-assets.
|
|
3
|
+
* `scripts/generate-brand-assets.ts` writes the shipped SVG files from it.
|
|
4
4
|
* Plain constants with no imports, so a Node script can load this file
|
|
5
5
|
* directly.
|
|
6
6
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Material Bank mark's geometry, in one place: `Logo` draws it and
|
|
3
|
-
* `scripts/generate-brand-assets.
|
|
3
|
+
* `scripts/generate-brand-assets.ts` writes the shipped SVG files from it.
|
|
4
4
|
* Plain constants with no imports, so a Node script can load this file
|
|
5
5
|
* directly.
|
|
6
6
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Material Bank logotype geometry, in one place: the `Logotype` component
|
|
3
|
-
* draws it and `scripts/generate-brand-assets.
|
|
3
|
+
* draws it and `scripts/generate-brand-assets.ts` writes the shipped SVG files
|
|
4
4
|
* from it. Plain constants with no imports, so a Node script can load this file
|
|
5
5
|
* directly.
|
|
6
6
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Material Bank logotype geometry, in one place: the `Logotype` component
|
|
3
|
-
* draws it and `scripts/generate-brand-assets.
|
|
3
|
+
* draws it and `scripts/generate-brand-assets.ts` writes the shipped SVG files
|
|
4
4
|
* from it. Plain constants with no imports, so a Node script can load this file
|
|
5
5
|
* directly.
|
|
6
6
|
*
|
|
@@ -41,6 +41,7 @@ export interface MonthYearPickerProps {
|
|
|
41
41
|
* @bestPractice `value` is a union - a `Date`, `"beyond"`, or `"unsure"` - so branch on the string sentinels in `onChange` before treating it as a date.
|
|
42
42
|
* @bestPractice Enable the "I'm not sure" escape hatch with `showUnsure` (off by default); `"unsure"`/`"beyond"` only ever arrive when their toggles are shown.
|
|
43
43
|
* @bestPractice Bound the range with `yearsAhead` (from the current year); it auto-advances and commits once both month and year are chosen, so don't add your own "next" control.
|
|
44
|
+
* @keywords date picker, date, month, year
|
|
44
45
|
* @category forms
|
|
45
46
|
*/
|
|
46
47
|
export declare const MonthYearPicker: ({ value, onChange, yearsAhead, beyondLabel, showUnsure, unsureLabel, size, variant, monthLabel, yearLabel, className, }: MonthYearPickerProps) => import("react").JSX.Element;
|
|
@@ -60,6 +60,7 @@ const SpecialOptions = ({ isBeyond, isUnsure, onBeyondSelect, onUnsureSelect, re
|
|
|
60
60
|
* @bestPractice `value` is a union - a `Date`, `"beyond"`, or `"unsure"` - so branch on the string sentinels in `onChange` before treating it as a date.
|
|
61
61
|
* @bestPractice Enable the "I'm not sure" escape hatch with `showUnsure` (off by default); `"unsure"`/`"beyond"` only ever arrive when their toggles are shown.
|
|
62
62
|
* @bestPractice Bound the range with `yearsAhead` (from the current year); it auto-advances and commits once both month and year are chosen, so don't add your own "next" control.
|
|
63
|
+
* @keywords date picker, date, month, year
|
|
63
64
|
* @category forms
|
|
64
65
|
*/
|
|
65
66
|
export const MonthYearPicker = ({ value, onChange, yearsAhead = 10, beyondLabel, showUnsure = false, unsureLabel = "I'm not sure", size = "lg", variant = "default", monthLabel = "Choose month", yearLabel = "Choose year", className, }) => {
|
|
@@ -7,6 +7,7 @@ import type * as React from "react";
|
|
|
7
7
|
* @bestPractice `NativeSelect` wraps a real `<select>` - use standard `value`/`defaultValue`/`onChange` and `NativeSelectOption`/`NativeSelectOptGroup` children, not `Select` parts.
|
|
8
8
|
* @bestPractice Reach for `NativeSelect` when the native mobile picker and zero-JS behaviour matter; use `Select` when you need custom-rendered option content or styling.
|
|
9
9
|
* @bestPractice It has no built-in label - associate a `Label` via `htmlFor`/`id` for an accessible name.
|
|
10
|
+
* @keywords dropdown, picker
|
|
10
11
|
* @category forms
|
|
11
12
|
*/
|
|
12
13
|
declare const NativeSelect: ({ className, ...props }: React.ComponentProps<"select">) => React.JSX.Element;
|
|
@@ -13,6 +13,7 @@ import { Icon } from "../icon.js";
|
|
|
13
13
|
* @bestPractice `NativeSelect` wraps a real `<select>` - use standard `value`/`defaultValue`/`onChange` and `NativeSelectOption`/`NativeSelectOptGroup` children, not `Select` parts.
|
|
14
14
|
* @bestPractice Reach for `NativeSelect` when the native mobile picker and zero-JS behaviour matter; use `Select` when you need custom-rendered option content or styling.
|
|
15
15
|
* @bestPractice It has no built-in label - associate a `Label` via `htmlFor`/`id` for an accessible name.
|
|
16
|
+
* @keywords dropdown, picker
|
|
16
17
|
* @category forms
|
|
17
18
|
*/
|
|
18
19
|
const NativeSelect = ({ className, ...props }) => (_jsxs("div", { className: "group/native-select relative w-fit has-[select:disabled]:opacity-50", "data-component": "native-select-wrapper", "data-slot": "native-select-wrapper", children: [_jsx("select", { className: cn(focusInput(), `h-12 w-full min-w-0 appearance-none ${INPUT_SHELL} selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground transition-color-shadow text-paragraph-sm px-4 py-3 pr-9 shadow-xs disabled:pointer-events-none disabled:cursor-not-allowed`, hasErrorInput, className), "data-component": "native-select", "data-slot": "native-select", ...props }), _jsx(Icon, { "aria-hidden": "true", className: "pointer-events-none absolute top-1/2 right-3 -translate-y-1/2 opacity-50 select-none", "data-component": "native-select-icon", "data-slot": "native-select-icon", icon: ChevronDown, size: "xs" })] }));
|
|
@@ -26,6 +26,7 @@ export interface PillProps extends React.HTMLAttributes<HTMLElement>, Omit<Varia
|
|
|
26
26
|
*
|
|
27
27
|
* @bestPractice Don't reach for `Pill` in app code - it's the shared styling base; use `Badge` for display-only labels/counts and `Tag` for interactive (clickable/dismissible) chips.
|
|
28
28
|
* @bestPractice `Pill` is presentation-only and has no button semantics or dismiss/click handling - those live on `Tag`; adding `onClick` here yields a non-accessible pseudo-button.
|
|
29
|
+
* @keywords chip
|
|
29
30
|
* @category data
|
|
30
31
|
*/
|
|
31
32
|
export declare const Pill: ({ as, className, tone, size, emphasis, radius, disabled, asInput, children, ref, render, ...props }: PillProps) => React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
@@ -11,6 +11,7 @@ import { DEFAULT_PILL_SIZE, PILL_SIZE_CLASSES, pillVariants, } from "../pill/pil
|
|
|
11
11
|
*
|
|
12
12
|
* @bestPractice Don't reach for `Pill` in app code - it's the shared styling base; use `Badge` for display-only labels/counts and `Tag` for interactive (clickable/dismissible) chips.
|
|
13
13
|
* @bestPractice `Pill` is presentation-only and has no button semantics or dismiss/click handling - those live on `Tag`; adding `onClick` here yields a non-accessible pseudo-button.
|
|
14
|
+
* @keywords chip
|
|
14
15
|
* @category data
|
|
15
16
|
*/
|
|
16
17
|
export const Pill = ({ as = "span", className, tone, size, emphasis, radius, disabled, asInput, children, ref, render, ...props }) => {
|
|
@@ -21,6 +21,7 @@ import type { ComponentSize } from "../../tokens/size.js";
|
|
|
21
21
|
* @bestPractice Use `Popover` for an anchored non-blocking panel dismissed on outside-click / Esc; a page-blocking modal is a `Dialog`, a menu of actions is a `DropdownMenu`.
|
|
22
22
|
* @bestPractice It's non-modal by default (`modal={false}`) so the page stays interactive - pass `modal` only when you must trap focus and block the background.
|
|
23
23
|
* @bestPractice `PopoverContent` portals to the body; anchor to a non-trigger element with its `anchor` prop.
|
|
24
|
+
* @keywords popup, flyout, popout
|
|
24
25
|
* @category overlays
|
|
25
26
|
*/
|
|
26
27
|
declare const Popover: <Payload>({ ...props }: PopoverPrimitive.Root.Props<Payload>) => import("react").JSX.Element;
|