@nadicodeai/ui 12.1.144 → 12.1.146
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/dist/components/collection-filters.d.ts +1 -1
- package/dist/components/collection-filters.d.ts.map +1 -1
- package/dist/components/collection-filters.js +2 -2
- package/dist/components/record-list.d.ts +13 -18
- package/dist/components/record-list.d.ts.map +1 -1
- package/dist/components/record-list.js +54 -39
- package/dist/components/scroll-area.d.ts +1 -1
- package/dist/components/scroll-area.js +1 -1
- package/dist/components/sidebar-sections.js +2 -2
- package/dist/components/sidebar.d.ts.map +1 -1
- package/dist/components/sidebar.js +2 -1
- package/dist/eslint/rules/server-action-discipline.js +53 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/internal/settings-save.d.ts +2 -2
- package/dist/internal/settings-save.d.ts.map +1 -1
- package/dist/internal/settings-save.js +30 -8
- package/dist/showcase/specimens/compositions.d.ts.map +1 -1
- package/dist/showcase/specimens/compositions.js +6 -1
- package/dist/showcase/specimens/index.d.ts +0 -1
- package/dist/showcase/specimens/index.d.ts.map +1 -1
- package/dist/showcase/specimens/other.d.ts +0 -1
- package/dist/showcase/specimens/other.d.ts.map +1 -1
- package/dist/showcase/specimens/other.js +0 -2
- package/dist/showcase/usage.generated.d.ts +1 -1
- package/dist/showcase/usage.generated.d.ts.map +1 -1
- package/dist/showcase/usage.generated.js +4 -15
- package/package.json +2 -3
- package/dist/components/carousel.d.ts +0 -46
- package/dist/components/carousel.d.ts.map +0 -1
- package/dist/components/carousel.js +0 -109
|
@@ -40,7 +40,7 @@ export type CollectionFiltersProps = {
|
|
|
40
40
|
* @family Compositions
|
|
41
41
|
* @when A collection or a feed a person narrows by a property its records share (its query facets): a status, an owner, a kind. It stands in the toolbar after the search and before the sort.
|
|
42
42
|
* @instead Finding one record by its name is the search. Changing the order is the sort. Switching between sibling collections is the page's tabs.
|
|
43
|
-
* @behaviour Add filter opens a picker of the facets, then of a facet's values, each searchable; Backspace in an empty search goes back to the facets. A facet in force is a chip that reopens its values, with a button that removes it. A suggested value waits as a dashed chip in the muted grey, led by a + and never by the value's own mark, so it never reads as a filter in force, while its facet is unset, and applies in one click. Focus returns to Add filter when a facet is removed. The product keeps each facet's value, in the URL where it has one.
|
|
43
|
+
* @behaviour Add filter opens a picker of the facets, then of a facet's values, each searchable; Backspace in an empty search goes back to the facets. The picker stays inside the window: where its values are taller than the room beside its trigger, it takes that room, Back and the search stay in view, and the values scroll under them. A facet in force is a chip that reopens its values, with a button that removes it. A suggested value waits as a dashed chip in the muted grey, led by a + and never by the value's own mark, so it never reads as a filter in force, while its facet is unset, and applies in one click. Focus returns to Add filter when a facet is removed. The product keeps each facet's value, in the URL where it has one.
|
|
44
44
|
* @words Every string is the product's: `copy` names Add filter, the two searches, the empty result, Back and Remove; each facet names itself, its values and its "All" choice.
|
|
45
45
|
* @access Each chip is a group named by its facet; its remove button reads Remove with the facet's name. The pickers are searchable lists named by what they search.
|
|
46
46
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection-filters.d.ts","sourceRoot":"","sources":["../../src/components/collection-filters.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAe/B,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC3C,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"collection-filters.d.ts","sourceRoot":"","sources":["../../src/components/collection-filters.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAe/B,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC3C,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA6HF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,sBAAsB,4BAmFzE"}
|
|
@@ -31,7 +31,7 @@ function FilterPicker({ facets, copy, initialField, returnFocus, children, }) {
|
|
|
31
31
|
setOpen(next);
|
|
32
32
|
if (next)
|
|
33
33
|
changeField(initialField);
|
|
34
|
-
}, children: [_jsx(PopoverTrigger, { render: children }), _jsxs(PopoverContent, { align: "start", initialFocus: input, children: [_jsx(PopoverTitle, { className: "sr-only", children: facet?.label ?? copy.add }), facet ? (_jsx(Button, { variant: "ghost", className: "justify-start", prefix: _jsx(ArrowLeft, {}), onClick: () => changeField(undefined), children: copy.back })) : null, _jsxs(Command, { label: facet ? `${copy.searchValues}: ${facet.label}` : copy.searchFields, resultCount: copy.results, onKeyDown: (event) => {
|
|
34
|
+
}, children: [_jsx(PopoverTrigger, { render: children }), _jsxs(PopoverContent, { align: "start", className: "max-h-(--available-height) overflow-y-auto", initialFocus: input, children: [_jsx(PopoverTitle, { className: "sr-only", children: facet?.label ?? copy.add }), facet ? (_jsx(Button, { variant: "ghost", className: "justify-start", prefix: _jsx(ArrowLeft, {}), onClick: () => changeField(undefined), children: copy.back })) : null, _jsxs(Command, { label: facet ? `${copy.searchValues}: ${facet.label}` : copy.searchFields, resultCount: copy.results, onKeyDown: (event) => {
|
|
35
35
|
if (event.key === "Backspace" && !search && facet) {
|
|
36
36
|
event.preventDefault();
|
|
37
37
|
changeField(undefined);
|
|
@@ -46,7 +46,7 @@ function FilterPicker({ facets, copy, initialField, returnFocus, children, }) {
|
|
|
46
46
|
* @family Compositions
|
|
47
47
|
* @when A collection or a feed a person narrows by a property its records share (its query facets): a status, an owner, a kind. It stands in the toolbar after the search and before the sort.
|
|
48
48
|
* @instead Finding one record by its name is the search. Changing the order is the sort. Switching between sibling collections is the page's tabs.
|
|
49
|
-
* @behaviour Add filter opens a picker of the facets, then of a facet's values, each searchable; Backspace in an empty search goes back to the facets. A facet in force is a chip that reopens its values, with a button that removes it. A suggested value waits as a dashed chip in the muted grey, led by a + and never by the value's own mark, so it never reads as a filter in force, while its facet is unset, and applies in one click. Focus returns to Add filter when a facet is removed. The product keeps each facet's value, in the URL where it has one.
|
|
49
|
+
* @behaviour Add filter opens a picker of the facets, then of a facet's values, each searchable; Backspace in an empty search goes back to the facets. The picker stays inside the window: where its values are taller than the room beside its trigger, it takes that room, Back and the search stay in view, and the values scroll under them. A facet in force is a chip that reopens its values, with a button that removes it. A suggested value waits as a dashed chip in the muted grey, led by a + and never by the value's own mark, so it never reads as a filter in force, while its facet is unset, and applies in one click. Focus returns to Add filter when a facet is removed. The product keeps each facet's value, in the URL where it has one.
|
|
50
50
|
* @words Every string is the product's: `copy` names Add filter, the two searches, the empty result, Back and Remove; each facet names itself, its values and its "All" choice.
|
|
51
51
|
* @access Each chip is a group named by its facet; its remove button reads Remove with the facet's name. The pickers are searchable lists named by what they search.
|
|
52
52
|
*/
|
|
@@ -74,7 +74,7 @@ export type RecordListFooter = {
|
|
|
74
74
|
/** One muted line about the whole list, with Learn more and one secondary action, in a strip of its own under the count and the paging. */
|
|
75
75
|
note?: CollectionNote;
|
|
76
76
|
};
|
|
77
|
-
type
|
|
77
|
+
export type RecordListProps<TRecord extends RowData> = {
|
|
78
78
|
/** Names the list for assistive technology: "Skills". */
|
|
79
79
|
label: string;
|
|
80
80
|
/** Already searched, filtered and ordered; undefined while they load. */
|
|
@@ -117,7 +117,10 @@ type RecordListBase<TRecord extends RowData> = {
|
|
|
117
117
|
label: string;
|
|
118
118
|
commands: readonly MenuCommand[];
|
|
119
119
|
} | null;
|
|
120
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Names the command column for assistive technology: "Actions". Left out, its heading is empty,
|
|
122
|
+
* since each of its controls names itself, and never the list's name a second time.
|
|
123
|
+
*/
|
|
121
124
|
commandsHeader?: string;
|
|
122
125
|
/** The record opens its own page: the whole row is one target. */
|
|
123
126
|
open?: {
|
|
@@ -154,12 +157,6 @@ type RecordListBase<TRecord extends RowData> = {
|
|
|
154
157
|
meta?: ReactNode;
|
|
155
158
|
};
|
|
156
159
|
footer?: RecordListFooter;
|
|
157
|
-
};
|
|
158
|
-
type RecordListCommands<TRecord extends RowData> = {
|
|
159
|
-
command?: never;
|
|
160
|
-
state?: never;
|
|
161
|
-
commandsSize?: number;
|
|
162
|
-
} | {
|
|
163
160
|
/**
|
|
164
161
|
* The row's visible commands, one or two outline buttons of 32 px before the three dots:
|
|
165
162
|
* "Connect account", "Open report". A third goes in the menu.
|
|
@@ -168,16 +165,14 @@ type RecordListCommands<TRecord extends RowData> = {
|
|
|
168
165
|
/** The record's own action failed or was refused: its message inside its row. */
|
|
169
166
|
state?: (record: TRecord) => RowMessage | null;
|
|
170
167
|
/**
|
|
171
|
-
* The commands column
|
|
172
|
-
*
|
|
173
|
-
*
|
|
168
|
+
* The least width of the commands column in pixels, for a row that draws a button or a failed
|
|
169
|
+
* action's next steps. The column is already as wide as its widest row's buttons, next steps,
|
|
170
|
+
* three dots and chevron need, worked out from their labels, so none is cut: a list gives it
|
|
171
|
+
* only to hold a wider column.
|
|
174
172
|
*/
|
|
175
|
-
commandsSize
|
|
173
|
+
commandsSize?: number;
|
|
176
174
|
};
|
|
177
|
-
export type
|
|
178
|
-
type WithoutKeys<List, Key extends PropertyKey> = List extends unknown ? Omit<List, Key> : never;
|
|
179
|
-
/** The list's props without some keys, keeping a row command and its `commandsSize` together. */
|
|
180
|
-
export type RecordListWithout<TRecord extends RowData, Key extends PropertyKey> = WithoutKeys<RecordListProps<TRecord>, Key>;
|
|
175
|
+
export type RecordListWithout<TRecord extends RowData, Key extends PropertyKey> = Omit<RecordListProps<TRecord>, Key>;
|
|
181
176
|
/**
|
|
182
177
|
* Entity rows: objects a person opens or acts on, one line each on one resting card: the
|
|
183
178
|
* identity mark and name over what it is, a few facts, a status only for the exception, when it
|
|
@@ -189,7 +184,7 @@ export type RecordListWithout<TRecord extends RowData, Key extends PropertyKey>
|
|
|
189
184
|
* @instead “For tabular data with sortable columns and shared row shape, use `Table` instead.” (https://vercel.com/geist/entity)
|
|
190
185
|
* “For a static key/value metadata block on a detail page, use `Description`.” (https://vercel.com/geist/entity)
|
|
191
186
|
* Ours: Geist's `Table` is a `DataTable`: this list has no visible headings and at most three facts, so a fourth fact is a table, and anything more than a few facts lives on the record's page. A screen gives `RecordList` the records and what each one says, never its own toolbar, table, rows or menus, and nothing else draws a record row. Its `Description` is `ObjectFacts`. Events in time are an `ActivityFeed`. Reusable things a person adds from a catalogue are a `LibraryShelf`. A descriptive row with prose is an `Item`.
|
|
192
|
-
* @behaviour One bordered card, a 1 px rule between records and none after the last. A row is 72 px, with 16 px above and below, and its columns stand left to right at the widths the list declares, so a person reads every list the same way: the `select` box (40 px, only when the list is picked from, an optional column), the identity (the rest: the one column without a size), the facts (each its `size`), the status (`status.size`), the time (`time.size`, tabular), the `checklist` ring (52 px, only when the record has steps to be ready) and the commands (
|
|
187
|
+
* @behaviour One bordered card, a 1 px rule between records and none after the last. A row is 72 px, with 16 px above and below, and its columns stand left to right at the widths the list declares, so a person reads every list the same way: the `select` box (40 px, only when the list is picked from, an optional column), the identity (the rest: the one column without a size), the facts (each its `size`), the status (`status.size`), the time (`time.size`, tabular), the `checklist` ring (52 px, only when the record has steps to be ready) and the commands (as wide as the widest row's buttons, a failed action's next steps and the three dots or the chevron after them need, worked out from their labels, each label at most 8 px a character and a button holding the longer of its label and its pending label, the dots at their 44 px touch target; 64 px for the three dots or the chevron alone; a row that draws a button or next steps is never narrower than a `commandsSize` the caller gives). A `checklist` puts the record's `ProgressChecklist` ring just before its commands, where Vercel ends a project's row with its Production Checklist; the ring opens its own drawer, never the row. Every row has its 32 px mark, its name (600) and, under it, one muted 14 px line; `name` and the mark are required; a record with nothing to say under its name leaves the line out and is the name alone, never a dash. Give every column a `size` in pixels; the name takes the rest. With `layout="line"`, as on Vercel's Projects page, the facts and the status share one muted line, joined by a middle dot, in a column as wide as the name's, and the row stays one line (mark, name over its line, that summary, the time, the ring, the three dots) on a card from 448 px, and on a narrower card the summary and the time move under the name as muted text joined by a middle dot that wraps, the status keeping its mark whole and breaking between its words only when it alone is wider than the line, in the same row, their labels read by assistive technology only. Rows of `columns` follow the same rule once the card is narrower than their columns: the facts and the time leave the row for that muted text, wrapping so every value stays readable, never a labelled list, and the status stands beside the name, which ends in an ellipsis before it, so the exception is never the part a phone's line cuts. `facts` takes at most three. A menu of one command that is not destructive, with no row command, is that command's button, except in a `line` row, which keeps it in the three dots as Vercel's project row does, and the column is as wide as the widest such button, so its label is never cut. Status is only for the exception, empty for the usual record, and its column stands only while a record in the list shows one, so the name and its line keep the room; the commands column likewise stands only while a record has a command, a menu or a message, or the rows open, and it widens for a failed action's next steps only while a row shows one. Never the three dots before the button, a decorative icon for the record's mark, a status on every row, or a destructive button on every row: a destructive command stays in the three dots. A `line` row's summary joins only the facts the record has, so it never ends in a dot. A failed or refused action of the record shows as its catalogue message inside its own row, never a notice under the row: it replaces the detail line, with its next steps beside its commands, or under the message on a card too narrow for the row's columns. With `open` the whole row is one target and takes the `accent` hover, and a row that only opens ends in a muted chevron; a row that opens nothing never reacts to hover. With `editor` the record's row opens its form under its line. `empty` is required: `null` is the choice to draw nothing for a list with no records, and any other value is the state it draws. A note about the whole list is `footer.note`: one muted line, an optional *Learn more* after it at the left and one secondary action at the right, in a strip of its own under the count and the paging, as Vercel ends its deployments list ("Deployment retention is enabled. Learn more", *View recently deleted*). Colour is neutral, the name in ink and every other cell in the body grey, except the status badge and a failed action's message.
|
|
193
188
|
* “Pick the variant by what the user needs: no-results for a filtered list that returned zero rows, blank slate or informational for a resource the user hasn’t created, cleared for completed work, permission for role or tier denials, error for a failed load.” (https://vercel.com/geist/empty-state)
|
|
194
189
|
* Ours: `failed`, `noMatch` and `empty` are those variants, drawn inside the card.
|
|
195
190
|
* “The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`.” (https://vercel.com/geist/entity)
|
|
@@ -201,7 +196,7 @@ export type RecordListWithout<TRecord extends RowData, Key extends PropertyKey>
|
|
|
201
196
|
* “Keep right-column buttons Verb + Noun (`Remove Member`, `Resend Invite`). Bare verbs like `Remove` or `Confirm` lose context once the row scrolls offscreen.” (https://vercel.com/geist/entity)
|
|
202
197
|
* Ours: every string is the product's: `label` names the list, a time's `phrase` writes its sentence ("Updated {when}"), `missing` is what a screen reader hears for a record with no time, the menu's `label` reads "More for {record}". A row command names its result in sentence case ("Edit domain"). A status is the exception's word ("Needs attention"), never "Active" on every row.
|
|
203
198
|
* @access “Wrap the loading region in `aria-busy="true"` and announce completion with `aria-live="polite"` on the destination container, not the skeleton itself.” (https://vercel.com/geist/skeleton)
|
|
204
|
-
* Ours: the loading rows sit in one `SkeletonRegion` that is busy while they stand and announces what replaces them. A table named by `label`, its column headings read by assistive technology only. The row link carries `open.label`; the three dots carry the menu's `label`, and the menu's first line names the record. The loading rows are a status named by `loadingLabel`, inside the one live region that announces what replaces them.
|
|
199
|
+
* Ours: the loading rows sit in one `SkeletonRegion` that is busy while they stand and announces what replaces them. A table named by `label`, its column headings read by assistive technology only; the commands column's is `commandsHeader`, and empty without one, since its controls name themselves, never the list's name a second time. The row link carries `open.label`; the three dots carry the menu's `label`, and the menu's first line names the record. The loading rows are a status named by `loadingLabel`, inside the one live region that announces what replaces them.
|
|
205
200
|
* “For multi-select rows, the leading `Checkbox` carries `aria-label="Select {entity name}"` so the row is selectable without relying on the visual label.” (https://vercel.com/geist/entity)
|
|
206
201
|
* Ours: each box is named by `select.label`, which reads "Select {record}".
|
|
207
202
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-list.d.ts","sourceRoot":"","sources":["../../src/components/record-list.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAiB,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAIjG,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAK9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAqC,MAAM,wBAAwB,CAAC;AAG5F,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,MAAM,MAAM,UAAU,GAAG;IACvB,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,0GAA0G;IAC1G,IAAI,EAAE,iBAAiB,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC;IACnC,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,gHAAgH;IAChH,KAAK,CAAC,EAAE,IAAI,CAAC;CACd,CAAC;AAEF,kGAAkG;AAClG,MAAM,MAAM,WAAW,CAAC,OAAO,IAC3B,SAAS,EAAE,GACX,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,GAC9B,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,GACnD,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAE7E,MAAM,MAAM,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"record-list.d.ts","sourceRoot":"","sources":["../../src/components/record-list.tsx"],"names":[],"mappings":"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"}
|
|
@@ -17,37 +17,57 @@ import { TableValue } from "./table-value.js";
|
|
|
17
17
|
import { soleMenuButton } from "../internal/record-menu-items.js";
|
|
18
18
|
import { RowMessageActions, RowMessageLine } from "../internal/row-message.js";
|
|
19
19
|
import { useTableLaidOutCompact } from "../internal/table-compact-line.js";
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
const CELL_START = 8;
|
|
21
|
+
const CELL_END_AT_CARD_EDGE = 20;
|
|
22
|
+
const COMMANDS_GAP = 8;
|
|
23
|
+
const TOUCH_TARGET = 44;
|
|
24
|
+
const DOTS_ALONE_SIZE = CELL_END_AT_CARD_EDGE + TOUCH_TARGET;
|
|
25
|
+
const BUTTON_EDGE = 1;
|
|
26
|
+
const BUTTON_PADDING = { sm: 6, default: 10 };
|
|
27
|
+
const BUTTON_LABEL_INSET = 6;
|
|
28
|
+
const BUTTON_ICON_SLOT = 20;
|
|
29
|
+
const BUTTON_ICON_GAP = 3;
|
|
30
|
+
const EXTERNAL_ARROW = 14;
|
|
31
|
+
const CHEVRON = 16;
|
|
32
|
+
const WIDEST_LABEL_CHARACTER = 8;
|
|
33
|
+
function shownCommands(list, record) {
|
|
34
|
+
const menu = list.menu?.(record);
|
|
35
|
+
const commands = menu?.commands ?? [];
|
|
36
|
+
const own = list.command?.(record);
|
|
37
|
+
const menuButton = own || list.layout === "line" ? undefined : soleMenuButton(commands);
|
|
38
|
+
const buttons = own ? [own].flat() : menuButton ? [menuButton] : [];
|
|
39
|
+
const state = list.state?.(record) ?? null;
|
|
40
|
+
const dots = menu && commands.length > 0 && !menuButton ? menu : undefined;
|
|
41
|
+
const chevron = !dots && !state && Boolean(list.open?.href(record));
|
|
42
|
+
return { buttons, state, dots, chevron };
|
|
43
|
+
}
|
|
44
|
+
function buttonRoom(command, size) {
|
|
45
|
+
const longerLabel = Math.max(command.label.length, command.pendingLabel?.length ?? 0);
|
|
46
|
+
return (2 * (BUTTON_EDGE + BUTTON_PADDING[size] + BUTTON_LABEL_INSET) +
|
|
47
|
+
(command.icon ? BUTTON_ICON_SLOT + BUTTON_ICON_GAP : 0) +
|
|
48
|
+
(command.external ? BUTTON_ICON_GAP + EXTERNAL_ARROW + BUTTON_ICON_GAP : 0) +
|
|
49
|
+
longerLabel * WIDEST_LABEL_CHARACTER);
|
|
50
|
+
}
|
|
51
|
+
function commandsRoom(list, record) {
|
|
52
|
+
const { buttons, state, dots, chevron } = shownCommands(list, record);
|
|
53
|
+
const widths = [
|
|
54
|
+
...buttons.map((command) => buttonRoom(command, "sm")),
|
|
55
|
+
...(state?.message.actions ?? []).map((action) => buttonRoom(action, "default")),
|
|
56
|
+
];
|
|
57
|
+
if (widths.length === 0)
|
|
58
|
+
return DOTS_ALONE_SIZE;
|
|
59
|
+
if (dots)
|
|
60
|
+
widths.push(TOUCH_TARGET);
|
|
61
|
+
if (chevron)
|
|
62
|
+
widths.push(CHEVRON);
|
|
63
|
+
const room = CELL_START +
|
|
64
|
+
widths.reduce((sum, width) => sum + width, 0) +
|
|
65
|
+
COMMANDS_GAP * (widths.length - 1) +
|
|
66
|
+
CELL_END_AT_CARD_EDGE;
|
|
67
|
+
return Math.max(room, list.commandsSize ?? 0);
|
|
44
68
|
}
|
|
45
69
|
function commandsColumnSize(props) {
|
|
46
|
-
|
|
47
|
-
const roomUnused = state !== undefined && !props.command && !props.records.some((record) => state(record));
|
|
48
|
-
return roomUnused || props.commandsSize === undefined
|
|
49
|
-
? defaultCommandsSize(props, props.records)
|
|
50
|
-
: props.commandsSize;
|
|
70
|
+
return props.records.reduce((widest, record) => Math.max(widest, commandsRoom(props, record)), DOTS_ALONE_SIZE);
|
|
51
71
|
}
|
|
52
72
|
/** The checklist's ring: one 36 px button and the cell's padding. */
|
|
53
73
|
const CHECKLIST_SIZE = 52;
|
|
@@ -110,15 +130,10 @@ function ChecklistCell({ row }) {
|
|
|
110
130
|
function CommandsCell({ row }) {
|
|
111
131
|
const list = useShownList();
|
|
112
132
|
const record = row.original;
|
|
113
|
-
const state = list
|
|
114
|
-
const menu = list.menu?.(record);
|
|
115
|
-
const commands = menu?.commands ?? [];
|
|
116
|
-
const own = list.command?.(record);
|
|
117
|
-
const menuButton = own || list.layout === "line" ? undefined : soleMenuButton(commands);
|
|
133
|
+
const { buttons, state, dots, chevron } = shownCommands(list, record);
|
|
118
134
|
// On a card too narrow for the row's columns the next steps stand under the message instead.
|
|
119
135
|
const laidOutCompact = useTableLaidOutCompact();
|
|
120
|
-
const
|
|
121
|
-
const end = menu && commands.length > 0 && !menuButton ? (_jsx(ActionMenu, { commands: commands, label: menu.label, record: list.name(record).name })) : list.open?.href(record) && !state ? (_jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 text-muted-foreground" })) : null;
|
|
136
|
+
const end = dots ? (_jsx(ActionMenu, { commands: dots.commands, label: dots.label, record: list.name(record).name })) : chevron ? (_jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 text-muted-foreground" })) : null;
|
|
122
137
|
if (buttons.length === 0 && !state && !end)
|
|
123
138
|
return null;
|
|
124
139
|
return (_jsxs("div", { className: "flex items-center justify-end gap-2", children: [buttons.length > 0 ? (_jsx("div", { className: "flex min-w-0 justify-end gap-2 [&>*]:max-w-full [&>*]:min-w-0 [&>*]:shrink [&>*>span:not([data-icon])]:truncate", children: buttons.map((command) => (_jsx(PageCommandButton, { command: command, size: "sm", variant: "outline" }, command.label))) })) : null, state && !laidOutCompact ? _jsx(RowMessageActions, { state: state }) : null, end] }));
|
|
@@ -206,7 +221,7 @@ function recordColumns(props) {
|
|
|
206
221
|
if (props.open || someRecordHasCommands) {
|
|
207
222
|
columns.push({
|
|
208
223
|
id: "commands",
|
|
209
|
-
header: props.commandsHeader ??
|
|
224
|
+
header: props.commandsHeader ?? "",
|
|
210
225
|
size: commandsColumnSize(props),
|
|
211
226
|
cell: CommandsCell,
|
|
212
227
|
});
|
|
@@ -250,7 +265,7 @@ function RecordRows(props) {
|
|
|
250
265
|
* @instead “For tabular data with sortable columns and shared row shape, use `Table` instead.” (https://vercel.com/geist/entity)
|
|
251
266
|
* “For a static key/value metadata block on a detail page, use `Description`.” (https://vercel.com/geist/entity)
|
|
252
267
|
* Ours: Geist's `Table` is a `DataTable`: this list has no visible headings and at most three facts, so a fourth fact is a table, and anything more than a few facts lives on the record's page. A screen gives `RecordList` the records and what each one says, never its own toolbar, table, rows or menus, and nothing else draws a record row. Its `Description` is `ObjectFacts`. Events in time are an `ActivityFeed`. Reusable things a person adds from a catalogue are a `LibraryShelf`. A descriptive row with prose is an `Item`.
|
|
253
|
-
* @behaviour One bordered card, a 1 px rule between records and none after the last. A row is 72 px, with 16 px above and below, and its columns stand left to right at the widths the list declares, so a person reads every list the same way: the `select` box (40 px, only when the list is picked from, an optional column), the identity (the rest: the one column without a size), the facts (each its `size`), the status (`status.size`), the time (`time.size`, tabular), the `checklist` ring (52 px, only when the record has steps to be ready) and the commands (
|
|
268
|
+
* @behaviour One bordered card, a 1 px rule between records and none after the last. A row is 72 px, with 16 px above and below, and its columns stand left to right at the widths the list declares, so a person reads every list the same way: the `select` box (40 px, only when the list is picked from, an optional column), the identity (the rest: the one column without a size), the facts (each its `size`), the status (`status.size`), the time (`time.size`, tabular), the `checklist` ring (52 px, only when the record has steps to be ready) and the commands (as wide as the widest row's buttons, a failed action's next steps and the three dots or the chevron after them need, worked out from their labels, each label at most 8 px a character and a button holding the longer of its label and its pending label, the dots at their 44 px touch target; 64 px for the three dots or the chevron alone; a row that draws a button or next steps is never narrower than a `commandsSize` the caller gives). A `checklist` puts the record's `ProgressChecklist` ring just before its commands, where Vercel ends a project's row with its Production Checklist; the ring opens its own drawer, never the row. Every row has its 32 px mark, its name (600) and, under it, one muted 14 px line; `name` and the mark are required; a record with nothing to say under its name leaves the line out and is the name alone, never a dash. Give every column a `size` in pixels; the name takes the rest. With `layout="line"`, as on Vercel's Projects page, the facts and the status share one muted line, joined by a middle dot, in a column as wide as the name's, and the row stays one line (mark, name over its line, that summary, the time, the ring, the three dots) on a card from 448 px, and on a narrower card the summary and the time move under the name as muted text joined by a middle dot that wraps, the status keeping its mark whole and breaking between its words only when it alone is wider than the line, in the same row, their labels read by assistive technology only. Rows of `columns` follow the same rule once the card is narrower than their columns: the facts and the time leave the row for that muted text, wrapping so every value stays readable, never a labelled list, and the status stands beside the name, which ends in an ellipsis before it, so the exception is never the part a phone's line cuts. `facts` takes at most three. A menu of one command that is not destructive, with no row command, is that command's button, except in a `line` row, which keeps it in the three dots as Vercel's project row does, and the column is as wide as the widest such button, so its label is never cut. Status is only for the exception, empty for the usual record, and its column stands only while a record in the list shows one, so the name and its line keep the room; the commands column likewise stands only while a record has a command, a menu or a message, or the rows open, and it widens for a failed action's next steps only while a row shows one. Never the three dots before the button, a decorative icon for the record's mark, a status on every row, or a destructive button on every row: a destructive command stays in the three dots. A `line` row's summary joins only the facts the record has, so it never ends in a dot. A failed or refused action of the record shows as its catalogue message inside its own row, never a notice under the row: it replaces the detail line, with its next steps beside its commands, or under the message on a card too narrow for the row's columns. With `open` the whole row is one target and takes the `accent` hover, and a row that only opens ends in a muted chevron; a row that opens nothing never reacts to hover. With `editor` the record's row opens its form under its line. `empty` is required: `null` is the choice to draw nothing for a list with no records, and any other value is the state it draws. A note about the whole list is `footer.note`: one muted line, an optional *Learn more* after it at the left and one secondary action at the right, in a strip of its own under the count and the paging, as Vercel ends its deployments list ("Deployment retention is enabled. Learn more", *View recently deleted*). Colour is neutral, the name in ink and every other cell in the body grey, except the status badge and a failed action's message.
|
|
254
269
|
* “Pick the variant by what the user needs: no-results for a filtered list that returned zero rows, blank slate or informational for a resource the user hasn’t created, cleared for completed work, permission for role or tier denials, error for a failed load.” (https://vercel.com/geist/empty-state)
|
|
255
270
|
* Ours: `failed`, `noMatch` and `empty` are those variants, drawn inside the card.
|
|
256
271
|
* “The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`.” (https://vercel.com/geist/entity)
|
|
@@ -262,7 +277,7 @@ function RecordRows(props) {
|
|
|
262
277
|
* “Keep right-column buttons Verb + Noun (`Remove Member`, `Resend Invite`). Bare verbs like `Remove` or `Confirm` lose context once the row scrolls offscreen.” (https://vercel.com/geist/entity)
|
|
263
278
|
* Ours: every string is the product's: `label` names the list, a time's `phrase` writes its sentence ("Updated {when}"), `missing` is what a screen reader hears for a record with no time, the menu's `label` reads "More for {record}". A row command names its result in sentence case ("Edit domain"). A status is the exception's word ("Needs attention"), never "Active" on every row.
|
|
264
279
|
* @access “Wrap the loading region in `aria-busy="true"` and announce completion with `aria-live="polite"` on the destination container, not the skeleton itself.” (https://vercel.com/geist/skeleton)
|
|
265
|
-
* Ours: the loading rows sit in one `SkeletonRegion` that is busy while they stand and announces what replaces them. A table named by `label`, its column headings read by assistive technology only. The row link carries `open.label`; the three dots carry the menu's `label`, and the menu's first line names the record. The loading rows are a status named by `loadingLabel`, inside the one live region that announces what replaces them.
|
|
280
|
+
* Ours: the loading rows sit in one `SkeletonRegion` that is busy while they stand and announces what replaces them. A table named by `label`, its column headings read by assistive technology only; the commands column's is `commandsHeader`, and empty without one, since its controls name themselves, never the list's name a second time. The row link carries `open.label`; the three dots carry the menu's `label`, and the menu's first line names the record. The loading rows are a status named by `loadingLabel`, inside the one live region that announces what replaces them.
|
|
266
281
|
* “For multi-select rows, the leading `Checkbox` carries `aria-label="Select {entity name}"` so the row is selectable without relying on the visual label.” (https://vercel.com/geist/entity)
|
|
267
282
|
* Ours: each box is named by `select.label`, which reads "Select {record}".
|
|
268
283
|
*/
|
|
@@ -30,7 +30,7 @@ type ScrollAreaProps = Omit<ScrollAreaPrimitive.Root.Props, "children" | "render
|
|
|
30
30
|
* Ours: Geist's `Scroller` is `ScrollArea`, and `vertical`, `horizontal` and `free` are `overflow="y"`,
|
|
31
31
|
* `"x"` and `"both"`. A bounded area whose content overflows: a side panel's list, a menu's long
|
|
32
32
|
* body, a rail of chips or logos.
|
|
33
|
-
* @instead Ours: a page scrolls as the document.
|
|
33
|
+
* @instead Ours: a page scrolls as the document.
|
|
34
34
|
* @behaviour “Buttons will automatically scroll to a given **direct** child.” (https://vercel.com/geist/scroller)
|
|
35
35
|
* “Auto-scroll buttons target direct children only. If items are wrapped in extra layout nodes the buttons won’t find their target.” (https://vercel.com/geist/scroller)
|
|
36
36
|
* “Show edge fade or shadow affordances on the clipped axis so users see there’s more content past the viewport.” (https://vercel.com/geist/scroller)
|
|
@@ -38,7 +38,7 @@ const buttonIcons = {
|
|
|
38
38
|
* Ours: Geist's `Scroller` is `ScrollArea`, and `vertical`, `horizontal` and `free` are `overflow="y"`,
|
|
39
39
|
* `"x"` and `"both"`. A bounded area whose content overflows: a side panel's list, a menu's long
|
|
40
40
|
* body, a rail of chips or logos.
|
|
41
|
-
* @instead Ours: a page scrolls as the document.
|
|
41
|
+
* @instead Ours: a page scrolls as the document.
|
|
42
42
|
* @behaviour “Buttons will automatically scroll to a given **direct** child.” (https://vercel.com/geist/scroller)
|
|
43
43
|
* “Auto-scroll buttons target direct children only. If items are wrapped in extra layout nodes the buttons won’t find their target.” (https://vercel.com/geist/scroller)
|
|
44
44
|
* “Show edge fade or shadow affordances on the clipped axis so users see there’s more content past the viewport.” (https://vercel.com/geist/scroller)
|
|
@@ -22,10 +22,10 @@ function actionProps(action, disabled = false) {
|
|
|
22
22
|
if (element) {
|
|
23
23
|
return { render: element, "aria-disabled": disabled || undefined };
|
|
24
24
|
}
|
|
25
|
-
// The row's tooltip trigger takes `disabled` for itself, so the button element carries it.
|
|
26
25
|
return {
|
|
26
|
+
disabled,
|
|
27
27
|
onClick: action.onClick,
|
|
28
|
-
|
|
28
|
+
type: "button",
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/components/sidebar.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/components/sidebar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -298,7 +298,8 @@ function SidebarMenuButton({ render, isActive = false, variant = "default", size
|
|
|
298
298
|
props: mergeProps({
|
|
299
299
|
className: cn(sidebarMenuButtonVariants({ variant, size }), className),
|
|
300
300
|
}, props),
|
|
301
|
-
|
|
301
|
+
// Base UI's tooltip trigger takes `disabled` for its tooltip, so the button element carries it too.
|
|
302
|
+
render: !tooltip ? (render) : (_jsx(TooltipTrigger, { render: render ?? _jsx("button", { disabled: props.disabled, type: props.type ?? "button" }) })),
|
|
302
303
|
state: {
|
|
303
304
|
slot: "sidebar-menu-button",
|
|
304
305
|
sidebar: "menu-button",
|
|
@@ -41,6 +41,12 @@ const AUTH_CALLS = new Set([
|
|
|
41
41
|
*/
|
|
42
42
|
const VALIDATION_CALLS = new Set(["parse", "safeParse"]);
|
|
43
43
|
|
|
44
|
+
const FUNCTION_TYPES = new Set([
|
|
45
|
+
"FunctionDeclaration",
|
|
46
|
+
"FunctionExpression",
|
|
47
|
+
"ArrowFunctionExpression",
|
|
48
|
+
]);
|
|
49
|
+
|
|
44
50
|
function hasUseServer(body) {
|
|
45
51
|
return (body ?? []).some(
|
|
46
52
|
(statement) =>
|
|
@@ -90,12 +96,40 @@ function exportedIdentifier(node) {
|
|
|
90
96
|
return undefined;
|
|
91
97
|
}
|
|
92
98
|
|
|
99
|
+
function inServerActionCode(node, moduleIsServer) {
|
|
100
|
+
if (moduleIsServer) return true;
|
|
101
|
+
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
|
|
102
|
+
if (FUNCTION_TYPES.has(ancestor.type) && hasUseServer(ancestor.body?.body)) return true;
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function inlineRejectionHandler(node) {
|
|
108
|
+
const handler = node.arguments[0];
|
|
109
|
+
if (node.callee.type !== "MemberExpression" || node.callee.property.type !== "Identifier") {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
if (node.callee.property.name !== "catch" || !FUNCTION_TYPES.has(handler?.type)) return undefined;
|
|
113
|
+
return handler;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function dropsTheError(sourceCode, node, bindings) {
|
|
117
|
+
if (bindings.length === 0) return true;
|
|
118
|
+
return sourceCode
|
|
119
|
+
.getDeclaredVariables(node)
|
|
120
|
+
.filter((variable) =>
|
|
121
|
+
variable.defs.some((def) => def.type === "CatchClause" || def.type === "Parameter"),
|
|
122
|
+
)
|
|
123
|
+
.every((variable) => variable.references.length === 0);
|
|
124
|
+
}
|
|
125
|
+
|
|
93
126
|
/** @type {import("eslint").Rule.RuleModule} */
|
|
94
127
|
export const serverActionDiscipline = {
|
|
95
128
|
meta: {
|
|
96
129
|
type: "problem",
|
|
97
130
|
docs: {
|
|
98
|
-
description:
|
|
131
|
+
description:
|
|
132
|
+
"An exported server action resolves its viewer and parses its client input, and server-action code never drops an error it catches.",
|
|
99
133
|
},
|
|
100
134
|
schema: [],
|
|
101
135
|
messages: {
|
|
@@ -103,10 +137,13 @@ export const serverActionDiscipline = {
|
|
|
103
137
|
"Server action '{{name}}' calls no viewer check. Resolve the viewer first (actionActor, requirePortalViewer, companyActionContext, …), or disable this rule inline with the reason it is public.",
|
|
104
138
|
missingValidation:
|
|
105
139
|
"Server action '{{name}}' takes client input and never parses it. Run the Zod schema's parse/safeParse before trusting the argument.",
|
|
140
|
+
droppedError:
|
|
141
|
+
"This catch drops the error it handles, so an outage reaches the form as an ordinary answer and leaves no log line. Name the error and translate it, answer the form's unavailable state with actionUnavailable, which logs it once, or rethrow it.",
|
|
106
142
|
},
|
|
107
143
|
},
|
|
108
144
|
create(context) {
|
|
109
|
-
const
|
|
145
|
+
const { sourceCode } = context;
|
|
146
|
+
const moduleIsServer = hasUseServer(sourceCode.ast.body);
|
|
110
147
|
/**
|
|
111
148
|
* One frame per function, holding only the calls written in that function's
|
|
112
149
|
* own body. A call parked inside a nested callback is not a call the action
|
|
@@ -160,7 +197,21 @@ export const serverActionDiscipline = {
|
|
|
160
197
|
if (local?.type === "Identifier") specifierExports.add(local.name);
|
|
161
198
|
}
|
|
162
199
|
},
|
|
200
|
+
CatchClause(node) {
|
|
201
|
+
const bindings = node.param ? [node.param] : [];
|
|
202
|
+
if (inServerActionCode(node, moduleIsServer) && dropsTheError(sourceCode, node, bindings)) {
|
|
203
|
+
context.report({ node, messageId: "droppedError" });
|
|
204
|
+
}
|
|
205
|
+
},
|
|
163
206
|
CallExpression(node) {
|
|
207
|
+
const handler = inlineRejectionHandler(node);
|
|
208
|
+
if (
|
|
209
|
+
handler &&
|
|
210
|
+
inServerActionCode(node, moduleIsServer) &&
|
|
211
|
+
dropsTheError(sourceCode, handler, handler.params)
|
|
212
|
+
) {
|
|
213
|
+
context.report({ node: handler, messageId: "droppedError" });
|
|
214
|
+
}
|
|
164
215
|
const name = calleeName(node);
|
|
165
216
|
if (!name) return;
|
|
166
217
|
callStack.at(-1)?.add(name);
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,6 @@ export * from "./components/button-group.js";
|
|
|
22
22
|
export * from "./components/calendar.js";
|
|
23
23
|
export * from "./components/card.js";
|
|
24
24
|
export * from "./components/card-row.js";
|
|
25
|
-
export * from "./components/carousel.js";
|
|
26
25
|
export * from "./components/catalog-drawer.js";
|
|
27
26
|
export * from "./components/chart.js";
|
|
28
27
|
export * from "./components/chart-area-stacked.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,6 @@ export * from "./components/button-group.js";
|
|
|
22
22
|
export * from "./components/calendar.js";
|
|
23
23
|
export * from "./components/card.js";
|
|
24
24
|
export * from "./components/card-row.js";
|
|
25
|
-
export * from "./components/carousel.js";
|
|
26
25
|
export * from "./components/catalog-drawer.js";
|
|
27
26
|
export * from "./components/chart.js";
|
|
28
27
|
export * from "./components/chart-area-stacked.js";
|
|
@@ -17,8 +17,8 @@ export type SettingsSave = {
|
|
|
17
17
|
/** "Saving" */
|
|
18
18
|
pendingLabel: string;
|
|
19
19
|
/**
|
|
20
|
-
* Called once a save resolves null,
|
|
21
|
-
* own toast,
|
|
20
|
+
* Called once a save resolves null, after the render that ends the save and before it paints: the product
|
|
21
|
+
* announces it through its own toast, which shows with Save ready again, as a state change made here renders.
|
|
22
22
|
*/
|
|
23
23
|
saved: () => void;
|
|
24
24
|
/** What is specific to this card, on the footer's left: a limit, what a value is for, a plan it needs, a link. Absent: nothing. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-save.d.ts","sourceRoot":"","sources":["../../src/internal/settings-save.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"settings-save.d.ts","sourceRoot":"","sources":["../../src/internal/settings-save.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAQf,MAAM,OAAO,CAAC;AAMf,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAOtF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IACpE,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,eAAe;IACf,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,mIAAmI;IACnI,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3F;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAuGF,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,OAAO,EACP,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB,+BAwGA;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,sCAqC1D"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, startTransition, use, useCallback, useEffect, useRef, useState, } from "react";
|
|
3
|
+
import { createContext, startTransition, use, useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react";
|
|
4
4
|
import { useFormStatus } from "react-dom";
|
|
5
5
|
import { Button } from "../components/button.js";
|
|
6
6
|
import { FieldError } from "../components/field.js";
|
|
@@ -52,8 +52,12 @@ function editableValues(form) {
|
|
|
52
52
|
? [name, [value.name, value.size, value.type, value.lastModified]]
|
|
53
53
|
: [name, value]));
|
|
54
54
|
}
|
|
55
|
-
function SaveFooter({ save, changed }) {
|
|
55
|
+
function SaveFooter({ announce, save, changed, }) {
|
|
56
56
|
const { pending } = useFormStatus();
|
|
57
|
+
useLayoutEffect(() => {
|
|
58
|
+
if (!pending)
|
|
59
|
+
announce();
|
|
60
|
+
}, [announce, pending]);
|
|
57
61
|
return (_jsxs(FooterStrip, { hint: save.hint, hintSlot: "settings-section-hint", children: [save.cancel ? (_jsx(Button, { disabled: pending, loading: save.cancel.pending ?? false, loadingLabel: save.cancel.pendingLabel ?? save.cancel.label, onClick: save.cancel.onCancel, type: "button", variant: "outline", children: save.cancel.label })) : null, _jsx(FormSubmitButton, { submit: {
|
|
58
62
|
label: save.label,
|
|
59
63
|
pendingLabel: save.pendingLabel,
|
|
@@ -64,6 +68,8 @@ function SaveFooter({ save, changed }) {
|
|
|
64
68
|
export function SettingsSaveForm({ save, titleId, children, }) {
|
|
65
69
|
const [fieldsChanged, setFieldsChanged] = useState(false);
|
|
66
70
|
const [failure, setFailure] = useState(null);
|
|
71
|
+
const unannounced = useRef(null);
|
|
72
|
+
const mounted = useRef(false);
|
|
67
73
|
const [claimedFields, setClaimedFields] = useState(() => new Set());
|
|
68
74
|
const submittedValues = useRef(null);
|
|
69
75
|
const keepValuesOnReset = useRef(false);
|
|
@@ -94,18 +100,34 @@ export function SettingsSaveForm({ save, titleId, children, }) {
|
|
|
94
100
|
element.addEventListener("reset", onReset);
|
|
95
101
|
return () => element.removeEventListener("reset", onReset);
|
|
96
102
|
}, [controlled]);
|
|
103
|
+
// A toast's store renders at once, outside the transition that ends the save, so `saved` waits for the commit
|
|
104
|
+
// that ends it, or for the section to close with it.
|
|
105
|
+
const announce = useCallback(() => {
|
|
106
|
+
const saved = unannounced.current;
|
|
107
|
+
unannounced.current = null;
|
|
108
|
+
saved?.();
|
|
109
|
+
}, []);
|
|
110
|
+
useLayoutEffect(() => {
|
|
111
|
+
mounted.current = true;
|
|
112
|
+
return () => {
|
|
113
|
+
mounted.current = false;
|
|
114
|
+
announce();
|
|
115
|
+
};
|
|
116
|
+
}, [announce]);
|
|
97
117
|
const changed = save.changed ?? fieldsChanged;
|
|
98
118
|
const sectionFailure = failure && (failure.field === undefined || !claimedFields.has(failure.field)) ? failure : null;
|
|
99
119
|
return (_jsx(SettingsSaveContext, { value: { failure, claim }, children: _jsxs("form", { ref: form, "aria-labelledby": titleId, className: "contents", "data-slot": "settings-section-form", action: async (formData) => {
|
|
100
120
|
const result = await save.action(formData);
|
|
101
121
|
keepValuesOnReset.current = result !== null;
|
|
122
|
+
if (result === null) {
|
|
123
|
+
if (mounted.current)
|
|
124
|
+
unannounced.current = save.saved;
|
|
125
|
+
else
|
|
126
|
+
save.saved();
|
|
127
|
+
}
|
|
102
128
|
// React leaves an update after an await out of the action, so it would render while Save still says
|
|
103
129
|
// Saving; inside a transition it renders with the end of the save.
|
|
104
|
-
startTransition(() =>
|
|
105
|
-
setFailure(result);
|
|
106
|
-
if (result === null)
|
|
107
|
-
save.saved();
|
|
108
|
-
});
|
|
130
|
+
startTransition(() => setFailure(result));
|
|
109
131
|
}, onChange: (event) => {
|
|
110
132
|
const edited = event.target;
|
|
111
133
|
if (edited instanceof Element &&
|
|
@@ -117,7 +139,7 @@ export function SettingsSaveForm({ save, titleId, children, }) {
|
|
|
117
139
|
setFailure(null);
|
|
118
140
|
keepValuesOnReset.current = false;
|
|
119
141
|
submittedValues.current = editableValues(event.currentTarget);
|
|
120
|
-
}, children: [_jsx("fieldset", { className: "contents", disabled: !hydrated, children: children }), sectionFailure ? (_jsx(CardContent, { children: _jsx(MessageNotice, { message: sectionFailure.message, placement: "action" }) })) : null, _jsx(SaveFooter, { changed: changed, save: save })] }) }));
|
|
142
|
+
}, children: [_jsx("fieldset", { className: "contents", disabled: !hydrated, children: children }), sectionFailure ? (_jsx(CardContent, { children: _jsx(MessageNotice, { message: sectionFailure.message, placement: "action" }) })) : null, _jsx(SaveFooter, { announce: announce, changed: changed, save: save })] }) }));
|
|
121
143
|
}
|
|
122
144
|
export function SettingsFieldFailure({ id }) {
|
|
123
145
|
const context = use(SettingsSaveContext);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compositions.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/compositions.tsx"],"names":[],"mappings":"AAoIA,iBAAS,oBAAoB,gCA+B5B;AAED,iBAAS,wBAAwB,gCAahC;AAED,iBAAS,qBAAqB,gCA0B7B;AAED,iBAAS,yBAAyB,gCAGjC;AAED,iBAAS,sBAAsB,gCAyD9B;AAED,iBAAS,yBAAyB,gCAUjC;AAED,iBAAS,qBAAqB,gCAwC7B;AAED,iBAAS,kBAAkB,gCAiB1B;AAED,iBAAS,kBAAkB,gCAuE1B;AAED,iBAAS,kBAAkB,gCAwB1B;AAED,iBAAS,oBAAoB,gCAkD5B;AAED,iBAAS,oBAAoB,gCAqC5B;AAED,iBAAS,mBAAmB,gCA2B3B;AAED,iBAAS,mBAAmB,gCAoB3B;AAwBD,iBAAS,uBAAuB,gCAkD/B;AA0BD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"compositions.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/compositions.tsx"],"names":[],"mappings":"AAoIA,iBAAS,oBAAoB,gCA+B5B;AAED,iBAAS,wBAAwB,gCAahC;AAED,iBAAS,qBAAqB,gCA0B7B;AAED,iBAAS,yBAAyB,gCAGjC;AAED,iBAAS,sBAAsB,gCAyD9B;AAED,iBAAS,yBAAyB,gCAUjC;AAED,iBAAS,qBAAqB,gCAwC7B;AAED,iBAAS,kBAAkB,gCAiB1B;AAED,iBAAS,kBAAkB,gCAuE1B;AAED,iBAAS,kBAAkB,gCAwB1B;AAED,iBAAS,oBAAoB,gCAkD5B;AAED,iBAAS,oBAAoB,gCAqC5B;AAED,iBAAS,mBAAmB,gCA2B3B;AAED,iBAAS,mBAAmB,gCAoB3B;AAwBD,iBAAS,uBAAuB,gCAkD/B;AA0BD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;CA8FE,CAAC"}
|
|
@@ -375,7 +375,12 @@ export const COMPOSITIONS = {
|
|
|
375
375
|
RecordList: () => (_jsxs("div", { className: "grid gap-6", children: [_jsx(RecordList, { ...MAILBOX_LIST, footer: { count: "3 mailboxes" }, label: "Mailboxes", records: MAILBOXES }), _jsx(RecordList, { ...MAILBOX_LIST, label: "Mailboxes with one command", menu: (mailbox) => ({
|
|
376
376
|
label: `More for ${mailbox.address}`,
|
|
377
377
|
commands: [{ label: "Reconnect", icon: _jsx(RefreshCw, {}), onClick: nothing }],
|
|
378
|
-
}), records: MAILBOXES }), _jsx(
|
|
378
|
+
}), records: MAILBOXES }), _jsx(RecordList, { ...MAILBOX_LIST, command: () => ({
|
|
379
|
+
label: "Reconnect",
|
|
380
|
+
pendingLabel: "Reconnecting…",
|
|
381
|
+
icon: _jsx(RefreshCw, {}),
|
|
382
|
+
onClick: nothing,
|
|
383
|
+
}), label: "Mailboxes with a row command", records: MAILBOXES }), _jsx(SelectableRecordListSpecimen, {})] })),
|
|
379
384
|
RecordSheet: RecordSheetSpecimen,
|
|
380
385
|
RowEditForm: RowEditFormSpecimen,
|
|
381
386
|
SettingsPage: () => (_jsx(SettingsPage, { children: _jsx(SenderSection, {}) })),
|
|
@@ -2,7 +2,6 @@ export declare const SPECIMENS: {
|
|
|
2
2
|
Accordion: () => import("react").JSX.Element;
|
|
3
3
|
AspectRatio: () => import("react").JSX.Element;
|
|
4
4
|
BrandField: () => import("react").JSX.Element;
|
|
5
|
-
Carousel: () => import("react").JSX.Element;
|
|
6
5
|
Collapsible: () => import("react").JSX.Element;
|
|
7
6
|
CompanyCard: () => import("react").JSX.Element;
|
|
8
7
|
Disclosure: () => import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,SAAS
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYiB,CAAC"}
|
|
@@ -6,7 +6,6 @@ export declare const OTHER: {
|
|
|
6
6
|
Accordion: () => import("react").JSX.Element;
|
|
7
7
|
AspectRatio: typeof AspectRatioSpecimen;
|
|
8
8
|
BrandField: () => import("react").JSX.Element;
|
|
9
|
-
Carousel: () => import("react").JSX.Element;
|
|
10
9
|
Collapsible: () => import("react").JSX.Element;
|
|
11
10
|
CompanyCard: typeof CompanyCardSpecimen;
|
|
12
11
|
Disclosure: () => import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"other.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/other.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"other.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/other.tsx"],"names":[],"mappings":"AAuCA,iBAAS,mBAAmB,gCAS3B;AAED,iBAAS,mBAAmB,gCAiB3B;AAED,iBAAS,iBAAiB,gCAczB;AAED,iBAAS,qBAAqB,gCAa7B;AAED,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;CA8KS,CAAC"}
|
|
@@ -7,7 +7,6 @@ import { AspectRatio } from "../../components/aspect-ratio.js";
|
|
|
7
7
|
import { BrandField } from "../../components/brand-field.js";
|
|
8
8
|
import { BrandWordmark } from "../../components/brand.js";
|
|
9
9
|
import { Button } from "../../components/button.js";
|
|
10
|
-
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, } from "../../components/carousel.js";
|
|
11
10
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible.js";
|
|
12
11
|
import { CompanyCard } from "../../components/company-card.js";
|
|
13
12
|
import { Disclosure } from "../../components/disclosure.js";
|
|
@@ -47,7 +46,6 @@ export const OTHER = {
|
|
|
47
46
|
Accordion: () => (_jsxs("div", { className: "grid max-w-lg gap-10", children: [["default", "small"].map((size) => (_jsxs(Accordion, { size: size, children: [_jsxs(AccordionItem, { value: "data", children: [_jsx(AccordionTrigger, { children: "Where does my data live?" }), _jsx(AccordionContent, { children: "In the EU, on servers nadicode runs." })] }), _jsxs(AccordionItem, { value: "agents", children: [_jsx(AccordionTrigger, { children: "Can an Agent send email on its own?" }), _jsx(AccordionContent, { children: "Only from a mailbox you connect, and only with approval." })] }), _jsxs(AccordionItem, { value: "export", children: [_jsx(AccordionTrigger, { children: "Can I take my data with me?" }), _jsx(AccordionContent, { hiddenUntilFound: false, children: "Yes. Export every record as a .zip from Settings." })] })] }, size))), _jsxs(Accordion, { multiple: true, children: [_jsxs(AccordionItem, { value: "invoices", children: [_jsx(AccordionTrigger, { children: "Invoices" }), _jsx(AccordionContent, { children: "Issued on the first of each month." })] }), _jsxs(AccordionItem, { value: "payments", children: [_jsx(AccordionTrigger, { children: "Payments" }), _jsx(AccordionContent, { children: "Card and bank transfer, in euro." })] })] })] })),
|
|
48
47
|
AspectRatio: AspectRatioSpecimen,
|
|
49
48
|
BrandField: () => (_jsxs(BrandField, { className: "grid gap-2 rounded-md p-8", children: [_jsx(BrandWordmark, {}), _jsx("p", { className: "text-sm text-muted-foreground", children: "White on ink, in either theme." })] })),
|
|
50
|
-
Carousel: () => (_jsxs(Carousel, { className: "mx-12 max-w-xs", children: [_jsx(CarouselContent, { children: ["Invoices", "Orders", "Support"].map((name) => (_jsx(CarouselItem, { children: _jsx("div", { className: "grid h-32 place-items-center rounded-md border border-border text-sm", children: name }) }, name))) }), _jsx(CarouselPrevious, {}), _jsx(CarouselNext, {})] })),
|
|
51
49
|
Collapsible: () => (_jsxs(Collapsible, { className: "max-w-sm", children: [_jsx(CollapsibleTrigger, { render: _jsx(Button, { prefix: _jsx(ChevronDown, { "aria-hidden": "true" }), variant: "ghost" }), children: "src" }), _jsxs(CollapsibleContent, { className: "grid gap-1 pl-8 font-mono text-sm", children: [_jsx("span", { children: "index.ts" }), _jsx("span", { children: "quote.ts" })] })] })),
|
|
52
50
|
CompanyCard: CompanyCardSpecimen,
|
|
53
51
|
Disclosure: () => (_jsx(Disclosure, { label: "Other formats", children: _jsx("p", { className: "text-sm text-muted-foreground", children: "Download for Windows, or as a .zip for macOS." }) })),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type UsageName = "ActivityFeed" | "AgentProfileCard" | "CatalogDrawer" | "CollectionFilters" | "CollectionPage" | "CollectionToolbar" | "ConfirmDialog" | "EntryScene" | "FormDialog" | "FormDrawer" | "LibraryShelf" | "ObjectPage" | "ObjectSection" | "OverviewPage" | "PageHeader" | "RecordList" | "RecordSheet" | "RowEditForm" | "SettingsPage" | "SettingsSection" | "Button" | "ButtonGroup" | "ButtonLink" | "CopyButton" | "LoadMoreButton" | "PageActions" | "Calendar" | "ClearableInput" | "CollectionSearch" | "Field" | "Input" | "InputGroup" | "InputOTP" | "Label" | "NativeSelect" | "SettingsField" | "SettingsRows" | "Slider" | "Textarea" | "Checkbox" | "ChoiceboxGroup" | "CollectionSort" | "Combobox" | "ModelSelect" | "MultiSelect" | "RadioGroup" | "SegmentedChoice" | "SegmentedControl" | "Select" | "Switch" | "ThemeModeSegments" | "ThemeModeSwitcher" | "Toggle" | "ToggleGroup" | "ActionStatus" | "AgentOrb" | "AppMark" | "ArchIcon" | "Avatar" | "Badge" | "BrandWordmark" | "CheckCounts" | "FileTypeIcon" | "IdentityMark" | "ModelIdentity" | "ModelMark" | "ObjectFactValue" | "PlatformMark" | "ProgressChecklist" | "RecordIdentity" | "StatusBadge" | "Tag" | "AgentListRow" | "Breadcrumb" | "CommandDialog" | "Footer" | "PortalSidebarFrame" | "ScopeSwitcher" | "Sidebar" | "SidebarBrand" | "SidebarFind" | "SidebarFrame" | "SidebarMenuChevron" | "SidebarSections" | "Tabs" | "TabsNav" | "textLinkVariants" | "AgentCard" | "Card" | "CardRow" | "CodeBlock" | "DataTable" | "DiffCount" | "DisclosureRow" | "FileDiff" | "Gauge" | "Item" | "Kbd" | "MiddleTruncate" | "ObjectFacts" | "PairingCode" | "Progress" | "QrCode" | "RecordTime" | "RunTimeline" | "SettingsFactsSection" | "Snippet" | "Table" | "TableCard" | "TableValue" | "TextWithCopyButton" | "UsageMeter" | "Alert" | "EmptyState" | "EntryProgress" | "EntryStageList" | "HoverCard" | "MessageNotice" | "NoticeBanner" | "PendingLabel" | "Skeleton" | "SkeletonRegion" | "Toaster" | "Tooltip" | "UpdateCard" | "WaitingLine" | "AccountMenu" | "ActionContextMenu" | "ActionMenu" | "AlertDialog" | "ContextMenu" | "Dialog" | "Drawer" | "DropdownMenu" | "GlassControl" | "MenuChoiceRow" | "Popover" | "Sheet" | "ThemeModeMenu" | "ActivityCalendar" | "ChartAreaStacked" | "ChartBarHorizontal" | "ChartBarMultiple" | "ChartBarStacked" | "ChartCard" | "ChartContainer" | "ChartRanking" | "ChartSparkline" | "DateRangeControl" | "KpiCard" | "TrendBadge" | "createEntityColorMap" | "Accordion" | "AspectRatio" | "BrandField" | "
|
|
1
|
+
export type UsageName = "ActivityFeed" | "AgentProfileCard" | "CatalogDrawer" | "CollectionFilters" | "CollectionPage" | "CollectionToolbar" | "ConfirmDialog" | "EntryScene" | "FormDialog" | "FormDrawer" | "LibraryShelf" | "ObjectPage" | "ObjectSection" | "OverviewPage" | "PageHeader" | "RecordList" | "RecordSheet" | "RowEditForm" | "SettingsPage" | "SettingsSection" | "Button" | "ButtonGroup" | "ButtonLink" | "CopyButton" | "LoadMoreButton" | "PageActions" | "Calendar" | "ClearableInput" | "CollectionSearch" | "Field" | "Input" | "InputGroup" | "InputOTP" | "Label" | "NativeSelect" | "SettingsField" | "SettingsRows" | "Slider" | "Textarea" | "Checkbox" | "ChoiceboxGroup" | "CollectionSort" | "Combobox" | "ModelSelect" | "MultiSelect" | "RadioGroup" | "SegmentedChoice" | "SegmentedControl" | "Select" | "Switch" | "ThemeModeSegments" | "ThemeModeSwitcher" | "Toggle" | "ToggleGroup" | "ActionStatus" | "AgentOrb" | "AppMark" | "ArchIcon" | "Avatar" | "Badge" | "BrandWordmark" | "CheckCounts" | "FileTypeIcon" | "IdentityMark" | "ModelIdentity" | "ModelMark" | "ObjectFactValue" | "PlatformMark" | "ProgressChecklist" | "RecordIdentity" | "StatusBadge" | "Tag" | "AgentListRow" | "Breadcrumb" | "CommandDialog" | "Footer" | "PortalSidebarFrame" | "ScopeSwitcher" | "Sidebar" | "SidebarBrand" | "SidebarFind" | "SidebarFrame" | "SidebarMenuChevron" | "SidebarSections" | "Tabs" | "TabsNav" | "textLinkVariants" | "AgentCard" | "Card" | "CardRow" | "CodeBlock" | "DataTable" | "DiffCount" | "DisclosureRow" | "FileDiff" | "Gauge" | "Item" | "Kbd" | "MiddleTruncate" | "ObjectFacts" | "PairingCode" | "Progress" | "QrCode" | "RecordTime" | "RunTimeline" | "SettingsFactsSection" | "Snippet" | "Table" | "TableCard" | "TableValue" | "TextWithCopyButton" | "UsageMeter" | "Alert" | "EmptyState" | "EntryProgress" | "EntryStageList" | "HoverCard" | "MessageNotice" | "NoticeBanner" | "PendingLabel" | "Skeleton" | "SkeletonRegion" | "Toaster" | "Tooltip" | "UpdateCard" | "WaitingLine" | "AccountMenu" | "ActionContextMenu" | "ActionMenu" | "AlertDialog" | "ContextMenu" | "Dialog" | "Drawer" | "DropdownMenu" | "GlassControl" | "MenuChoiceRow" | "Popover" | "Sheet" | "ThemeModeMenu" | "ActivityCalendar" | "ChartAreaStacked" | "ChartBarHorizontal" | "ChartBarMultiple" | "ChartBarStacked" | "ChartCard" | "ChartContainer" | "ChartRanking" | "ChartSparkline" | "DateRangeControl" | "KpiCard" | "TrendBadge" | "createEntityColorMap" | "Accordion" | "AspectRatio" | "BrandField" | "Collapsible" | "CompanyCard" | "Disclosure" | "HiveScene" | "NadiaPresence" | "NumberedSteps" | "Prose" | "ReadingColumn" | "ResizablePanelGroup" | "ScrollArea" | "Separator" | "ToolIcon";
|
|
2
2
|
export type UsageFamily = "Compositions" | "Actions" | "Inputs" | "Choices" | "Status" | "Navigation" | "Data" | "Feedback" | "Menus" | "Charts" | "Other";
|
|
3
3
|
export type ComponentUsage = {
|
|
4
4
|
name: UsageName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.generated.d.ts","sourceRoot":"","sources":["../../src/showcase/usage.generated.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GACjB,cAAc,GACd,kBAAkB,GAClB,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,GACf,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,YAAY,GACZ,eAAe,GACf,cAAc,GACd,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,aAAa,GACb,cAAc,GACd,iBAAiB,GACjB,QAAQ,GACR,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,gBAAgB,GAChB,aAAa,GACb,UAAU,GACV,gBAAgB,GAChB,kBAAkB,GAClB,OAAO,GACP,OAAO,GACP,YAAY,GACZ,UAAU,GACV,OAAO,GACP,cAAc,GACd,eAAe,GACf,cAAc,GACd,QAAQ,GACR,UAAU,GACV,UAAU,GACV,gBAAgB,GAChB,gBAAgB,GAChB,UAAU,GACV,aAAa,GACb,aAAa,GACb,YAAY,GACZ,iBAAiB,GACjB,kBAAkB,GAClB,QAAQ,GACR,QAAQ,GACR,mBAAmB,GACnB,mBAAmB,GACnB,QAAQ,GACR,aAAa,GACb,cAAc,GACd,UAAU,GACV,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,GACP,eAAe,GACf,aAAa,GACb,cAAc,GACd,cAAc,GACd,eAAe,GACf,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,mBAAmB,GACnB,gBAAgB,GAChB,aAAa,GACb,KAAK,GACL,cAAc,GACd,YAAY,GACZ,eAAe,GACf,QAAQ,GACR,oBAAoB,GACpB,eAAe,GACf,SAAS,GACT,cAAc,GACd,aAAa,GACb,cAAc,GACd,oBAAoB,GACpB,iBAAiB,GACjB,MAAM,GACN,SAAS,GACT,kBAAkB,GAClB,WAAW,GACX,MAAM,GACN,SAAS,GACT,WAAW,GACX,WAAW,GACX,WAAW,GACX,eAAe,GACf,UAAU,GACV,OAAO,GACP,MAAM,GACN,KAAK,GACL,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,UAAU,GACV,QAAQ,GACR,YAAY,GACZ,aAAa,GACb,sBAAsB,GACtB,SAAS,GACT,OAAO,GACP,WAAW,GACX,YAAY,GACZ,oBAAoB,GACpB,YAAY,GACZ,OAAO,GACP,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,WAAW,GACX,eAAe,GACf,cAAc,GACd,cAAc,GACd,UAAU,GACV,gBAAgB,GAChB,SAAS,GACT,SAAS,GACT,YAAY,GACZ,aAAa,GACb,aAAa,GACb,mBAAmB,GACnB,YAAY,GACZ,aAAa,GACb,aAAa,GACb,QAAQ,GACR,QAAQ,GACR,cAAc,GACd,cAAc,GACd,eAAe,GACf,SAAS,GACT,OAAO,GACP,eAAe,GACf,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,kBAAkB,GAClB,iBAAiB,GACjB,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,SAAS,GACT,YAAY,GACZ,sBAAsB,GACtB,WAAW,GACX,aAAa,GACb,YAAY,GACZ,
|
|
1
|
+
{"version":3,"file":"usage.generated.d.ts","sourceRoot":"","sources":["../../src/showcase/usage.generated.ts"],"names":[],"mappings":"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"}
|
|
@@ -54,7 +54,7 @@ export const USAGE = [
|
|
|
54
54
|
summary: "The filters in a collection's toolbar: one Add filter button, a chip for each facet in force, and the facets most often narrowed to waiting as dashed chips.",
|
|
55
55
|
when: "A collection or a feed a person narrows by a property its records share (its query facets): a status, an owner, a kind. It stands in the toolbar after the search and before the sort.",
|
|
56
56
|
instead: "Finding one record by its name is the search. Changing the order is the sort. Switching between sibling collections is the page's tabs.",
|
|
57
|
-
behaviour: "Add filter opens a picker of the facets, then of a facet's values, each searchable; Backspace in an empty search goes back to the facets. A facet in force is a chip that reopens its values, with a button that removes it. A suggested value waits as a dashed chip in the muted grey, led by a + and never by the value's own mark, so it never reads as a filter in force, while its facet is unset, and applies in one click. Focus returns to Add filter when a facet is removed. The product keeps each facet's value, in the URL where it has one.",
|
|
57
|
+
behaviour: "Add filter opens a picker of the facets, then of a facet's values, each searchable; Backspace in an empty search goes back to the facets. The picker stays inside the window: where its values are taller than the room beside its trigger, it takes that room, Back and the search stay in view, and the values scroll under them. A facet in force is a chip that reopens its values, with a button that removes it. A suggested value waits as a dashed chip in the muted grey, led by a + and never by the value's own mark, so it never reads as a filter in force, while its facet is unset, and applies in one click. Focus returns to Add filter when a facet is removed. The product keeps each facet's value, in the URL where it has one.",
|
|
58
58
|
words: 'Every string is the product\'s: `copy` names Add filter, the two searches, the empty result, Back and Remove; each facet names itself, its values and its "All" choice.',
|
|
59
59
|
access: "Each chip is a group named by its facet; its remove button reads Remove with the facet's name. The pickers are searchable lists named by what they search.",
|
|
60
60
|
},
|
|
@@ -186,9 +186,9 @@ export const USAGE = [
|
|
|
186
186
|
summary: "Entity rows: objects a person opens or acts on, one line each on one resting card: the identity mark and name over what it is, a few facts, a status only for the exception, when it happened, at most two row commands, and the three dots last.",
|
|
187
187
|
when: "“Use `<Entity>` for a row of descriptive content paired with one or two controls (member rows, integration rows, domain rows).” (https://vercel.com/geist/entity) Ours: the records are things a person opens or acts on and that name themselves: projects, deployments, domains, members, integrations, Agents, Skills, mailboxes. A list inside another page: an Overview's exceptions, an object page's \"Needs attention\". A page whose whole job is the list is a `CollectionPage`, which draws this. Values edited in place (a domain, an environment variable) are the same rows with an `editor`: the row expands into its form. Of the three kinds of list, entity rows and rows edited in place are this; records compared across columns are a `DataTable`.",
|
|
188
188
|
instead: "“For tabular data with sortable columns and shared row shape, use `Table` instead.” (https://vercel.com/geist/entity) “For a static key/value metadata block on a detail page, use `Description`.” (https://vercel.com/geist/entity) Ours: Geist's `Table` is a `DataTable`: this list has no visible headings and at most three facts, so a fourth fact is a table, and anything more than a few facts lives on the record's page. A screen gives `RecordList` the records and what each one says, never its own toolbar, table, rows or menus, and nothing else draws a record row. Its `Description` is `ObjectFacts`. Events in time are an `ActivityFeed`. Reusable things a person adds from a catalogue are a `LibraryShelf`. A descriptive row with prose is an `Item`.",
|
|
189
|
-
behaviour: "One bordered card, a 1 px rule between records and none after the last. A row is 72 px, with 16 px above and below, and its columns stand left to right at the widths the list declares, so a person reads every list the same way: the `select` box (40 px, only when the list is picked from, an optional column), the identity (the rest: the one column without a size), the facts (each its `size`), the status (`status.size`), the time (`time.size`, tabular), the `checklist` ring (52 px, only when the record has steps to be ready) and the commands (
|
|
189
|
+
behaviour: "One bordered card, a 1 px rule between records and none after the last. A row is 72 px, with 16 px above and below, and its columns stand left to right at the widths the list declares, so a person reads every list the same way: the `select` box (40 px, only when the list is picked from, an optional column), the identity (the rest: the one column without a size), the facts (each its `size`), the status (`status.size`), the time (`time.size`, tabular), the `checklist` ring (52 px, only when the record has steps to be ready) and the commands (as wide as the widest row's buttons, a failed action's next steps and the three dots or the chevron after them need, worked out from their labels, each label at most 8 px a character and a button holding the longer of its label and its pending label, the dots at their 44 px touch target; 64 px for the three dots or the chevron alone; a row that draws a button or next steps is never narrower than a `commandsSize` the caller gives). A `checklist` puts the record's `ProgressChecklist` ring just before its commands, where Vercel ends a project's row with its Production Checklist; the ring opens its own drawer, never the row. Every row has its 32 px mark, its name (600) and, under it, one muted 14 px line; `name` and the mark are required; a record with nothing to say under its name leaves the line out and is the name alone, never a dash. Give every column a `size` in pixels; the name takes the rest. With `layout=\"line\"`, as on Vercel's Projects page, the facts and the status share one muted line, joined by a middle dot, in a column as wide as the name's, and the row stays one line (mark, name over its line, that summary, the time, the ring, the three dots) on a card from 448 px, and on a narrower card the summary and the time move under the name as muted text joined by a middle dot that wraps, the status keeping its mark whole and breaking between its words only when it alone is wider than the line, in the same row, their labels read by assistive technology only. Rows of `columns` follow the same rule once the card is narrower than their columns: the facts and the time leave the row for that muted text, wrapping so every value stays readable, never a labelled list, and the status stands beside the name, which ends in an ellipsis before it, so the exception is never the part a phone's line cuts. `facts` takes at most three. A menu of one command that is not destructive, with no row command, is that command's button, except in a `line` row, which keeps it in the three dots as Vercel's project row does, and the column is as wide as the widest such button, so its label is never cut. Status is only for the exception, empty for the usual record, and its column stands only while a record in the list shows one, so the name and its line keep the room; the commands column likewise stands only while a record has a command, a menu or a message, or the rows open, and it widens for a failed action's next steps only while a row shows one. Never the three dots before the button, a decorative icon for the record's mark, a status on every row, or a destructive button on every row: a destructive command stays in the three dots. A `line` row's summary joins only the facts the record has, so it never ends in a dot. A failed or refused action of the record shows as its catalogue message inside its own row, never a notice under the row: it replaces the detail line, with its next steps beside its commands, or under the message on a card too narrow for the row's columns. With `open` the whole row is one target and takes the `accent` hover, and a row that only opens ends in a muted chevron; a row that opens nothing never reacts to hover. With `editor` the record's row opens its form under its line. `empty` is required: `null` is the choice to draw nothing for a list with no records, and any other value is the state it draws. A note about the whole list is `footer.note`: one muted line, an optional *Learn more* after it at the left and one secondary action at the right, in a strip of its own under the count and the paging, as Vercel ends its deployments list (\"Deployment retention is enabled. Learn more\", *View recently deleted*). Colour is neutral, the name in ink and every other cell in the body grey, except the status badge and a failed action's message. “Pick the variant by what the user needs: no-results for a filtered list that returned zero rows, blank slate or informational for a resource the user hasn’t created, cleared for completed work, permission for role or tier denials, error for a failed load.” (https://vercel.com/geist/empty-state) Ours: `failed`, `noMatch` and `empty` are those variants, drawn inside the card. “The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`.” (https://vercel.com/geist/entity) Ours: one or two row commands (outline buttons of 32 px) stand before the three dots (36 px), the Dots Menu. “Render the Skeleton variant (`entity-with-skeleton`) during load instead of an empty row, and swap to real content once data resolves.” (https://vercel.com/geist/entity) Ours: three still skeleton rows hold the place, in a region that announces what replaces them; then the first that holds: the failed read, no match, the empty state, the rows.",
|
|
190
190
|
words: '“Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`).” (https://vercel.com/geist/entity) Ours: the name is the record\'s own and the labels around it are sentence case, not Title Case. “Keep right-column buttons Verb + Noun (`Remove Member`, `Resend Invite`). Bare verbs like `Remove` or `Confirm` lose context once the row scrolls offscreen.” (https://vercel.com/geist/entity) Ours: every string is the product\'s: `label` names the list, a time\'s `phrase` writes its sentence ("Updated {when}"), `missing` is what a screen reader hears for a record with no time, the menu\'s `label` reads "More for {record}". A row command names its result in sentence case ("Edit domain"). A status is the exception\'s word ("Needs attention"), never "Active" on every row.',
|
|
191
|
-
access: '“Wrap the loading region in `aria-busy="true"` and announce completion with `aria-live="polite"` on the destination container, not the skeleton itself.” (https://vercel.com/geist/skeleton) Ours: the loading rows sit in one `SkeletonRegion` that is busy while they stand and announces what replaces them. A table named by `label`, its column headings read by assistive technology only. The row link carries `open.label`; the three dots carry the menu\'s `label`, and the menu\'s first line names the record. The loading rows are a status named by `loadingLabel`, inside the one live region that announces what replaces them. “For multi-select rows, the leading `Checkbox` carries `aria-label="Select {entity name}"` so the row is selectable without relying on the visual label.” (https://vercel.com/geist/entity) Ours: each box is named by `select.label`, which reads "Select {record}".',
|
|
191
|
+
access: '“Wrap the loading region in `aria-busy="true"` and announce completion with `aria-live="polite"` on the destination container, not the skeleton itself.” (https://vercel.com/geist/skeleton) Ours: the loading rows sit in one `SkeletonRegion` that is busy while they stand and announces what replaces them. A table named by `label`, its column headings read by assistive technology only; the commands column\'s is `commandsHeader`, and empty without one, since its controls name themselves, never the list\'s name a second time. The row link carries `open.label`; the three dots carry the menu\'s `label`, and the menu\'s first line names the record. The loading rows are a status named by `loadingLabel`, inside the one live region that announces what replaces them. “For multi-select rows, the leading `Checkbox` carries `aria-label="Select {entity name}"` so the row is selectable without relying on the visual label.” (https://vercel.com/geist/entity) Ours: each box is named by `select.label`, which reads "Select {record}".',
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
name: "RecordSheet",
|
|
@@ -1719,17 +1719,6 @@ export const USAGE = [
|
|
|
1719
1719
|
words: "None of its own.",
|
|
1720
1720
|
access: "A plain container.",
|
|
1721
1721
|
},
|
|
1722
|
-
{
|
|
1723
|
-
name: "Carousel",
|
|
1724
|
-
module: "carousel",
|
|
1725
|
-
family: "Other",
|
|
1726
|
-
summary: "A rail of slides moved with Previous and Next.",
|
|
1727
|
-
when: "A controlled, finite rail of like items whose neighbours have a meaningful sequence: screens, testimonials.",
|
|
1728
|
-
instead: "A product's records are a list or a table, never a carousel; a sortable record collection is a table or an entity list. One overflowing row is `ScrollArea`.",
|
|
1729
|
-
behaviour: "Slides move by swipe, drag or the Previous and Next buttons; the buttons disable at the ends. Left and Right arrow keys move when the carousel holds focus, in both orientations; Up and Down do nothing. The rail is horizontal; `orientation` also accepts `vertical`, which stacks the buttons above and below. The motion is Embla's, and the component does not read the reduced-motion setting, so a page that must honour it sets Embla's `duration` itself through `opts` (Embla jumps with a duration of 0).",
|
|
1730
|
-
words: "The buttons name their move: *Previous slide*, *Next slide*.",
|
|
1731
|
-
access: "A `region` described as a carousel; each slide is a `group` described as a slide.",
|
|
1732
|
-
},
|
|
1733
1722
|
{
|
|
1734
1723
|
name: "Collapsible",
|
|
1735
1724
|
module: "collapsible",
|
|
@@ -1835,7 +1824,7 @@ export const USAGE = [
|
|
|
1835
1824
|
family: "Other",
|
|
1836
1825
|
summary: "An area that scrolls along one axis, with a fade where more is waiting.",
|
|
1837
1826
|
when: '“Use Scroller for an overflowing list of peer items along a single axis: chip rows, log streams, code snippets, command palettes.” (https://vercel.com/geist/scroller) “Pick `vertical` for stacked feeds, `horizontal` for chip and tile rails, `free` only when content genuinely scrolls in both directions (logs with very long lines).” (https://vercel.com/geist/scroller) “For paginated or virtualized data sets larger than a few hundred items, render with a virtualization library inside the Scroller rather than dumping every node into the DOM.” (https://vercel.com/geist/scroller) Ours: Geist\'s `Scroller` is `ScrollArea`, and `vertical`, `horizontal` and `free` are `overflow="y"`, `"x"` and `"both"`. A bounded area whose content overflows: a side panel\'s list, a menu\'s long body, a rail of chips or logos.',
|
|
1838
|
-
instead: "Ours: a page scrolls as the document.
|
|
1827
|
+
instead: "Ours: a page scrolls as the document.",
|
|
1839
1828
|
behaviour: '“Buttons will automatically scroll to a given **direct** child.” (https://vercel.com/geist/scroller) “Auto-scroll buttons target direct children only. If items are wrapped in extra layout nodes the buttons won’t find their target.” (https://vercel.com/geist/scroller) “Show edge fade or shadow affordances on the clipped axis so users see there’s more content past the viewport.” (https://vercel.com/geist/scroller) “Keep item widths and gaps consistent in horizontal scrollers; ragged edges break the snap rhythm and make the rail feel broken.” (https://vercel.com/geist/scroller) Ours: `overflow` is required, and `buttonLabels` goes only with `overflow="y"` or `"x"`, never `"both"`. Give the area its height or width with `className`, and a border or radius with `frameClassName`, which draws only the scrolling box and leaves the buttons outside it. The scrollbar is hidden; a 40 px fade of the surface at each clipped edge is the only sign there is more, and it is gone at an edge with nothing beyond it. The viewport scrolls natively, so wheel, touch and keyboard all reach it. `buttonLabels` adds two round 32 px outline buttons, 16 px from the area: above it and centred for `y`, below it and at the start for `x`. Each moves to the nearest direct child that is clipped at that end, not by a fixed amount, and sits disabled at the end with nothing beyond it. Smooth scrolling gives way to an instant jump under reduced motion. Colour is neutral only.',
|
|
1840
1829
|
words: "“Scroller buttons need `aria-label`s that name the direction and content (`Scroll customer logos left`), not bare `Previous`/`Next`.” (https://vercel.com/geist/scroller) Ours: *Scroll installations left*; both labels are required with the buttons.",
|
|
1841
1830
|
access: "“Tab order follows DOM order, so place items in reading order regardless of visual scroll direction.” (https://vercel.com/geist/scroller) “Make sure focusing an off-screen item scrolls it into view; the default browser behavior covers this, but custom focus traps can break it.” (https://vercel.com/geist/scroller) Ours: the content keeps its own semantics. The viewport is a tab stop when it scrolls.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nadicodeai/ui",
|
|
3
|
-
"version": "12.1.
|
|
3
|
+
"version": "12.1.146",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -83,14 +83,13 @@
|
|
|
83
83
|
"@base-ui/react": "^1.9.0",
|
|
84
84
|
"@iconify-icons/logos": "^2.0.3",
|
|
85
85
|
"@iconify/react": "^6.0.2",
|
|
86
|
-
"@nadicodeai/design-system": "12.1.
|
|
86
|
+
"@nadicodeai/design-system": "12.1.146",
|
|
87
87
|
"@tanstack/react-table": "^9.3.1",
|
|
88
88
|
"@vgpu/wgsl": "0.6.0",
|
|
89
89
|
"class-variance-authority": "^0.7.1",
|
|
90
90
|
"clsx": "^2.1.1",
|
|
91
91
|
"cmdk": "^1.1.1",
|
|
92
92
|
"date-fns": "^4.4.0",
|
|
93
|
-
"embla-carousel-react": "^8.6.0",
|
|
94
93
|
"input-otp": "^1.5.0",
|
|
95
94
|
"lucide-react": "1.58.0",
|
|
96
95
|
"motion": "^14.3.0",
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react";
|
|
3
|
-
import { type IconButtonPartProps } from "./button.js";
|
|
4
|
-
type CarouselApi = UseEmblaCarouselType[1];
|
|
5
|
-
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
|
6
|
-
type CarouselOptions = UseCarouselParameters[0];
|
|
7
|
-
type CarouselPlugin = UseCarouselParameters[1];
|
|
8
|
-
type CarouselProps = {
|
|
9
|
-
opts?: CarouselOptions;
|
|
10
|
-
plugins?: CarouselPlugin;
|
|
11
|
-
orientation?: "horizontal" | "vertical";
|
|
12
|
-
setApi?: (api: CarouselApi) => void;
|
|
13
|
-
};
|
|
14
|
-
type CarouselContextProps = {
|
|
15
|
-
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
|
|
16
|
-
api: ReturnType<typeof useEmblaCarousel>[1];
|
|
17
|
-
scrollPrev: () => void;
|
|
18
|
-
scrollNext: () => void;
|
|
19
|
-
canScrollPrev: boolean;
|
|
20
|
-
canScrollNext: boolean;
|
|
21
|
-
} & CarouselProps;
|
|
22
|
-
declare function useCarousel(): CarouselContextProps;
|
|
23
|
-
/**
|
|
24
|
-
* A rail of slides moved with Previous and Next.
|
|
25
|
-
*
|
|
26
|
-
* @family Other
|
|
27
|
-
* @when A controlled, finite rail of like items whose neighbours have a meaningful sequence:
|
|
28
|
-
* screens, testimonials.
|
|
29
|
-
* @instead A product's records are a list or a table, never a carousel; a sortable record
|
|
30
|
-
* collection is a table or an entity list. One overflowing row is `ScrollArea`.
|
|
31
|
-
* @behaviour Slides move by swipe, drag or the Previous and Next buttons; the buttons disable at
|
|
32
|
-
* the ends. Left and Right arrow keys move when the carousel holds focus, in both orientations;
|
|
33
|
-
* Up and Down do nothing. The rail is horizontal; `orientation` also accepts `vertical`, which
|
|
34
|
-
* stacks the buttons above and below. The motion is Embla's, and the component does not read the
|
|
35
|
-
* reduced-motion setting, so a page that must honour it sets Embla's `duration` itself through
|
|
36
|
-
* `opts` (Embla jumps with a duration of 0).
|
|
37
|
-
* @words The buttons name their move: *Previous slide*, *Next slide*.
|
|
38
|
-
* @access A `region` described as a carousel; each slide is a `group` described as a slide.
|
|
39
|
-
*/
|
|
40
|
-
declare function Carousel({ orientation, opts, setApi, plugins, className, children, ...props }: React.ComponentProps<"div"> & CarouselProps): React.JSX.Element;
|
|
41
|
-
declare function CarouselContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
42
|
-
declare function CarouselItem({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
43
|
-
declare function CarouselPrevious({ className, variant, size, "aria-label": ariaLabel, ...props }: IconButtonPartProps): React.JSX.Element;
|
|
44
|
-
declare function CarouselNext({ className, variant, size, "aria-label": ariaLabel, ...props }: IconButtonPartProps): React.JSX.Element;
|
|
45
|
-
export { type CarouselApi, Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, useCarousel, };
|
|
46
|
-
//# sourceMappingURL=carousel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"carousel.d.ts","sourceRoot":"","sources":["../../src/components/carousel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,gBAAgB,EAAE,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAGnF,OAAO,EAAU,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGvE,KAAK,WAAW,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC3C,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AACjE,KAAK,eAAe,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAChD,KAAK,cAAc,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAE/C,KAAK,aAAa,GAAG;IACnB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,WAAW,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,GAAG,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,aAAa,CAAC;AAIlB,iBAAS,WAAW,yBAQnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,iBAAS,QAAQ,CAAC,EAChB,WAA0B,EAC1B,IAAI,EACJ,MAAM,EACN,OAAO,EACP,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,aAAa,qBAgF7C;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW5E;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAgBzE;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,YAAY,EAAE,SAA4B,EAC1C,GAAG,KAAK,EACT,EAAE,mBAAmB,qBAuBrB;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,YAAY,EAAE,SAAwB,EACtC,GAAG,KAAK,EACT,EAAE,mBAAmB,qBAuBrB;AAED,OAAO,EACL,KAAK,WAAW,EAChB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACZ,CAAC"}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import useEmblaCarousel from "embla-carousel-react";
|
|
5
|
-
import { cn } from "../lib/utils.js";
|
|
6
|
-
import { Button } from "./button.js";
|
|
7
|
-
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
8
|
-
const CarouselContext = React.createContext(null);
|
|
9
|
-
function useCarousel() {
|
|
10
|
-
const context = React.useContext(CarouselContext);
|
|
11
|
-
if (!context) {
|
|
12
|
-
throw new Error("useCarousel must be used within a <Carousel />");
|
|
13
|
-
}
|
|
14
|
-
return context;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* A rail of slides moved with Previous and Next.
|
|
18
|
-
*
|
|
19
|
-
* @family Other
|
|
20
|
-
* @when A controlled, finite rail of like items whose neighbours have a meaningful sequence:
|
|
21
|
-
* screens, testimonials.
|
|
22
|
-
* @instead A product's records are a list or a table, never a carousel; a sortable record
|
|
23
|
-
* collection is a table or an entity list. One overflowing row is `ScrollArea`.
|
|
24
|
-
* @behaviour Slides move by swipe, drag or the Previous and Next buttons; the buttons disable at
|
|
25
|
-
* the ends. Left and Right arrow keys move when the carousel holds focus, in both orientations;
|
|
26
|
-
* Up and Down do nothing. The rail is horizontal; `orientation` also accepts `vertical`, which
|
|
27
|
-
* stacks the buttons above and below. The motion is Embla's, and the component does not read the
|
|
28
|
-
* reduced-motion setting, so a page that must honour it sets Embla's `duration` itself through
|
|
29
|
-
* `opts` (Embla jumps with a duration of 0).
|
|
30
|
-
* @words The buttons name their move: *Previous slide*, *Next slide*.
|
|
31
|
-
* @access A `region` described as a carousel; each slide is a `group` described as a slide.
|
|
32
|
-
*/
|
|
33
|
-
function Carousel({ orientation = "horizontal", opts, setApi, plugins, className, children, ...props }) {
|
|
34
|
-
const [carouselRef, api] = useEmblaCarousel({
|
|
35
|
-
...opts,
|
|
36
|
-
axis: orientation === "horizontal" ? "x" : "y",
|
|
37
|
-
}, plugins);
|
|
38
|
-
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
|
|
39
|
-
const [canScrollNext, setCanScrollNext] = React.useState(false);
|
|
40
|
-
const onSelect = React.useCallback((api) => {
|
|
41
|
-
if (!api)
|
|
42
|
-
return;
|
|
43
|
-
setCanScrollPrev(api.canScrollPrev());
|
|
44
|
-
setCanScrollNext(api.canScrollNext());
|
|
45
|
-
}, []);
|
|
46
|
-
const scrollPrev = React.useCallback(() => {
|
|
47
|
-
api?.scrollPrev();
|
|
48
|
-
}, [api]);
|
|
49
|
-
const scrollNext = React.useCallback(() => {
|
|
50
|
-
api?.scrollNext();
|
|
51
|
-
}, [api]);
|
|
52
|
-
const handleKeyDown = React.useCallback((event) => {
|
|
53
|
-
if (event.key === "ArrowLeft") {
|
|
54
|
-
event.preventDefault();
|
|
55
|
-
scrollPrev();
|
|
56
|
-
}
|
|
57
|
-
else if (event.key === "ArrowRight") {
|
|
58
|
-
event.preventDefault();
|
|
59
|
-
scrollNext();
|
|
60
|
-
}
|
|
61
|
-
}, [scrollPrev, scrollNext]);
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
if (!api || !setApi)
|
|
64
|
-
return;
|
|
65
|
-
setApi(api);
|
|
66
|
-
}, [api, setApi]);
|
|
67
|
-
React.useEffect(() => {
|
|
68
|
-
if (!api)
|
|
69
|
-
return;
|
|
70
|
-
onSelect(api);
|
|
71
|
-
api.on("reInit", onSelect);
|
|
72
|
-
api.on("select", onSelect);
|
|
73
|
-
return () => {
|
|
74
|
-
api.off("reInit", onSelect);
|
|
75
|
-
api.off("select", onSelect);
|
|
76
|
-
};
|
|
77
|
-
}, [api, onSelect]);
|
|
78
|
-
return (_jsx(CarouselContext.Provider, { value: {
|
|
79
|
-
carouselRef,
|
|
80
|
-
api: api,
|
|
81
|
-
opts,
|
|
82
|
-
orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
|
83
|
-
scrollPrev,
|
|
84
|
-
scrollNext,
|
|
85
|
-
canScrollPrev,
|
|
86
|
-
canScrollNext,
|
|
87
|
-
}, children: _jsx("div", { onKeyDownCapture: handleKeyDown, className: cn("relative", className), role: "region", "aria-roledescription": "carousel", "data-slot": "carousel", ...props, children: children }) }));
|
|
88
|
-
}
|
|
89
|
-
function CarouselContent({ className, ...props }) {
|
|
90
|
-
const { carouselRef, orientation } = useCarousel();
|
|
91
|
-
return (_jsx("div", { ref: carouselRef, className: "overflow-hidden", "data-slot": "carousel-content", children: _jsx("div", { className: cn("flex", orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col", className), ...props }) }));
|
|
92
|
-
}
|
|
93
|
-
function CarouselItem({ className, ...props }) {
|
|
94
|
-
const { orientation } = useCarousel();
|
|
95
|
-
return (_jsx("div", { role: "group", "aria-roledescription": "slide", "data-slot": "carousel-item", className: cn("min-w-0 shrink-0 grow-0 basis-full", orientation === "horizontal" ? "pl-4" : "pt-4", className), ...props }));
|
|
96
|
-
}
|
|
97
|
-
function CarouselPrevious({ className, variant = "outline", size = "icon-sm", "aria-label": ariaLabel = "Previous slide", ...props }) {
|
|
98
|
-
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
|
99
|
-
return (_jsx(Button, { "data-slot": "carousel-previous", "aria-label": ariaLabel, variant: variant, size: size, className: cn("absolute touch-manipulation", orientation === "horizontal"
|
|
100
|
-
? "inset-y-0 -left-12 my-auto"
|
|
101
|
-
: "-top-12 left-1/2 -translate-x-1/2 rotate-90", className), disabled: !canScrollPrev, onClick: scrollPrev, ...props, children: _jsx(ChevronLeftIcon, {}) }));
|
|
102
|
-
}
|
|
103
|
-
function CarouselNext({ className, variant = "outline", size = "icon-sm", "aria-label": ariaLabel = "Next slide", ...props }) {
|
|
104
|
-
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
|
105
|
-
return (_jsx(Button, { "data-slot": "carousel-next", "aria-label": ariaLabel, variant: variant, size: size, className: cn("absolute touch-manipulation", orientation === "horizontal"
|
|
106
|
-
? "inset-y-0 -right-12 my-auto"
|
|
107
|
-
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90", className), disabled: !canScrollNext, onClick: scrollNext, ...props, children: _jsx(ChevronRightIcon, {}) }));
|
|
108
|
-
}
|
|
109
|
-
export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, useCarousel, };
|