@scattered-light/loomiere-mojave 0.5.3 → 0.7.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 (102) hide show
  1. package/dist/exports/AGENTS.md +24 -8
  2. package/dist/exports/catalog.json +21 -0
  3. package/dist/exports/chakra.js +333 -0
  4. package/dist/exports/design-system/README.md +23 -7
  5. package/dist/exports/design-system/components/Accordion/README.md +20 -20
  6. package/dist/exports/design-system/components/Accordion/preview.html +1 -1
  7. package/dist/exports/design-system/components/AlertDialog/README.md +8 -8
  8. package/dist/exports/design-system/components/AlertDialog/preview.html +1 -1
  9. package/dist/exports/design-system/components/Autocomplete/README.md +9 -9
  10. package/dist/exports/design-system/components/Autocomplete/preview.html +1 -1
  11. package/dist/exports/design-system/components/Avatar/README.md +3 -4
  12. package/dist/exports/design-system/components/Avatar/preview.html +1 -1
  13. package/dist/exports/design-system/components/Badge/README.md +35 -0
  14. package/dist/exports/design-system/components/Badge/preview.html +19 -0
  15. package/dist/exports/design-system/components/Checkbox/README.md +5 -5
  16. package/dist/exports/design-system/components/Checkbox/preview.html +1 -1
  17. package/dist/exports/design-system/components/CheckboxGroup/README.md +14 -14
  18. package/dist/exports/design-system/components/CheckboxGroup/preview.html +1 -1
  19. package/dist/exports/design-system/components/Collapsible/README.md +6 -6
  20. package/dist/exports/design-system/components/Collapsible/preview.html +1 -1
  21. package/dist/exports/design-system/components/Collection/README.md +14 -0
  22. package/dist/exports/design-system/components/CollectionPagination/README.md +15 -0
  23. package/dist/exports/design-system/components/CollectionToolbar/README.md +24 -0
  24. package/dist/exports/design-system/components/Combobox/README.md +11 -11
  25. package/dist/exports/design-system/components/Combobox/preview.html +1 -1
  26. package/dist/exports/design-system/components/ContextMenu/README.md +9 -9
  27. package/dist/exports/design-system/components/ContextMenu/preview.html +1 -1
  28. package/dist/exports/design-system/components/DataList/README.md +39 -0
  29. package/dist/exports/design-system/components/DataList/preview.html +475 -0
  30. package/dist/exports/design-system/components/DataTable/README.md +41 -0
  31. package/dist/exports/design-system/components/DataTable/preview.html +475 -0
  32. package/dist/exports/design-system/components/DatePicker/README.md +55 -0
  33. package/dist/exports/design-system/components/DatePicker/preview.html +475 -0
  34. package/dist/exports/design-system/components/Dialog/README.md +6 -6
  35. package/dist/exports/design-system/components/Dialog/preview.html +1 -1
  36. package/dist/exports/design-system/components/Drawer/README.md +1 -1
  37. package/dist/exports/design-system/components/Drawer/preview.html +1 -1
  38. package/dist/exports/design-system/components/EditableList/README.md +33 -0
  39. package/dist/exports/design-system/components/EditableList/preview.html +475 -0
  40. package/dist/exports/design-system/components/EmptyState/README.md +60 -0
  41. package/dist/exports/design-system/components/EmptyState/preview.html +475 -0
  42. package/dist/exports/design-system/components/ListDetail/README.md +43 -0
  43. package/dist/exports/design-system/components/ListDetail/preview.html +475 -0
  44. package/dist/exports/design-system/components/Menu/README.md +11 -11
  45. package/dist/exports/design-system/components/Menu/preview.html +1 -1
  46. package/dist/exports/design-system/components/Menubar/README.md +32 -32
  47. package/dist/exports/design-system/components/Menubar/preview.html +1 -1
  48. package/dist/exports/design-system/components/Meter/README.md +9 -8
  49. package/dist/exports/design-system/components/Meter/preview.html +1 -1
  50. package/dist/exports/design-system/components/MoneyField/README.md +52 -0
  51. package/dist/exports/design-system/components/MoneyField/preview.html +475 -0
  52. package/dist/exports/design-system/components/NumberField/README.md +10 -10
  53. package/dist/exports/design-system/components/NumberField/preview.html +1 -1
  54. package/dist/exports/design-system/components/OTPField/README.md +5 -5
  55. package/dist/exports/design-system/components/OTPField/preview.html +1 -1
  56. package/dist/exports/design-system/components/Popover/README.md +7 -7
  57. package/dist/exports/design-system/components/Popover/preview.html +1 -1
  58. package/dist/exports/design-system/components/PreviewCard/README.md +9 -11
  59. package/dist/exports/design-system/components/PreviewCard/preview.html +1 -1
  60. package/dist/exports/design-system/components/Progress/README.md +8 -8
  61. package/dist/exports/design-system/components/Progress/preview.html +1 -1
  62. package/dist/exports/design-system/components/Radio/README.md +16 -23
  63. package/dist/exports/design-system/components/Radio/preview.html +1 -1
  64. package/dist/exports/design-system/components/ScrollArea/README.md +6 -6
  65. package/dist/exports/design-system/components/ScrollArea/preview.html +2 -2
  66. package/dist/exports/design-system/components/Select/README.md +13 -12
  67. package/dist/exports/design-system/components/Select/preview.html +1 -1
  68. package/dist/exports/design-system/components/Separator/README.md +2 -2
  69. package/dist/exports/design-system/components/Separator/preview.html +1 -1
  70. package/dist/exports/design-system/components/Slider/README.md +6 -6
  71. package/dist/exports/design-system/components/Slider/preview.html +1 -1
  72. package/dist/exports/design-system/components/Splitter/README.md +42 -0
  73. package/dist/exports/design-system/components/Splitter/preview.html +475 -0
  74. package/dist/exports/design-system/components/Switch/README.md +3 -3
  75. package/dist/exports/design-system/components/Switch/preview.html +1 -1
  76. package/dist/exports/design-system/components/Table/README.md +2 -1
  77. package/dist/exports/design-system/components/Table/preview.html +1 -1
  78. package/dist/exports/design-system/components/Tabs/README.md +9 -9
  79. package/dist/exports/design-system/components/Tabs/preview.html +1 -1
  80. package/dist/exports/design-system/components/Toast/README.md +7 -7
  81. package/dist/exports/design-system/components/Toast/preview.html +1 -1
  82. package/dist/exports/design-system/components/Toggle/README.md +2 -2
  83. package/dist/exports/design-system/components/Toggle/preview.html +1 -1
  84. package/dist/exports/design-system/components/ToggleGroup/README.md +5 -5
  85. package/dist/exports/design-system/components/ToggleGroup/preview.html +1 -1
  86. package/dist/exports/design-system/components/Toolbar/README.md +11 -11
  87. package/dist/exports/design-system/components/Toolbar/preview.html +1 -1
  88. package/dist/exports/design-system/components/Tooltip/README.md +4 -4
  89. package/dist/exports/design-system/components/Tooltip/preview.html +1 -1
  90. package/dist/exports/design-system/components/bundle.css +2394 -193
  91. package/dist/exports/design-system/components/bundle.js +7 -5
  92. package/dist/exports/design-system/components/index.d.ts +627 -29
  93. package/dist/exports/design-system/tokens.json +15 -0
  94. package/dist/exports/figma.json +1 -1
  95. package/dist/exports/mui.js +727 -0
  96. package/dist/exports/tailwind.css +36 -0
  97. package/dist/exports/tokens.dtcg.json +316 -2
  98. package/dist/tokens.css +111 -4
  99. package/dist/tokens.d.ts +93 -0
  100. package/dist/tokens.js +94 -1
  101. package/dist/tokens.json +572 -2
  102. package/package.json +2 -2
