@photon-ai/pho-ui 4.11.0 → 4.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/chunks/animated-height-zr7BmFY1.js +56 -0
  2. package/dist/chunks/animated-height-zr7BmFY1.js.map +1 -0
  3. package/dist/chunks/basic-page-6dDfY33L.js +2197 -0
  4. package/dist/chunks/basic-page-6dDfY33L.js.map +1 -0
  5. package/dist/chunks/box-search-C9EVZgcb.js +56 -0
  6. package/dist/chunks/box-search-C9EVZgcb.js.map +1 -0
  7. package/dist/chunks/{chat-B0WIgEyM.js → chat-Bu8UyIbT.js} +207 -205
  8. package/dist/chunks/chat-Bu8UyIbT.js.map +1 -0
  9. package/dist/chunks/{checkbox-CLPmblNA.js → checkbox-CwvoEJhd.js} +2 -2
  10. package/dist/chunks/{checkbox-CLPmblNA.js.map → checkbox-CwvoEJhd.js.map} +1 -1
  11. package/dist/chunks/choice-card-_Ocs0iUj.js +17 -0
  12. package/dist/chunks/choice-card-_Ocs0iUj.js.map +1 -0
  13. package/dist/chunks/chrome-Ds7WykBJ.js +14 -0
  14. package/dist/chunks/chrome-Ds7WykBJ.js.map +1 -0
  15. package/dist/chunks/{command-iYvU6Mhf.js → command-D5g49VqR.js} +3 -3
  16. package/dist/chunks/{command-iYvU6Mhf.js.map → command-D5g49VqR.js.map} +1 -1
  17. package/dist/chunks/{data-table-B1dmrN6r.js → data-table-hzZb7Otx.js} +58 -56
  18. package/dist/chunks/{data-table-B1dmrN6r.js.map → data-table-hzZb7Otx.js.map} +1 -1
  19. package/dist/chunks/{dialog-MPvem7yV.js → dialog-ChS0tdHa.js} +120 -116
  20. package/dist/chunks/dialog-ChS0tdHa.js.map +1 -0
  21. package/dist/chunks/{filter-bar-B-oYYBsU.js → filter-bar-C4sPEjw1.js} +63 -66
  22. package/dist/chunks/filter-bar-C4sPEjw1.js.map +1 -0
  23. package/dist/chunks/ghost-search-8PzP73zS.js +50 -0
  24. package/dist/chunks/ghost-search-8PzP73zS.js.map +1 -0
  25. package/dist/chunks/{input-DjvZoF8v.js → input-fFWvPJOf.js} +2 -1
  26. package/dist/chunks/{input-DjvZoF8v.js.map → input-fFWvPJOf.js.map} +1 -1
  27. package/dist/chunks/{trace-D1fOFzJt.js → trace-DyjsBY-S.js} +15 -13
  28. package/dist/chunks/{trace-D1fOFzJt.js.map → trace-DyjsBY-S.js.map} +1 -1
  29. package/dist/components/chat.js +1 -1
  30. package/dist/components/checkbox.js +1 -1
  31. package/dist/components/command.js +1 -1
  32. package/dist/components/data-table.js +4 -3
  33. package/dist/components/dialog.js +1 -1
  34. package/dist/components/field.js +34 -29
  35. package/dist/components/field.js.map +1 -1
  36. package/dist/components/filter-bar.js +1 -1
  37. package/dist/components/input.js +1 -1
  38. package/dist/components/radio-group.js +64 -59
  39. package/dist/components/radio-group.js.map +1 -1
  40. package/dist/components/scope.js +418 -0
  41. package/dist/components/scope.js.map +1 -0
  42. package/dist/components/trace.js +1 -1
  43. package/dist/index.js +176 -175
  44. package/dist/motion.js +61 -36
  45. package/dist/motion.js.map +1 -1
  46. package/dist/sections/basic-page.js +2 -2
  47. package/dist/src/components/chat/chat.d.ts +7 -4
  48. package/dist/src/components/dialog/dialog.d.ts +9 -1
  49. package/dist/src/components/field/field.d.ts +11 -1
  50. package/dist/src/components/input-group/box-search.d.ts +29 -0
  51. package/dist/src/components/radio-group/radio-card.d.ts +11 -4
  52. package/dist/src/components/scope/index.d.ts +1 -0
  53. package/dist/src/components/scope/scope.d.ts +98 -0
  54. package/dist/src/motion/index.d.ts +52 -0
  55. package/dist/src/sections/basic-page/basic-page.d.ts +145 -15
  56. package/dist/src/sections/basic-page/index.d.ts +1 -1
  57. package/dist/src/utils/animated-height.d.ts +16 -7
  58. package/dist/src/utils/choice-card.d.ts +8 -1
  59. package/dist/src/utils/ghost-search.d.ts +19 -3
  60. package/package.json +5 -1
  61. package/dist/chunks/animated-height-I44sUq0n.js +0 -48
  62. package/dist/chunks/animated-height-I44sUq0n.js.map +0 -1
  63. package/dist/chunks/basic-page-B5FsORRi.js +0 -1885
  64. package/dist/chunks/basic-page-B5FsORRi.js.map +0 -1
  65. package/dist/chunks/chat-B0WIgEyM.js.map +0 -1
  66. package/dist/chunks/choice-card-BVNP1NB6.js +0 -17
  67. package/dist/chunks/choice-card-BVNP1NB6.js.map +0 -1
  68. package/dist/chunks/dialog-MPvem7yV.js.map +0 -1
  69. package/dist/chunks/filter-bar-B-oYYBsU.js.map +0 -1
  70. package/dist/chunks/ghost-search-CNVs9k1o.js +0 -34
  71. package/dist/chunks/ghost-search-CNVs9k1o.js.map +0 -1
