ionbase-ui 0.70.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/components/SettingRow.d.ts +54 -0
  2. package/dist/components/SettingRow.d.ts.map +1 -0
  3. package/dist/components/SettingRow.js +60 -0
  4. package/dist/components/SettingRow.js.map +1 -0
  5. package/dist/components/StatTile.d.ts +65 -0
  6. package/dist/components/StatTile.d.ts.map +1 -0
  7. package/dist/components/StatTile.js +54 -0
  8. package/dist/components/StatTile.js.map +1 -0
  9. package/dist/components/index.d.ts +4 -0
  10. package/dist/components/index.d.ts.map +1 -1
  11. package/dist/components/index.js +2 -0
  12. package/dist/components/index.js.map +1 -1
  13. package/dist/figma-descriptions.json +78 -63
  14. package/dist/figma-map.json +149 -1
  15. package/dist/meta/SettingRow.json +102 -0
  16. package/dist/meta/StatGroup.json +65 -0
  17. package/dist/meta/StatTile.json +163 -0
  18. package/dist/meta/components.json +331 -1
  19. package/dist/meta/contrast.json +264 -0
  20. package/dist/meta/index.json +32 -1
  21. package/dist/meta/patterns/SettingsPanel.json +2 -1
  22. package/dist/meta/patterns/index.json +2 -1
  23. package/dist/styles/index.css +2 -0
  24. package/dist/styles/setting-row.css +58 -0
  25. package/dist/styles/stat-tile.css +66 -0
  26. package/dist/styles/tokens/base.css +36 -8
  27. package/dist/styles/tokens/theme-dark.css +12 -0
  28. package/dist/tokens/index.d.ts +193 -40
  29. package/dist/tokens/index.d.ts.map +1 -1
  30. package/dist/tokens/index.js +157 -32
  31. package/dist/tokens/index.js.map +1 -1
  32. package/eslint-plugin/meta-data.js +9 -0
  33. package/eslint-plugin/rules/needs-accessible-name.js +14 -1
  34. package/llms.txt +11 -2
  35. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "ionbase-ui",
3
- "version": "0.70.0",
3
+ "version": "0.73.0",
4
4
  "generated": "by scripts/build-meta.mjs — do not edit; intent lives in meta/*.json",
5
5
  "hooks": [
6
6
  "useToast"
@@ -9745,6 +9745,108 @@
9745
9745
  "other": 0
9746
9746
  }
9747
9747
  },