@@ -2,7 +2,7 @@
2
2
 
3
3
  This folder is a Loomiere theme. Load `tokens.css` (every token as a `--sl-` variable, light and dark) and `utilities.css` (text styles, focus ring, brand pairs). Framework adapters sit in `exports/`: `tailwind.css` (Tailwind v4: text styles by tier such as `text-body-base`, concept classes such as `bg-field` and `text-link`, no bare sizes like `text-sm`), `shadcn.css` (shadcn/ui), `mui.js`, `chakra.js`, AG Grid themes, `tokens.dtcg.json`. `tokens.json` lists every token with its path, value, modes and the reason it exists; read a token's `description` before using it.
4
4
 
5
- Components: `@scattered-light/loomiere-base-ui` (Base UI parts styled by class name; import `@scattered-light/loomiere-base-ui/styles.css` after the theme). `exports/design-system/components/<Name>/README.md` lists each component's classes and an example.
5
+ Components: `@scattered-light/loomiere-base-ui` (Base UI parts styled by class name; import `@scattered-light/loomiere-base-ui/styles.css` after the theme). Collection (`DataTable`, `DataList`, `CollectionToolbar`, `CollectionPagination`) is imported from `@scattered-light/loomiere-base-ui/custom/collection`, and the app installs `@tanstack/react-table`. `EditableList` comes from `@scattered-light/loomiere-base-ui/custom`. Use AG Grid only for spreadsheet work (cell-by-cell editing, ranges, tens of thousands of rows); say why in the code. `exports/design-system/components/<Name>/README.md` lists each component's classes and an example.
6
6
 
7
7
  Change the brand only in the brand file and rebuild (`loomiere build`); never edit generated files.
8
8
 
