@nadicodeai/ui 12.1.89 → 12.1.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/components/agent-profile.d.ts +12 -5
  2. package/dist/components/agent-profile.d.ts.map +1 -1
  3. package/dist/components/agent-profile.js +10 -10
  4. package/dist/components/catalog-entry.d.ts +8 -5
  5. package/dist/components/catalog-entry.d.ts.map +1 -1
  6. package/dist/components/catalog-entry.js +9 -6
  7. package/dist/components/collection-page.d.ts +125 -0
  8. package/dist/components/collection-page.d.ts.map +1 -0
  9. package/dist/components/collection-page.js +149 -0
  10. package/dist/components/data-table.d.ts +12 -3
  11. package/dist/components/data-table.d.ts.map +1 -1
  12. package/dist/components/data-table.js +2 -2
  13. package/dist/components/form-dialog.d.ts +8 -3
  14. package/dist/components/form-dialog.d.ts.map +1 -1
  15. package/dist/components/form-dialog.js +7 -4
  16. package/dist/components/form-drawer.d.ts +15 -22
  17. package/dist/components/form-drawer.d.ts.map +1 -1
  18. package/dist/components/form-drawer.js +4 -4
  19. package/dist/components/record-identity.d.ts +12 -2
  20. package/dist/components/record-identity.d.ts.map +1 -1
  21. package/dist/components/record-identity.js +11 -2
  22. package/dist/components/record-time.d.ts +25 -0
  23. package/dist/components/record-time.d.ts.map +1 -0
  24. package/dist/components/record-time.js +52 -0
  25. package/dist/components/row-edit-form.d.ts +22 -0
  26. package/dist/components/row-edit-form.d.ts.map +1 -0
  27. package/dist/components/row-edit-form.js +16 -0
  28. package/dist/components/sidebar.js +3 -3
  29. package/dist/components/theme-mode-switcher.d.ts.map +1 -1
  30. package/dist/components/theme-mode-switcher.js +2 -8
  31. package/dist/hooks/use-mobile.d.ts +2 -0
  32. package/dist/hooks/use-mobile.d.ts.map +1 -1
  33. package/dist/hooks/use-mobile.js +9 -11
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -0
  37. package/dist/internal/form-submit.d.ts +25 -0
  38. package/dist/internal/form-submit.d.ts.map +1 -0
  39. package/dist/internal/form-submit.js +8 -0
  40. package/dist/internal/row-message.d.ts +18 -0
  41. package/dist/internal/row-message.d.ts.map +1 -0
  42. package/dist/internal/row-message.js +12 -0
  43. package/package.json +2 -2
@@ -4,11 +4,16 @@ import type { AgentOrbSize } from "./agent-orb.js";
4
4
  import { type PageActionsProps } from "./page-actions.js";
5
5
  import { RadioGroup } from "./radio-group.js";
6
6
  import { type StatusBadgeTone } from "./status-badge.js";
7
- /** A fact on the card whose label stays in place when its value is missing. */
7
+ /**
8
+ * A fact on the card whose label stays in place when its value is missing.
9
+ * `pending` draws the value's place while it is read, so a value not yet known
10
+ * never reads as missing.
11
+ */
8
12
  export type AgentProfileFact = {
9
13
  label: string;
10
14
  value?: string | null;
11
15
  missingLabel: string;
16
+ pending?: boolean;
12
17
  };
