@instruments/materia-ui 0.4.9 → 0.4.10

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/agent-docs.md CHANGED
@@ -14,7 +14,7 @@ Do and don't guidance for coding agents, one section per component, taken from `
14
14
  - Import icons through `Icon` and primitives through these components, never from `lucide-react` or `@base-ui/react` directly.
15
15
  - Check your work with the `materia-ui-lint` class scanner (`--all` for every rule). The Oxlint preset is `@instruments/materia-ui/lint/oxlint`.
16
16
 
17
- Documented components: 197
17
+ Documented components: 198
18
18
 
19
19
  ## AccordionRoot
20
20
 
@@ -88,7 +88,7 @@ Constrains its content to a fixed width-to-height ratio, sizing itself to the av
88
88
 
89
89
  AttributeCard UI component. Import from "@instruments/materia-ui/compositions/attribute-card".
90
90
 
91
- - Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead.
91
+ - Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead, and for a bare figure without a card, `Stat`.
92
92
  - Pass a Lucide component to `icon` (e.g. `RulerIcon`), not a rendered `<Icon/>` - it is handed to the internal `Icon` at a fixed `sm` size.
93
93
  - This is a preset composition of `Card`; restyle via the surrounding layout rather than reaching inside - for a bespoke layout compose `Card`/`CardContent` directly.
94
94
 
@@ -1782,6 +1782,15 @@ Orchestrates staggered entrance animations for child `StaggerItem` components. U
1782
1782
  - Tune rhythm with `stagger` (gap between items) and `delay` (lead-in) on the parent, rather than hand-setting per-child transition delays.
1783
1783
  - Needs `ReducedMotionProvider` in the tree so the orchestrated entrance both runs and honours the reduced-motion setting.
1784
1784
 
1785
+ ## Stat
1786
+
1787
+ `@instruments/materia-ui/components/stat`
1788
+
1789
+ A figure, what it measures and where it comes from, value first. The component owns the type of all three, so a page's figures match without setting a size or weight at the call site. Import from "@instruments/materia-ui/components/stat".
1790
+
1791
+ - Use `Stat` for a bare figure in running layout (a row of results, a cover, beside a chart); for a label-first tile in its own card reach for `AttributeCard`.
1792
+ - Keep `value` to the figure alone ("24", "1,284", "3–5") and put the sentence in `label`; `note` is for the source or date window, not a second label.
1793
+
1785
1794
  ## Stepper
1786
1795
 
1787
1796
  `@instruments/materia-ui/components/stepper`