@@ -5,7 +5,17 @@ type StyledProps<T extends ElementType> = Omit<ComponentProps<T>, "className"> &
5
5
  className?: string;
6
6
  };
7
7
  declare function Root({ className, ...props }: StyledProps<typeof BaseField.Root>): import("react").JSX.Element;
8
- declare function Label({ className, ...props }: StyledProps<typeof BaseField.Label>): import("react").JSX.Element;
8
+ /**
9
+ * The field's label. `required` marks it the way `Input required` marks
10
+ * its own: a brand-coloured star after the words. A form marks every
11
+ * required field or none, so a field built from parts (a `Select`, a
12
+ * `PhoneInput`, a pair of inputs under one label) takes `required` here to
13
+ * match the `Input`s beside it.
14
+ */
15
+ declare function Label({ className, required, children, ...props }: StyledProps<typeof BaseField.Label> & {
16
+ /** Mark the field required: a star after the label's words. */
17
+ required?: boolean;
18
+ }): import("react").JSX.Element;
9
19
  declare function Control({ className, ...props }: StyledProps<typeof BaseField.Control>): import("react").JSX.Element;
10
20
  /**
11
21
  * Several controls under one label: the lines of an address, first and
@@ -0,0 +1,29 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ /**
3
+ * The quiet focus of a search riding on a list or table. The field keeps
4
+ * its resting hairline when it takes focus: the list it narrows is where
5
+ * the eye goes, and a ring would box the field off from it. Focus shows
6
+ * in the caret and in the magnifier, which takes the primary ink. Put it
7
+ * on the field's surface after the surface's own classes (an `Input`'s
8
+ * `wrapperClassName`, an `InputGroup.Root`'s `className`): tailwind-merge
9
+ * keeps the ring at its rest width and ink.
10
+ */
11
+ export declare const QUIET_SEARCH_FOCUS = "has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-pho-primary has-[input:focus-visible]:ring-1 has-[input:focus-visible]:ring-pho-primary";
12
+ export interface BoxSearchProps extends Omit<ComponentProps<"input">, "type" | "size" | "children"> {
13
+ /**
14
+ * Empties the query from the field's own clear button, shown while the
15
+ * field holds text; focus stays in the field. Without it, no button.
16
+ */
17
+ onClear?: () => void;
18
+ /** Quiet words at the field's end, before the clear button — a count. */
19
+ trailing?: ReactNode;
20
+ /** Classes for the field's surface: its width, its place in a row. */
21
+ className?: string;
22
+ }
23
+ /**
24
+ * The boxed search over a list or table — an `sm` field with the
25
+ * magnifier leading, a `trailing` slot, and a clear button. Its focus is
26
+ * quiet (see `QUIET_SEARCH_FOCUS`). Shared by `BasicPage.Search`,
27
+ * `FilterBar`, and `Scope`; the boxless face is `GhostSearch`.
28
+ */
29
+ export declare function BoxSearch({ className, onClear, trailing, value, onChange, disabled, ref, ...props }: BoxSearchProps): import("react").JSX.Element;
@@ -8,14 +8,21 @@ export interface RadioCardProps extends Omit<ComponentProps<typeof BaseRadio.Roo
8
8
  description?: ReactNode;
9
9
  /** Glyph stacked above the title. When set, it replaces the radio dot. */
10
10
  icon?: ReactNode;
11
+ /**
12
+ * Glyph at the end of the title row in place of the radio dot, for a
13
+ * choice that adds something rather than picks it — a plus on "New
14
+ * brand". The tile's ring still shows it chosen. For tiles without an
15
+ * `icon` (those have no dot to replace).
16
+ */
17
+ trailing?: ReactNode;
11
18
  }
12
19
  /**
13
20
  * A `Radio` styled as a bordered, selectable tile — title, optional
14
- * description, and either a stacked icon above them or the radio dot at
15
- * the end of the title row. The tile *is* the radio (see `usePressPulse`);
16
- * an inner glyph is decorative.
21
+ * description, and either a stacked icon above them or, at the end of the
22
+ * title row, the radio dot (or a `trailing` glyph in its place). The tile
23
+ * *is* the radio (see `usePressPulse`); an inner glyph is decorative.
17
24
  */
18
- export declare function RadioCard({ className, title, description, icon, disabled, ...props }: RadioCardProps): import("react").JSX.Element;
25
+ export declare function RadioCard({ className, title, description, icon, trailing, disabled, ...props }: RadioCardProps): import("react").JSX.Element;
19
26
  export declare namespace RadioCard {
20
27
  var displayName: string;
21
28
  }