@@ -152,7 +152,7 @@ Looks: this brand can look 2 ways. With no `data-look` it is Mojave; `data-look=
152
152
 
153
153
  ### Components
154
154
 
155
- The components are [Base UI](https://base-ui.com) parts styled by class name: `Accordion`, `AlertDialog`, `Autocomplete`, `Avatar`, `Button`, `Checkbox`, `CheckboxGroup`, `Collapsible`, `Combobox`, `ContextMenu`, `Dialog`, `Drawer`, `Field`, `Fieldset`, `Form`, `Input`, `Menu`, `Menubar`, `Meter`, `NavigationMenu`, `NumberField`, `OTPField`, `Popover`, `PreviewCard`, `Progress`, `Radio`, `ScrollArea`, `Select`, `Separator`, `Slider`, `Switch`, `Table`, `Tabs`, `Toast`, `Toggle`, `ToggleGroup`, `Toolbar`, `Tooltip`. Each component's README lists the classes its parts take and the data attributes they answer to (`data-size="sm|lg"`, `data-emphasis`, `data-color`).
155
+ The components are [Base UI](https://base-ui.com) parts styled by class name: `Accordion`, `AlertDialog`, `Autocomplete`, `Avatar`, `Badge`, `Button`, `Checkbox`, `CheckboxGroup`, `Collapsible`, `Collection`, `CollectionPagination`, `CollectionToolbar`, `Combobox`, `ContextMenu`, `DataList`, `DataTable`, `DatePicker`, `Dialog`, `Drawer`, `EditableList`, `EmptyState`, `Field`, `Fieldset`, `Form`, `Input`, `ListDetail`, `Menu`, `Menubar`, `Meter`, `MoneyField`, `NavigationMenu`, `NumberField`, `OTPField`, `Popover`, `PreviewCard`, `Progress`, `Radio`, `ScrollArea`, `Select`, `Separator`, `Slider`, `Splitter`, `Switch`, `Table`, `Tabs`, `Toast`, `Toggle`, `ToggleGroup`, `Toolbar`, `Tooltip`. Each component's README lists the classes its parts take and the data attributes they answer to (`data-size="sm|lg"`, `data-emphasis`, `data-color`).
156
156
 
157
157
  Icons are Material Symbols Outlined by ligature name (`<span class="material-symbols-outlined">search</span>`, or `Loomiere.MaterialSymbol name="search"`), sized by the `.icon-<tier>` utilities to match the text beside them.
158
158
 
@@ -166,8 +166,8 @@ Load three things, in this order:
166
166
 
167
167
  `window.Loomiere` holds two kinds of component:
168
168
 
169
- - **Wrappers** put their own classes on, so use them bare: `Loomiere.Button`, `Loomiere.Input`, `Loomiere.Field`, `Loomiere.Fieldset`, `Loomiere.Form`, `Loomiere.NavigationMenu`. `Loomiere.Button` also takes `emphasis` (`bold|standard|subtle|quiet`) and `palette` props, and a Button holding only an icon draws itself square (it sets `data-icon-only`). A plain `.Button`, such as a Popover or Toolbar trigger, is drawn square when it has an `aria-label` and a single icon inside, or when you set `data-icon-only` on it.
170
- - **Everything else is the bare Base UI part** under its usual name (`Loomiere.Popover.Popup`, `Loomiere.ToggleGroup`). It draws nothing until you give each part its class, which is the component and part names joined: `<Loomiere.Popover.Popup className="PopoverPopup">`, `<Loomiere.Toggle className="Toggle">`. The component READMEs list every class.
169
+ - **Wrappers** put their own classes on, so use them bare: `Loomiere.Button`, `Loomiere.Input`, `Loomiere.Field`, `Loomiere.Fieldset`, `Loomiere.Form`, `Loomiere.NavigationMenu`, `Loomiere.Select`, `Loomiere.NumberField`, `Loomiere.OTPField`, `Loomiere.Autocomplete`, `Loomiere.Combobox`, `Loomiere.Checkbox`, `Loomiere.Radio`, `Loomiere.CheckboxGroup`, `Loomiere.Toggle`, `Loomiere.ToggleGroup`, `Loomiere.Dialog`, `Loomiere.AlertDialog`, `Loomiere.Meter`, `Loomiere.Progress`, `Loomiere.Slider`, `Loomiere.Menu`, `Loomiere.ContextMenu`, `Loomiere.Menubar`, `Loomiere.Popover`, `Loomiere.PreviewCard`, `Loomiere.Tooltip`, `Loomiere.Drawer`, `Loomiere.Accordion`, `Loomiere.Collapsible`, `Loomiere.Tabs`, `Loomiere.Switch`, `Loomiere.Toast`, `Loomiere.Avatar`, `Loomiere.Toolbar`, `Loomiere.ScrollArea`, `Loomiere.Separator`, `Loomiere.Badge`, `Loomiere.DatePicker`, `Loomiere.MoneyField`, `Loomiere.Splitter`, `Loomiere.ListDetail`, `Loomiere.EmptyState`, `Loomiere.DataTable`, `Loomiere.DataList`, `Loomiere.CollectionToolbar`, `Loomiere.CollectionPagination`, `Loomiere.EditableList`. `Loomiere.Button` also takes `emphasis` (`bold|standard|subtle|quiet`) and `palette` props, and a Button holding only an icon draws itself square (it sets `data-icon-only`). Wrapped parts that are buttons (`Dialog.Trigger`, `Menu.Trigger`, `Toolbar.Button`, `Drawer.Close`...) take the same `emphasis` and `palette` props and draw square the same way. `Popover.Trigger`, `Tooltip.Trigger`, `Select.Trigger` and `Dialog.Close` become Buttons only when they set `emphasis`, `palette` or `className="Button"`. A plain `.Button` on a bare part is drawn square when it has an `aria-label` and a single icon inside, or when you set `data-icon-only` on it. `Loomiere.Badge` takes the same `emphasis` and `palette` props, plus `status`, `size` and `dot`.
170
+ - **Table, Badge, DatePicker, MoneyField, Splitter, ListDetail, EmptyState, DataTable, DataList, CollectionToolbar, CollectionPagination and EditableList are Loomiere components**, not Base UI parts. Table is plain HTML for a static table or a report: use the classes in its stylesheet. Badge is `Loomiere.Badge`. DatePicker is `Loomiere.DatePicker`; `Loomiere.Calendar` is the month grid on its own and `Loomiere.DatePresets` is the quick-selection list. MoneyField is `Loomiere.MoneyField`: an amount of money, stored as minor units. Splitter is `Loomiere.Splitter`. ListDetail is `Loomiere.ListDetail`. EmptyState is `Loomiere.EmptyState`. DataTable, DataList, CollectionToolbar and CollectionPagination come from `@scattered-light/loomiere-base-ui/custom/collection` and need `@tanstack/react-table` installed. EditableList comes from the package root or `./custom`.
171
171
 
172
172
  `Loomiere.Base` holds the bare Base UI parts for the wrappers too (`Loomiere.Base.Button`), for when you need the part without its classes.
173
173
 
@@ -177,18 +177,19 @@ Pick by what the person is doing, not by look:
177
177
 
178
178
  | Component | Use it to |
179
179
  |---|---|
180
- | `Button` | Run one action. Set its emphasis by how much the action matters. For a small, frequent action shown as an icon alone (calendar arrows, row actions), use a quiet neutral icon-only Button: `<Loomiere.Button emphasis="quiet" palette="neutral" data-size="xs" aria-label="Next month">` with one icon inside. |
180
+ | `Button` | Run one action. Set its emphasis by how much the action matters. For a small, frequent action shown as an icon alone (the month arrows inside DatePicker, row actions), use a quiet neutral icon-only Button: `<Loomiere.Button emphasis="quiet" palette="neutral" data-size="xs" aria-label="Next month">` with one icon inside. |
181
181
  | `Switch` | Turn one setting on or off, taking effect at once. |
182
182
  | `Checkbox` | Turn one option on or off inside a form that is submitted later. |
183
183
  | `Toggle` | A tool that stays pressed, such as Bold in a toolbar. |
184
- | `ToggleGroup` | Switch between 2 to 5 short modes or views that apply at once (Single date / Date range, List / Grid). |
184
+ | `ToggleGroup` | Switch between 2 to 5 short modes or views that apply at once (List / Grid). Picking a date or a period is DatePicker, not a toggle. |
185
185
  | `Tabs` | Switch between panels of content in the same place. |
186
186
  | `Radio` | Choose one of 2 to 6 options in a form, where each option can carry a label and description. |
187
187
  | `CheckboxGroup` | Choose any number of a few visible options. |
188
188
  | `Select` | Choose one of a fixed list too long to show (about 6 to 15 items). |
189
189
  | `Combobox` | Choose one or more from a long list by typing to filter it. |
190
190
  | `Autocomplete` | Type free text, with suggestions to speed it up. |
191
- | `NumberField` | Enter an exact number, with steppers. |
191
+ | `NumberField` | Enter an exact number, with steppers. For an amount of money, use MoneyField. |
192
+ | `MoneyField` | Enter an amount of money in one or more currencies. Use NumberField for plain quantities and percentages. |
192
193
  | `Slider` | Set a value in a range where roughly is good enough. |
193
194
  | `OTPField` | Enter a one-time code. |
194
195
  | `Menu` | Offer commands from a button. Menus run actions; they don't hold a value. |
@@ -202,11 +203,26 @@ Pick by what the person is doing, not by look:
202
203
  | `Dialog` | A task that needs full attention before the page goes on. |
203
204
  | `AlertDialog` | Confirm a destructive or hard-to-undo action. |
204
205
  | `Drawer` | A side task or detail panel that keeps the page in view. |
206
+ | `Splitter` | Let people resize side-by-side or stacked areas, like a sidebar or a documents column. |
207
+ | `ListDetail` | Show the details of one item next to its list, falling back to a drawer or a page on narrow screens. Use Dialog when the detail must block the list. |
205
208
  | `Accordion` | Several sections where only some need to be open. |
206
209
  | `Collapsible` | One section to show or hide. |
207
210
  | `Toast` | Report the result of an action, briefly. |
211
+ | `Badge` | Label a status or a count next to something else. Not clickable; use Button or Toggle for that. |
212
+ | `DatePicker` | Pick a date or a period, with quick selections. Use Input type=date only when you can't load React. Calendar is the grid on its own; DatePresets is the list of quick selections. |
213
+ | `EmptyState` | Show that a list, table or page has nothing in it yet, nothing matches, failed to load, or is all done. Pick the kind; write your own copy. |
214
+ | `DataList` | A list people work through: a review queue, inbox, search results. Default for narrow panes. |
215
+ | `DataTable` | Rows people compare across several columns. Use the plain Table for static tables and reports. |
216
+ | `EditableList` | Repeating form rows people add, edit and remove: line items, allocations. |
217
+ | `CollectionToolbar` | Search, tabs, filters and the selection bar for a DataTable or a DataList. |
218
+ | `CollectionPagination` | Which page of a long list you are on. It also works without a collection. |
219
+ | `EmptyState` | Don't use it for a message about something that just happened (use Toast) or a warning above content that still shows (use a notice or an inline alert). |
208
220
  | `Progress` | Show how far a task has got. |
209
221
  | `Meter` | Show a measured amount within known limits, such as storage used. |
210
222
 
211
- A list of choices that stays on screen inside a panel, one of them selected (quick picks, saved filters, presets), has no Base UI part. Make each row a `<button aria-pressed>` drawn from the item concept: `--sl-item-padding-block`, `-padding-inline`, `-radius` and `-gap`, `--sl-item-background-hover` and `-color-hover` on hover, `--sl-item-background-selected` and `-color-selected` with the `-selected` text style when chosen. These are the same rows menus and selects use. When the choice is a form value, use Radio instead.
223
+ A date or a period, including the quick selections beside the calendar, is DatePicker. Any other list of choices that stays on screen inside a panel, one of them selected (saved filters, views), has no Base UI part. Make each row a `<button aria-pressed>` drawn from the item concept: `--sl-item-padding-block`, `-padding-inline`, `-radius` and `-gap`, `--sl-item-background-hover` and `-color-hover` on hover, `--sl-item-background-selected` and `-color-selected` with the `-selected` text style when chosen. These are the same rows menus and selects use. When the choice is a form value, use Radio instead.
224
+
225
+ An empty state's title says what is empty in plain words ("No invoices yet"). The description says why, or what to do next, in one sentence. The action is a verb ("Create invoice", "Clear filters"). The first action is the main one: bold when the person is creating the first thing, standard everywhere else, and a secondary action quiet. Error and no-access stay straight: no jokes.
226
+
227
+ Use AG Grid only for spreadsheet work (cell-by-cell editing, ranges, tens of thousands of rows). A screen that is a list people work through uses DataList or DataTable, and the code should say why if it reaches for the grid.
212
228
 
@@ -103,6 +103,8 @@
103
103
  "design-system/components/Autocomplete/preview.html",
104
104
  "design-system/components/Avatar/README.md",
105
105
  "design-system/components/Avatar/preview.html",
106
+ "design-system/components/Badge/README.md",
107
+ "design-system/components/Badge/preview.html",
106
108
  "design-system/components/Button/README.md",
107
109
  "design-system/components/Button/preview.html",
108
110
  "design-system/components/Checkbox/README.md",
@@ -111,14 +113,27 @@
111
113
  "design-system/components/CheckboxGroup/preview.html",
112
114
  "design-system/components/Collapsible/README.md",
113
115
  "design-system/components/Collapsible/preview.html",
116
+ "design-system/components/Collection/README.md",
117
+ "design-system/components/CollectionPagination/README.md",
118
+ "design-system/components/CollectionToolbar/README.md",
114
119
  "design-system/components/Combobox/README.md",
115
120
  "design-system/components/Combobox/preview.html",
116
121
  "design-system/components/ContextMenu/README.md",
117
122
  "design-system/components/ContextMenu/preview.html",
123
+ "design-system/components/DataList/README.md",
124
+ "design-system/components/DataList/preview.html",
125
+ "design-system/components/DataTable/README.md",
126
+ "design-system/components/DataTable/preview.html",
127
+ "design-system/components/DatePicker/README.md",
128
+ "design-system/components/DatePicker/preview.html",
118
129
  "design-system/components/Dialog/README.md",
119
130
  "design-system/components/Dialog/preview.html",
120
131
  "design-system/components/Drawer/README.md",
121
132
  "design-system/components/Drawer/preview.html",
133
+ "design-system/components/EditableList/README.md",
134
+ "design-system/components/EditableList/preview.html",
135
+ "design-system/components/EmptyState/README.md",
136
+ "design-system/components/EmptyState/preview.html",
122
137
  "design-system/components/Field/README.md",
123
138
  "design-system/components/Field/preview.html",
124
139
  "design-system/components/Fieldset/README.md",
@@ -127,12 +142,16 @@
127
142
  "design-system/components/Form/preview.html",
128
143
  "design-system/components/Input/README.md",
129
144
  "design-system/components/Input/preview.html",
145
+ "design-system/components/ListDetail/README.md",
146
+ "design-system/components/ListDetail/preview.html",
130
147
  "design-system/components/Menu/README.md",
131
148
  "design-system/components/Menu/preview.html",
132
149
  "design-system/components/Menubar/README.md",
133
150
  "design-system/components/Menubar/preview.html",
134
151
  "design-system/components/Meter/README.md",
135
152
  "design-system/components/Meter/preview.html",
153
+ "design-system/components/MoneyField/README.md",
154
+ "design-system/components/MoneyField/preview.html",
136
155
  "design-system/components/NavigationMenu/README.md",
137
156
  "design-system/components/NavigationMenu/preview.html",
138
157
  "design-system/components/NumberField/README.md",
@@ -155,6 +174,8 @@
155
174
  "design-system/components/Separator/preview.html",
156
175
  "design-system/components/Slider/README.md",
157
176
  "design-system/components/Slider/preview.html",
177
+ "design-system/components/Splitter/README.md",
178
+ "design-system/components/Splitter/preview.html",
158
179
  "design-system/components/Switch/README.md",
159
180
  "design-system/components/Switch/preview.html",
160
181
  "design-system/components/Table/README.md",
@@ -11,6 +11,8 @@
11
11
  * Every palette, plus "accent" and "chrome", works as a colorPalette. Button variants are
12
12
  * the brand's emphasis levels (solid = bold, outline = standard, subtle = subtle,
13
13
  * ghost = quiet); each keeps its own color unless you pass colorPalette.
14
+ * Badge uses the same levels (solid = bold, outline = standard, subtle and surface = subtle,
15
+ * plain = quiet) and does not change on hover.
14
16
  * To add your own config on top: createSystem(config, yours).
15
17
  */
16
18
  import { createSystem, defaultConfig, mergeConfigs } from '@chakra-ui/react';
@@ -350,6 +352,194 @@ const recipes = {
350
352
  }
351
353
  }
352
354
  },
355
+ badge: {
356
+ base: {
357
+ colorPalette: "chrome",
358
+ display: "inline-flex",
359
+ alignItems: "center",
360
+ whiteSpace: "nowrap",
361
+ bg: "colorPalette.soft",
362
+ color: "colorPalette.on-soft",
363
+ borderColor: "colorPalette.soft",
364
+ borderWidth: "var(--sl-stroke-default)",
365
+ borderStyle: "solid",
366
+ borderRadius: "var(--sl-radius-pill)",
367
+ height: "var(--sl-badge-height-condense)",
368
+ minH: "var(--sl-badge-height-condense)",
369
+ minW: "var(--sl-badge-height-condense)",
370
+ px: "var(--sl-badge-padding-inline-condense)",
371
+ gap: "var(--sl-badge-gap-condense)",
372
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
373
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
374
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
375
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
376
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
377
+ },
378
+ variants: {
379
+ variant: {
380
+ solid: {
381
+ colorPalette: "accent",
382
+ display: "inline-flex",
383
+ alignItems: "center",
384
+ whiteSpace: "nowrap",
385
+ bg: "colorPalette.solid",
386
+ color: "colorPalette.on-solid",
387
+ borderColor: "colorPalette.solid",
388
+ borderWidth: "var(--sl-stroke-default)",
389
+ borderStyle: "solid",
390
+ borderRadius: "var(--sl-radius-pill)",
391
+ height: "var(--sl-badge-height-condense)",
392
+ minH: "var(--sl-badge-height-condense)",
393
+ minW: "var(--sl-badge-height-condense)",
394
+ px: "var(--sl-badge-padding-inline-condense)",
395
+ gap: "var(--sl-badge-gap-condense)",
396
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
397
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
398
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
399
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
400
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
401
+ },
402
+ subtle: {
403
+ colorPalette: "chrome",
404
+ display: "inline-flex",
405
+ alignItems: "center",
406
+ whiteSpace: "nowrap",
407
+ bg: "colorPalette.soft",
408
+ color: "colorPalette.on-soft",
409
+ borderColor: "colorPalette.soft",
410
+ borderWidth: "var(--sl-stroke-default)",
411
+ borderStyle: "solid",
412
+ borderRadius: "var(--sl-radius-pill)",
413
+ height: "var(--sl-badge-height-condense)",
414
+ minH: "var(--sl-badge-height-condense)",
415
+ minW: "var(--sl-badge-height-condense)",
416
+ px: "var(--sl-badge-padding-inline-condense)",
417
+ gap: "var(--sl-badge-gap-condense)",
418
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
419
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
420
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
421
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
422
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
423
+ },
424
+ surface: {
425
+ colorPalette: "chrome",
426
+ display: "inline-flex",
427
+ alignItems: "center",
428
+ whiteSpace: "nowrap",
429
+ bg: "colorPalette.soft",
430
+ color: "colorPalette.on-soft",
431
+ borderColor: "colorPalette.soft",
432
+ borderWidth: "var(--sl-stroke-default)",
433
+ borderStyle: "solid",
434
+ borderRadius: "var(--sl-radius-pill)",
435
+ height: "var(--sl-badge-height-condense)",
436
+ minH: "var(--sl-badge-height-condense)",
437
+ minW: "var(--sl-badge-height-condense)",
438
+ px: "var(--sl-badge-padding-inline-condense)",
439
+ gap: "var(--sl-badge-gap-condense)",
440
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
441
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
442
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
443
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
444
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
445
+ },
446
+ outline: {
447
+ colorPalette: "accent",
448
+ display: "inline-flex",
449
+ alignItems: "center",
450
+ whiteSpace: "nowrap",
451
+ bg: "transparent",
452
+ color: "colorPalette.fg",
453
+ borderColor: "colorPalette.border",
454
+ borderWidth: "var(--sl-stroke-default)",
455
+ borderStyle: "solid",
456
+ borderRadius: "var(--sl-radius-pill)",
457
+ height: "var(--sl-badge-height-condense)",
458
+ minH: "var(--sl-badge-height-condense)",
459
+ minW: "var(--sl-badge-height-condense)",
460
+ px: "var(--sl-badge-padding-inline-condense)",
461
+ gap: "var(--sl-badge-gap-condense)",
462
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
463
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
464
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
465
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
466
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
467
+ },
468
+ plain: {
469
+ colorPalette: "chrome",
470
+ display: "inline-flex",
471
+ alignItems: "center",
472
+ whiteSpace: "nowrap",
473
+ bg: "transparent",
474
+ color: "colorPalette.fg",
475
+ borderColor: "colorPalette.border",
476
+ borderWidth: "var(--sl-stroke-default)",
477
+ borderStyle: "solid",
478
+ borderRadius: "var(--sl-radius-pill)",
479
+ height: "var(--sl-badge-height-condense)",
480
+ minH: "var(--sl-badge-height-condense)",
481
+ minW: "var(--sl-badge-height-condense)",
482
+ px: "var(--sl-badge-padding-inline-condense)",
483
+ gap: "var(--sl-badge-gap-condense)",
484
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
485
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
486
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
487
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
488
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
489
+ }
490
+ },
491
+ size: {
492
+ xs: {
493
+ height: "var(--sl-badge-height-minimize)",
494
+ minH: "var(--sl-badge-height-minimize)",
495
+ minW: "var(--sl-badge-height-minimize)",
496
+ px: "var(--sl-badge-padding-inline-minimize)",
497
+ gap: "var(--sl-badge-gap-minimize)",
498
+ fontFamily: "var(--sl-font-trigger-minimize-font-family)",
499
+ fontSize: "var(--sl-font-trigger-minimize-font-size)",
500
+ fontWeight: "var(--sl-font-trigger-minimize-font-weight)",
501
+ lineHeight: "var(--sl-font-trigger-minimize-line-height)",
502
+ letterSpacing: "var(--sl-font-trigger-minimize-letter-spacing)"
503
+ },
504
+ sm: {
505
+ height: "var(--sl-badge-height-condense)",
506
+ minH: "var(--sl-badge-height-condense)",
507
+ minW: "var(--sl-badge-height-condense)",
508
+ px: "var(--sl-badge-padding-inline-condense)",
509
+ gap: "var(--sl-badge-gap-condense)",
510
+ fontFamily: "var(--sl-font-trigger-condense-font-family)",
511
+ fontSize: "var(--sl-font-trigger-condense-font-size)",
512
+ fontWeight: "var(--sl-font-trigger-condense-font-weight)",
513
+ lineHeight: "var(--sl-font-trigger-condense-line-height)",
514
+ letterSpacing: "var(--sl-font-trigger-condense-letter-spacing)"
515
+ },
516
+ md: {
517
+ height: "var(--sl-badge-height-base)",
518
+ minH: "var(--sl-badge-height-base)",
519
+ minW: "var(--sl-badge-height-base)",
520
+ px: "var(--sl-badge-padding-inline-base)",
521
+ gap: "var(--sl-badge-gap-base)",
522
+ fontFamily: "var(--sl-font-trigger-base-font-family)",
523
+ fontSize: "var(--sl-font-trigger-base-font-size)",
524
+ fontWeight: "var(--sl-font-trigger-base-font-weight)",
525
+ lineHeight: "var(--sl-font-trigger-base-line-height)",
526
+ letterSpacing: "var(--sl-font-trigger-base-letter-spacing)"
527
+ },
528
+ lg: {
529
+ height: "var(--sl-badge-height-base)",
530
+ minH: "var(--sl-badge-height-base)",
531
+ minW: "var(--sl-badge-height-base)",
532
+ px: "var(--sl-badge-padding-inline-base)",
533
+ gap: "var(--sl-badge-gap-base)",
534
+ fontFamily: "var(--sl-font-trigger-base-font-family)",
535
+ fontSize: "var(--sl-font-trigger-base-font-size)",
536
+ fontWeight: "var(--sl-font-trigger-base-font-weight)",
537
+ lineHeight: "var(--sl-font-trigger-base-line-height)",
538
+ letterSpacing: "var(--sl-font-trigger-base-letter-spacing)"
539
+ }
540
+ }
541
+ }
542
+ },
353
543
  input: {
354
544
  base: {
355
545
  boxSizing: "border-box",
@@ -538,6 +728,149 @@ const recipes = {
538
728
  };
539
729
 
540
730
  const slotRecipes = {
731
+ emptyState: {
732
+ base: {
733
+ root: {
734
+ width: "100%",
735
+ color: "var(--sl-text-primary)",
736
+ textAlign: "center"
737
+ },
738
+ content: {
739
+ display: "flex",
740
+ alignItems: "center",
741
+ justifyContent: "center"
742
+ },
743
+ indicator: {
744
+ display: "flex",
745
+ alignItems: "center",
746
+ justifyContent: "center"
747
+ },
748
+ title: {
749
+ margin: 0
750
+ },
751
+ description: {
752
+ margin: 0
753
+ }
754
+ },
755
+ variants: {
756
+ size: {
757
+ sm: {
758
+ root: {
759
+ px: "var(--sl-empty-padding-inline-compact)",
760
+ py: "var(--sl-empty-padding-block-compact)"
761
+ },
762
+ content: {
763
+ gap: "var(--sl-empty-gap-compact)",
764
+ flexDirection: "row"
765
+ },
766
+ title: {
767
+ fontFamily: "var(--sl-font-subtitle-condense-font-family)",
768
+ fontSize: "var(--sl-font-subtitle-condense-font-size)",
769
+ fontWeight: "var(--sl-font-subtitle-condense-font-weight)",
770
+ lineHeight: "var(--sl-font-subtitle-condense-line-height)",
771
+ letterSpacing: "var(--sl-font-subtitle-condense-letter-spacing)",
772
+ textStyle: null,
773
+ color: "var(--sl-text-primary)"
774
+ },
775
+ description: {
776
+ fontFamily: "var(--sl-font-body-condense-font-family)",
777
+ fontSize: "var(--sl-font-body-condense-font-size)",
778
+ fontWeight: "var(--sl-font-body-condense-font-weight)",
779
+ lineHeight: "var(--sl-font-body-condense-line-height)",
780
+ letterSpacing: "var(--sl-font-body-condense-letter-spacing)",
781
+ textStyle: null,
782
+ color: "var(--sl-text-secondary)",
783
+ maxWidth: "var(--sl-empty-description-max-width)"
784
+ },
785
+ indicator: {
786
+ width: "auto",
787
+ height: "auto",
788
+ background: "transparent",
789
+ color: "var(--sl-scope-chrome-on-soft)",
790
+ borderRadius: 0,
791
+ fontSize: "var(--sl-icon-size-condense)",
792
+ textStyle: null
793
+ }
794
+ },
795
+ md: {
796
+ root: {
797
+ px: "var(--sl-empty-padding-inline-standard)",
798
+ py: "var(--sl-empty-padding-block-standard)"
799
+ },
800
+ content: {
801
+ gap: "var(--sl-empty-gap-standard)",
802
+ flexDirection: "column"
803
+ },
804
+ title: {
805
+ fontFamily: "var(--sl-font-title-condense-font-family)",
806
+ fontSize: "var(--sl-font-title-condense-font-size)",
807
+ fontWeight: "var(--sl-font-title-condense-font-weight)",
808
+ lineHeight: "var(--sl-font-title-condense-line-height)",
809
+ letterSpacing: "var(--sl-font-title-condense-letter-spacing)",
810
+ textStyle: null,
811
+ color: "var(--sl-text-primary)"
812
+ },
813
+ description: {
814
+ fontFamily: "var(--sl-font-body-base-font-family)",
815
+ fontSize: "var(--sl-font-body-base-font-size)",
816
+ fontWeight: "var(--sl-font-body-base-font-weight)",
817
+ lineHeight: "var(--sl-font-body-base-line-height)",
818
+ letterSpacing: "var(--sl-font-body-base-letter-spacing)",
819
+ textStyle: null,
820
+ color: "var(--sl-text-secondary)",
821
+ maxWidth: "var(--sl-empty-description-max-width)"
822
+ },
823
+ indicator: {
824
+ width: "var(--sl-empty-media-size-standard)",
825
+ height: "var(--sl-empty-media-size-standard)",
826
+ background: "var(--sl-scope-chrome-soft)",
827
+ color: "var(--sl-scope-chrome-on-soft)",
828
+ borderRadius: "var(--sl-radius-pill)",
829
+ fontSize: "var(--sl-icon-size-magnify)",
830
+ textStyle: null
831
+ }
832
+ },
833
+ lg: {
834
+ root: {
835
+ px: "var(--sl-empty-padding-inline-spacious)",
836
+ py: "var(--sl-empty-padding-block-spacious)"
837
+ },
838
+ content: {
839
+ gap: "var(--sl-empty-gap-spacious)",
840
+ flexDirection: "column"
841
+ },
842
+ title: {
843
+ fontFamily: "var(--sl-font-title-magnify-font-family)",
844
+ fontSize: "var(--sl-font-title-magnify-font-size)",
845
+ fontWeight: "var(--sl-font-title-magnify-font-weight)",
846
+ lineHeight: "var(--sl-font-title-magnify-line-height)",
847
+ letterSpacing: "var(--sl-font-title-magnify-letter-spacing)",
848
+ textStyle: null,
849
+ color: "var(--sl-text-primary)"
850
+ },
851
+ description: {
852
+ fontFamily: "var(--sl-font-body-base-font-family)",
853
+ fontSize: "var(--sl-font-body-base-font-size)",
854
+ fontWeight: "var(--sl-font-body-base-font-weight)",
855
+ lineHeight: "var(--sl-font-body-base-line-height)",
856
+ letterSpacing: "var(--sl-font-body-base-letter-spacing)",
857
+ textStyle: null,
858
+ color: "var(--sl-text-secondary)",
859
+ maxWidth: "var(--sl-empty-description-max-width)"
860
+ },
861
+ indicator: {
862
+ width: "var(--sl-empty-media-size-spacious)",
863
+ height: "var(--sl-empty-media-size-spacious)",
864
+ background: "var(--sl-scope-chrome-soft)",
865
+ color: "var(--sl-scope-chrome-on-soft)",
866
+ borderRadius: "var(--sl-radius-pill)",
867
+ fontSize: "var(--sl-icon-size-maximize)",
868
+ textStyle: null
869
+ }
870
+ }
871
+ }
872
+ }
873
+ },
541
874
  field: {
542
875
  base: {
543
876
  root: {
@@ -144,7 +144,7 @@ Looks: this brand can look 2 ways. With no `data-look` it is Mojave; `data-look=
144
144
 