@@ -0,0 +1,32 @@
1
+ import type * as React from "react";
2
+ /** The sizes a Stat comes in: `base` sits among other content, `lg` leads a page or a section. */
3
+ export declare const STAT_SIZES: readonly ["base", "lg"];
4
+ /** A size a Stat comes in; see {@link STAT_SIZES}. */
5
+ export type StatSize = (typeof STAT_SIZES)[number];
6
+ interface StatProps {
7
+ /** CSS class name */
8
+ className?: string;
9
+ /** What the value measures, set under it. */
10
+ label?: React.ReactNode;
11
+ /** Where the value comes from, set small and muted under the label. */
12
+ note?: React.ReactNode;
13
+ /**
14
+ * `base` for a figure among other content (a table cell, a side panel); `lg` for one that leads a page or section.
15
+ * @default "base"
16
+ */
17
+ size?: StatSize;
18
+ /** The figure itself: a number, a percentage, a ratio. */
19
+ value: React.ReactNode;
20
+ }
21
+ /**
22
+ * A figure, what it measures and where it comes from, value first. The component owns the type of all three, so a
23
+ * page's figures match without setting a size or weight at the call site.
24
+ * Import from "@instruments/materia-ui/components/stat".
25
+ *
26
+ * @bestPractice Use `Stat` for a bare figure in running layout (a row of results, a cover, beside a chart); for a label-first tile in its own card reach for `AttributeCard`.
27
+ * @bestPractice Keep `value` to the figure alone ("24", "1,284", "3–5") and put the sentence in `label`; `note` is for the source or date window, not a second label.
28
+ * @category data
29
+ */
30
+ declare const Stat: ({ value, label, note, size, className }: StatProps) => React.JSX.Element;
31
+ export type { StatProps };
32
+ export { Stat };
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "@instruments/materia-ui/utils/cn";
3
+ import { Stack } from "../stack.js";
4
+ import { Text } from "../text.js";
5
+ /** The sizes a Stat comes in: `base` sits among other content, `lg` leads a page or a section. */
6
+ export const STAT_SIZES = ["base", "lg"];
7
+ /** The value's role at each size. `heading-lg` is past the sizes Text takes, so the value sets its own role. */
8
+ const VALUE_CLASSES = {
9
+ base: "text-subheading-lg",
10
+ lg: "text-heading-lg",
11
+ };
12
+ /** The label's role at each size. */
13
+ const LABEL_SIZES = {
14
+ base: "paragraph-sm",
15
+ lg: "paragraph",
16
+ };
17
+ const isSet = (node) => node !== undefined && node !== null && node !== "";
18
+ /**
19
+ * A figure, what it measures and where it comes from, value first. The component owns the type of all three, so a
20
+ * page's figures match without setting a size or weight at the call site.
21
+ * Import from "@instruments/materia-ui/components/stat".
22
+ *
23
+ * @bestPractice Use `Stat` for a bare figure in running layout (a row of results, a cover, beside a chart); for a label-first tile in its own card reach for `AttributeCard`.
24
+ * @bestPractice Keep `value` to the figure alone ("24", "1,284", "3–5") and put the sentence in `label`; `note` is for the source or date window, not a second label.
25
+ * @category data
26
+ */
27
+ const Stat = ({ value, label, note, size = "base", className }) => (_jsxs(Stack, { className: className, "data-component": "stat", "data-slot": "stat", gap: "xs", children: [_jsx("p", { className: cn("trim-both font-medium text-pretty", VALUE_CLASSES[size]), "data-slot": "stat-value", children: value }), isSet(label) && (_jsx(Text, { "data-slot": "stat-label", size: LABEL_SIZES[size], children: label })), isSet(note) && (_jsx(Text, { "data-slot": "stat-note", size: "caption", variant: "muted", children: note }))] }));
28
+ export { Stat };
@@ -0,0 +1,2 @@
1
+ export type { StatProps, StatSize } from "./stat/stat-root.js";
2
+ export { STAT_SIZES, Stat } from "./stat/stat-root.js";
@@ -0,0 +1 @@
1
+ export { STAT_SIZES, Stat } from "./stat/stat-root.js";
@@ -16,7 +16,7 @@ interface AttributeCardProps {
16
16
  * AttributeCard UI component.
17
17
  * Import from "@instruments/materia-ui/compositions/attribute-card".
18
18
  *
19
- * @bestPractice Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead.
19
+ * @bestPractice Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead, and for a bare figure without a card, `Stat`.
20
20
  * @bestPractice Pass a Lucide component to `icon` (e.g. `RulerIcon`), not a rendered `<Icon/>` - it is handed to the internal `Icon` at a fixed `sm` size.
21
21
  * @bestPractice This is a preset composition of `Card`; restyle via the surrounding layout rather than reaching inside - for a bespoke layout compose `Card`/`CardContent` directly.
22
22
  * @category catalogue
@@ -7,7 +7,7 @@ import { Icon } from "../components/icon.js";
7
7
  * AttributeCard UI component.
8
8
  * Import from "@instruments/materia-ui/compositions/attribute-card".
9
9
  *
10
- * @bestPractice Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead.
10
+ * @bestPractice Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead, and for a bare figure without a card, `Stat`.
11
11
  * @bestPractice Pass a Lucide component to `icon` (e.g. `RulerIcon`), not a rendered `<Icon/>` - it is handed to the internal `Icon` at a fixed `sm` size.
12
12
  * @bestPractice This is a preset composition of `Card`; restyle via the surrounding layout rather than reaching inside - for a bespoke layout compose `Card`/`CardContent` directly.
13
13
  * @category catalogue
@@ -74,5 +74,5 @@ export interface DocsManifest {
74
74
  storybook: DocsStorybookInventory;
75
75
  }
76
76
  /** The slug of every documented component and composition. */
77
- export type DocsUnitSlug = "accordion" | "alert" | "alert-dialog" | "anchor" | "animated-number" | "aspect-ratio" | "attribute-card" | "avatar" | "badge" | "border-beam" | "box" | "breadcrumb" | "button" | "button-group" | "calendar" | "card" | "card-grid" | "carousel" | "center" | "chart" | "checkbox" | "checkbox-card" | "checkbox-field" | "code" | "collapsible" | "color-palette" | "color-wheel" | "combobox" | "command" | "container" | "context-menu" | "cookie-banner" | "country-combobox" | "country-select" | "data-grid" | "data-grid-column-filter" | "data-grid-column-header" | "data-grid-column-visibility" | "data-grid-pagination" | "data-grid-table" | "delivery-banner" | "description-list" | "dialog" | "document-list" | "dot" | "dot-matrix-loader" | "drawer" | "dropdown-menu" | "easing-curve" | "editorial-card" | "empty" | "empty-state" | "error-boundary" | "error-state" | "expand-button" | "expandable-text" | "fade-overlay" | "field" | "file-upload" | "flex" | "folder-tile" | "gallery" | "grid" | "group" | "heading" | "hotspot-indicator" | "hover-card" | "icon" | "icon-box" | "icon-card" | "icon-morph" | "identified-surface" | "input" | "input-card" | "input-group" | "input-otp" | "item" | "kbd" | "label" | "loading-state" | "location-input" | "logo" | "logotype" | "marquee-text" | "media-frame" | "mega-menu" | "menu-item" | "menubar" | "mobile-navigation" | "month-year-picker" | "morph-dialog" | "motion-config" | "native-select" | "navigation-menu" | "page-header" | "page-toolbar" | "pagination" | "phone-input" | "pill" | "pixel-loader" | "popover" | "product-card" | "product-specifications-selector" | "progress" | "progress-dots" | "prompt-panel" | "quantity-control" | "quick-view" | "radio" | "radio-card" | "radio-group" | "requirement-item" | "resizable" | "scrim" | "scroll-area" | "scroll-fade" | "scroll-frame" | "search-input" | "section" | "section-header" | "segmented-control" | "select" | "separator" | "settings-card" | "sheet" | "shimmer" | "shine" | "sidebar" | "sidepanel" | "simple-grid" | "site-footer" | "skeleton" | "slider" | "social-icon" | "space" | "spinner" | "stack" | "stagger" | "stepper" | "streaming-text" | "sub-navigation" | "success-tick-ripple" | "swatch" | "swatch-fan" | "swatch-group" | "swatch-selector" | "switch" | "tab-navigation" | "table" | "tabs" | "tag" | "tag-selector" | "text" | "textarea" | "thinking-loader" | "thinking-orb" | "thinking-trace" | "time-slot-picker" | "toast" | "toggle" | "toggle-group" | "tooltip" | "variant-selector" | "verge" | "visually-hidden" | "voice";
77
+ export type DocsUnitSlug = "accordion" | "alert" | "alert-dialog" | "anchor" | "animated-number" | "aspect-ratio" | "attribute-card" | "avatar" | "badge" | "border-beam" | "box" | "breadcrumb" | "button" | "button-group" | "calendar" | "card" | "card-grid" | "carousel" | "center" | "chart" | "checkbox" | "checkbox-card" | "checkbox-field" | "code" | "collapsible" | "color-palette" | "color-wheel" | "combobox" | "command" | "container" | "context-menu" | "cookie-banner" | "country-combobox" | "country-select" | "data-grid" | "data-grid-column-filter" | "data-grid-column-header" | "data-grid-column-visibility" | "data-grid-pagination" | "data-grid-table" | "delivery-banner" | "description-list" | "dialog" | "document-list" | "dot" | "dot-matrix-loader" | "drawer" | "dropdown-menu" | "easing-curve" | "editorial-card" | "empty" | "empty-state" | "error-boundary" | "error-state" | "expand-button" | "expandable-text" | "fade-overlay" | "field" | "file-upload" | "flex" | "folder-tile" | "gallery" | "grid" | "group" | "heading" | "hotspot-indicator" | "hover-card" | "icon" | "icon-box" | "icon-card" | "icon-morph" | "identified-surface" | "input" | "input-card" | "input-group" | "input-otp" | "item" | "kbd" | "label" | "loading-state" | "location-input" | "logo" | "logotype" | "marquee-text" | "media-frame" | "mega-menu" | "menu-item" | "menubar" | "mobile-navigation" | "month-year-picker" | "morph-dialog" | "motion-config" | "native-select" | "navigation-menu" | "page-header" | "page-toolbar" | "pagination" | "phone-input" | "pill" | "pixel-loader" | "popover" | "product-card" | "product-specifications-selector" | "progress" | "progress-dots" | "prompt-panel" | "quantity-control" | "quick-view" | "radio" | "radio-card" | "radio-group" | "requirement-item" | "resizable" | "scrim" | "scroll-area" | "scroll-fade" | "scroll-frame" | "search-input" | "section" | "section-header" | "segmented-control" | "select" | "separator" | "settings-card" | "sheet" | "shimmer" | "shine" | "sidebar" | "sidepanel" | "simple-grid" | "site-footer" | "skeleton" | "slider" | "social-icon" | "space" | "spinner" | "stack" | "stagger" | "stat" | "stepper" | "streaming-text" | "sub-navigation" | "success-tick-ripple" | "swatch" | "swatch-fan" | "swatch-group" | "swatch-selector" | "switch" | "tab-navigation" | "table" | "tabs" | "tag" | "tag-selector" | "text" | "textarea" | "thinking-loader" | "thinking-orb" | "thinking-trace" | "time-slot-picker" | "toast" | "toggle" | "toggle-group" | "tooltip" | "variant-selector" | "verge" | "visually-hidden" | "voice";
78
78
  export declare const docsManifest: DocsManifest;
@@ -11403,6 +11403,7 @@ export const docsManifest = {
11403
11403
  "sidepanel",
11404
11404
  "site-footer",
11405
11405
  "skeleton",
11406
+ "stat",
11406
11407
  ],
11407
11408
  },