@@ -0,0 +1 @@
1
+ export { Scope, type ScopeProps, type ScopeItem, type ScopeAll } from './scope';
@@ -0,0 +1,98 @@
1
+ import { ComponentProps, Ref } from 'react';
2
+ /**
3
+ * Scope — pick what something covers out of a catalog: the events a webhook
4
+ * destination receives, the permissions an app or key holds. A searchable,
5
+ * grouped checklist with a catch-all row; `collapsible` folds it to a
6
+ * two-line summary for a resource that already exists, opening on click.
7
+ */
8
+ export interface ScopeItem {
9
+ /**
10
+ * What the selection holds — an event type, a permission id. It is also
11
+ * the row's name unless `label` says otherwise.
12
+ */
13
+ value: string;
14
+ /** The row's name, when it shouldn't be the value itself. */
15
+ label?: string;
16
+ /** One line on what it covers. Searched along with the name. */
17
+ description?: string;
18
+ /**
19
+ * The group it files under — the resource, the namespace. Groups keep
20
+ * the order they first appear in; items without one come first.
21
+ */
22
+ group?: string;
23
+ }
24
+ export interface ScopeAll {
25
+ /** The row's name — `All events`. */
26
+ label: string;
27
+ /** What choosing it means — `Every current and future event.` */
28
+ description?: string;
29
+ /**
30
+ * A wildcard the selection holds in place of the items — `*`. With it,
31
+ * the row stands for every item, now and later: choosing it sets the
32
+ * selection to `[value]`, and leaving it spells every item out by name so
33
+ * the reader prunes from there, never from nothing. Without it, the row
34
+ * selects every item listed.
35
+ */
36
+ value?: string;
37
+ }
38
+ export interface ScopeProps extends Omit<ComponentProps<"div">, "defaultValue" | "onChange" | "children"> {
39
+ /** The catalog — everything that can be picked, in display order. */
40
+ items: readonly ScopeItem[];
41
+ /** The selected values, controlled. */
42
+ value?: readonly string[];
43
+ /** The selected values at first, uncontrolled. */
44
+ defaultValue?: readonly string[];
45
+ /**
46
+ * Called with the next selection, in catalog order (values no longer in
47
+ * the catalog follow in the order they were held).
48
+ */
49
+ onValueChange?: (value: string[]) => void;
50
+ /** The catch-all row at the top. Leave it out for no such row. */
51
+ all?: ScopeAll;
52
+ /** The search field's placeholder, which also names it. @default "Search" */
53
+ placeholder?: string;
54
+ /**
55
+ * Fold to a two-line summary of the selection, opening to the full list
56
+ * on click — for a resource that already exists, where the scope is read
57
+ * far more often than it changes. The page saves the change (its "Save
58
+ * changes" below the card) and folds the list through `open`; the ✕ in
59
+ * the search row, or `Escape` on an empty search, drops the edit: the
60
+ * selection goes back to what it was when the list opened, and folds.
61
+ */
62
+ collapsible?: boolean;
63
+ /** Whether the collapsible list is open, controlled. */
64
+ open?: boolean;
65
+ /** Whether the collapsible list starts open. @default false */
66
+ defaultOpen?: boolean;
67
+ /** Called when the collapsible list opens or folds. */
68
+ onOpenChange?: (open: boolean) => void;
69
+ /** The catalog is on its way: bones in place of rows. */
70
+ loading?: boolean;
71
+ /**
72
+ * Read-only: the list can be searched but not changed, and a folded one
73
+ * stays folded. Held open by `open` (a save in flight), nothing in it
74
+ * changes the selection, the ✕ and Escape included.
75
+ */
76
+ disabled?: boolean;
77
+ ref?: Ref<HTMLDivElement>;
78
+ }
79
+ /**
80
+ * A searchable, grouped checklist for choosing what something covers.
81
+ *
82
+ * Every row is one line on a wide card — the name, then its description in
83
+ * a second column that opens whole on hover when it doesn't fit. Groups are
84
+ * thin tinted bands carrying a checkbox for the whole group (mixed when
85
+ * partly chosen). The search matches names, descriptions, and group names,
86
+ * word by word; while it holds a query the catch-all row steps aside and a
87
+ * group's checkbox covers the rows it shows.
88
+ *
89
+ * With `collapsible`, the card rests as a summary — whole groups by name,
90
+ * the rest by item, over a count — and opens in place, the search taking
91
+ * focus, when clicked; its ✕ drops the edit and folds it back, the page's
92
+ * own save below the card commits it. Values the catalog no longer offers keep a row
93
+ * under "No longer offered": they can be removed, never added in bulk.
94
+ */
95
+ export declare function Scope({ items, value: valueProp, defaultValue, onValueChange, all, placeholder, collapsible, open: openProp, defaultOpen, onOpenChange, loading, disabled, className, ref, ...props }: ScopeProps): import("react").JSX.Element;
96
+ export declare namespace Scope {
97
+ var displayName: string;
98
+ }
@@ -128,6 +128,58 @@ export declare function fadeThroughBlur(reduceMotion?: boolean | null): {
128
128
  readonly duration: 0;
129
129
  };
130
130
  };