9748
+ "SettingRow": {
9749
+ "name": "SettingRow",
9750
+ "source": "src/components/SettingRow.tsx",
9751
+ "propsType": "SettingRowProps",
9752
+ "description": "SettingRow — one setting: its name and what it does on the left, the control\non the right. The row the SettingsPanel pattern is built from.\n\nTHE WIRING IS THE POINT, NOT THE LAYOUT\n\nA label placed beside a Toggle looks labelled and is not: a screen reader\nannounces \"switch, off\" and nothing else, and the description is never read\nat all. The pattern names this as its first a11y requirement, and the demo\napp's stand-in handed the ids to a render function — which still left the\nwiring as a step to remember. Here an element child is cloned with\n`aria-labelledby` and `aria-describedby` already set, so the row cannot be\nused without them. A value the caller passes explicitly wins, so an\nexisting name is never overwritten.\n\nA CONTROL WITH ITS OWN TEXT KEEPS ITS OWN NAME\n\nA Button reading \"Delete workspace…\" must be announced by that text — WCAG\n2.5.3 wants the visible words inside the accessible name, and a row label of\n\"Danger zone\" would replace them. So a child with children of its own is\nleft named by them, and the row's label joins its description instead: the\nsetting is still announced, just as context rather than as the name.\n\nThe label is text rather than a `<label>` because the control may not be a\nform field, and a `<label>` pointing at a button is invalid.\n\nIt stacks below 30rem of its OWN width, not the viewport's, so the same row\nworks in a full page and in a narrow drawer.",
9753
+ "import": "import { SettingRow } from 'ionbase-ui';",
9754
+ "status": "stable",
9755
+ "since": "0.72.0",
9756
+ "summary": "One setting: its name and description on the left, the control on the right — and the control named and described by them automatically.",
9757
+ "useWhen": [
9758
+ "a settings or preferences panel, one row per setting",
9759
+ "a control whose meaning needs a sentence of explanation beside it"
9760
+ ],
9761
+ "useInstead": [
9762
+ {
9763
+ "when": "it is a form field with its own visible label above it",
9764
+ "use": "Input",
9765
+ "why": "Input, Select and the pickers carry their own label and description; a SettingRow around them names the field twice"
9766
+ },
9767
+ {
9768
+ "when": "a group of options answers one question",
9769
+ "use": "RadioGroup",
9770
+ "why": "the group has its own label; put the RadioGroup under a heading rather than in a row"
9771
+ }
9772
+ ],
9773
+ "slots": {
9774
+ "children": {
9775
+ "accepts": [
9776
+ "Toggle",
9777
+ "Checkbox",
9778
+ "Select",
9779
+ "Button"
9780
+ ],
9781
+ "note": "an element is cloned with aria-labelledby and aria-describedby pointing at the row's text; a function receives the ids instead, for a control that needs them somewhere else"
9782
+ }
9783
+ },
9784
+ "a11y": {
9785
+ "namesChild": true,
9786
+ "guarantees": [
9787
+ "an element child with no text of its own — a Toggle, a Checkbox with no label — is named by the row's label and described by its description, so it is announced as \"Weekly digest, switch, off\" plus what it does, not \"switch, off\"",
9788
+ "a child with its own text — a Button — keeps that text as its name (WCAG 2.5.3), and the row's label and description are attached as its description instead",
9789
+ "an aria-labelledby or aria-describedby the caller passes explicitly is kept, never overwritten",
9790
+ "it stacks by its own width, so it reads the same in a page and in a narrow drawer"
9791
+ ],
9792
+ "requires": [
9793
+ "one control per row — the ids name one element"
9794
+ ],
9795
+ "notes": [
9796
+ "The label is text, not a <label>, because the control may be a Button; a <label> pointing at a button is invalid."
9797
+ ]
9798
+ },
9799
+ "antiPatterns": [
9800
+ {
9801
+ "dont": "a Toggle or Checkbox with its own visible label inside a SettingRow",
9802
+ "why": "the control then names itself, the row's label becomes a description, and the setting's name is shown twice"
9803
+ },
9804
+ {
9805
+ "dont": "a Checkbox row that saves immediately",
9806
+ "why": "Toggle is immediate and Checkbox is saved with a submit — the SettingsPanel pattern's first rule"
9807
+ }
9808
+ ],
9809
+ "stylesheet": "src/styles/setting-row.css",
9810
+ "tokens": [
9811
+ "--font-family-sans",
9812
+ "--font-weight-semibold",
9813
+ "--spacing-16",
9814
+ "--spacing-2",
9815
+ "--spacing-8",
9816
+ "--text-default",
9817
+ "--text-secondary",
9818
+ "--type-body",
9819
+ "--type-body-line-height",
9820
+ "--type-body-sm",
9821
+ "--type-body-sm-line-height"
9822
+ ],
9823
+ "props": {
9824
+ "label": {
9825
+ "type": "React.ReactNode",
9826
+ "required": true,
9827
+ "origin": "own",
9828
+ "description": "The setting's name. It becomes the control's accessible name."
9829
+ },
9830
+ "description": {
9831
+ "type": "React.ReactNode",
9832
+ "required": false,
9833
+ "origin": "own",
9834
+ "description": "What the setting does, announced with the control."
9835
+ },
9836
+ "children": {
9837
+ "type": "React.ReactElement<{ 'aria-labelledby'?: string; 'aria-describedby'?: string; children?: React.ReactNode; }, string | React.JSXElementConstructor<any>> | ((ids: SettingRowIds) => React.ReactNode)",
9838
+ "required": true,
9839
+ "origin": "own",
9840
+ "description": "The control. Pass it as an element — `<Toggle />`, `<Select />`,\n`<Button />` — and the row names and describes it for you. Pass a\nfunction when the ids have to go somewhere other than the element's own\nprops; it receives them."
9841
+ }
9842
+ },
9843
+ "propCounts": {
9844
+ "own": 3,
9845
+ "aria": 0,
9846
+ "dom": 277,
9847
+ "other": 0
9848
+ }
9849
+ },
9748
9850
  "Sidebar": {
9749
9851
  "name": "Sidebar",
9750
9852
  "source": "src/components/Sidebar.tsx",
@@ -10453,6 +10555,234 @@
10453
10555
  "other": 0
10454
10556
  }
