@scattered-light/loomiere-base-ui 0.6.1 → 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.
- package/README.md +135 -5
- package/dist/chunk-JUUPOOQQ.js +3723 -0
- package/dist/chunk-JUUPOOQQ.js.map +1 -0
- package/dist/chunk-M7KJASGK.js +802 -0
- package/dist/chunk-M7KJASGK.js.map +1 -0
- package/dist/chunk-Y2CPBMFJ.js +147 -0
- package/dist/chunk-Y2CPBMFJ.js.map +1 -0
- package/dist/custom/collection/index.d.ts +534 -0
- package/dist/custom/collection/index.js +1471 -0
- package/dist/custom/collection/index.js.map +1 -0
- package/dist/custom/index.d.ts +5 -0
- package/dist/custom/index.js +4 -0
- package/dist/custom/index.js.map +1 -0
- package/dist/design-system/components/Badge/README.md +35 -0
- package/dist/design-system/components/Badge/preview.html +19 -0
- package/dist/design-system/components/Collection/README.md +14 -0
- package/dist/design-system/components/CollectionPagination/README.md +15 -0
- package/dist/design-system/components/CollectionToolbar/README.md +24 -0
- package/dist/design-system/components/DataList/README.md +39 -0
- package/dist/design-system/components/DataList/preview.html +475 -0
- package/dist/design-system/components/DataTable/README.md +41 -0
- package/dist/design-system/components/DataTable/preview.html +475 -0
- package/dist/design-system/components/DatePicker/README.md +55 -0
- package/dist/design-system/components/DatePicker/preview.html +475 -0
- package/dist/design-system/components/EditableList/README.md +33 -0
- package/dist/design-system/components/EditableList/preview.html +475 -0
- package/dist/design-system/components/EmptyState/README.md +60 -0
- package/dist/design-system/components/EmptyState/preview.html +475 -0
- package/dist/design-system/components/ListDetail/README.md +43 -0
- package/dist/design-system/components/ListDetail/preview.html +475 -0
- package/dist/design-system/components/MoneyField/README.md +52 -0
- package/dist/design-system/components/MoneyField/preview.html +475 -0
- package/dist/design-system/components/Splitter/README.md +42 -0
- package/dist/design-system/components/Splitter/preview.html +475 -0
- package/dist/design-system/components/Table/README.md +2 -1
- package/dist/design-system/components/Table/preview.html +1 -1
- package/dist/design-system/components/bundle.js +7 -5
- package/dist/design-system/components/index.d.ts +3 -21
- package/dist/design-system/components/styles.css +2266 -186
- package/dist/index-ChJXlxzq.d.ts +809 -0
- package/dist/index.d.ts +3 -21
- package/dist/index.js +176 -891
- package/dist/index.js.map +1 -1
- package/dist/styles/components/Accordion.css +1 -1
- package/dist/styles/components/AlertDialog.css +1 -1
- package/dist/styles/components/Autocomplete.css +1 -1
- package/dist/styles/components/Avatar.css +1 -1
- package/dist/styles/components/Button.css +1 -1
- package/dist/styles/components/Checkbox.css +1 -1
- package/dist/styles/components/CheckboxGroup.css +1 -1
- package/dist/styles/components/Collapsible.css +1 -1
- package/dist/styles/components/Combobox.css +1 -1
- package/dist/styles/components/ContextMenu.css +1 -1
- package/dist/styles/components/Dialog.css +1 -1
- package/dist/styles/components/Drawer.css +1 -1
- package/dist/styles/components/Field.css +1 -1
- package/dist/styles/components/Fieldset.css +1 -1
- package/dist/styles/components/Form.css +1 -1
- package/dist/styles/components/Input.css +1 -1
- package/dist/styles/components/Menu.css +1 -1
- package/dist/styles/components/Menubar.css +1 -1
- package/dist/styles/components/Meter.css +1 -1
- package/dist/styles/components/NavigationMenu.css +1 -1
- package/dist/styles/components/NumberField.css +1 -1
- package/dist/styles/components/OTPField.css +1 -1
- package/dist/styles/components/Popover.css +1 -1
- package/dist/styles/components/PreviewCard.css +1 -1
- package/dist/styles/components/Progress.css +1 -1
- package/dist/styles/components/Radio.css +1 -1
- package/dist/styles/components/ScrollArea.css +1 -1
- package/dist/styles/components/Select.css +1 -1
- package/dist/styles/components/Separator.css +1 -1
- package/dist/styles/components/Slider.css +1 -1
- package/dist/styles/components/Switch.css +1 -1
- package/dist/styles/components/Tabs.css +1 -1
- package/dist/styles/components/Toast.css +1 -1
- package/dist/styles/components/Toggle.css +1 -1
- package/dist/styles/components/ToggleGroup.css +1 -1
- package/dist/styles/components/Toolbar.css +1 -1
- package/dist/styles/components/Tooltip.css +1 -1
- package/dist/styles/custom/Badge.css +104 -0
- package/dist/styles/custom/Collection.css +15 -0
- package/dist/styles/custom/CollectionPagination.css +24 -0
- package/dist/styles/custom/CollectionToolbar.css +57 -0
- package/dist/styles/custom/DataList.css +123 -0
- package/dist/styles/custom/DataTable.css +120 -0
- package/dist/styles/custom/DatePicker.css +572 -0
- package/dist/styles/custom/EditableList.css +98 -0
- package/dist/styles/custom/EmptyState.css +255 -0
- package/dist/styles/custom/ListDetail.css +126 -0
- package/dist/styles/custom/MoneyField.css +344 -0
- package/dist/styles/custom/Splitter.css +207 -0
- package/dist/styles/{components → custom}/Table.css +31 -4
- package/dist/styles/index.css +12 -2
- package/dist/styles/reset/accessibility.css +1 -1
- package/dist/styles/reset/reset-accessibility.css +1 -1
- package/dist/styles/reset/reset-tailwind.css +1 -1
- package/dist/styles/reset/reset.css +1 -1
- package/dist/styles/tailwind.css +12 -2
- package/package.json +35 -7
package/README.md
CHANGED
|
@@ -29,13 +29,143 @@ Use Base UI as usual, with the class names the styles target, or the few wrapper
|
|
|
29
29
|
|
|
30
30
|
```tsx
|
|
31
31
|
import {
|
|
32
|
-
Accordion, AlertDialog, Autocomplete, Avatar, Button, Checkbox, CheckboxGroup, Collapsible,
|
|
33
|
-
Combobox, ContextMenu, Dialog, Drawer, Field, Form, Input, Menu, Menubar, Meter, NumberField,
|
|
34
|
-
OTPField, Popover, PreviewCard, Progress, Radio, ScrollArea, Select, Separator, Slider, Switch,
|
|
35
|
-
Tabs, Toast, Toggle, ToggleGroup, Toolbar, Tooltip,
|
|
32
|
+
Accordion, AlertDialog, Autocomplete, Avatar, Badge, Button, Calendar, Checkbox, CheckboxGroup, Collapsible,
|
|
33
|
+
Combobox, ContextMenu, DatePicker, DatePresets, Dialog, Drawer, EmptyState, Field, Form, Input, ListDetail, Menu, Menubar, Meter, MoneyField, NumberField,
|
|
34
|
+
OTPField, Popover, PreviewCard, Progress, Radio, ScrollArea, Select, Separator, Slider, Splitter, Switch,
|
|
35
|
+
Tabs, Toast, Toggle, ToggleGroup, Toolbar, Tooltip, useListDetail,
|
|
36
36
|
} from '@scattered-light/loomiere-base-ui';
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Base UI version
|
|
40
40
|
|
|
41
|
-
The styles are written against Base UI `baseUi.target` in [package.json](package.json) (1.9.0), and the peer dependency starts there. Every published CSS file names that release in its first line. `npm run check:base-ui` fails if an older Base UI is installed and warns if a newer minor one is.
|
|
41
|
+
The styles are written against Base UI `baseUi.target` in [package.json](package.json) (1.9.0), and the peer dependency starts there. Every published CSS file names that release in its first line. `npm run check:base-ui` fails if an older Base UI is installed and warns if a newer minor one is. That check, and `baseUi.target`, cover Base UI parts only. Custom components are left out of it. Check MoneyField when Number Field changes: it is built on `NumberField.Root`, and a new root prop should keep working without a change here. Money field's default maximum is `10^15 - 1` minor units. A major amount with more than 15 significant digits is not exact as a float, and Number field counts in floats. `formatMoney` passes the exact decimal string to `Intl.NumberFormat`. Number field 1.9 leaves a controlled input showing the typed text on blur when the number did not change (`12.5` stays `12.5` instead of `1,234.50`). Money field rewrites that text after Number field's layout effect, without remounting. Drop the rewrite when Number field formats this case itself. Check Collection when Checkbox, Tabs, Select or Menu change. Check Collection when the `@tanstack/react-table` major changes.
|
|
42
|
+
|
|
43
|
+
## Custom components
|
|
44
|
+
|
|
45
|
+
A custom component is one Base UI does not have. It is built here from concepts and tokens that already exist (emphasis, status, type, space), not as a new package. React lives in `src/custom/`, CSS in `styles/custom/`. Both export from the package root and from `@scattered-light/loomiere-base-ui/custom`. Table is custom too: plain HTML, with no React wrapper. A Badge that is only a number needs an accessible name: `aria-label` (for example "3 unread") or visually hidden text. Collection is the exception to the main export: it lives at `@scattered-light/loomiere-base-ui/custom/collection` so an app that only imports Badge does not have to install TanStack.
|
|
46
|
+
|
|
47
|
+
### DatePicker
|
|
48
|
+
|
|
49
|
+
A field that opens a calendar for one date or a period. The developer sets `mode`. The person using it cannot switch. `Calendar` is the month grid on its own. `DatePresets` is the quick-selection list. The preset `today` is the quick selection; `todayDate()` is the local calendar day.
|
|
50
|
+
|
|
51
|
+
| Prop | What it does |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `mode` | `single` or `range`. Defaults to `single`. |
|
|
54
|
+
| `value`, `defaultValue`, `onValueChange` | An ISO date, or `{ start, end }` for a range. `null` clears a single date. |
|
|
55
|
+
| `defaultMonth` | The month to open on when there is no value yet. Any day in that month. |
|
|
56
|
+
| `months` | `1`, `2`, `3`, or `auto` (2 for a range, 1 for a single date). The panel can only show fewer: one month under 32rem, in a drawer, or for a coarse pointer under 48rem; at most two under 40rem. |
|
|
57
|
+
| `min`, `max` | Inclusive ISO dates. Days outside them stay visible and disabled. |
|
|
58
|
+
| `isDateDisabled` | Extra days to disable, such as weekends. |
|
|
59
|
+
| `minLength`, `maxLength` | Inclusive length of a range. |
|
|
60
|
+
| `presets` | `true` (the default list), `false`, or your own. |
|
|
61
|
+
| `weekStartsOn` | `0` Sunday through `6` Saturday. The locale decides when this is omitted. |
|
|
62
|
+
| `locale`, `showOutsideDays`, `showWeekNumbers` | Formatting, trailing days, and ISO week numbers. |
|
|
63
|
+
| `commit` | `immediate` writes as soon as a day is picked. `apply` keeps a draft until Apply or Cancel. The default is immediate for one date and apply for a range. |
|
|
64
|
+
| `clearable`, `placeholder`, `formatValue` | The trigger. |
|
|
65
|
+
| `name`, `nameStart`, `nameEnd`, `required` | Submitted through a visually hidden input so `required` and `Field` validation see the value. |
|
|
66
|
+
| `disabled`, `readOnly` | Disabled leaves the tab order. Read-only stays focusable, announces the value, and does not open. |
|
|
67
|
+
| `open`, `defaultOpen`, `onOpenChange`, `popup` | `popup` is `auto`, `popover`, or `drawer`. |
|
|
68
|
+
| `label` | Names the trigger and the dialog when there is no `Field.Label`. The value is described, not part of the name. |
|
|
69
|
+
|
|
70
|
+
A range is a start click, then an end click. An end before the start swaps. Clicking the start again makes a one-day range. Hover or focus previews the band until the end is chosen; the preview is not announced as selected. Immediate mode writes `{ start, end: null }` on the first click and leaves the popup open, then writes the finished range and closes on the second click. Apply mode keeps that draft until Apply or Cancel.
|
|
71
|
+
|
|
72
|
+
Escape on a half-picked range clears the start and stays open. A second Escape closes. Escape in the month or year chooser returns to the days. Clicking outside, or any other close, throws the draft away and shows the committed value again. In immediate mode the half range is already committed, so that close keeps it.
|
|
73
|
+
|
|
74
|
+
Page Down with two months showing shifts the view by one month, so the focused day lands in the last column. Direction is read when the popup opens. A `dir` change while it is open is not picked up.
|
|
75
|
+
|
|
76
|
+
When you add one:
|
|
77
|
+
|
|
78
|
+
- Add `src/custom/<name>.tsx` and `styles/custom/<Name>.css`, and import the CSS from `styles/index.css` in the custom block (after the Base UI imports).
|
|
79
|
+
- Export it from `src/index.ts` and `src/custom/index.ts`.
|
|
80
|
+
- List it in `build/build-design-system.mjs`: `GROUPS`, `WRAPPERS` when it has a React component, and `CUSTOM`.
|
|
81
|
+
- Add it to the brand book in `packages/loomiere/exporters/design-system.mjs`: the wrappers sentence, the "which component for what" list, and the custom-components line.
|
|
82
|
+
- Add `src/stories/components/<Name>.stories.tsx` (`autodocs`, `ds:lib`). The default story is the Design System preview.
|
|
83
|
+
- Mark it included in `src/stories/OverviewChecklist.stories.jsx` and `src/stories/README.md`.
|
|
84
|
+
- If MUI or Chakra already has the component, point that override at the same variables through `exporters/component-styles.mjs`.
|
|
85
|
+
- If it paints with `--sl-e-*`, give its default level a selector in `DEFAULT_LEVELS` (`packages/loomiere/build/build-tokens.mjs`).
|
|
86
|
+
- Add a Figma page script under `packages/loomiere/figma/library/pages/` and a step in `run-order.json`. Leave `check/mojave.json` until that page has been built in Figma.
|
|
87
|
+
|
|
88
|
+
### Splitter
|
|
89
|
+
|
|
90
|
+
A window splitter. The handle is a separator you drag or move with the arrow keys. One panel has no size and fills what the others leave. Sizes can mix pixels and percent. `id` is the panel's key in storage and in a controlled `layout`. The DOM id is that key prefixed with the splitter's `useId`, so two splitters can both name a panel `main`, and `aria-controls` points at the element. Pass `layout` to control the sizes: the component renders from it and only reports changes. Children are `Splitter.Panel` and `Splitter.Handle`. A Fragment is flattened (a `.map()` can return one). Any other child throws in development, because a wrapper would hide its panel. Escape during a drag puts the sizes back.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Splitter.Root orientation="horizontal" storageKey="workstation">
|
|
94
|
+
<Splitter.Panel id="nav" defaultSize="240px" minSize="180px" maxSize="400px" collapsible />
|
|
95
|
+
<Splitter.Handle aria-label="Resize navigation" />
|
|
96
|
+
<Splitter.Panel id="main">…</Splitter.Panel>
|
|
97
|
+
</Splitter.Root>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### ListDetail
|
|
101
|
+
|
|
102
|
+
The detail of one selected item. Wide, it is a Splitter. Narrow, the detail opens in a Drawer, or replaces the list. The list stays in the first panel the whole time, so its scroll survives opening, closing, and the width change. The app keeps the selected id. `useListDetail()` returns the layout and a `close()`. `headingLevel` is the detail heading in every layout, including the drawer. `listLabel` names the list as a region.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<ListDetail.Root open={!!selectedId} onOpenChange={(open) => !open && setSelectedId(null)} storageKey="register">
|
|
106
|
+
<ListDetail.List>
|
|
107
|
+
<table className="Table">…</table>
|
|
108
|
+
</ListDetail.List>
|
|
109
|
+
<ListDetail.Detail title="Transaction 1042" closeDisabled={dirty}>…</ListDetail.Detail>
|
|
110
|
+
</ListDetail.Root>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### EmptyState
|
|
114
|
+
|
|
115
|
+
The block a page, pane, table, list or popup shows when it has nothing to show. `kind` picks the default icon, the media tone and whether a screen reader hears it. The title is required. Everything else is optional, so a title on its own is a valid empty state. It does not choose button emphasis: the first action is the main one (`bold` for `start`, `standard` for the other kinds) and a secondary action is `quiet`. `Media` and `Title` read `kind` and `size` from the root. Their own props override that. The announcement is a visually hidden live region that starts empty and fills one frame later, so the words are a change. `done` stays quiet on the render that mounts it, and is read when the kind becomes `done` after that.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<EmptyState
|
|
119
|
+
kind="no-results"
|
|
120
|
+
title="No transactions match"
|
|
121
|
+
description="Try a different date range, or clear the filters."
|
|
122
|
+
actions={<Button emphasis="standard" onClick={clearFilters}>Clear filters</Button>}
|
|
123
|
+
/>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
A filtered table keeps its header. The empty row does not hover:
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<tr>
|
|
130
|
+
<td data-empty colSpan={4}>
|
|
131
|
+
<EmptyState size="compact" kind="no-results" title="No transactions match" />
|
|
132
|
+
</td>
|
|
133
|
+
</tr>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`Combobox.Empty`, `Autocomplete.Empty` and `Menu.Empty` stay the popup's own slots. Put a compact empty state inside one:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<Combobox.Empty>
|
|
140
|
+
<EmptyState size="compact" kind="no-results" title="No fruits match" />
|
|
141
|
+
</Combobox.Empty>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Collection
|
|
145
|
+
|
|
146
|
+
Install the peer, then import the views from their own entry. `EditableList` does not need it, and comes from `./custom` like Badge.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
npm install @tanstack/react-table
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import { DataList, DataTable, CollectionToolbar, CollectionPagination, defineColumns, useCollection } from '@scattered-light/loomiere-base-ui/custom/collection';
|
|
154
|
+
import { EditableList } from '@scattered-light/loomiere-base-ui/custom';
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`useCollection` holds search, sort, filters, selection, grouping, paging, and column order and visibility. DataTable and DataList render that same state. Switch views by changing the component. The plain `<table class="Table">` is unchanged, for static tables and reports.
|
|
158
|
+
|
|
159
|
+
Columns decide how a value sorts, searches, filters and totals. `rowHeader` names the row. One column may use a tabs filter. Money totals add in minor units. Search is deferred, not debounced.
|
|
160
|
+
|
|
161
|
+
The toolbar keeps the tabs and the search while rows are selected, and swaps the trailing controls for the selection bar, so the bar does not push the search down. A list sorts from the toolbar. A table sorts from its headers. Sort cycles ascending, descending, then back to the system's default.
|
|
162
|
+
|
|
163
|
+
Keyboard, on a table or a list, when a row can be activated: the row-header buttons are one tab stop. Up and Down move between rows. Home and End go to the first and last row on the page. Space toggles that row's checkbox. Enter activates the row. Escape clears the search when it has text. Arrow keys do nothing while focus is in a field inside a cell. This is a data table, not a grid.
|
|
164
|
+
|
|
165
|
+
State attributes on the view: `data-sorted`, `data-filtered`, `data-selecting`, `data-loading`, `data-grouped`, `data-view` (`table` or `list`), `data-size` (`sm` or `md`).
|
|
166
|
+
|
|
167
|
+
A tree stays a data table. The row header's accessible name carries the level ("Cash, level 2, in Assets"). It is not a treegrid. ArrowRight opens a closed parent and ArrowLeft closes an open one, swapped in right-to-left. Totals add leaf rows only, so a parent's amount is not added again. A click on `[data-no-activate]` does not activate the row.
|
|
168
|
+
|
|
169
|
+
EditableList can take `defaultValue` with no `value`. `itemLabel` names one row ("Allocation"). Pass `EditableList.useField(column)`'s `id` and `aria-labelledby` to the input, including a Select or MoneyField that draws its own input. `name` writes hidden inputs for primitive fields other than `id`, or for the keys in `fields`. Do not combine `name` with fields the app names itself.
|
|
170
|
+
|
|
171
|
+
Not built, and the state is ready for the first three: user column show/hide and reorder, row reorder, inline cell editing, virtualization, multi-sort, column resize. EditableList has no move-up or drag yet; those buttons would sit in the row, ahead of any drag handle.
|