131
+ /**
132
+ * The presence recipe — `BasicPage.Reveal`'s: a block opens from no height
133
+ * on `SPRING_ENTRANCE` while `FADE_ENTRANCE` brings the ink, and closes the
134
+ * same way. Spread onto a keyed motion element inside `AnimatePresence`,
135
+ * clipped while it moves so what hasn't opened stays out of sight:
136
+ *
137
+ * <motion.div {...revealIn(reduceMotion)} />
138
+ *
139
+ * `collapseGap` is a flex gap the block trades against its height (a
140
+ * negative margin as it closes), so neighbours glide to where they end up
141
+ * instead of snapping by the gap when it unmounts. Under reduced motion the
142
+ * block snaps.
143
+ */
144
+ export declare function revealIn(reduceMotion?: boolean | null, collapseGap?: string): {
145
+ readonly initial: {
146
+ readonly height: 0;
147
+ readonly opacity: 0;
148
+ readonly marginTop: string;
149
+ };
150
+ readonly animate: {
151
+ readonly height: "auto";
152
+ readonly opacity: 1;
153
+ readonly marginTop: 0;
154
+ };
155
+ readonly exit: {
156
+ readonly height: 0;
157
+ readonly opacity: 0;
158
+ readonly marginTop: string;
159
+ };
160
+ readonly transition: {
161
+ readonly duration: 0;
162
+ readonly height?: undefined;
163
+ readonly marginTop?: undefined;
164
+ readonly opacity?: undefined;
165
+ } | {
166
+ readonly height: {
167
+ readonly type: "spring";
168
+ readonly stiffness: 400;
169
+ readonly damping: 40;
170
+ };
171
+ readonly marginTop: {
172
+ readonly type: "spring";
173
+ readonly stiffness: 400;
174
+ readonly damping: 40;
175
+ };
176
+ readonly opacity: {
177
+ readonly duration: 0.25;
178
+ readonly ease: "easeOut";
179
+ };
180
+ readonly duration?: undefined;
181
+ };
182
+ };
131
183
  /**
132
184
  * The entrance recipe — rise `RISE_PX` on `SPRING_ENTRANCE` while
133
185
  * `FADE_ENTRANCE` brings the ink. What `Stack` and `Reveal` do; spread it
@@ -8,12 +8,12 @@ import { CodeBlock } from '../../components/code-block';
8
8
  * card's own: Stack used to force `gap-3` onto a bare Card and open 12px
9
9
  * bands between `divide-y` rows. The marker below lets Stack skip it.
10
10
  */
11
- export declare const BASIC_PAGE_CARD = "rounded-base border border-pho-secondary bg-pho-primary divide-y divide-pho-secondary [&>:has(+[data-basic-page-alert])]:border-b-0 gap-0";
11
+ export declare const BASIC_PAGE_CARD = "rounded-base border border-pho-secondary bg-pho-primary [--choice-card-inset:0.75rem] divide-y divide-pho-secondary [&>:has(+[data-basic-page-alert])]:border-b-0 gap-0";
12
12
  /**
13
13
  * Standalone callout surface — featured block (invite form, notice, etc.).
14
14
  * Don't wrap in `Card`; this is the outer chrome.
15
15
  */
16
- export declare const BASIC_PAGE_CALLOUT = "flex min-w-0 flex-col gap-3 rounded-base border border-pho-secondary bg-pho-page p-5";
16
+ export declare const BASIC_PAGE_CALLOUT = "flex min-w-0 flex-col gap-3 rounded-base border border-pho-secondary bg-pho-page p-5 [--choice-card-inset:0.75rem]";
17
17
  /**
18
18
  * One row — label (+ optional description) left, control right.
19
19
  * `min-h-[4.25rem]` (68px) keeps avatar/control rows from collapsing shorter
@@ -227,6 +227,25 @@ export interface BasicPageTitleProps extends ComponentProps<"h1"> {
227
227
  trailing?: ReactNode;
228
228
  ref?: Ref<HTMLHeadingElement>;
229
229
  }
230
+ export interface BasicPageTitleAccessoryProps {
231
+ /**
232
+ * Whether it goes with the words into the condensed bar once the title
233
+ * has scrolled away. A status the name can't be read without does (a
234
+ * badge); an action on the page doesn't (a Rename pencil): the bar is a
235
+ * way back and a name, not a toolbar.
236
+ * @default true
237
+ */
238
+ inBar?: boolean;
239
+ children?: ReactNode;
240
+ }
241
+ /**
242
+ * A part of the title beside its words — a badge, a status, an action on
243
+ * the page itself — that says whether it follows the words into the
244
+ * condensed bar (`Root condense`). Put it inside `Title` after the words.
245
+ * Everything in a title's children goes into the bar unless it says
246
+ * otherwise; `Title`'s `trailing` never does.
247
+ */
248
+ declare function TitleAccessory({ inBar, children, }: BasicPageTitleAccessoryProps): import("react").JSX.Element | null;
230
249
  /**
231
250
  * Page title — largest heading on the surface. Plain-text children get a slug
232
251
  * `id` for hash targets (`#profile`); the heading itself is not a link.
@@ -308,11 +327,12 @@ export interface BasicPageHeaderProps extends Omit<ComponentProps<"div">, Reveal
308
327
  declare function Header({ enter: enterProp, className, ...props }: BasicPageHeaderProps): import("react").JSX.Element;
309
328
  /**
310
329
  * An action at the header row's end — a small button (or two) seated in
311
- * the `Header` grid the way `Search` is: top-right of the block, its top
312
- * edge on the header's top, its right edge on the title / card-content
313
- * inset (`mr-5` matching `SectionTitle`'s `px-5`). A callout already
314
- * carries `p-5` and its title has no `px-5`, so the inset drops there.
315
- * Text shorter than the seat centers against it. Put it inside `Header`
330
+ * the `Header` grid the way `Search` is, its right edge on the title /
331
+ * card-content inset (`mr-5` matching `SectionTitle`'s `px-5`). A callout
332
+ * already carries `p-5` and its title has no `px-5`, so the inset drops
333
+ * there. It centers on the text block whichever is taller: beside a
334
+ * description that wraps to a third line it stays on the block's middle,
335
+ * and text shorter than it centers against it. Put it inside `Header`
316
336
  * after the text; with a `Search` present it stands to the search's right.
317
337
  */