145
145
  ## Components
146
146
 
147
- The components are [Base UI](https://base-ui.com) parts styled by class name: `Accordion`, `AlertDialog`, `Autocomplete`, `Avatar`, `Button`, `Checkbox`, `CheckboxGroup`, `Collapsible`, `Combobox`, `ContextMenu`, `Dialog`, `Drawer`, `Field`, `Fieldset`, `Form`, `Input`, `Menu`, `Menubar`, `Meter`, `NavigationMenu`, `NumberField`, `OTPField`, `Popover`, `PreviewCard`, `Progress`, `Radio`, `ScrollArea`, `Select`, `Separator`, `Slider`, `Switch`, `Table`, `Tabs`, `Toast`, `Toggle`, `ToggleGroup`, `Toolbar`, `Tooltip`. Each component's README lists the classes its parts take and the data attributes they answer to (`data-size="sm|lg"`, `data-emphasis`, `data-color`).
147
+ The components are [Base UI](https://base-ui.com) parts styled by class name: `Accordion`, `AlertDialog`, `Autocomplete`, `Avatar`, `Badge`, `Button`, `Checkbox`, `CheckboxGroup`, `Collapsible`, `Collection`, `CollectionPagination`, `CollectionToolbar`, `Combobox`, `ContextMenu`, `DataList`, `DataTable`, `DatePicker`, `Dialog`, `Drawer`, `EditableList`, `EmptyState`, `Field`, `Fieldset`, `Form`, `Input`, `ListDetail`, `Menu`, `Menubar`, `Meter`, `MoneyField`, `NavigationMenu`, `NumberField`, `OTPField`, `Popover`, `PreviewCard`, `Progress`, `Radio`, `ScrollArea`, `Select`, `Separator`, `Slider`, `Splitter`, `Switch`, `Table`, `Tabs`, `Toast`, `Toggle`, `ToggleGroup`, `Toolbar`, `Tooltip`. Each component's README lists the classes its parts take and the data attributes they answer to (`data-size="sm|lg"`, `data-emphasis`, `data-color`).
148
148
 
149
149
  Icons are Material Symbols Outlined by ligature name (`<span class="material-symbols-outlined">search</span>`, or `Loomiere.MaterialSymbol name="search"`), sized by the `.icon-<tier>` utilities to match the text beside them.
150
150
 
@@ -158,8 +158,8 @@ Load three things, in this order:
158
158
 
159
159
  `window.Loomiere` holds two kinds of component:
160
160
 
161
- - **Wrappers** put their own classes on, so use them bare: `Loomiere.Button`, `Loomiere.Input`, `Loomiere.Field`, `Loomiere.Fieldset`, `Loomiere.Form`, `Loomiere.NavigationMenu`. `Loomiere.Button` also takes `emphasis` (`bold|standard|subtle|quiet`) and `palette` props, and a Button holding only an icon draws itself square (it sets `data-icon-only`). A plain `.Button`, such as a Popover or Toolbar trigger, is drawn square when it has an `aria-label` and a single icon inside, or when you set `data-icon-only` on it.
162
- - **Everything else is the bare Base UI part** under its usual name (`Loomiere.Popover.Popup`, `Loomiere.ToggleGroup`). It draws nothing until you give each part its class, which is the component and part names joined: `<Loomiere.Popover.Popup className="PopoverPopup">`, `<Loomiere.Toggle className="Toggle">`. The component READMEs list every class.
161
+ - **Wrappers** put their own classes on, so use them bare: `Loomiere.Button`, `Loomiere.Input`, `Loomiere.Field`, `Loomiere.Fieldset`, `Loomiere.Form`, `Loomiere.NavigationMenu`, `Loomiere.Select`, `Loomiere.NumberField`, `Loomiere.OTPField`, `Loomiere.Autocomplete`, `Loomiere.Combobox`, `Loomiere.Checkbox`, `Loomiere.Radio`, `Loomiere.CheckboxGroup`, `Loomiere.Toggle`, `Loomiere.ToggleGroup`, `Loomiere.Dialog`, `Loomiere.AlertDialog`, `Loomiere.Meter`, `Loomiere.Progress`, `Loomiere.Slider`, `Loomiere.Menu`, `Loomiere.ContextMenu`, `Loomiere.Menubar`, `Loomiere.Popover`, `Loomiere.PreviewCard`, `Loomiere.Tooltip`, `Loomiere.Drawer`, `Loomiere.Accordion`, `Loomiere.Collapsible`, `Loomiere.Tabs`, `Loomiere.Switch`, `Loomiere.Toast`, `Loomiere.Avatar`, `Loomiere.Toolbar`, `Loomiere.ScrollArea`, `Loomiere.Separator`, `Loomiere.Badge`, `Loomiere.DatePicker`, `Loomiere.MoneyField`, `Loomiere.Splitter`, `Loomiere.ListDetail`, `Loomiere.EmptyState`, `Loomiere.DataTable`, `Loomiere.DataList`, `Loomiere.CollectionToolbar`, `Loomiere.CollectionPagination`, `Loomiere.EditableList`. `Loomiere.Button` also takes `emphasis` (`bold|standard|subtle|quiet`) and `palette` props, and a Button holding only an icon draws itself square (it sets `data-icon-only`). Wrapped parts that are buttons (`Dialog.Trigger`, `Menu.Trigger`, `Toolbar.Button`, `Drawer.Close`...) take the same `emphasis` and `palette` props and draw square the same way. `Popover.Trigger`, `Tooltip.Trigger`, `Select.Trigger` and `Dialog.Close` become Buttons only when they set `emphasis`, `palette` or `className="Button"`. A plain `.Button` on a bare part is drawn square when it has an `aria-label` and a single icon inside, or when you set `data-icon-only` on it. `Loomiere.Badge` takes the same `emphasis` and `palette` props, plus `status`, `size` and `dot`.
162
+ - **Table, Badge, DatePicker, MoneyField, Splitter, ListDetail, EmptyState, DataTable, DataList, CollectionToolbar, CollectionPagination and EditableList are Loomiere components**, not Base UI parts. Table is plain HTML for a static table or a report: use the classes in its stylesheet. Badge is `Loomiere.Badge`. DatePicker is `Loomiere.DatePicker`; `Loomiere.Calendar` is the month grid on its own and `Loomiere.DatePresets` is the quick-selection list. MoneyField is `Loomiere.MoneyField`: an amount of money, stored as minor units. Splitter is `Loomiere.Splitter`. ListDetail is `Loomiere.ListDetail`. EmptyState is `Loomiere.EmptyState`. DataTable, DataList, CollectionToolbar and CollectionPagination come from `@scattered-light/loomiere-base-ui/custom/collection` and need `@tanstack/react-table` installed. EditableList comes from the package root or `./custom`.
163
163
 
164
164
  `Loomiere.Base` holds the bare Base UI parts for the wrappers too (`Loomiere.Base.Button`), for when you need the part without its classes.
165
165
 
@@ -169,18 +169,19 @@ Pick by what the person is doing, not by look:
169
169
 
170
170
  | Component | Use it to |
171
171
  |---|---|
172
- | `Button` | Run one action. Set its emphasis by how much the action matters. For a small, frequent action shown as an icon alone (calendar arrows, row actions), use a quiet neutral icon-only Button: `<Loomiere.Button emphasis="quiet" palette="neutral" data-size="xs" aria-label="Next month">` with one icon inside. |
172
+ | `Button` | Run one action. Set its emphasis by how much the action matters. For a small, frequent action shown as an icon alone (the month arrows inside DatePicker, row actions), use a quiet neutral icon-only Button: `<Loomiere.Button emphasis="quiet" palette="neutral" data-size="xs" aria-label="Next month">` with one icon inside. |
173
173
  | `Switch` | Turn one setting on or off, taking effect at once. |
174
174
  | `Checkbox` | Turn one option on or off inside a form that is submitted later. |
175
175
  | `Toggle` | A tool that stays pressed, such as Bold in a toolbar. |
176
- | `ToggleGroup` | Switch between 2 to 5 short modes or views that apply at once (Single date / Date range, List / Grid). |
176
+ | `ToggleGroup` | Switch between 2 to 5 short modes or views that apply at once (List / Grid). Picking a date or a period is DatePicker, not a toggle. |
177
177
  | `Tabs` | Switch between panels of content in the same place. |
178
178
  | `Radio` | Choose one of 2 to 6 options in a form, where each option can carry a label and description. |
179
179
  | `CheckboxGroup` | Choose any number of a few visible options. |
180
180
  | `Select` | Choose one of a fixed list too long to show (about 6 to 15 items). |
181
181
  | `Combobox` | Choose one or more from a long list by typing to filter it. |
182
182
  | `Autocomplete` | Type free text, with suggestions to speed it up. |
183
- | `NumberField` | Enter an exact number, with steppers. |
183
+ | `NumberField` | Enter an exact number, with steppers. For an amount of money, use MoneyField. |
184
+ | `MoneyField` | Enter an amount of money in one or more currencies. Use NumberField for plain quantities and percentages. |
184
185
  | `Slider` | Set a value in a range where roughly is good enough. |
185
186
  | `OTPField` | Enter a one-time code. |
186
187
  | `Menu` | Offer commands from a button. Menus run actions; they don't hold a value. |
@@ -194,11 +195,26 @@ Pick by what the person is doing, not by look:
194
195
  | `Dialog` | A task that needs full attention before the page goes on. |
195
196
  | `AlertDialog` | Confirm a destructive or hard-to-undo action. |
196
197
  | `Drawer` | A side task or detail panel that keeps the page in view. |
198
+ | `Splitter` | Let people resize side-by-side or stacked areas, like a sidebar or a documents column. |
199
+ | `ListDetail` | Show the details of one item next to its list, falling back to a drawer or a page on narrow screens. Use Dialog when the detail must block the list. |
197
200
  | `Accordion` | Several sections where only some need to be open. |
198
201
  | `Collapsible` | One section to show or hide. |
199
202
  | `Toast` | Report the result of an action, briefly. |
203
+ | `Badge` | Label a status or a count next to something else. Not clickable; use Button or Toggle for that. |
204
+ | `DatePicker` | Pick a date or a period, with quick selections. Use Input type=date only when you can't load React. Calendar is the grid on its own; DatePresets is the list of quick selections. |
205
+ | `EmptyState` | Show that a list, table or page has nothing in it yet, nothing matches, failed to load, or is all done. Pick the kind; write your own copy. |
206
+ | `DataList` | A list people work through: a review queue, inbox, search results. Default for narrow panes. |
207
+ | `DataTable` | Rows people compare across several columns. Use the plain Table for static tables and reports. |
208
+ | `EditableList` | Repeating form rows people add, edit and remove: line items, allocations. |
209
+ | `CollectionToolbar` | Search, tabs, filters and the selection bar for a DataTable or a DataList. |
210
+ | `CollectionPagination` | Which page of a long list you are on. It also works without a collection. |
211
+ | `EmptyState` | Don't use it for a message about something that just happened (use Toast) or a warning above content that still shows (use a notice or an inline alert). |
200
212
  | `Progress` | Show how far a task has got. |
201
213
  | `Meter` | Show a measured amount within known limits, such as storage used. |
202
214
 
203
- A list of choices that stays on screen inside a panel, one of them selected (quick picks, saved filters, presets), has no Base UI part. Make each row a `<button aria-pressed>` drawn from the item concept: `--sl-item-padding-block`, `-padding-inline`, `-radius` and `-gap`, `--sl-item-background-hover` and `-color-hover` on hover, `--sl-item-background-selected` and `-color-selected` with the `-selected` text style when chosen. These are the same rows menus and selects use. When the choice is a form value, use Radio instead.
215
+ A date or a period, including the quick selections beside the calendar, is DatePicker. Any other list of choices that stays on screen inside a panel, one of them selected (saved filters, views), has no Base UI part. Make each row a `<button aria-pressed>` drawn from the item concept: `--sl-item-padding-block`, `-padding-inline`, `-radius` and `-gap`, `--sl-item-background-hover` and `-color-hover` on hover, `--sl-item-background-selected` and `-color-selected` with the `-selected` text style when chosen. These are the same rows menus and selects use. When the choice is a form value, use Radio instead.
216
+
217
+ An empty state's title says what is empty in plain words ("No invoices yet"). The description says why, or what to do next, in one sentence. The action is a verb ("Create invoice", "Clear filters"). The first action is the main one: bold when the person is creating the first thing, standard everywhere else, and a secondary action quiet. Error and no-access stay straight: no jokes.
218
+
219
+ Use AG Grid only for spreadsheet work (cell-by-cell editing, ranges, tens of thousands of rows). A screen that is a list people work through uses DataList or DataTable, and the code should say why if it reaches for the grid.
204
220