11408
11409
  {
@@ -11465,6 +11466,74 @@ export const docsManifest = {
11465
11466
  uses: [],
11466
11467
  usedBy: [],
11467
11468
  },
11469
+ {
11470
+ slug: "stat",
11471
+ module: "components/stat",
11472
+ title: "Stat",
11473
+ category: "data",
11474
+ description: 'A figure, what it measures and where it comes from, value first. The component owns the type of all three, so a\npage\'s figures match without setting a size or weight at the call site.\nImport from "@instruments/materia-ui/components/stat".',
11475
+ exports: [
11476
+ {
11477
+ name: "Stat",
11478
+ kind: "component",
11479
+ props: [
11480
+ {
11481
+ name: "className",
11482
+ type: "string",
11483
+ required: false,
11484
+ description: "CSS class name",
11485
+ },
11486
+ {
11487
+ name: "label",
11488
+ type: "React.ReactNode",
11489
+ required: false,
11490
+ description: "What the value measures, set under it.",
11491
+ },
11492
+ {
11493
+ name: "note",
11494
+ type: "React.ReactNode",
11495
+ required: false,
11496
+ description: "Where the value comes from, set small and muted under the label.",
11497
+ },
11498
+ {
11499
+ name: "size",
11500
+ type: '"base" | "lg"',
11501
+ required: false,
11502
+ defaultValue: '"base"',
11503
+ description: "`base` for a figure among other content (a table cell, a side panel); `lg` for one that leads a page or section.",
11504
+ },
11505
+ {
11506
+ name: "value",
11507
+ type: "React.ReactNode",
11508
+ required: true,
11509
+ description: "The figure itself: a number, a percentage, a ratio.",
11510
+ },
11511
+ ],
11512
+ },
11513
+ {
11514
+ name: "STAT_SIZES",
11515
+ kind: "const",
11516
+ props: [],
11517
+ },
11518
+ {
11519
+ name: "StatProps",
11520
+ kind: "interface",
11521
+ props: [],
11522
+ },
11523
+ {
11524
+ name: "StatSize",
11525
+ kind: "type",
11526
+ props: [],
11527
+ },
11528
+ ],
11529
+ bestPractices: [
11530
+ "Use `Stat` for a bare figure in running layout (a row of results, a cover, beside a chart); for a label-first tile in its own card reach for `AttributeCard`.",
11531
+ 'Keep `value` to the figure alone ("24", "1,284", "3–5") and put the sentence in `label`; `note` is for the source or date window, not a second label.',
11532
+ ],
11533
+ keywords: [],
11534
+ uses: ["stack", "text"],
11535
+ usedBy: [],
11536
+ },
11468
11537
  {
11469
11538
  slug: "stepper",
11470
11539
  module: "components/stepper",
@@ -12839,6 +12908,7 @@ export const docsManifest = {
12839
12908
  "section-header",
12840
12909
  "site-footer",
12841
12910
  "slider",
12911
+ "stat",
12842
12912
  "streaming-text",
12843
12913
  "thinking-trace",
12844
12914
  ],
@@ -13876,7 +13946,7 @@ export const docsManifest = {
13876
13946
  },
13877
13947
  ],
13878
13948
  bestPractices: [
13879
- "Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead.",
13949
+ "Use `AttributeCard` for a single label + prominent value stat tile (a KPI/metric); for many key/value pairs about one entity reach for `DescriptionList` instead, and for a bare figure without a card, `Stat`.",
13880
13950
  "Pass a Lucide component to `icon` (e.g. `RulerIcon`), not a rendered `<Icon/>` - it is handed to the internal `Icon` at a fixed `sm` size.",
13881
13951
  "This is a preset composition of `Card`; restyle via the surrounding layout rather than reaching inside - for a bespoke layout compose `Card`/`CardContent` directly.",
13882
13952
  ],
@@ -23834,7 +23904,7 @@ export const docsManifest = {
23834
23904
  storybook: {
23835
23905
  addons: ["@storybook/addon-docs", "@storybook/react-vite"],
23836
23906
  anatomyFiles: 31,
23837
- storyFiles: 172,
23907
+ storyFiles: 173,
23838
23908
  storiesWithPlay: 63,
23839
23909
  },
23840
23910
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instruments/materia-ui",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "Materia design system: React components, tokens and Tailwind v4 styles.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
@@ -462,6 +462,10 @@
462
462
  "types": "./dist/components/stagger.d.ts",
463
463
  "default": "./dist/components/stagger.js"
464
464
  },
465
+ "./components/stat": {
466
+ "types": "./dist/components/stat.d.ts",
467
+ "default": "./dist/components/stat.js"
468
+ },
465
469
  "./components/stepper": {
466
470
  "types": "./dist/components/stepper.d.ts",
467
471
  "default": "./dist/components/stepper.js"