13
18
  export type AgentProfileCardProps = {
14
19
  /** Draws the Agent's orb at the size the card gives it. */
@@ -27,9 +32,10 @@ export type AgentProfileCardProps = {
27
32
  ref?: Ref<HTMLButtonElement>;
28
33
  } | undefined;
29
34
  /**
30
- * Her name, description and look as fields, drawn under her name in place of
31
- * her description and facts while the person edits; the card's footer saves
32
- * them with the rest of the card.
35
+ * Her name, description and look as fields, drawn in place of her name and
36
+ * description while the person edits, with her facts kept under them; her
37
+ * name stays the page's heading for assistive technology, and the card's
38
+ * footer saves the fields with the rest of the card.
33
39
  */
34
40
  editor?: ReactNode;
35
41
  state: {
@@ -57,7 +63,8 @@ export type AgentProfileCardProps = {
57
63
  /**
58
64
  * The card an Agent's Profile opens with in every product (DESIGN.md, "Page
59
65
  * compositions"): on the left her orb at 64, her name with the pencil, her
60
- * description and her facts, which the pencil turns into fields in place; on
66
+ * description and her facts; the pencil turns her name and description into
67
+ * fields in place, above the same facts; on
61
68
  * the right her model and her reasoning; the card's footer saves both sides. Each product brings its own data,
62
69
  * fields and words; the shape, sizes and order are this component's.
63
70
  */
@@ -1 +1 @@
1
- {"version":3,"file":"agent-profile.d.ts","sourceRoot":"","sources":["../../src/components/agent-profile.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-profile.d.ts","sourceRoot":"","sources":["../../src/components/agent-profile.tsx"],"names":[],"mappings":"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"}
@@ -11,31 +11,31 @@ import { ModelIdentity } from "./model-identity.js";
11
11
  import { PageActionsRow } from "./page-actions.js";
12
12
  import { RadioGroup } from "./radio-group.js";
13
13
  import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger } from "./select.js";
14
+ import { Skeleton } from "./skeleton.js";
14
15
  import { StatusBadge } from "./status-badge.js";
15
16
  import { TableValue } from "./table-value.js";
16
17
  import { toggleVariants } from "./toggle.js";
17
18
  const AGENT_PROFILE_ORB_SIZE = 64;
19
+ function FactValue({ fact }) {
20
+ return fact.pending ? (_jsx(Skeleton, { "aria-busy": "true", className: "h-4 w-24" })) : (_jsx(TableValue, { missingLabel: fact.missingLabel, value: fact.value }));
21
+ }
18
22
  /**
19
23
  * The card an Agent's Profile opens with in every product (DESIGN.md, "Page
20
24
  * compositions"): on the left her orb at 64, her name with the pencil, her
21
- * description and her facts, which the pencil turns into fields in place; on
25
+ * description and her facts; the pencil turns her name and description into
26
+ * fields in place, above the same facts; on
22
27
  * the right her model and her reasoning; the card's footer saves both sides. Each product brings its own data,
23
28
  * fields and words; the shape, sizes and order are this component's.
24
29
  */
25
30
  export function AgentProfileCard({ orb, name, description, descriptionMissingLabel, edit, editor, state, activity, origin, settings, footer, footerHint, actions, headingProps, }) {
26
31
  const facts = [
27
32
  { label: state.label, value: _jsx(StatusBadge, { label: state.text, tone: state.tone }) },
28
- {
29
- label: activity.label,
30
- value: _jsx(TableValue, { missingLabel: activity.missingLabel, value: activity.value }),
31
- },
32
- {
33
- label: origin.label,
34
- value: _jsx(TableValue, { missingLabel: origin.missingLabel, value: origin.value }),
35
- },
33
+ { label: activity.label, value: _jsx(FactValue, { fact: activity }) },
34
+ { label: origin.label, value: _jsx(FactValue, { fact: origin }) },
36
35
  ];
36
+ const factList = (_jsx("dl", { className: "mt-nadicode-sm flex min-w-0 flex-wrap gap-x-nadicode-lg gap-y-nadicode-sm", "data-slot": "agent-profile-facts", children: facts.map((fact) => (_jsxs("div", { className: "grid min-w-0 gap-1", children: [_jsx("dt", { className: "text-xs text-muted-foreground", children: fact.label }), _jsx("dd", { className: "flex min-h-6 min-w-0 items-center text-sm", children: fact.value })] }, fact.label))) }));
37
37
  const text = description?.trim();
38
- return (_jsxs(Card, { className: "@container/agent-profile min-w-0", render: _jsx("section", { "aria-labelledby": headingProps?.id }), "data-slot": "agent-profile", children: [_jsxs(CardContent, { className: "grid min-w-0 gap-nadicode-lg @3xl/agent-profile:grid-cols-[minmax(0,1fr)_minmax(18rem,22rem)] @3xl/agent-profile:gap-nadicode-xl", children: [_jsxs("div", { className: "grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-start gap-nadicode-md", children: [_jsx("div", { className: "shrink-0", children: orb(AGENT_PROFILE_ORB_SIZE) }), editor ? (_jsxs("div", { className: "grid min-w-0 gap-nadicode-md", "data-slot": "agent-profile-editor", children: [_jsx("h1", { ...headingProps, className: cn("min-w-0 text-heading-md break-words text-foreground outline-none", headingProps?.className), children: name }), editor] })) : (_jsxs("div", { className: "grid min-w-0 gap-1", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-1 gap-y-nadicode-sm", children: [_jsx("h1", { ...headingProps, className: cn("min-w-0 text-heading-md break-words text-foreground outline-none", headingProps?.className), children: name }), edit ? (_jsx(Button, { "aria-label": edit.label, onClick: edit.onClick, ref: edit.ref, size: "icon", title: edit.label, type: "button", variant: "ghost", children: _jsx(PencilIcon, { "aria-hidden": "true", "data-icon": true }) })) : null, actions ? (_jsx("div", { className: "ml-auto flex shrink-0 items-center gap-2 pl-nadicode-sm", "data-slot": "agent-profile-actions", children: _jsx(PageActionsRow, { ...actions }) })) : null] }), _jsx("p", { className: "line-clamp-2 min-w-0 text-sm text-muted-foreground", title: text, children: _jsx(TableValue, { missingLabel: descriptionMissingLabel, value: text }) }), _jsx("dl", { className: "mt-nadicode-sm flex min-w-0 flex-wrap gap-x-nadicode-lg gap-y-nadicode-sm", "data-slot": "agent-profile-facts", children: facts.map((fact) => (_jsxs("div", { className: "grid min-w-0 gap-1", children: [_jsx("dt", { className: "text-xs text-muted-foreground", children: fact.label }), _jsx("dd", { className: "flex min-h-6 min-w-0 items-center text-sm", children: fact.value })] }, fact.label))) })] }))] }), settings ? (_jsx("div", { className: "grid min-w-0 content-start gap-nadicode-md border-t border-border pt-nadicode-md @3xl/agent-profile:border-t-0 @3xl/agent-profile:border-l @3xl/agent-profile:pt-0 @3xl/agent-profile:pl-nadicode-lg", "data-slot": "agent-profile-settings", children: settings })) : null] }), _jsx(FooterStrip, { hint: footerHint, hintSlot: "agent-profile-hint", children: footer })] }));
38
+ return (_jsxs(Card, { className: "@container/agent-profile min-w-0", render: _jsx("section", { "aria-labelledby": headingProps?.id }), "data-slot": "agent-profile", children: [_jsxs(CardContent, { className: "grid min-w-0 gap-nadicode-lg @3xl/agent-profile:grid-cols-[minmax(0,1fr)_minmax(18rem,22rem)] @3xl/agent-profile:gap-nadicode-xl", children: [_jsxs("div", { className: "grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-start gap-nadicode-md", children: [_jsx("div", { className: "shrink-0", children: orb(AGENT_PROFILE_ORB_SIZE) }), editor ? (_jsxs("div", { className: "grid min-w-0 gap-nadicode-md", "data-slot": "agent-profile-editor", children: [_jsx("h1", { ...headingProps, className: cn("sr-only", headingProps?.className), children: name }), editor, factList] })) : (_jsxs("div", { className: "grid min-w-0 gap-1", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-1 gap-y-nadicode-sm", children: [_jsx("h1", { ...headingProps, className: cn("min-w-0 text-heading-md break-words text-foreground outline-none", headingProps?.className), children: name }), edit ? (_jsx(Button, { "aria-label": edit.label, onClick: edit.onClick, ref: edit.ref, size: "icon", title: edit.label, type: "button", variant: "ghost", children: _jsx(PencilIcon, { "aria-hidden": "true", "data-icon": true }) })) : null, actions ? (_jsx("div", { className: "ml-auto flex shrink-0 items-center gap-2 pl-nadicode-sm", "data-slot": "agent-profile-actions", children: _jsx(PageActionsRow, { ...actions }) })) : null] }), _jsx("p", { className: "line-clamp-2 min-w-0 text-sm text-muted-foreground", title: text, children: _jsx(TableValue, { missingLabel: descriptionMissingLabel, value: text }) }), factList] }))] }), settings ? (_jsx("div", { className: "grid min-w-0 content-start gap-nadicode-md border-t border-border pt-nadicode-md @3xl/agent-profile:border-t-0 @3xl/agent-profile:border-l @3xl/agent-profile:pt-0 @3xl/agent-profile:pl-nadicode-lg", "data-slot": "agent-profile-settings", children: settings })) : null] }), _jsx(FooterStrip, { hint: footerHint, hintSlot: "agent-profile-hint", children: footer })] }));
39
39
  }
40
40
  /**
41
41
  * A model chosen from a list: the trigger and every option read the model the
@@ -1,4 +1,6 @@
1
1
  import type * as React from "react";
2
+ import { type RowMessage } from "../internal/row-message.js";
3
+ export type { RowMessage };
2
4
  /**
3
5
  * The line icon a catalog entry names. A name outside `CATALOG_ICONS`, or
4
6
  * none, draws the sparkles every unnamed entry shares.
@@ -17,15 +19,16 @@ export declare function CatalogEntryList({ children, className, columns, }: {
17
19
  }): React.JSX.Element;
18
20
  /**
19
21
  * One entry of a Library shelf: its kind's tile, its name, one line of
20
- * description, and at the trailing end what the viewer can do with it. A
21
- * failure of that action sits under the entry, in `notice`. The caller writes
22
- * the entry's `<li>`.
22
+ * description, and at the trailing end what the viewer can do with it. When
23
+ * that action failed or cannot run, `state` puts its message in the
24
+ * description's place and its actions before the entry's own, inside the entry. The
25
+ * caller writes the entry's `<li>`.
23
26
  */
24
- export declare function CatalogEntryRow({ actions, description, media, notice, title, }: {
27
+ export declare function CatalogEntryRow({ actions, description, media, state, title, }: {
25
28
  actions?: React.ReactNode;
26
29
  description: React.ReactNode;
27
30
  media: React.ReactNode;
28
- notice?: React.ReactNode;
31
+ state?: RowMessage | null;
29
32
  title: React.ReactNode;
30
33
  }): React.JSX.Element;
31
34
  //# sourceMappingURL=catalog-entry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-entry.d.ts","sourceRoot":"","sources":["../../src/components/catalog-entry.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AA+CpC;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,qBAGxE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,OAAW,GACZ,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB,qBASA;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,WAAW,EACX,KAAK,EACL,MAAM,EACN,KAAK,GACN,EAAE;IACD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB,qBAcA"}
1
+ {"version":3,"file":"catalog-entry.d.ts","sourceRoot":"","sources":["../../src/components/catalog-entry.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAYpC,OAAO,EAAE,KAAK,UAAU,EAAqC,MAAM,wBAAwB,CAAC;AAE5F,YAAY,EAAE,UAAU,EAAE,CAAC;AAoC3B;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,qBAGxE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,OAAW,GACZ,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB,qBASA;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,WAAW,EACX,KAAK,EACL,KAAK,EACL,KAAK,GACN,EAAE;IACD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB,qBAqBA"}
@@ -1,6 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { BookOpen, Briefcase, Calculator, Calendar, FileCheck, FileSearch, FileText, Globe, Inbox, Landmark, Languages, ListChecks, Mail, MessageCircle, Mic, NotebookPen, Phone, Presentation, Receipt, Scale, Send, ShieldCheck, Sparkles, Truck, Users, Wallet, } from "lucide-react";
3
3
  import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle, } from "./item.js";
4
+ import { RowMessageActions, RowMessageLine } from "../internal/row-message.js";
4
5
  import { cn } from "../lib/utils.js";
5
6
  const ICONS = {
6
7
  "book-open": BookOpen,
@@ -50,10 +51,12 @@ export function CatalogEntryList({ children, className, columns = 1, }) {
50
51
  }
51
52
  /**
52
53
  * One entry of a Library shelf: its kind's tile, its name, one line of
53
- * description, and at the trailing end what the viewer can do with it. A
54
- * failure of that action sits under the entry, in `notice`. The caller writes
55
- * the entry's `<li>`.
54
+ * description, and at the trailing end what the viewer can do with it. When
55
+ * that action failed or cannot run, `state` puts its message in the
56
+ * description's place and its actions before the entry's own, inside the entry. The
57
+ * caller writes the entry's `<li>`.
56
58
  */
57
- export function CatalogEntryRow({ actions, description, media, notice, title, }) {
58
- return (_jsxs(_Fragment, { children: [_jsxs(Item, { children: [_jsx(ItemMedia, { children: media }), _jsxs(ItemContent, { className: "min-w-0", children: [_jsx(ItemTitle, { children: title }), _jsx(ItemDescription, { className: "line-clamp-1", children: description })] }), actions ? _jsx(ItemActions, { children: actions }) : null] }), notice] }));
59
+ export function CatalogEntryRow({ actions, description, media, state, title, }) {
60
+ const controls = state ? (_jsxs(_Fragment, { children: [_jsx(RowMessageActions, { state: state }), actions] })) : (actions);
61
+ return (_jsxs(Item, { children: [_jsx(ItemMedia, { children: media }), _jsxs(ItemContent, { className: "min-w-0", children: [_jsx(ItemTitle, { children: title }), _jsx(ItemDescription, { className: state ? undefined : "line-clamp-1", children: state ? _jsx(RowMessageLine, { state: state }) : description })] }), controls ? _jsx(ItemActions, { children: controls }) : null] }));
59
62
  }
@@ -0,0 +1,125 @@
1
+ import type { RowData } from "@tanstack/react-table";
2
+ import { type ReactElement, type ReactNode } from "react";
3
+ import { type CollectionSortProps } from "./collection-sort.js";
4
+ import { type DataTableRowLinkProps } from "./data-table.js";
5
+ import { type EmptyStateProps } from "./empty-state.js";
6
+ import { type PageActionsProps } from "./page-actions.js";
7
+ import { type StatusBadgeTone } from "./status-badge.js";
8
+ import { type RowMessage } from "../internal/row-message.js";
9
+ /** One thing a person can do to a record. */
10
+ export type RecordCommand = {
11
+ label: string;
12
+ /** Its name for assistive technology when the label alone does not say what it does: "Let Sofia use Gmail". */
13
+ accessibleName?: string;
14
+ icon: ReactElement;
15
+ onSelect: () => void;
16
+ destructive?: boolean;
17
+ disabled?: boolean;
18
+ /** Why the command cannot run now, read after its name. */
19
+ reason?: ReactNode;
20
+ };
21
+ export type { RowMessage };
22
+ export type CollectionPageProps<TRecord extends RowData> = {
23
+ /** Names the collection for assistive technology: "Skills". */
24
+ label: string;
25
+ /** The page's title, when the collection is the page; a section titled by its shell leaves it out. */
26
+ title?: string;
27
+ /** The title's commands; a `primary` that is also the first-use action shows only once there are records. */
28
+ actions?: PageActionsProps;
29
+ search?: {
30
+ label: string;
31
+ value: string;
32
+ onValueChange: (value: string) => void;
33
+ };
34
+ sort?: CollectionSortProps;
35
+ /** The records to show, already searched and ordered; `undefined` while they load. */
36
+ records: readonly TRecord[] | undefined;
37
+ /** Names the rows while they load; the collection's `label` when left out. */
38
+ loadingLabel?: string;
39
+ /** The read failed: shown in place of the rows. */
40
+ failed?: Extract<EmptyStateProps, {
41
+ kind: "failed";
42
+ }>;
43
+ /** There are no records at all; a collection shown only when it has records leaves it out. */
44
+ empty?: Extract<EmptyStateProps, {
45
+ kind: "firstUse" | "nothingYet";
46
+ }>;
47
+ /** The search matched nothing; a collection without one leaves it out. */
48
+ noMatch?: Omit<Extract<EmptyStateProps, {
49
+ kind: "noResults";
50
+ }>, "kind">;
51
+ getId: (record: TRecord) => string;
52
+ /** The record's name, and one line saying what it is or where it comes from. */
53
+ name: (record: TRecord) => {
54
+ name: ReactNode;
55
+ detail?: ReactNode;
56
+ mark?: ReactNode;
57
+ };
58
+ /** The name is the record's whole text, such as a memory, and wraps in full instead of ending in an ellipsis. */
59
+ wraps?: boolean;
60
+ /**
61
+ * Facts of one kind each, a column apiece after the name, every value saying
62
+ * what it is by its own word or mark: "Skills: price-quotes", a commit. A fact
63
+ * holds one line at its own width; `prose` is a phrase that takes the row's spare width.
64
+ */
65
+ facts?: readonly {
66
+ id: string;
67
+ label: string;
68
+ of: (record: TRecord) => ReactNode;
69
+ prose?: boolean;
70
+ }[];
71
+ /** A status only when it tells this record apart from the others; `null` for the usual case. */
72
+ status?: {
73
+ label: string;
74
+ of: (record: TRecord) => {
75
+ label: string;
76
+ tone: StatusBadgeTone;
77
+ } | null;
78
+ };
79
+ /** When something happened to the record, in its verb's sentence. */
80
+ time?: {
81
+ label: string;
82
+ of: (record: TRecord) => Date | number | string | null | undefined;
83
+ phrase: (when: string) => string;
84
+ /** What a screen reader hears where a record has no time, beside the muted dash. */
85
+ missing: string;
86
+ locale?: string;
87
+ };
88
+ /**
89
+ * What a person can do to the record: one command is a button in the row; two or
90
+ * more, or a destructive one, open the row's menu, the destructive last.
91
+ */
92
+ commands?: (record: TRecord) => readonly RecordCommand[];
93
+ /**
94
+ * The row's one outline button that starts what the record is not doing yet,
95
+ * "Connect", with what it is waiting for; its commands then stay in the menu after it.
96
+ */
97
+ start?: (record: TRecord) => ReactNode;
98
+ commandsLabel?: (record: TRecord) => string;
99
+ /** Names the commands column for assistive technology: "Actions". */
100
+ commandsHeader?: string;
101
+ /** The record opens its own page; the row shows the way in. A record that opens nothing has no `href`. */
102
+ open?: {
103
+ href: (record: TRecord) => string | null;
104
+ label: (record: TRecord) => string;
105
+ /** Draws the row's link, for a router that opens it itself. */
106
+ renderLink?: (props: DataTableRowLinkProps) => ReactNode;
107
+ };
108
+ /** The record's own action failed or cannot run: its message, inside the row. */
109
+ state?: (record: TRecord) => RowMessage | null;
110
+ /** The record being edited, and its `RowEditForm`, drawn inside its row. */
111
+ editor?: {
112
+ id: string;
113
+ render: (record: TRecord) => ReactNode;
114
+ };
115
+ };
116
+ /**
117
+ * The Collection composition (DESIGN.md "Page compositions", "Tables and
118
+ * missing values"), whole: the title with the page's actions, the toolbar's
119
+ * search and sort, then one row per record that reads without a header row:
120
+ * its name over what it is, a status only when it is the exception, when it
121
+ * happened in its verb's sentence, and its commands. A failed or refused action
122
+ * and an edit stay inside their own row.
123
+ */
124
+ export declare function CollectionPage<TRecord extends RowData>(props: CollectionPageProps<TRecord>): import("react").JSX.Element;
125
+ //# sourceMappingURL=collection-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-page.d.ts","sourceRoot":"","sources":["../../src/components/collection-page.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronRight } from "lucide-react";
4
+ import { createContext, useContext } from "react";
5
+ import { ActionMenu } from "./action-menu.js";
6
+ import { Button } from "./button.js";
7
+ import { CollectionSearch } from "./collection-search.js";
8
+ import { CollectionSort } from "./collection-sort.js";
9
+ import { CollectionToolbar } from "./collection-toolbar.js";
10
+ import { DataTable, } from "./data-table.js";
11
+ import { DropdownMenuCommand, DropdownMenuSeparator } from "./dropdown-menu.js";
12
+ import { EmptyState } from "./empty-state.js";
13
+ import { PageActions } from "./page-actions.js";
14
+ import { PageHeader } from "./page-header.js";
15
+ import { RecordIdentity } from "./record-identity.js";
16
+ import { RecordTime, recordDate } from "./record-time.js";
17
+ import { TableValue } from "./table-value.js";
18
+ import { Skeleton } from "./skeleton.js";
19
+ import { StatusBadge } from "./status-badge.js";
20
+ import { TableCard } from "./table-card.js";
21
+ import { RowMessageActions, RowMessageLine } from "../internal/row-message.js";
22
+ const ShownCollection = createContext(undefined);
23
+ function useShownCollection() {
24
+ return useContext(ShownCollection);
25
+ }
26
+ /*
27
+ * Each cell is one component for the page's whole life: TanStack renders a
28
+ * column's `cell` as a component, so a function made anew on each render would
29
+ * remount every row's cells on every render, closing a row's open menu when
30
+ * the records are read again. The cells read the page's current props instead.
31
+ */
32
+ function NameCell({ row }) {
33
+ const props = useShownCollection();
34
+ const shown = props.name(row.original);
35
+ const state = props.state?.(row.original);
36
+ return (_jsx(RecordIdentity, { detail: state ? _jsx(RowMessageLine, { state: state }) : shown.detail, mark: shown.mark, name: shown.name, wraps: props.wraps }));
37
+ }
38
+ function FactCell({ column, row }) {
39
+ const fact = useShownCollection().facts?.find((each) => each.id === column.id);
40
+ return _jsx(_Fragment, { children: fact?.of(row.original) });
41
+ }
42
+ function StatusCell({ row }) {
43
+ const shown = useShownCollection().status?.of(row.original);
44
+ return shown ? _jsx(StatusBadge, { label: shown.label, tone: shown.tone }) : null;
45
+ }
46
+ function TimeCell({ row }) {
47
+ const time = useShownCollection().time;
48
+ if (!time)
49
+ return null;
50
+ const at = recordDate(time.of(row.original));
51
+ return (_jsx(TableValue, { missingLabel: time.missing, value: at ? _jsx(RecordTime, { at: at, locale: time.locale, phrase: time.phrase }) : null }));
52
+ }
53
+ function CommandsCell({ row }) {
54
+ const props = useShownCollection();
55
+ const state = props.state?.(row.original);
56
+ const commands = props.commands?.(row.original) ?? [];
57
+ const way = commands.length > 0 ? (_jsx(Commands, { commands: commands, label: props.commandsLabel?.(row.original) ?? props.label, menu: props.start !== undefined })) : props.open?.href(row.original) && !state ? (_jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 text-muted-foreground" })) : null;
58
+ if (!props.start && !state)
59
+ return way;
60
+ return (_jsxs("div", { className: "flex items-center justify-end gap-2", children: [props.start?.(row.original), state ? _jsx(RowMessageActions, { state: state }) : null, way] }));
61
+ }
62
+ function LoadingRecords({ label }) {
63
+ return (_jsx("div", { "aria-busy": "true", "aria-label": label, className: "divide-y divide-border", role: "status", children: Array.from({ length: 3 }, (_, index) => (_jsxs("div", { className: "flex h-16 items-center gap-3 px-4", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Skeleton, { className: "h-4 w-40 max-w-full" }), _jsx(Skeleton, { className: "h-3 w-56 max-w-full" })] }), _jsx(Skeleton, { className: "ml-auto h-4 w-28" })] }, index))) }));
64
+ }
65
+ function Commands({ commands, label, menu, }) {
66
+ const [only] = commands;
67
+ if (!only)
68
+ return null;
69
+ if (commands.length === 1 && !only.destructive && !menu) {
70
+ return (_jsx(Button, { "aria-label": only.accessibleName, disabled: only.disabled, onClick: only.onSelect, type: "button", variant: "outline", children: only.label }));
71
+ }
72
+ const kept = commands.filter((command) => !command.destructive);
73
+ const destructive = commands.filter((command) => command.destructive);
74
+ return (_jsxs(ActionMenu, { label: label, children: [kept.map((command) => (_jsx(DropdownMenuCommand, { "aria-label": command.accessibleName, disabled: command.disabled, icon: command.icon, onClick: command.onSelect, reason: command.reason, children: command.label }, command.label))), kept.length > 0 && destructive.length > 0 ? _jsx(DropdownMenuSeparator, {}) : null, destructive.map((command) => (_jsx(DropdownMenuCommand, { "aria-label": command.accessibleName, disabled: command.disabled, icon: command.icon, onClick: command.onSelect, reason: command.reason, variant: "destructive", children: command.label }, command.label)))] }));
75
+ }
76
+ /**
77
+ * The Collection composition (DESIGN.md "Page compositions", "Tables and
78
+ * missing values"), whole: the title with the page's actions, the toolbar's
79
+ * search and sort, then one row per record that reads without a header row:
80
+ * its name over what it is, a status only when it is the exception, when it
81
+ * happened in its verb's sentence, and its commands. A failed or refused action
82
+ * and an edit stay inside their own row.
83
+ */
84
+ export function CollectionPage(props) {
85
+ const { label, title, actions, search, sort, records } = props;
86
+ const hasRecords = records !== undefined && records.length > 0;
87
+ const searching = Boolean(search?.value);
88
+ const addsFirst = props.empty?.kind === "firstUse" && props.empty.action === actions?.primary;
89
+ const shownActions = addsFirst && !hasRecords && !searching ? { ...actions, primary: undefined } : actions;
90
+ const columns = [
91
+ { id: "name", header: label, meta: props.wraps ? { wraps: true } : undefined, cell: NameCell },
92
+ ];
93
+ for (const fact of props.facts ?? []) {
94
+ columns.push({
95
+ id: fact.id,
96
+ header: fact.label,
97
+ meta: fact.prose ? { prose: true } : { narrow: true },
98
+ cell: FactCell,
99
+ });
100
+ }
101
+ if (props.status) {
102
+ columns.push({
103
+ id: "status",
104
+ header: props.status.label,
105
+ meta: { narrow: true },
106
+ cell: StatusCell,
107
+ });
108
+ }
109
+ if (props.time) {
110
+ columns.push({ id: "time", header: props.time.label, meta: { narrow: true }, cell: TimeCell });
111
+ }
112
+ if (props.commands || props.open || props.state || props.start) {
113
+ columns.push({
114
+ id: "commands",
115
+ header: props.commandsHeader ?? label,
116
+ meta: { narrow: true },
117
+ cell: CommandsCell,
118
+ });
119
+ }
120
+ const primaryColumns = columns.map((column) => String(column.id));
121
+ let body;
122
+ if (props.failed) {
123
+ body = _jsx(EmptyState, { ...props.failed });
124
+ }
125
+ else if (records === undefined) {
126
+ body = _jsx(LoadingRecords, { label: props.loadingLabel ?? label });
127
+ }
128
+ else if (!hasRecords && searching && props.noMatch) {
129
+ body = _jsx(EmptyState, { kind: "noResults", ...props.noMatch });
130
+ }
131
+ else if (!hasRecords) {
132
+ body = props.empty ? _jsx(EmptyState, { ...props.empty }) : null;
133
+ }
134
+ else {
135
+ const table = {
136
+ columns,
137
+ data: [...records],
138
+ embedded: true,
139
+ empty: { kind: "nothingYet", message: label },
140
+ getRowId: props.getId,
141
+ primaryColumns,
142
+ showColumnHeaders: false,
143
+ rowEditor: props.editor ? { rowId: props.editor.id, render: props.editor.render } : undefined,
144
+ tableLabel: label,
145
+ };
146
+ body = props.open ? (_jsx(DataTable, { ...table, primaryColumnId: "name", renderRowLink: props.open.renderLink, rowHref: props.open.href, rowLabel: props.open.label })) : (_jsx(DataTable, { ...table }));
147
+ }
148
+ return (_jsxs("div", { className: "grid min-w-0 gap-4", "data-slot": "collection-page", children: [title ? _jsx(PageHeader, { title: title }) : null, shownActions ? _jsx(PageActions, { ...shownActions }) : null, search && (hasRecords || searching) ? (_jsx(CollectionToolbar, { actions: sort ? _jsx(CollectionSort, { ...sort }) : undefined, label: label, search: _jsx(CollectionSearch, { ...search }), surface: "plain" })) : null, _jsx(TableCard, { children: _jsx(ShownCollection.Provider, { value: props, children: body }) })] }));
149
+ }
@@ -135,14 +135,23 @@ type DataTableBaseProps<TData extends RowData> = {
135
135
  renderToolbar?: (slots: DataTableToolbarSlots) => React.ReactNode;
136
136
  /** Wraps the card, such as a frame that keeps it readable while new data loads. */
137
137
  wrapCard?: (card: React.ReactNode) => React.ReactNode;
138
+ /**
139
+ * The record being edited and its form, drawn inside its row under the
140
+ * record's own line (DESIGN.md "Menus and commands"); `rowId` is the
141
+ * `getRowId` of that record. The form is a `RowEditForm`.
142
+ */
143
+ rowEditor?: {
144
+ rowId: string;
145
+ render: (row: TData) => React.ReactNode;
146
+ };
138
147
  };
139
148
  type DataTableRowNav<TData extends RowData> = {
140
149
  rowHref?: undefined;
141
150
  rowLabel?: undefined;
142
151
  primaryColumnId?: undefined;
143
152
  } | {
144
- /** Makes each row navigable through exactly one link placed on the primary cell. */
145
- rowHref: (row: TData) => string;
153
+ /** Makes each row navigable through exactly one link placed on the primary cell; `null` for a row that opens nothing. */
154
+ rowHref: (row: TData) => string | null;
146
155
  /** Purposeful, localized accessible name for the row link (e.g. "Open Studio Rossi"). */
147
156
  rowLabel: (row: TData) => string;
148
157
  /** Column id that carries the link; defaults to the row's first visible column. */
@@ -150,6 +159,6 @@ type DataTableRowNav<TData extends RowData> = {
150
159
  };
151
160
  export type DataTableProps<TData extends RowData> = DataTableBaseProps<TData> & DataTableRowNav<TData>;
152
161
  export declare function columnMenuLabel<TData extends RowData, TValue extends CellData = CellData>(column: DataTableColumn<TData, TValue>): string;
153
- export declare function DataTable<TData extends RowData>({ columns, data, getRowId, filterColumnId, filterPlaceholder, primaryColumns, compactLayout: requestedCompactLayout, tableLabel, heading, footer, showColumnHeaders, density, interactive, embedded, summary, rowHref, rowLabel, primaryColumnId, empty, noMatchMessage, columnsLabel, clearSearchLabel, pageLabels, toolbarActions, externalFilter, sorting: externalSorting, pagination, renderRowLink, renderToolbar, wrapCard, }: DataTableProps<TData>): React.JSX.Element;
162
+ export declare function DataTable<TData extends RowData>({ columns, data, getRowId, filterColumnId, filterPlaceholder, primaryColumns, compactLayout: requestedCompactLayout, tableLabel, heading, footer, showColumnHeaders, density, interactive, embedded, summary, rowHref, rowLabel, primaryColumnId, empty, noMatchMessage, columnsLabel, clearSearchLabel, pageLabels, toolbarActions, externalFilter, sorting: externalSorting, pagination, renderRowLink, renderToolbar, wrapCard, rowEditor, }: DataTableProps<TData>): React.JSX.Element;
154
163
  export {};
155
164
  //# sourceMappingURL=data-table.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/components/data-table.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/components/data-table.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EAEnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,WAAW,EAGX,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,SAAS,EAGd,KAAK,OAAO,EAEb,MAAM,uBAAuB,CAAC;AAa/B,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EACL,KAAK,EAON,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAE1F,KAAK,iBAAiB,GAAG;IACvB,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,gBAAgB,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;IAC5D,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,cAAc,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;IACxD,SAAS,EAAE;QACT,WAAW,EAAE,OAAO,oBAAoB,CAAC;QACzC,MAAM,EAAE,OAAO,eAAe,CAAC;QAC/B,WAAW,EAAE,OAAO,oBAAoB,CAAC;QACzC,cAAc,EAAE,OAAO,uBAAuB,CAAC;QAC/C,aAAa,EAAE,OAAO,sBAAsB,CAAC;QAC7C,UAAU,EAAE,OAAO,mBAAmB,CAAC;KACxC,CAAC;IACF,OAAO,EAAE;QACP,YAAY,EAAE,OAAO,mBAAmB,CAAC;QACzC,QAAQ,EAAE,OAAO,eAAe,CAAC;QACjC,IAAI,EAAE,OAAO,WAAW,CAAC;KAC1B,CAAC;IACF,UAAU,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACvF,CAAC;AA0BF,8DAA8D;AAC9D,MAAM,MAAM,kBAAkB,CAC5B,KAAK,SAAS,OAAO,EACrB,MAAM,SAAS,QAAQ,GAAG,QAAQ,IAChC,SAAS,CAAC,iBAAiB,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEhD,uEAAuE;AACvE,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,OAAO,EAAE,MAAM,SAAS,QAAQ,GAAG,QAAQ,IAAI,MAAM,CAC7F,iBAAiB,EACjB,KAAK,EACL,MAAM,CACP,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,EAAE,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACnC,CAAC;IACF,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,CAAC;AAEF,KAAK,kBAAkB,CAAC,KAAK,SAAS,OAAO,IAAI;IAC/C,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IACrC,IAAI,EAAE,KAAK,EAAE,CAAC;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,MAAM,CAAC;IAClC,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,mEAAmE;IACnE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC;IACpD,+CAA+C;IAC/C,KAAK,EAAE,eAAe,CAAC;IACvB,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC,mEAAmE;IACnE,UAAU,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IACzC,wEAAwE;IACxE,cAAc,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,gFAAgF;IAChF,OAAO,CAAC,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IACnD,qDAAqD;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,KAAK,CAAC,SAAS,CAAC;IAClE,2GAA2G;IAC3G,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,KAAK,CAAC,SAAS,CAAC;IAClE,mFAAmF;IACnF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC;IACtD;;;;OAIG;IACH,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC;CACxE,CAAC;AAEF,KAAK,eAAe,CAAC,KAAK,SAAS,OAAO,IACtC;IAAE,OAAO,CAAC,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,eAAe,CAAC,EAAE,SAAS,CAAA;CAAE,GAC1E;IACE,yHAAyH;IACzH,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,MAAM,GAAG,IAAI,CAAC;IACvC,yFAAyF;IACzF,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,MAAM,CAAC;IACjC,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,cAAc,CAAC,KAAK,SAAS,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,GAC3E,eAAe,CAAC,KAAK,CAAC,CAAC;AA6DzB,wBAAgB,eAAe,CAAC,KAAK,SAAS,OAAO,EAAE,MAAM,SAAS,QAAQ,GAAG,QAAQ,EACvF,MAAM,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,GACrC,MAAM,CAGR;AAqFD,wBAAgB,SAAS,CAAC,KAAK,SAAS,OAAO,EAAE,EAC/C,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,aAAa,EAAE,sBAAsB,EACrC,UAAU,EACV,OAAO,EACP,MAAM,EACN,iBAAwB,EACxB,OAAuB,EACvB,WAAkB,EAClB,QAAgB,EAChB,OAAO,EACP,OAAO,EACP,QAAQ,EACR,eAAe,EACf,KAAK,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,cAAc,EACd,OAAO,EAAE,eAAe,EACxB,UAAU,EACV,aAA8B,EAC9B,aAA8B,EAC9B,QAAQ,EACR,SAAS,GACV,EAAE,cAAc,CAAC,KAAK,CAAC,qBAkUvB"}
@@ -137,7 +137,7 @@ const defaultRowLink = (props) => _jsx("a", { ...props });
137
137
  function DefaultToolbar({ actions }) {
138
138
  return actions ? _jsx(CollectionToolbar, { label: "", actions: actions }) : null;
139
139
  }
140
- export function DataTable({ columns, data, getRowId, filterColumnId, filterPlaceholder, primaryColumns, compactLayout: requestedCompactLayout, tableLabel, heading, footer, showColumnHeaders = true, density = "comfortable", interactive = true, embedded = false, summary, rowHref, rowLabel, primaryColumnId, empty, noMatchMessage, columnsLabel, clearSearchLabel, pageLabels, toolbarActions, externalFilter, sorting: externalSorting, pagination, renderRowLink = defaultRowLink, renderToolbar = DefaultToolbar, wrapCard, }) {
140
+ export function DataTable({ columns, data, getRowId, filterColumnId, filterPlaceholder, primaryColumns, compactLayout: requestedCompactLayout, tableLabel, heading, footer, showColumnHeaders = true, density = "comfortable", interactive = true, embedded = false, summary, rowHref, rowLabel, primaryColumnId, empty, noMatchMessage, columnsLabel, clearSearchLabel, pageLabels, toolbarActions, externalFilter, sorting: externalSorting, pagination, renderRowLink = defaultRowLink, renderToolbar = DefaultToolbar, wrapCard, rowEditor, }) {
141
141
  const [sorting, setSorting] = React.useState([]);
142
142
  const [columnFilters, setColumnFilters] = React.useState([]);
143
143
  const [columnVisibility, setColumnVisibility] = React.useState({});
@@ -220,7 +220,7 @@ export function DataTable({ columns, data, getRowId, filterColumnId, filterPlace
220
220
  ...(identity ? { onFocus: titleWhenCut, onPointerEnter: titleWhenCut } : {}),
221
221
  children: content,
222
222
  })) : identity ? (_jsx("div", { className: IDENTITY_CONTENT_CLASS, onFocus: titleWhenCut, onPointerEnter: titleWhenCut, children: content })) : prose ? (_jsx("div", { className: PROSE_FRAME_CLASS, children: _jsx("div", { className: PROSE_CONTENT_CLASS, onFocus: titleWhenCut, onPointerEnter: titleWhenCut, children: content }) })) : (content) }, cell.id));
223
- }) }), detailCells.length > 0 && shownLayout !== "columns" ? (_jsx(TableDetailRow, { layout: compactLayout, colSpan: visibleCells.filter((cell) => !collapseClass(cell.column.id, primaryColumns, compactLayout)).length, facts: detailCells.map((cell) => ({
223
+ }) }), rowEditor?.rowId === row.id ? (_jsx(TableRow, { "data-slot": "table-row-editor", className: "in-[tbody]:hover:bg-transparent", children: _jsx(TableCell, { colSpan: visibleCells.length, className: "p-0 whitespace-normal", children: rowEditor.render(row.original) }) })) : null, detailCells.length > 0 && shownLayout !== "columns" ? (_jsx(TableDetailRow, { layout: compactLayout, colSpan: visibleCells.filter((cell) => !collapseClass(cell.column.id, primaryColumns, compactLayout)).length, facts: detailCells.map((cell) => ({
224
224
  id: cell.id,
225
225
  label: columnMenuLabel(cell.column),
226
226
  numeric: isNumericColumn(cell.column),
@@ -1,4 +1,9 @@
1
- import type { FormDrawerProps, FormDrawerFormProps } from "./form-drawer.js";
2
- export declare function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, }: FormDrawerProps): import("react").JSX.Element;
3
- export declare function FormDialogForm({ cancelLabel, submit, notice, children, ...form }: FormDrawerFormProps): import("react").JSX.Element;
1
+ import type { FormSurfaceProps } from "./form-drawer.js";
2
+ import { type FormProps } from "../internal/form-submit.js";
3
+ export type FormDialogProps = FormSurfaceProps & {
4
+ /** Its form's save is running: the dialog stays open until it settles. */
5
+ pending?: boolean;
6
+ };
7
+ export declare function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, pending, }: FormDialogProps): import("react").JSX.Element;
8
+ export declare function FormDialogForm({ cancelLabel, submit, notice, children, ...form }: FormProps): import("react").JSX.Element;
4
9
  //# sourceMappingURL=form-dialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-dialog.d.ts","sourceRoot":"","sources":["../../src/components/form-dialog.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAErF,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,EAAE,eAAe,+BAiBjB;AAED,wBAAgB,cAAc,CAAC,EAC7B,WAAW,EACX,MAAM,EACN,MAAM,EACN,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,mBAAmB,+BA2BrB"}
1
+ {"version":3,"file":"form-dialog.d.ts","sourceRoot":"","sources":["../../src/components/form-dialog.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,wBAAwB,CAAC;AAE1E,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC/C,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,OAAe,GAChB,EAAE,eAAe,+BAuBjB;AAED,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,+BAsB3F"}
@@ -3,11 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Button } from "./button.js";
4
4
  import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "./dialog.js";
5
5
  import { WaitingLine } from "./waiting-line.js";
6
- import { PendingLabel } from "./pending-label.js";
7
- export function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, }) {
8
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(DialogContent, { className: "sm:max-w-lg", closeLabel: closeLabel, initialFocus: initialFocus, finalFocus: finalFocus, children: [_jsxs(DialogHeader, { className: "pr-8", children: [_jsx(DialogTitle, { children: title }), description ? _jsx(DialogDescription, { children: description }) : null] }), children] }) }));
6
+ import { FormSubmitButton } from "../internal/form-submit.js";
7
+ export function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, pending = false, }) {
8
+ return (_jsx(Dialog, { open: open, onOpenChange: (next) => {
9
+ if (next || !pending)
10
+ onOpenChange(next);
11
+ }, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(DialogContent, { className: "sm:max-w-lg", closeLabel: closeLabel, initialFocus: initialFocus, finalFocus: finalFocus, children: [_jsxs(DialogHeader, { className: "pr-8", children: [_jsx(DialogTitle, { children: title }), description ? _jsx(DialogDescription, { children: description }) : null] }), children] }) }));
9
12
  }
10
13
  export function FormDialogForm({ cancelLabel, submit, notice, children, ...form }) {
11
14
  const pending = submit.pending === true;
12
- return (_jsxs("form", { className: "flex min-h-0 flex-col gap-6", "aria-busy": pending || undefined, ...form, children: [_jsx(DialogBody, { children: children }), notice, _jsxs(DialogFooter, { className: "relative", children: [_jsx(DialogClose, { disabled: pending, render: _jsx(Button, { type: "button", variant: "outline" }), children: cancelLabel }), _jsx(Button, { "aria-busy": pending || undefined, "aria-describedby": submit.describedBy, disabled: pending || submit.disabled, type: "submit", variant: submit.destructive ? "destructive" : "default", children: _jsx(PendingLabel, { pending: pending, pendingLabel: submit.pendingLabel ?? submit.label, children: submit.label }) }), pending ? (_jsx(WaitingLine, { className: "absolute inset-x-nadicode-lg bottom-1 w-auto", decorative: true })) : null] })] }));
15
+ return (_jsxs("form", { className: "flex min-h-0 flex-col gap-6", "aria-busy": pending || undefined, "data-slot": "form-dialog-form", ...form, children: [_jsx(DialogBody, { children: children }), notice, _jsxs(DialogFooter, { className: "relative", children: [_jsx(DialogClose, { disabled: pending, render: _jsx(Button, { type: "button", variant: "outline" }), children: cancelLabel }), _jsx(FormSubmitButton, { submit: submit }), pending ? (_jsx(WaitingLine, { className: "absolute inset-x-nadicode-lg bottom-1 w-auto", decorative: true })) : null] })] }));
13
16
  }
@@ -1,6 +1,9 @@
1
1
  import type { ComponentProps, ReactNode } from "react";
2
2
  import { SheetContent } from "./sheet.js";
3
- export type FormDrawerProps = {
3
+ import { type FormProps } from "../internal/form-submit.js";
4
+ export type { FormProps, FormSubmit } from "../internal/form-submit.js";
5
+ /** What a form surface is told by its caller, whether it draws a drawer or a dialog. */
6
+ export type FormSurfaceProps = {
4
7
  open: boolean;
5
8
  onOpenChange: (open: boolean) => void;
6
9
  /** Runs once the drawer has finished opening or closing, such as to return focus. */
@@ -17,7 +20,16 @@ export type FormDrawerProps = {
17
20
  /** Where focus returns when the drawer closes, when its opener is gone. */
18
21
  finalFocus?: ComponentProps<typeof SheetContent>["finalFocus"];
19
22
  };
20
- /** A substantial workflow whose fields need a separate scrolling working surface. */
23
+ export type FormDrawerProps = FormSurfaceProps & {
24
+ /**
25
+ * Why this is a drawer and not a dialog: "catalog" chooses from a list too
26
+ * long for a dialog, "steps" sets something up over several steps, with a
27
+ * wait. A form of a few fields is a `FormDialog`, and a record already on
28
+ * screen edits inside its row.
29
+ */
30
+ job: "catalog" | "steps";
31
+ };
32
+ /** The right-side drawer for a catalog or a setup in steps, at one width. */
21
33
  export declare function FormDrawer({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, }: FormDrawerProps): import("react").JSX.Element;
22
34
  /** The part of the drawer that scrolls between its title and its footer. */
23
35
  export declare function FormDrawerBody({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
@@ -32,29 +44,10 @@ export type FormDrawerFooterProps = {
32
44
  };
33
45
  /** The footer that stays in place under the body: Cancel, then the actions, right-aligned. */
34
46
  export declare function FormDrawerFooter({ cancel, children }: FormDrawerFooterProps): import("react").JSX.Element;
35
- export type FormDrawerSubmit = {
36
- label: string;
37
- /** The button's own word while the save runs. */
38
- pendingLabel?: string;
39
- /** The save is running: the button says so and holds, and the waiting line follows. */
40
- pending?: boolean;
41
- /** Nothing to save yet, or a field still needs an answer. */
42
- disabled?: boolean;
43
- destructive?: boolean;
44
- /** The id of the line that says why the save cannot run yet. */
45
- describedBy?: string;
46
- };
47
- export type FormDrawerFormProps = Omit<ComponentProps<"form">, "children" | "className"> & {
48
- cancelLabel: string;
49
- submit: FormDrawerSubmit;
50
- /** A refusal or a failure of the save, between the body and the footer, where the button is. */
51
- notice?: ReactNode;
52
- children: ReactNode;
53
- };
54
47
  /**
55
48
  * The drawer's form: the fields in the body, a notice where the save button
56
49
  * is, and the footer with Cancel and the save rightmost. Cancel holds while the
57
50
  * save runs, so a running save is never left without its drawer.
58
51
  */
59
- export declare function FormDrawerForm({ cancelLabel, submit, notice, children, ...form }: FormDrawerFormProps): import("react").JSX.Element;
52
+ export declare function FormDrawerForm({ cancelLabel, submit, notice, children, ...form }: FormProps): import("react").JSX.Element;
60
53
  //# sourceMappingURL=form-drawer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-drawer.d.ts","sourceRoot":"","sources":["../../src/components/form-drawer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvD,OAAO,EAGL,YAAY,EAKb,MAAM,oBAAoB,CAAC;AAI5B,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,6FAA6F;IAC7F,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,QAAQ,EAAE,SAAS,CAAC;IACpB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC,cAAc,CAAC,CAAC;IACnE,2EAA2E;IAC3E,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC;CAChE,CAAC;AAEF,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,EAAE,eAAe,+BAkBjB;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAW5E;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,+DAA+D;IAC/D,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,qBAAqB,+BAc3E;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IACzF,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,gGAAgG;IAChG,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,WAAW,EACX,MAAM,EACN,MAAM,EACN,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,mBAAmB,+BA+BrB"}
1
+ {"version":3,"file":"form-drawer.d.ts","sourceRoot":"","sources":["../../src/components/form-drawer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvD,OAAO,EAGL,YAAY,EAKb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,wBAAwB,CAAC;AAG1E,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpE,wFAAwF;AACxF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,6FAA6F;IAC7F,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,QAAQ,EAAE,SAAS,CAAC;IACpB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC,cAAc,CAAC,CAAC;IACnE,2EAA2E;IAC3E,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC;CAChE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC/C;;;;;OAKG;IACH,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,EAAE,eAAe,+BAkBjB;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAW5E;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,+DAA+D;IAC/D,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,qBAAqB,+BAc3E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,+BAqB3F"}
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Button } from "./button.js";
4
- import { PendingLabel } from "./pending-label.js";
5
4
  import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "./sheet.js";
6
5
  import { WaitingLine } from "./waiting-line.js";
6
+ import { FormSubmitButton } from "../internal/form-submit.js";
7
7
  import { cn } from "../lib/utils.js";
8
- /** A substantial workflow whose fields need a separate scrolling working surface. */
8
+ /** The right-side drawer for a catalog or a setup in steps, at one width. */
9
9
  export function FormDrawer({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, }) {
10
- return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(SheetContent, { className: "max-sm:data-[side=right]:left-nadicode-sm max-sm:data-[side=right]:w-auto", closeLabel: closeLabel, finalFocus: finalFocus, initialFocus: initialFocus, side: "right", children: [_jsxs(SheetHeader, { className: "pr-12", children: [_jsx(SheetTitle, { className: "break-words", children: title }), description ? _jsx(SheetDescription, { children: description }) : null] }), children] }) }));
10
+ return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(SheetContent, { className: "max-sm:data-[side=right]:left-nadicode-sm max-sm:data-[side=right]:w-auto data-[side=right]:sm:w-[560px] data-[side=right]:sm:max-w-[calc(100%-var(--nc-lg))]", closeLabel: closeLabel, finalFocus: finalFocus, initialFocus: initialFocus, side: "right", children: [_jsxs(SheetHeader, { className: "pr-12", children: [_jsx(SheetTitle, { className: "break-words", children: title }), description ? _jsx(SheetDescription, { children: description }) : null] }), children] }) }));
11
11
  }
12
12
  /** The part of the drawer that scrolls between its title and its footer. */
13
13
  export function FormDrawerBody({ className, ...props }) {
@@ -24,5 +24,5 @@ export function FormDrawerFooter({ cancel, children }) {
24
24
  */
25
25
  export function FormDrawerForm({ cancelLabel, submit, notice, children, ...form }) {
26
26
  const pending = submit.pending === true;
27
- return (_jsxs("form", { "aria-busy": pending || undefined, className: "flex min-h-0 flex-1 flex-col", "data-slot": "form-drawer-form", ...form, children: [_jsx(FormDrawerBody, { children: children }), notice ? (_jsx("div", { className: "px-nadicode-lg pt-nadicode-md", "data-slot": "form-drawer-notice", children: notice })) : null, _jsxs(FormDrawerFooter, { cancel: { label: cancelLabel, disabled: pending }, children: [_jsx(Button, { "aria-busy": pending || undefined, "aria-describedby": submit.describedBy, disabled: pending || submit.disabled, type: "submit", variant: submit.destructive ? "destructive" : "default", children: _jsx(PendingLabel, { pending: pending, pendingLabel: submit.pendingLabel ?? submit.label, children: submit.label }) }), pending ? _jsx(WaitingLine, { className: "basis-full", decorative: true }) : null] })] }));
27
+ return (_jsxs("form", { "aria-busy": pending || undefined, className: "flex min-h-0 flex-1 flex-col", "data-slot": "form-drawer-form", ...form, children: [_jsx(FormDrawerBody, { children: children }), notice ? (_jsx("div", { className: "px-nadicode-lg pt-nadicode-md", "data-slot": "form-drawer-notice", children: notice })) : null, _jsxs(FormDrawerFooter, { cancel: { label: cancelLabel, disabled: pending }, children: [_jsx(FormSubmitButton, { submit: submit }), pending ? _jsx(WaitingLine, { className: "basis-full", decorative: true }) : null] })] }));
28
28
  }
@@ -1,8 +1,18 @@
1
1
  import type { ReactNode } from "react";
2
- declare function RecordIdentity({ name, mark, hint }: {
3
- name: string;
2
+ /**
3
+ * A record's identity in a row (DESIGN.md "Tables and missing values"): its
4
+ * mark, its name, and under it one muted `detail` line saying what the record
5
+ * is or where it comes from, so the row reads without a column heading. The
6
+ * name holds one line and ends in an ellipsis, whole in its title, unless it
7
+ * is the record's whole text, such as a memory, which `wraps` in full.
8
+ */
9
+ declare function RecordIdentity({ name, mark, hint, detail, wraps, }: {
10
+ name: ReactNode;
4
11
  mark?: ReactNode;
12
+ /** Read after the name in its title, such as an identifier the row does not show. */
5
13
  hint?: string;
14
+ detail?: ReactNode;
15
+ wraps?: boolean;
6
16
  }): import("react").JSX.Element;
7
17
  export { RecordIdentity };
8
18
  //# sourceMappingURL=record-identity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"record-identity.d.ts","sourceRoot":"","sources":["../../src/components/record-identity.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,iBAAS,cAAc,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BAS9F;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"record-identity.d.ts","sourceRoot":"","sources":["../../src/components/record-identity.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;;;;GAMG;AACH,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,KAAa,GACd,EAAE;IACD,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,+BA0BA;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -1,5 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- function RecordIdentity({ name, mark, hint }) {
3
- return (_jsxs("span", { className: "flex min-w-0 items-center gap-2.5", "data-slot": "record-identity", children: [mark, _jsx("span", { className: "min-w-0 truncate font-medium", title: hint ? `${name} · ${hint}` : name, children: name })] }));
2
+ import { cn } from "../lib/utils.js";
3
+ /**
4
+ * A record's identity in a row (DESIGN.md "Tables and missing values"): its
5
+ * mark, its name, and under it one muted `detail` line saying what the record
6
+ * is or where it comes from, so the row reads without a column heading. The
7
+ * name holds one line and ends in an ellipsis, whole in its title, unless it
8
+ * is the record's whole text, such as a memory, which `wraps` in full.
9
+ */
10
+ function RecordIdentity({ name, mark, hint, detail, wraps = false, }) {
11
+ const title = typeof name === "string" ? (hint ? `${name} · ${hint}` : name) : undefined;
12
+ return (_jsxs("span", { className: "flex min-w-0 items-center gap-2.5", "data-slot": "record-identity", children: [mark, _jsxs("span", { className: "grid min-w-0", children: [_jsx("span", { className: cn("min-w-0 font-medium", wraps ? "break-words whitespace-pre-wrap" : "truncate"), title: wraps ? undefined : title, children: name }), detail ? (_jsx("span", { className: "text-xs break-words text-muted-foreground", "data-slot": "record-identity-detail", children: detail })) : null] })] }));
4
13
  }
5
14
  export { RecordIdentity };
@@ -0,0 +1,25 @@
1
+ export type RecordTimeProps = {
2
+ /** When it happened. */
3
+ at: Date | number | string;
4
+ /**
5
+ * The sentence the time sits in, which says what happened:
6
+ * `(when) => t("skills.updated", { when })` gives "Updated 3 hours ago".
7
+ */
8
+ phrase: (when: string) => string;
9
+ /** The person's language; the runtime's when left out. */
10
+ locale?: string;
11
+ /** The current time, for a reading that must not drift while it renders. */
12
+ now?: number;
13
+ };
14
+ /** "3 hours ago" within a week, then "12 Sep", with the year when it is not this year. */
15
+ export declare function formatRecordTime(at: Date, locale?: string, now?: number): string;
16
+ /** The moment `at` names, or null when it names none, such as an empty or malformed time. */
17
+ export declare function recordDate(at: Date | number | string | null | undefined): Date | null;
18
+ /**
19
+ * When something happened to a record, in the sentence that says what
20
+ * (DESIGN.md "Complete compositions", relative timestamp preview): hovering it
21
+ * shows the exact moment in the person's time and in UTC, as Vercel's
22
+ * dashboard does, and assistive technology reads the exact moment with it.
23
+ */
24
+ export declare function RecordTime({ at, phrase, locale, now }: RecordTimeProps): import("react").JSX.Element | null;
25
+ //# sourceMappingURL=record-time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-time.d.ts","sourceRoot":"","sources":["../../src/components/record-time.tsx"],"names":[],"mappings":"AAWA,MAAM,MAAM,eAAe,GAAG;IAC5B,wBAAwB;IACxB,EAAE,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC3B;;;OAGG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM,CAepF;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,EAAE,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,CAIrF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,eAAe,sCAwCtE"}
@@ -0,0 +1,52 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from "./hover-card.js";
3
+ const DAY = 86_400_000;
4
+ const WEEK = 7 * DAY;
5
+ const UNITS = [
6
+ ["day", DAY],
7
+ ["hour", 3_600_000],
8
+ ["minute", 60_000],
9
+ ];
10
+ /** "3 hours ago" within a week, then "12 Sep", with the year when it is not this year. */
11
+ export function formatRecordTime(at, locale, now = Date.now()) {
12
+ const elapsed = now - at.getTime();
13
+ if (elapsed >= 0 && elapsed < WEEK) {
14
+ const relative = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
15
+ for (const [unit, size] of UNITS) {
16
+ if (elapsed >= size)
17
+ return relative.format(-Math.floor(elapsed / size), unit);
18
+ }
19
+ return relative.format(0, "minute");
20
+ }
21
+ const sameYear = at.getFullYear() === new Date(now).getFullYear();
22
+ return new Intl.DateTimeFormat(locale, {
23
+ day: "numeric",
24
+ month: "short",
25
+ ...(sameYear ? {} : { year: "numeric" }),
26
+ }).format(at);
27
+ }
28
+ /** The moment `at` names, or null when it names none, such as an empty or malformed time. */
29
+ export function recordDate(at) {
30
+ if (at == null)
31
+ return null;
32
+ const date = at instanceof Date ? at : new Date(at);
33
+ return Number.isNaN(date.getTime()) ? null : date;
34
+ }
35
+ /**
36
+ * When something happened to a record, in the sentence that says what
37
+ * (DESIGN.md "Complete compositions", relative timestamp preview): hovering it
38
+ * shows the exact moment in the person's time and in UTC, as Vercel's
39
+ * dashboard does, and assistive technology reads the exact moment with it.
40
+ */
41
+ export function RecordTime({ at, phrase, locale, now }) {
42
+ const date = recordDate(at);
43
+ if (!date)
44
+ return null;
45
+ const local = new Intl.DateTimeFormat(locale, { dateStyle: "long", timeStyle: "medium" }).format(date);
46
+ const utc = new Intl.DateTimeFormat(locale, {
47
+ dateStyle: "long",
48
+ timeStyle: "medium",
49
+ timeZone: "UTC",
50
+ }).format(date);
51
+ return (_jsxs(HoverCard, { children: [_jsxs(HoverCardTrigger, { render: _jsx("time", { className: "whitespace-nowrap text-muted-foreground", "data-slot": "record-time", dateTime: date.toISOString() }), children: [phrase(formatRecordTime(date, locale, now)), _jsxs("span", { className: "sr-only", children: [", ", local] })] }), _jsx(HoverCardContent, { className: "w-auto", children: _jsxs("dl", { className: "grid grid-cols-[auto_auto] gap-x-4 gap-y-1 text-xs", "data-slot": "record-time-exact", children: [_jsx("dt", { className: "text-muted-foreground", children: "UTC" }), _jsx("dd", { className: "tabular-nums", children: utc }), _jsx("dt", { className: "text-muted-foreground", children: Intl.DateTimeFormat(locale).resolvedOptions().timeZone }), _jsx("dd", { className: "tabular-nums", children: local })] }) })] }));
52
+ }
@@ -0,0 +1,22 @@
1
+ import type { ComponentProps, ReactNode } from "react";
2
+ import { type FormSubmit } from "../internal/form-submit.js";
3
+ export type RowEditFormProps = Omit<ComponentProps<"form">, "children" | "className"> & {
4
+ cancelLabel: string;
5
+ /** Closes the form and keeps the record as it was. */
6
+ onCancel: () => void;
7
+ submit: FormSubmit;
8
+ /** A refusal or a failure of the save, above the footer, where the button is. */
9
+ notice?: ReactNode;
10
+ /** A way on beside the actions, such as where to find a token, at the footer's leading edge. */
11
+ hint?: ReactNode;
12
+ children: ReactNode;
13
+ };
14
+ /**
15
+ * A record's form opened inside its own row (DESIGN.md "Menus and commands"),
16
+ * a `DataTable`'s `rowEditor`: the fields under the record's line, then a
17
+ * footer one tone below with an optional hint at its leading edge, then Cancel
18
+ * and the save rightmost. Cancel holds while
19
+ * the save runs.
20
+ */
21
+ export declare function RowEditForm({ cancelLabel, onCancel, submit, notice, hint, children, ...form }: RowEditFormProps): import("react").JSX.Element;
22
+ //# sourceMappingURL=row-edit-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"row-edit-form.d.ts","sourceRoot":"","sources":["../../src/components/row-edit-form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvD,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,wBAAwB,CAAC;AAE3E,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IACtF,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,iFAAiF;IACjF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,gGAAgG;IAChG,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAC1B,WAAW,EACX,QAAQ,EACR,MAAM,EACN,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,gBAAgB,+BAqBlB"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button } from "./button.js";
4
+ import { WaitingLine } from "./waiting-line.js";
5
+ import { FormSubmitButton } from "../internal/form-submit.js";
6
+ /**
7
+ * A record's form opened inside its own row (DESIGN.md "Menus and commands"),
8
+ * a `DataTable`'s `rowEditor`: the fields under the record's line, then a
9
+ * footer one tone below with an optional hint at its leading edge, then Cancel
10
+ * and the save rightmost. Cancel holds while
11
+ * the save runs.
12
+ */
13
+ export function RowEditForm({ cancelLabel, onCancel, submit, notice, hint, children, ...form }) {
14
+ const pending = submit.pending === true;
15
+ return (_jsxs("form", { "aria-busy": pending || undefined, "data-slot": "row-edit-form", ...form, children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)] gap-4 px-nadicode-md pt-nadicode-sm pb-nadicode-md", children: [children, notice ? _jsx("div", { "data-slot": "row-edit-form-notice", children: notice }) : null] }), _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-3 border-t border-border bg-recessed px-nadicode-md py-3", "data-slot": "row-edit-form-footer", children: [hint ? _jsx("div", { className: "mr-auto min-w-0", children: hint }) : null, _jsx(Button, { disabled: pending, onClick: onCancel, type: "button", variant: "outline", children: cancelLabel }), _jsx(FormSubmitButton, { submit: submit }), pending ? _jsx(WaitingLine, { className: "basis-full", decorative: true }) : null] })] }));
16
+ }
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { mergeProps } from "@base-ui/react/merge-props";
5
5
  import { useRender } from "@base-ui/react/use-render";
6
6
  import { cva } from "class-variance-authority";
7
- import { useIsMobile } from "../hooks/use-mobile.js";
7
+ import { isMobileNow, useIsMobile } from "../hooks/use-mobile.js";
8
8
  import { cn } from "../lib/utils.js";
9
9
  import { Button } from "./button.js";
10
10
  import { Input } from "./input.js";
@@ -49,8 +49,8 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: set
49
49
  }, [setOpenProp, open, passive]);
50
50
  // Helper to toggle the sidebar.
51
51
  const toggleSidebar = React.useCallback(() => {
52
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
53
- }, [isMobile, setOpen, setOpenMobile]);
52
+ return mobileSheet && isMobileNow() ? setOpenMobile((open) => !open) : setOpen((open) => !open);
53
+ }, [mobileSheet, setOpen, setOpenMobile]);
54
54
  // Adds a keyboard shortcut to toggle the sidebar.
55
55
  React.useEffect(() => {
56
56
  if (passive)
@@ -1 +1 @@
1
- {"version":3,"file":"theme-mode-switcher.d.ts","sourceRoot":"","sources":["../../src/components/theme-mode-switcher.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,UAAU,EAAkB,MAAM,0BAA0B,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AACnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAE9D,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,KAAK,CAAC,cAAc,CAAC,OAAO,UAAU,CAAC,EACvC,UAAU,GAAG,cAAc,GAAG,eAAe,GAAG,OAAO,CACxD,GAAG;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1D,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAQF,iBAAS,iBAAiB,CAAC,EACzB,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,OAAe,EACf,QAAQ,EACR,aAAa,EACb,MAAM,EACN,aAAa,EACb,UAAU,EACV,KAAK,EACL,GAAG,KAAK,EACT,EAAE,sBAAsB,qBAkDxB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,KAAK,EACL,aAAa,EACb,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,qBAkBA"}
1
+ {"version":3,"file":"theme-mode-switcher.d.ts","sourceRoot":"","sources":["../../src/components/theme-mode-switcher.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,UAAU,EAAkB,MAAM,0BAA0B,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AACnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAE9D,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,KAAK,CAAC,cAAc,CAAC,OAAO,UAAU,CAAC,EACvC,UAAU,GAAG,cAAc,GAAG,eAAe,GAAG,OAAO,CACxD,GAAG;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1D,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAQF,iBAAS,iBAAiB,CAAC,EACzB,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,OAAe,EACf,QAAQ,EACR,aAAa,EACb,MAAM,EACN,aAAa,EACb,UAAU,EACV,KAAK,EACL,GAAG,KAAK,EACT,EAAE,sBAAsB,qBA6CxB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,KAAK,EACL,aAAa,EACb,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,qBAkBA"}
@@ -13,7 +13,7 @@ const themeModeIcons = {
13
13
  system: MonitorIcon,
14
14
  };
15
15
  function ThemeModeSwitcher({ "aria-label": ariaLabel, className, compact = false, disabled, itemClassName, labels, onValueChange, renderItem, value, ...props }) {
16
- return (_jsx(RadioGroup, { "aria-label": ariaLabel, className: cn("max-w-full", className), disabled: disabled, onValueChange: (nextMode) => {
16
+ return (_jsx(RadioGroup, { "aria-label": ariaLabel, className: cn("max-w-full grid-cols-3", className), disabled: disabled, onValueChange: (nextMode) => {
17
17
  if (isThemeMode(nextMode)) {
18
18
  onValueChange(nextMode);
19
19
  }
@@ -21,13 +21,7 @@ function ThemeModeSwitcher({ "aria-label": ariaLabel, className, compact = false
21
21
  const Icon = themeModeIcons[mode];
22
22
  const label = labels[mode];
23
23
  const selected = value === mode;
24
- return (_jsx(RadioGroupItem, { "aria-label": label, className: cn(toggleVariants({ variant: "outline" }),
25
- // The selected tile takes the muted interaction surface the
26
- // toggle uses for its own on-state, so it takes that surface's
27
- // foreground with it. Left on the radio primitive's on-primary
28
- // foreground, the selected label reads white on near-white in
29
- // light and black on black in dark.
30
- "aspect-auto w-auto gap-1.5 data-checked:bg-muted data-checked:text-foreground", compact && "text-xs", itemClassName), disabled: disabled, value: mode, children: renderItem ? (renderItem({ Icon, label, mode, selected })) : (_jsxs(_Fragment, { children: [_jsx(Icon, { "aria-hidden": "true", "data-icon": true }), _jsx("span", { className: "min-w-0 truncate", children: label })] })) }, mode));
24
+ return (_jsx(RadioGroupItem, { "aria-label": label, className: cn(toggleVariants({ variant: "outline" }), "aspect-auto w-auto min-w-0 gap-1.5 data-checked:border-transparent data-checked:bg-selection data-checked:text-selection-foreground", compact && "text-xs", itemClassName), disabled: disabled, value: mode, children: renderItem ? (renderItem({ Icon, label, mode, selected })) : (_jsxs(_Fragment, { children: [_jsx(Icon, { "aria-hidden": "true", "data-icon": true }), _jsx("span", { className: "min-w-0 truncate", children: label })] })) }, mode));
31
25
  }) }));
32
26
  }
33
27
  export { ThemeModeSwitcher };
@@ -1,2 +1,4 @@
1
+ /** Whether the window is under the mobile breakpoint at the moment of asking, whatever the page last drew. */
2
+ export declare const isMobileNow: () => boolean;
1
3
  export declare function useIsMobile(): boolean;
2
4
  //# sourceMappingURL=use-mobile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-mobile.d.ts","sourceRoot":"","sources":["../../src/hooks/use-mobile.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,YAc1B"}
1
+ {"version":3,"file":"use-mobile.d.ts","sourceRoot":"","sources":["../../src/hooks/use-mobile.ts"],"names":[],"mappings":"AAUA,8GAA8G;AAC9G,eAAO,MAAM,WAAW,eAA8C,CAAC;AAGvE,wBAAgB,WAAW,YAE1B"}
@@ -1,15 +1,13 @@
1
1
  import * as React from "react";
2
2
  const MOBILE_BREAKPOINT = 768;
3
+ function subscribe(onChange) {
4
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
5
+ mql.addEventListener("change", onChange);
6
+ return () => mql.removeEventListener("change", onChange);
7
+ }
8
+ /** Whether the window is under the mobile breakpoint at the moment of asking, whatever the page last drew. */
9
+ export const isMobileNow = () => window.innerWidth < MOBILE_BREAKPOINT;
10
+ const onServer = () => false;
3
11
  export function useIsMobile() {
4
- const [isMobile, setIsMobile] = React.useState(undefined);
5
- React.useEffect(() => {
6
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
7
- const onChange = () => {
8
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
9
- };
10
- mql.addEventListener("change", onChange);
11
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
12
- return () => mql.removeEventListener("change", onChange);
13
- }, []);
14
- return !!isMobile;
12
+ return React.useSyncExternalStore(subscribe, isMobileNow, onServer);
15
13
  }
package/dist/index.d.ts CHANGED
@@ -41,6 +41,7 @@ export * from "./components/checkbox.js";
41
41
  export * from "./components/code-block.js";
42
42
  export * from "./components/collapsible.js";
43
43
  export * from "./components/collection-filters.js";
44
+ export * from "./components/collection-page.js";
44
45
  export * from "./components/collection-search.js";
45
46
  export * from "./components/collection-sort.js";
46
47
  export * from "./components/collection-toolbar.js";
@@ -110,7 +111,9 @@ export * from "./components/qr-code.js";
110
111
  export * from "./components/radio-group.js";
111
112
  export * from "./components/reading-column.js";
112
113
  export * from "./components/record-identity.js";
114
+ export * from "./components/record-time.js";
113
115
  export * from "./components/resizable.js";
116
+ export * from "./components/row-edit-form.js";
114
117
  export * from "./components/run-timeline.js";
115
118
  export * from "./components/scope-switcher.js";
116
119
  export * from "./components/scroll-area.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ export * from "./components/checkbox.js";
41
41
  export * from "./components/code-block.js";
42
42
  export * from "./components/collapsible.js";
43
43
  export * from "./components/collection-filters.js";
44
+ export * from "./components/collection-page.js";
44
45
  export * from "./components/collection-search.js";
45
46
  export * from "./components/collection-sort.js";
46
47
  export * from "./components/collection-toolbar.js";
@@ -110,7 +111,9 @@ export * from "./components/qr-code.js";
110
111
  export * from "./components/radio-group.js";
111
112
  export * from "./components/reading-column.js";
112
113
  export * from "./components/record-identity.js";
114
+ export * from "./components/record-time.js";
113
115
  export * from "./components/resizable.js";
116
+ export * from "./components/row-edit-form.js";
114
117
  export * from "./components/run-timeline.js";
115
118
  export * from "./components/scope-switcher.js";
116
119
  export * from "./components/scroll-area.js";
@@ -0,0 +1,25 @@
1
+ import type { ComponentProps, ReactNode } from "react";
2
+ /** The save of a drawer's, a dialog's or a row's form. */
3
+ export type FormSubmit = {
4
+ label: string;
5
+ /** The button's own word while the save runs. */
6
+ pendingLabel?: string;
7
+ /** The save is running: the button says so and holds, and the waiting line follows. */
8
+ pending?: boolean;
9
+ /** Nothing to save yet, or a field still needs an answer. */
10
+ disabled?: boolean;
11
+ destructive?: boolean;
12
+ /** The id of the line that says why the save cannot run yet. */
13
+ describedBy?: string;
14
+ };
15
+ export type FormProps = Omit<ComponentProps<"form">, "children" | "className"> & {
16
+ cancelLabel: string;
17
+ submit: FormSubmit;
18
+ /** A refusal or a failure of the save, above the footer, where the button is. */
19
+ notice?: ReactNode;
20
+ children: ReactNode;
21
+ };
22
+ export declare function FormSubmitButton({ submit }: {
23
+ submit: FormSubmit;
24
+ }): import("react").JSX.Element;
25
+ //# sourceMappingURL=form-submit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-submit.d.ts","sourceRoot":"","sources":["../../src/internal/form-submit.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvD,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,iFAAiF;IACjF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,+BAelE"}
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Button } from "../components/button.js";
4
+ import { PendingLabel } from "../components/pending-label.js";
5
+ export function FormSubmitButton({ submit }) {
6
+ const pending = submit.pending === true;
7
+ return (_jsx(Button, { "aria-busy": pending || undefined, "aria-describedby": submit.describedBy, disabled: pending || submit.disabled, type: "submit", variant: submit.destructive ? "destructive" : "default", children: _jsx(PendingLabel, { pending: pending, pendingLabel: submit.pendingLabel ?? submit.label, children: submit.label }) }));
8
+ }
@@ -0,0 +1,18 @@
1
+ import { type ResolvedMessage } from "../components/product-message.js";
2
+ /**
3
+ * A record's own action that failed or cannot run, drawn inside its row
4
+ * (DESIGN.md "Tables and missing values"): the message takes the line under
5
+ * the record's name and its actions take the row's controls.
6
+ */
7
+ export type RowMessage = {
8
+ kind: "failed" | "refused";
9
+ message: ResolvedMessage;
10
+ };
11
+ export declare function RowMessageLine({ state }: {
12
+ state: RowMessage;
13
+ }): import("react").JSX.Element;
14
+ /** The message's next steps, laid out by the row's own controls beside its commands. */
15
+ export declare function RowMessageActions({ state }: {
16
+ state: RowMessage;
17
+ }): import("react").JSX.Element[];
18
+ //# sourceMappingURL=row-message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"row-message.d.ts","sourceRoot":"","sources":["../../src/internal/row-message.tsx"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAGrF;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAElF,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,+BAY9D;AAED,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,iCAIjE"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PageCommandButton } from "../components/page-actions.js";
3
+ import { bodyBeyondTitle } from "../components/product-message.js";
4
+ import { cn } from "../lib/utils.js";
5
+ export function RowMessageLine({ state }) {
6
+ const body = bodyBeyondTitle(state.message);
7
+ return (_jsxs("span", { className: cn(state.kind === "failed" && "text-destructive"), "data-slot": "row-message", role: state.kind === "failed" ? "alert" : undefined, children: [_jsx("span", { children: state.message.title }), body ? _jsxs("span", { children: [" ", body] }) : null] }));
8
+ }
9
+ /** The message's next steps, laid out by the row's own controls beside its commands. */
10
+ export function RowMessageActions({ state }) {
11
+ return state.message.actions.map((action) => (_jsx(PageCommandButton, { command: action, variant: "outline" }, action.label)));
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "12.1.89",
3
+ "version": "12.1.91",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -75,7 +75,7 @@
75
75
  "@base-ui/react": "^1.9.0",
76
76
  "@iconify-icons/logos": "^2.0.2",
77
77
  "@iconify/react": "^6.0.2",
78
- "@nadicodeai/design-system": "12.1.89",
78
+ "@nadicodeai/design-system": "12.1.91",
79
79
  "@tanstack/react-table": "^9.2.8",
80
80
  "class-variance-authority": "^0.7.1",
81
81
  "clsx": "^2.1.1",