10455
10557
  },
10558
+ "StatGroup": {
10559
+ "name": "StatGroup",
10560
+ "source": "src/components/StatTile.tsx",
10561
+ "propsType": "StatGroupProps",
10562
+ "description": "StatGroup — a row of StatTiles.\n\nA `<dl>`: each tile is a term (the label) and its description (the figure),\nwhich is what a screen reader announces as a pair. The grid wraps on its own,\nso four tiles are one row on a desktop and two on a phone with no breakpoint\nin the caller's code.",
10563
+ "import": "import { StatGroup } from 'ionbase-ui';",
10564
+ "status": "stable",
10565
+ "since": "0.71.0",
10566
+ "summary": "A row of StatTiles, as a description list. Wraps on its own — no breakpoints in the caller's code.",
10567
+ "useWhen": [
10568
+ "two or more headline figures shown side by side"
10569
+ ],
10570
+ "useInstead": [
10571
+ {
10572
+ "when": "the figures are rows of records to compare field by field",
10573
+ "use": "Table"
10574
+ }
10575
+ ],
10576
+ "composition": {
10577
+ "order": [
10578
+ "StatGroup",
10579
+ "StatTile"
10580
+ ],
10581
+ "note": "StatGroup renders the <dl>; each StatTile renders a <dt> and a <dd> inside it. A StatTile outside a StatGroup is invalid HTML.",
10582
+ "example": "<StatGroup><StatTile label=\"Runs\" value=\"1.2k\" change={4.1} goodWhen=\"neutral\" /><StatTile label=\"Median run time\" value=\"38s\" change={-6.2} goodWhen=\"down\" /></StatGroup>"
10583
+ },
10584
+ "slots": {
10585
+ "children": {
10586
+ "accepts": [
10587
+ "StatTile"
10588
+ ],
10589
+ "note": "StatTiles only — the group is a <dl>, so anything else inside it is invalid"
10590
+ }
10591
+ },
10592
+ "a11y": {
10593
+ "guarantees": [
10594
+ "a <dl>, so each label is announced as the term for its figure"
10595
+ ],
10596
+ "notes": [
10597
+ "Give the group a heading or aria-label when the page has more than one, so a screen reader can tell them apart."
10598
+ ]
10599
+ },
10600
+ "antiPatterns": [
10601
+ {
10602
+ "dont": "adding media queries to change the column count",
10603
+ "why": "the grid already wraps by tile width; a breakpoint fights it"
10604
+ }
10605
+ ],
10606
+ "stylesheet": null,
10607
+ "tokens": [],
10608
+ "props": {
10609
+ "children": {
10610
+ "type": "React.ReactNode",
10611
+ "required": false,
10612
+ "origin": "own",
10613
+ "description": "StatTile elements."
10614
+ }
10615
+ },
10616
+ "propCounts": {
10617
+ "own": 1,
10618
+ "aria": 0,
10619
+ "dom": 277,
10620
+ "other": 0
10621
+ }
10622
+ },
10623
+ "StatTile": {
10624
+ "name": "StatTile",
10625
+ "source": "src/components/StatTile.tsx",
10626
+ "propsType": "StatTileProps",
10627
+ "description": "StatTile — one headline figure, and how it moved.\n\nPromoted from the demo app, where it was built for the Overview KPI row and\nsurvived three phases unchanged.\n\nGOOD AND BAD ARE NOT UP AND DOWN\n\nA rising median run time is bad news and a rising success rate is good, so\nthe colour comes from `goodWhen` and the direction together — never from the\nsign alone. `neutral` never colours: a run count going up is not a verdict.\nThe verdict is also spoken, as visually hidden text after the change, so it\nnever rests on the badge's colour.\n\nThe change is rounded BEFORE it is judged, so −0.04 reads \"No change\" rather\nthan a red \"−0.0%\".\n\nIt must sit inside a StatGroup: the tile renders a `<dt>` and a `<dd>`, which\nare only valid inside a `<dl>`.",
10628
+ "import": "import { StatTile } from 'ionbase-ui';",
10629
+ "status": "stable",
10630
+ "since": "0.71.0",
10631
+ "summary": "One headline figure and how it moved against a comparison period. Good and bad come from `goodWhen`, never from the sign alone.",
10632
+ "useWhen": [
10633
+ "a dashboard or overview leads with a handful of key numbers",
10634
+ "a change against a previous period is part of what the number means"
10635
+ ],
10636
+ "useInstead": [
10637
+ {
10638
+ "when": "it is a summary with text and media rather than a number",
10639
+ "use": "FullCard"
10640
+ },
10641
+ {
10642
+ "when": "the figure is progress toward a known total",
10643
+ "use": "ProgressBar"
10644
+ },
10645
+ {
10646
+ "when": "there are more than about six figures, or they need comparing across rows",
10647
+ "use": "Table"
10648
+ }
10649
+ ],
10650
+ "composition": {
10651
+ "order": [
10652
+ "StatGroup",
10653
+ "StatTile"
10654
+ ],
10655
+ "note": "Always inside a StatGroup: the tile renders a <dt> and a <dd>, which are only valid inside a <dl>.",
10656
+ "example": "<StatGroup><StatTile label=\"Success rate\" value=\"96.2%\" change={1.1} changeUnit=\"points\" /></StatGroup>"
10657
+ },
10658
+ "variants": {
10659
+ "goodWhen": {
10660
+ "up": {
10661
+ "use": "the default — revenue, success rate, anything where more is better"
10662
+ },
10663
+ "down": {
10664
+ "use": "costs, durations, error counts and queues, where a rise is bad news"
10665
+ },
10666
+ "neutral": {
10667
+ "use": "a change that is neither — run volume, traffic — so it is never coloured"
10668
+ }
10669
+ },
10670
+ "changeUnit": {
10671
+ "percent": {
10672
+ "use": "the default — a relative change"
10673
+ },
10674
+ "points": {
10675
+ "use": "the metric is itself a percentage: 95% to 96% is +1.0 pts, not +1.1%"
10676
+ }
10677
+ }
10678
+ },
10679
+ "a11y": {
10680
+ "guarantees": [
10681
+ "the verdict is spoken as text (\"better\" or \"worse\") after the change, so it never rests on the badge's colour",
10682
+ "the direction is in the text as a sign as well as in the arrow",
10683
+ "`isLoading` marks the tile aria-busy while its placeholder shows"
10684
+ ],
10685
+ "requires": [
10686
+ "`value` already formatted — the tile cannot know the locale, precision or unit",
10687
+ "the right `goodWhen` for the metric; the default `up` colours a rising cost green"
10688
+ ]
10689
+ },
10690
+ "antiPatterns": [
10691
+ {
10692
+ "dont": "leaving `goodWhen` at `up` for a duration, cost or error count",
10693
+ "why": "a slower, costlier or more error-prone week is shown green and announced as better"
10694
+ },
10695
+ {
10696
+ "dont": "a percentage change for a metric that is already a percentage",
10697
+ "why": "95% to 96% is +1 point; +1.1% misreports it — use changeUnit=\"points\""
10698
+ },
10699
+ {
10700
+ "dont": "passing a change of 0 to mean \"no data\"",
10701
+ "why": "0 renders \"No change\", a claim; omit `change` when there is nothing to compare"
10702
+ }
10703
+ ],
10704
+ "stylesheet": "src/styles/stat-tile.css",
10705
+ "tokens": [
10706
+ "--border-subtle",
10707
+ "--border-width-default",
10708
+ "--font-family-sans",
10709
+ "--font-weight-semibold",
10710
+ "--radius-lg",
10711
+ "--spacing-12",
10712
+ "--spacing-16",
10713
+ "--spacing-6",
10714
+ "--spacing-8",
10715
+ "--surface-default",
10716
+ "--text-default",
10717
+ "--text-secondary",
10718
+ "--text-tertiary",
10719
+ "--type-body-sm",
10720
+ "--type-body-sm-line-height",
10721
+ "--type-caption",
10722
+ "--type-caption-line-height",
10723
+ "--type-h4",
10724
+ "--type-h4-line-height"
10725
+ ],
10726
+ "props": {
10727
+ "label": {
10728
+ "type": "string",
10729
+ "required": true,
10730
+ "origin": "own",
10731
+ "description": "What is being measured. Short: \"Success rate\", not a sentence."
10732
+ },
10733
+ "value": {
10734
+ "type": "React.ReactNode",
10735
+ "required": true,
10736
+ "origin": "own",
10737
+ "description": "The figure, already formatted — \"1.2k\", \"96.2%\", \"38s\". Formatting is the\ncaller's: only it knows the locale, the precision and the unit."
10738
+ },
10739
+ "change": {
10740
+ "type": "number | undefined",
10741
+ "required": false,
10742
+ "origin": "own",
10743
+ "description": "Change against the comparison period. Omit when there is none."
10744
+ },
10745
+ "changeUnit": {
10746
+ "type": "StatTileChangeUnit | undefined",
10747
+ "required": false,
10748
+ "origin": "own",
10749
+ "description": "`percent` for a relative change; `points` for a metric that is already a\npercentage — 95% to 96% is +1 pt, and calling it +1.1% misreports it.",
10750
+ "values": [
10751
+ "points",
10752
+ "percent"
10753
+ ]
10754
+ },
10755
+ "goodWhen": {
10756
+ "type": "StatTileGoodWhen | undefined",
10757
+ "required": false,
10758
+ "origin": "own",
10759
+ "description": "Which direction is good news. `down` for costs, durations and queues;\n`neutral` when a change is neither, so it is never coloured.",
10760
+ "values": [
10761
+ "neutral",
10762
+ "up",
10763
+ "down"
10764
+ ]
10765
+ },
10766
+ "comparison": {
10767
+ "type": "string | undefined",
10768
+ "required": false,
10769
+ "origin": "own",
10770
+ "description": "What `change` is measured against."
10771
+ },
10772
+ "isLoading": {
10773
+ "type": "boolean | undefined",
10774
+ "required": false,
10775
+ "origin": "own",
10776
+ "description": "Shows a placeholder for the value and change while data loads."
10777
+ }
10778
+ },
10779
+ "propCounts": {
10780
+ "own": 7,
10781
+ "aria": 0,
10782
+ "dom": 277,
10783
+ "other": 0
10784
+ }
10785
+ },
10456
10786
  "Stepper": {
10457
10787
  "name": "Stepper",
10458
10788
  "source": "src/components/Stepper.tsx",