318
338
  declare function HeaderAction({ className, ...props }: ComponentProps<"div"> & {
@@ -425,6 +445,16 @@ declare function CalloutDescription({ className, ...props }: ComponentProps<"p">
425
445
  ref?: Ref<HTMLParagraphElement>;
426
446
  }): import("react").JSX.Element;
427
447
  export interface BasicPageOnboardProps extends ComponentProps<"ol"> {
448
+ /**
449
+ * One page per step, the steps in a row above it, instead of the card
450
+ * with the step at hand folded open — for a setup whose steps are
451
+ * pages of their own: a registration that asks who is registering,
452
+ * then for the brand, then for the campaign. Each `Step`'s children are
453
+ * its page (a `Stack`, or a `Form` around one), and the paged `Onboard`
454
+ * stands where the page's `Stack` would, under the `Title`. The rest of
455
+ * the props go to the row, the ordered list of steps.
456
+ */
457
+ paged?: boolean;
428
458
  ref?: Ref<HTMLOListElement>;
429
459
  }
430
460
  /**
@@ -438,30 +468,40 @@ export interface BasicPageOnboardProps extends ComponentProps<"ol"> {
438
468
  * with a check and what they came to, the waiting ones muted. A step
439
469
  * finishing folds closed as the next opens, on the Accordion's spring.
440
470
  * When the last step is done the service is on — render the page in its
441
- * place.
471
+ * place. `paged` turns the card into a row of steps over the page at
472
+ * hand (see `PagedOnboard`).
442
473
  */
443
- declare function Onboard({ className, children, ...props }: BasicPageOnboardProps): import("react").JSX.Element;
474
+ declare function Onboard({ paged, className, children, ...props }: BasicPageOnboardProps): import("react").JSX.Element;
444
475
  export interface BasicPageStepProps extends Omit<ComponentProps<"li">, "title"> {
445
476
  /**
446
477
  * Decorative glyph for the step at hand, top-right of its body the way a
447
478
  * `Callout`'s is — typically a Tabler outline icon at stroke 1.25. It is
448
479
  * aria-hidden (keep the meaning in the title) and folds away with the
449
- * body: a done or waiting step shows none.
480
+ * body: a done or waiting step shows none. In a paged list it is what a
481
+ * done step came to, drawn in its ring in place of the check — the
482
+ * choice a step made, say — and a step without one keeps the check.
450
483
  */
451
484
  icon?: ReactNode;
452
485
  /**
453
486
  * Something to look at beside the step at hand — a code to scan, with
454
487
  * its caption — in the corner where the `icon` would be, its top on the
455
488
  * title's, holding still as the fold opens beside it. It takes the
456
- * icon's place when both are given, and folds away with the body.
489
+ * icon's place when both are given, and folds away with the body. Not
490
+ * shown in a paged list.
457
491
  */
458
492
  aside?: ReactNode;
459
- /** The title: a verb and its object — "Choose a number". */
493
+ /**
494
+ * The title: a verb and its object — "Choose a number". In a paged
495
+ * list, the step's name in the row, a word or two — "Brand" — which a
496
+ * done step may trade for what it came to ("Business"); the row
497
+ * crossfades it.
498
+ */
460
499
  title: ReactNode;
461
500
  /**
462
501
  * The line under the title while the step is at hand: what it involves,
463
502
  * or, while it waits, how long. Folded away with the rest once the step
464
- * is done or before its turn.
503
+ * is done or before its turn. Not shown in a paged list; the page says
504
+ * it in its own `Header`.
465
505
  */
466
506
  description?: ReactNode;
467
507
  /**
@@ -486,11 +526,95 @@ export interface BasicPageStepProps extends Omit<ComponentProps<"li">, "title">
486
526
  /**
487
527
  * At hand: the step's action — a small `Button` or `ButtonLink` — under
488
528
  * its line. Done: what it came to — a `Value` — at the title's end.
489
- * Waiting its turn: not shown.
529
+ * Waiting its turn: not shown. In a paged list, the step's page — a
530
+ * `Stack`, or a `Form` around one — shown under the row while the step
531
+ * is at hand.
490
532
  */
491
533
  children?: ReactNode;
492
534
  ref?: Ref<HTMLLIElement>;
493
535
  }
536
+ /**
537
+ * Where a check stands. As `Step`'s: `done` draws the check, `working`
538
+ * spins while Photon is at it, `pending` is dashed while it waits on
539
+ * someone else (a carrier, a DNS host, the visitor), `upcoming` is faint
540
+ * while it waits its turn. `failed` trades the ring for an X and says so.
541
+ */
542
+ export type BasicPageCheckState = "done" | "working" | "pending" | "upcoming" | "failed";
543
+ /**
544
+ * A list of checks Photon reports on, one line each: DNS records found, a
545
+ * registration's stages. Not steps someone takes (that is `Onboard`), and
546
+ * not a percentage (that is `Progress`). It speaks the `Onboard` ring's
547
+ * language at the line's size. The check where the list stands, whatever
548
+ * came of it, is its current step: its label one weight up, and
549
+ * `aria-current` for assistive tech. Put it in a `Card`'s `Item`, and say
550
+ * when it was last checked, if that matters, in a `SectionFooter`.
551
+ */
552
+ declare function Checklist({ className, children, ...props }: ComponentProps<"ul"> & {
553
+ ref?: Ref<HTMLUListElement>;
554
+ }): import("react").JSX.Element;
555
+ export interface BasicPageCheckProps extends Omit<ComponentProps<"li">, "value"> {
556
+ /** @default "upcoming" */
557
+ state?: BasicPageCheckState;
558
+ /**
559
+ * What the check came to, at the line's end in description ink: the
560
+ * date it passed, a count.
561
+ */
562
+ value?: ReactNode;
563
+ /**
564
+ * A line (or a few) right under the label, on its start edge, at
565
+ * `text-xs`: why a failed check failed, in error ink with no surface of
566
+ * its own (the X already marks it); otherwise what the check waits on,
567
+ * in description ink. Several reasons are several block children.
568
+ */
569
+ description?: ReactNode;
570
+ /**
571
+ * What a failed check's failure is called, beside its label in error
572
+ * ink: "Rejected", "Suspended". Read only when `state` is `failed`.
573
+ * @default "Failed"
574
+ */
575
+ failure?: ReactNode;
576
+ ref?: Ref<HTMLLIElement>;
577
+ }
578
+ /**
579
+ * One check: its ring, its label, its `value` at the line's end, and its
580
+ * `description` under the label. The ring is `Step`'s at the text's size;
581
+ * a check that turns done draws its mark on, one that loads done shows it
582
+ * drawn. The list says which check is current; its label and a failed
583
+ * one's "Failed" go one weight up.
584
+ */
585
+ declare function Check({ state, value, description, failure, className, children, ...props }: BasicPageCheckProps): import("react").JSX.Element;
586
+ /**
587
+ * What happened, in order: a registration's reviews, a domain's checks
588
+ * over time, a key's uses. One event per `TimelineItem`, newest first
589
+ * unless the page says otherwise, each on the checklist's mark with a
590
+ * faint line down to the next. Where `Checklist` is where things stand
591
+ * now, a timeline is how they got there. Put it in a `Card`'s `Item`.
592
+ */
593
+ declare function Timeline({ className, ...props }: ComponentProps<"ol"> & {
594
+ ref?: Ref<HTMLOListElement>;
595
+ }): import("react").JSX.Element;
596
+ export interface BasicPageTimelineItemProps extends Omit<ComponentProps<"li">, "title"> {
597
+ /** What came of the event, on the checklist's mark. @default "done" */
598
+ state?: BasicPageCheckState;
599
+ /** The event, in words: "Carrier review failed". */
600
+ title: ReactNode;
601
+ /** When it happened, under the title in description ink. */
602
+ time?: ReactNode;
603
+ /**
604
+ * What there is to say about it, under the time at `text-xs` in
605
+ * description ink: a reviewer's reasons, a note. A record, not an alarm:
606
+ * a failure's mark says it failed, and the page's current state says
607
+ * what to do about it.
608
+ */
609
+ children?: ReactNode;
610
+ ref?: Ref<HTMLLIElement>;
611
+ }
612
+ /**
613
+ * One event: its mark on the rail, a line from it down to the next
614
+ * event's, and beside it the title, the time and the details. The mark
615
+ * sits on the title's line; the last event draws no line.
616
+ */
617
+ declare function TimelineItem({ state, title, time, className, children, ...props }: BasicPageTimelineItemProps): import("react").JSX.Element;
494
618
  /**
495
619
  * One step of an `Onboard`, left to right: the ring, the words, the
496
620
  * corner. The ring and the title share one row and center on each
@@ -503,7 +627,8 @@ export interface BasicPageStepProps extends Omit<ComponentProps<"li">, "title">
503
627
  * does; the others stay on the card's white. The title and the line wear the
504
628
  * section's type — `SectionTitle` over `Description`, both
505
629
  * `text-display-xs`. Its standing comes from the list; on its own it is
506
- * the step at hand.
630
+ * the step at hand. In a paged list it is its place in the row instead
631
+ * (`StepInRow`), and the list shows its children as the page.
507
632
  */
508
633
  declare function Step({ icon, aside, title, description, done, working, pending, className, children, ...props }: BasicPageStepProps): import("react").JSX.Element;
509
634
  export interface BasicPageRowProps extends Omit<ComponentProps<"div">, "title" | RevealMotionConflicts> {
@@ -1139,6 +1264,7 @@ export declare const BasicPage: {
1139
1264
  Crumb: typeof Crumb;
1140
1265
  Back: typeof Back;
1141
1266
  Title: typeof Title;
1267
+ TitleAccessory: typeof TitleAccessory;
1142
1268
  Stack: typeof Stack;
1143
1269
  Columns: typeof Columns;
1144
1270
  Header: typeof Header;
@@ -1155,6 +1281,10 @@ export declare const BasicPage: {
1155
1281
  CalloutDescription: typeof CalloutDescription;
1156
1282
  Onboard: typeof Onboard;
1157
1283
  Step: typeof Step;
1284
+ Checklist: typeof Checklist;
1285
+ Check: typeof Check;
1286
+ Timeline: typeof Timeline;
1287
+ TimelineItem: typeof TimelineItem;
1158
1288
  Row: typeof Row;
1159
1289
  RowLink: typeof RowLink;
1160
1290
  Value: typeof Value;
@@ -1,3 +1,3 @@
1
- export { BasicPage, formToasts, AUTO_SAVE_DELAY_MS, useCondense, useAutoSave, type BasicPageCondense, BASIC_PAGE_CARD, CONDENSE_BAR_ENTER, CONDENSE_BAR_TRAVEL, CONDENSE_BAR_RISE_PX, BASIC_PAGE_CALLOUT, BASIC_PAGE_ROW, BASIC_PAGE_ITEM, BASIC_PAGE_ITEM_PANEL, BASIC_PAGE_ITEM_PANEL_DIVIDED, type BasicPageRootProps, type BasicPageColumnsProps, type BasicPageAsideProps, type BasicPageAsideWidth, type BasicPageAsidePresentation, type BasicPageRowProps, type BasicPageRowLinkProps, type BasicPageBackProps, type BasicPageBreadcrumbsProps, type BasicPageCrumbProps, type BasicPageFooterProps, type BasicPageFormProps, type BasicPageFormErrors, type BasicPageItemPanelProps, type BasicPageOnboardProps, type BasicPageStepProps, type BasicPageReceiptProps, type BasicPageReceiptGroupProps, type BasicPageReceiptLineProps, type BasicPageReceiptTotalProps, } from './basic-page';
1
+ export { BasicPage, formToasts, AUTO_SAVE_DELAY_MS, useCondense, useAutoSave, type BasicPageCondense, BASIC_PAGE_CARD, CONDENSE_BAR_ENTER, CONDENSE_BAR_TRAVEL, CONDENSE_BAR_RISE_PX, BASIC_PAGE_CALLOUT, BASIC_PAGE_ROW, BASIC_PAGE_ITEM, BASIC_PAGE_ITEM_PANEL, BASIC_PAGE_ITEM_PANEL_DIVIDED, type BasicPageRootProps, type BasicPageColumnsProps, type BasicPageAsideProps, type BasicPageAsideWidth, type BasicPageAsidePresentation, type BasicPageRowProps, type BasicPageRowLinkProps, type BasicPageBackProps, type BasicPageBreadcrumbsProps, type BasicPageCrumbProps, type BasicPageFooterProps, type BasicPageFormProps, type BasicPageFormErrors, type BasicPageItemPanelProps, type BasicPageOnboardProps, type BasicPageStepProps, type BasicPageTitleAccessoryProps, type BasicPageCheckProps, type BasicPageCheckState, type BasicPageTimelineItemProps, type BasicPageReceiptProps, type BasicPageReceiptGroupProps, type BasicPageReceiptLineProps, type BasicPageReceiptTotalProps, } from './basic-page';
2
2
  export { createColumns, type DataTableColumn, type DataTableColumnMeta, type DataTableProps, type SortingState, } from '../../components/data-table';
3
3
  export { type DescriptionListRootProps as BasicPageMetaProps, type DescriptionListItemProps as BasicPageMetaItemProps, type DescriptionListLayout as BasicPageMetaLayout, } from '../../components/description-list';
@@ -1,15 +1,24 @@
1
- import { ReactNode } from 'react';
2
- import { ValueAnimationTransition } from 'motion/react';
1
+ import { ReactNode, RefObject } from 'react';
2
+ import { MotionValue, ValueAnimationTransition } from 'motion/react';
3
3
  /**
4
- * Animates its own height to follow the measured height of `children`, so
5
- * content swaps (search filtering, skeleton → data) glide instead of jumping.
6
- * Honors `prefers-reduced-motion` by snapping height with no spring.
4
+ * Keeps a container's size on one axis following the measured size of its
5
+ * content on a spring — the core of `AnimatedHeight`, and of any part whose
6
+ * box should glide as its content changes (a paged `Onboard`'s step titles
7
+ * follow their words' width this way). Returns the motion value to put on
8
+ * the container's `style`. Reduced motion snaps it.
7
9
  *
8
10
  * The container clips only while the spring is in flight. ResizeObserver
9
11
  * callbacks run after layout but before paint, so the clip lands before the
10
12
  * swap frame can show; once the spring settles it is lifted again, so a focus
11
- * ring, an effect button's rim, or any other overhang on the last row paints
12
- * normally at rest instead of being cut off at the container's edge.
13
+ * ring, an effect button's rim, or any other overhang paints normally at
14
+ * rest instead of being cut off at the container's edge.
15
+ */
16
+ export declare function useSizeFollow(axis: "height" | "width", containerRef: RefObject<HTMLElement | null>, contentRef: RefObject<HTMLElement | null>, transition: ValueAnimationTransition<number | "auto">): MotionValue<number | "auto">;
17
+ /**
18
+ * Animates its own height to follow the measured height of `children`, so
19
+ * content swaps (search filtering, skeleton → data) glide instead of jumping.
20
+ * Honors `prefers-reduced-motion` by snapping height with no spring. Clips
21
+ * only while the spring is in flight (see `useSizeFollow`).
13
22
  */
14
23
  export declare function AnimatedHeight({ className, transition, children, }: {
15
24
  className?: string;
@@ -4,8 +4,15 @@ import { Transition } from 'motion/react';
4
4
  * tile. Applied to the radio/checkbox root itself so the whole tile is the
5
5
  * hit target. Hover fills (`bg-pho-ghost-hover`); selected uses the brand
6
6
  * ring. Press feedback lives on this surface (see `usePressPulse`).
7
+ *
8
+ * The side padding is `--choice-card-inset`, 12px unless the page says
9
+ * otherwise, and the padding above and below is three quarters of it: a
10
+ * `BasicPage.Stack` sets it to the page's text edge (20px), so tiles
11
+ * standing on the page as its surfaces reach the column's edge as a card
12
+ * does and start their words on the headings' line; a card, sheet or
13
+ * callout sets it back, so tiles inside one stay compact.
7
14
  */
8
- export declare const CHOICE_CARD_BASE = "group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base p-3 text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2";
15
+ export declare const CHOICE_CARD_BASE = "group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base px-[var(--choice-card-inset,0.75rem)] py-[calc(var(--choice-card-inset,0.75rem)*0.75)] text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2";
9
16
  /** Stacked icon above the copy — tighter than the checkbox/radio row gap. */
10
17
  export declare const CHOICE_CARD_WITH_ICON = "flex-col gap-1.5";
11
18
  /** Same press as Select's default trigger — field-sized, not Button's whileTap. */
@@ -1,11 +1,27 @@
1
- import { ComponentProps } from 'react';
1
+ import { ComponentProps, ReactNode } from 'react';
2
2
  export interface GhostSearchProps extends Omit<ComponentProps<"input">, "value" | "onChange" | "type" | "children"> {
3
3
  value: string;
4
4
  onChange: (value: string) => void;
5
+ /**
6
+ * Empties the query from the field's own clear button, shown while it
7
+ * holds text; focus stays in the field. Without it, the browser's own
8
+ * clear glyph stays.
9
+ */
10
+ onClear?: () => void;
11
+ /** Quiet words at the field's end, before the clear button — a count. */
12
+ trailing?: ReactNode;
5
13
  }
6
14
  /**
7
15
  * A search box with no box: the glyph and the text on the surface's own
8
16
  * line, the way a toolbar band inside a card carries it (a `DataTable`'s
9
- * search, a `Trace.Waterfall`'s). Quiet ink, no ring until focus.
17
+ * search, a `Trace.Waterfall`'s, a `Scope`'s first row). Quiet ink, and no
18
+ * ring on focus either: a ring would draw the box the face exists not to
19
+ * have. Focus shows in the caret and in the magnifier, which takes the
20
+ * primary ink while the field holds focus.
21
+ *
22
+ * The query is the list's, not a form's: its change stops at the field, so
23
+ * an enclosing form that saves on change (BasicPage `Form autoSave`) or
24
+ * shows a save row once dirty never hears it. The type is an `sm` field's:
25
+ * 16px on small viewports, where iOS zooms into anything smaller.
10
26
  */
11
- export declare function GhostSearch({ value, onChange, className, ...props }: GhostSearchProps): import("react").JSX.Element;
27
+ export declare function GhostSearch({ value, onChange, onClear, trailing, className, ref, ...props }: GhostSearchProps): import("react").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@photon-ai/pho-ui",
3
- "version": "4.11.0",
3
+ "version": "4.13.0",
4
4
  "description": "Pho Design System — Photon's React component library, built on Base UI",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -85,6 +85,10 @@
85
85
  "types": "./dist/src/components/checkbox/index.d.ts",
86
86
  "import": "./dist/components/checkbox.js"
87
87
  },
88
+ "./components/scope": {
89
+ "types": "./dist/src/components/scope/index.d.ts",
90
+ "import": "./dist/components/scope.js"
91
+ },
88
92
  "./components/radio-group": {
89
93
  "types": "./dist/src/components/radio-group/index.d.ts",
90
94
  "import": "./dist/components/radio-group.js"
@@ -1,48 +0,0 @@
1
- "use client";
2
- import { SPRING_SETTLE as b } from "../motion.js";
3
- import { useEffect as R, useRef as m } from "react";
4
- import { jsx as d } from "react/jsx-runtime";
5
- import { animate as x, motion as S, useMotionValue as g, useReducedMotion as w } from "motion/react";
6
- var y = b;
7
- function G({ className: p, transition: s, children: v }) {
8
- const i = m(null), c = m(null), t = g("auto"), l = w();
9
- return R(() => {
10
- const o = i.current, n = c.current;
11
- if (!o || !n) return;
12
- let e = null;
13
- const u = new ResizeObserver((h) => {
14
- const f = h[0]?.borderBoxSize?.[0], r = f ? f.blockSize : n.offsetHeight, a = t.get();
15
- if (a === "auto" || l) {
16
- e?.stop(), e = null, o.style.overflow = "", t.set(r);
17
- return;
18
- }
19
- !e && Math.abs(a - r) < 0.5 || (o.style.overflow = "hidden", e?.stop(), e = x(t, r, {
20
- ...s ?? y,
21
- onComplete: () => {
22
- e = null, o.style.overflow = "";
23
- }
24
- }));
25
- });
26
- return u.observe(n), () => {
27
- u.disconnect(), e?.stop();
28
- };
29
- }, [
30
- t,
31
- l,
32
- s
33
- ]), /* @__PURE__ */ d(S.div, {
34
- ref: i,
35
- className: "min-h-0",
36
- style: { height: t },
37
- children: /* @__PURE__ */ d("div", {
38
- ref: c,
39
- className: p,
40
- children: v
41
- })
42
- });
43
- }
44
- export {
45
- G as t
46
- };
47
-
48
- //# sourceMappingURL=animated-height-I44sUq0n.js.map