@photon-ai/pho-ui 2.2.0 → 2.4.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 (69) hide show
  1. package/dist/chunks/basic-page-c_7Ii5Fr.js +1117 -0
  2. package/dist/chunks/basic-page-c_7Ii5Fr.js.map +1 -0
  3. package/dist/chunks/{button-BmhyLgy5.js → button-DNNs5RsT.js} +6 -6
  4. package/dist/chunks/{button-BmhyLgy5.js.map → button-DNNs5RsT.js.map} +1 -1
  5. package/dist/chunks/{dialog-DtFO7oy0.js → dialog-8SRNi_rv.js} +3 -3
  6. package/dist/chunks/{dialog-DtFO7oy0.js.map → dialog-8SRNi_rv.js.map} +1 -1
  7. package/dist/chunks/{error-Da7P5WZi.js → error-Crs-wqMC.js} +14 -14
  8. package/dist/chunks/{error-Da7P5WZi.js.map → error-Crs-wqMC.js.map} +1 -1
  9. package/dist/chunks/form-AiHbbw4m.js +17 -0
  10. package/dist/chunks/form-AiHbbw4m.js.map +1 -0
  11. package/dist/chunks/{input-QSAUO30c.js → input-DjvZoF8v.js} +48 -43
  12. package/dist/chunks/input-DjvZoF8v.js.map +1 -0
  13. package/dist/chunks/{input-group-5AtpIhC_.js → input-group-fc9_jD4d.js} +44 -38
  14. package/dist/chunks/input-group-fc9_jD4d.js.map +1 -0
  15. package/dist/chunks/kbd-DNI10uy7.js +18 -0
  16. package/dist/chunks/kbd-DNI10uy7.js.map +1 -0
  17. package/dist/chunks/{menu-Cgj3lq9z.js → menu-BQeprfxB.js} +5 -5
  18. package/dist/chunks/{menu-Cgj3lq9z.js.map → menu-BQeprfxB.js.map} +1 -1
  19. package/dist/chunks/scroll-area-Bu7egArU.js +166 -0
  20. package/dist/chunks/scroll-area-Bu7egArU.js.map +1 -0
  21. package/dist/chunks/sidebar-DvB-G0BP.js +231 -0
  22. package/dist/chunks/sidebar-DvB-G0BP.js.map +1 -0
  23. package/dist/chunks/toast-DoXaRPIZ.js +167 -0
  24. package/dist/chunks/toast-DoXaRPIZ.js.map +1 -0
  25. package/dist/components/button.js +1 -1
  26. package/dist/components/command.js +125 -172
  27. package/dist/components/command.js.map +1 -1
  28. package/dist/components/context-menu.js +23 -23
  29. package/dist/components/dialog.js +1 -1
  30. package/dist/components/error.js +1 -1
  31. package/dist/components/field.js +12 -5
  32. package/dist/components/field.js.map +1 -1
  33. package/dist/components/form.js +2 -14
  34. package/dist/components/input-group.js +1 -1
  35. package/dist/components/input.js +1 -1
  36. package/dist/components/kbd.js +2 -15
  37. package/dist/components/menu.js +1 -1
  38. package/dist/components/phone-input.js +1 -1
  39. package/dist/components/scroll-area.js +3 -2
  40. package/dist/components/toast.js +3 -57
  41. package/dist/index.js +65 -58
  42. package/dist/primitives.js +3 -3
  43. package/dist/sections/basic-page.js +15 -8
  44. package/dist/sections/sidebar.js +1 -1
  45. package/dist/src/components/command/command.d.ts +5 -4
  46. package/dist/src/components/field/field.d.ts +9 -0
  47. package/dist/src/components/input/input.d.ts +10 -1
  48. package/dist/src/components/input-group/input-group.d.ts +9 -2
  49. package/dist/src/components/scroll-area/index.d.ts +1 -0
  50. package/dist/src/components/scroll-area/scroll-area-edges.d.ts +11 -1
  51. package/dist/src/components/scroll-area/scroll-area.d.ts +15 -2
  52. package/dist/src/components/toast/index.d.ts +1 -1
  53. package/dist/src/components/toast/toast.d.ts +22 -7
  54. package/dist/src/sections/basic-page/basic-page.d.ts +210 -30
  55. package/dist/src/sections/basic-page/index.d.ts +1 -1
  56. package/dist/src/sections/sidebar/sidebar.d.ts +33 -3
  57. package/package.json +1 -1
  58. package/src/styles/pho.css +19 -0
  59. package/dist/chunks/basic-page-CB36yrpL.js +0 -643
  60. package/dist/chunks/basic-page-CB36yrpL.js.map +0 -1
  61. package/dist/chunks/input-QSAUO30c.js.map +0 -1
  62. package/dist/chunks/input-group-5AtpIhC_.js.map +0 -1
  63. package/dist/chunks/scroll-area-Cw4JFqNG.js +0 -152
  64. package/dist/chunks/scroll-area-Cw4JFqNG.js.map +0 -1
  65. package/dist/chunks/sidebar-BETMObNj.js +0 -186
  66. package/dist/chunks/sidebar-BETMObNj.js.map +0 -1
  67. package/dist/components/form.js.map +0 -1
  68. package/dist/components/kbd.js.map +0 -1
  69. package/dist/components/toast.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { AnchorHTMLAttributes, ComponentProps, ReactNode, Ref } from 'react';
2
- import { ButtonLinkProps } from '../../components/button';
2
+ import { ButtonLinkProps, ButtonProps } from '../../components/button';
3
+ import { Form as FormElement } from '../../components/form';
3
4
  /** Bordered card that stacks rows with hairline dividers. */
4
5
  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";
5
6
  /**
@@ -59,9 +60,78 @@ export declare const BASIC_PAGE_ITEM_PANEL_DIVIDED = "-mx-2 -mt-1.5 flex items-c
59
60
  * `Title` and `Back` (the page chrome) stay put while the body below rises
60
61
  * in.
61
62
  */
62
- declare function Root({ className, ...props }: ComponentProps<"div"> & {
63
+ export interface BasicPageRootProps extends ComponentProps<"div"> {
63
64
  ref?: Ref<HTMLDivElement>;
65
+ /**
66
+ * Condense on scroll — on by default. Once the title has scrolled out of
67
+ * the pane, a sticky bar pins to the top with the way back and the page
68
+ * name: the large title collapsing into its bar. It assembles itself
69
+ * from `Title` and the trail's tail crumb; nothing to wire. Pass `false`
70
+ * for a page that should scroll away whole.
71
+ */
72
+ condense?: boolean;
73
+ }
74
+ declare function Root({ condense, className, children, ...props }: BasicPageRootProps): import("react").JSX.Element;
75
+ /**
76
+ * Condensing header — the page's way back once the title has scrolled away.
77
+ * `Root condense` renders a sticky bar in the reserved top zone; `Title` and
78
+ * `Breadcrumbs` report what belongs in it (the heading, the tail crumb)
79
+ * through this context, so the bar assembles itself and consumers only set
80
+ * the flag. The bar stays out of the way until the whole heading has left
81
+ * the scrollport, then fades in pinned to the top.
82
+ */
83
+ interface CondenseTail {
84
+ label: ReactNode;
85
+ href: string;
86
+ onClick?: ComponentProps<"a">["onClick"];
87
+ }
88
+ /**
89
+ * What the condensed bar would show, for an app shell that shows it
90
+ * itself: whether the title has left the pane, the page name, the way
91
+ * back. Idle (`condensed: false`, both null) outside any `CondenseScope`.
92
+ */
93
+ export interface BasicPageCondense {
94
+ condensed: boolean;
95
+ title: ReactNode | null;
96
+ back: CondenseTail | null;
97
+ }
98
+ /**
99
+ * Hands the condensed bar to the app shell. On a narrow viewport the shell
100
+ * already has a bar of its own; two stacked bars is one too many. Wrap the
101
+ * shell (its bar and the routed pages) in `CondenseScope` and read
102
+ * `useCondense()` where the bar is: while `condensed`, show `title` in the
103
+ * middle and `back` as a plain chevron beside the menu button. While
104
+ * `adopt` is true the page renders no bar of its own; pass `adopt={false}`
105
+ * on viewports where the shell bar does not exist (desktop) and the page's
106
+ * bar returns. State still tracks either way — `useCondense()` always
107
+ * answers.
108
+ */
109
+ declare function CondenseScope({ adopt, children, }: {
110
+ adopt?: boolean;
111
+ children?: ReactNode;
64
112
  }): import("react").JSX.Element;
113
+ /** The nearest scope's condense state — see `CondenseScope`. */
114
+ export declare function useCondense(): BasicPageCondense;
115
+ /**
116
+ * The condensed bar's motion, exported for a shell that adopts the bar
117
+ * (`CondenseScope`) so its swap moves the same way: 0.2s ease-out, dropping
118
+ * in from 8px above and leaving the same way.
119
+ */
120
+ export declare const CONDENSE_BAR_ENTER: {
121
+ readonly duration: 0.2;
122
+ readonly ease: "easeOut";
123
+ };
124
+ /**
125
+ * The displacement channel of the same move: travel is linear, like the
126
+ * library's other linear transitions (the 100ms control inks), while the
127
+ * fade and the soft focus keep the ease-out. Spread it per axis:
128
+ * `transition={{ ...CONDENSE_BAR_ENTER, y: CONDENSE_BAR_TRAVEL }}`.
129
+ */
130
+ export declare const CONDENSE_BAR_TRAVEL: {
131
+ readonly duration: 0.2;
132
+ readonly ease: "linear";
133
+ };
134
+ export declare const CONDENSE_BAR_RISE_PX = -8;
65
135
  export interface BasicPageTitleProps extends ComponentProps<"h1"> {
66
136
  /**
67
137
  * Shared-element key. Pair with the same `morphId` on the subpage's
@@ -113,7 +183,7 @@ export interface BasicPageStackProps extends Omit<ComponentProps<"div">, RevealM
113
183
  *
114
184
  * Static under reduced motion.
115
185
  */
116
- declare function Stack({ className, ...props }: BasicPageStackProps): import("react").JSX.Element;
186
+ declare function Stack({ className, children, ...props }: BasicPageStackProps): import("react").JSX.Element;
117
187
  /**
118
188
  * Title + optional description pair. No gap between them — the block's
119
189
  * `gap-3` only applies between this header and the card.
@@ -178,7 +248,7 @@ declare function Card({ animateHeight, className, children, ...props }: BasicPag
178
248
  * </BasicPage.Card>
179
249
  * ```
180
250
  */
181
- declare function Item({ className, ...props }: ComponentProps<"div"> & {
251
+ declare function Item({ className, ...props }: Omit<ComponentProps<"div">, RevealMotionConflicts> & {
182
252
  ref?: Ref<HTMLDivElement>;
183
253
  }): import("react").JSX.Element;
184
254
  export interface BasicPageItemPanelProps extends ComponentProps<"div"> {
@@ -222,7 +292,7 @@ declare function CalloutTitle({ id, className, children, ...props }: ComponentPr
222
292
  declare function CalloutDescription({ className, ...props }: ComponentProps<"p"> & {
223
293
  ref?: Ref<HTMLParagraphElement>;
224
294
  }): import("react").JSX.Element;
225
- export interface BasicPageRowProps extends Omit<ComponentProps<"div">, "title"> {
295
+ export interface BasicPageRowProps extends Omit<ComponentProps<"div">, "title" | RevealMotionConflicts> {
226
296
  /** Left-side field name — plain text, or compose with a trailing hint. */
227
297
  label: ReactNode;
228
298
  /** Optional helper under the label. */
@@ -272,23 +342,117 @@ export interface BasicPageAlertProps extends Omit<ComponentProps<"div">, "childr
272
342
  * For a page that failed to load outright, swap the stack for an `ErrorView`
273
343
  * instead.
274
344
  */
275
- declare function Alert({ error, show, className, children, ...props }: BasicPageAlertProps): import("react").JSX.Element;
345
+ declare function Alert({ error: errorProp, show, className, children, ...props }: BasicPageAlertProps): import("react").JSX.Element;
346
+ /**
347
+ * The nearest `Form autoSave`'s trigger, for controls whose changes never
348
+ * bubble as native events (a Base UI checkbox, a select): call it in the
349
+ * control's own onChange and the save runs after the usual pause. Null
350
+ * outside an auto-saving form.
351
+ */
352
+ export declare function useAutoSave(): ((field?: string) => void) | null;
353
+ /** Typing pause before an auto-save fires; blur flushes it immediately. */
354
+ export declare const AUTO_SAVE_DELAY_MS = 800;
355
+ /**
356
+ * The toast lane auto-save failures speak through. Host it once in the app
357
+ * shell — `<Toast.Provider toastManager={formToasts}>` around a viewport —
358
+ * and every `Form autoSave` reaches it without wiring. A failure toast
359
+ * carries Retry and stays until the save lands (the next success closes it).
360
+ */
361
+ export declare const formToasts: import('@base-ui/react').ToastManager<any>;
362
+ /** Field errors keyed by `name`, the shape Base UI `Form` maps onto fields. */
363
+ export type BasicPageFormErrors = Record<string, string | string[]>;
364
+ export interface BasicPageFormProps<Values extends Record<string, unknown> = Record<string, unknown>> extends Omit<ComponentProps<typeof FormElement>, "onFormSubmit" | "errors" | "action" | "autoSave"> {
365
+ /**
366
+ * Documents save themselves; transactions submit. With `autoSave`, the
367
+ * form runs `action` on its own — after a typing pause, immediately on
368
+ * blur — once native validation passes, and skips quietly while it does
369
+ * not. Controls stay enabled throughout; put a `Saved` in the field's
370
+ * hint for the inline Saving…/Saved word. A failure keeps the value in
371
+ * place and raises a Retry toast on `formToasts` that stays until a
372
+ * save lands. Keep the explicit `Submit` for creations and anything
373
+ * paid or irreversible.
374
+ */
375
+ autoSave?: boolean;
376
+ /**
377
+ * The save. Receives the field values keyed by `name`, after native
378
+ * validation passed. Resolve to finish; return `{ errors }` to put
379
+ * messages on fields; throw (a `Problem`, an `Error`) for the form's
380
+ * `Alert`. While it runs, every control and the submit are disabled.
381
+ */
382
+ action?: (values: Values) => void | {
383
+ errors?: BasicPageFormErrors;
384
+ } | Promise<void | {
385
+ errors?: BasicPageFormErrors;
386
+ }>;
387
+ /** Field errors to start with — from a previous round trip. */
388
+ errors?: BasicPageFormErrors;
389
+ }
390
+ /**
391
+ * The form. A `<form>` that owns the save lifecycle so the page parts can
392
+ * read it: `Submit` shows pending, `Footer show="dirty"` appears after the
393
+ * first edit and leaves when the action lands, `Alert` shows what the
394
+ * action threw, and field errors the action returns land under their
395
+ * fields. Uncontrolled by design — give fields `defaultValue` and a `name`,
396
+ * and remount with `key` when the record changes; there is no state to
397
+ * seed. Lay the fields out in `Fields` (the form card, its `Footer` inside
398
+ * at the bottom), or keep a `Card` of `Row`s for a settings page that
399
+ * saves, its `Footer` following the card one block gap below.
400
+ *
401
+ * The form adds no spacing. Inside a `Stack`, one form around a card and
402
+ * its footer is one block; a form that spans several blocks goes around
403
+ * the `Stack` instead, and the blocks keep the Stack's rhythm.
404
+ */
405
+ declare function Form<Values extends Record<string, unknown>>({ action, errors: initialErrors, autoSave, className, children, onChange, onBlur, ...props }: BasicPageFormProps<Values>): import("react").JSX.Element;
406
+ /**
407
+ * The inline word for an auto-saving field — put it inside the field at
408
+ * its trailing edge (`Input trailing`), where the eye already is while
409
+ * typing. Quiet gray, never colored, so it cannot be read as validation:
410
+ * "Saving…" while the save runs, "Saved" for a breath after it lands,
411
+ * then nothing at all — idle it renders nothing and reserves nothing.
412
+ * Words fade through the system's 1px soft focus — no travel — and
413
+ * carry their own surface wash, so long
414
+ * input text fades beneath them instead of colliding. With `name` it
415
+ * speaks only for that field; without, for the whole form.
416
+ */
417
+ declare function Saved({ name, className, ...props }: Omit<ComponentProps<"output">, RevealMotionConflicts> & {
418
+ name?: string;
419
+ }): import("react").JSX.Element;
420
+ /**
421
+ * The form card: labelled fields stacked, label above control, one rhythm
422
+ * (`gap-5`). Where a `Card` of `Row`s is a table of settings, this is a
423
+ * sheet to fill in — a create page, a long edit. `Input` brings its own
424
+ * label and hint; wrap other controls in `Field`. `Alert` and `Footer`
425
+ * sit inside, at the bottom — unlike a `Card` of rows, a sheet keeps its
426
+ * submit: the button's box lines up with the fields' edge.
427
+ */
428
+ declare function Fields({ className, ...props }: ComponentProps<"div"> & {
429
+ ref?: Ref<HTMLDivElement>;
430
+ }): import("react").JSX.Element;
431
+ /** Fields side by side from `sm` (a first and last name), stacked below. */
432
+ declare function Inline({ className, ...props }: ComponentProps<"div"> & {
433
+ ref?: Ref<HTMLDivElement>;
434
+ }): import("react").JSX.Element;
435
+ /** The submit. A small effect `Button`, pending while the action runs. */
436
+ declare function Submit({ children, ...props }: Omit<ButtonProps, "type">): import("react").JSX.Element;
276
437
  export interface BasicPageFooterProps extends ComponentProps<"div"> {
277
438
  /**
278
- * Animated presence for dirty-state bars: the card glides open/closed on a
279
- * height spring while the content fades. Omit for a static, always-visible
280
- * footer (no animation). No reveal plays on first mount — only on flips.
439
+ * Animated presence for the dirty-state action: the card glides
440
+ * open/closed on a height spring while the button fades. Omit for a
441
+ * static, always-visible footer (no animation). No reveal plays on first
442
+ * mount — only on flips.
281
443
  */
282
- show?: boolean;
444
+ show?: boolean | "dirty";
283
445
  ref?: Ref<HTMLDivElement>;
284
446
  }
285
447
  /**
286
- * Trailing bar inside a card — typically a save status + submit button that
287
- * appears after the form is dirty. Same horizontal/vertical padding as a row.
288
- * Pass `show` (instead of conditional rendering) to animate the bar in and
289
- * out following the onboarding card's motion language.
448
+ * Save action for a card. After a `Card` of rows it sits outside, below the
449
+ * surface, its trailing edge on the rows' text edge, so the card
450
+ * holds only rows; inside `Fields` it sits at the bottom of the sheet.
451
+ * Typically a submit button that appears after the form is dirty; pass
452
+ * `show` (instead of conditional rendering) to animate it in and out
453
+ * following the onboarding card's motion language.
290
454
  */
291
- declare function Footer({ show, className, ...props }: BasicPageFooterProps): import("react").JSX.Element;
455
+ declare function Footer({ show: showProp, className, ...props }: BasicPageFooterProps): import("react").JSX.Element;
292
456
  /**
293
457
  * DOM handlers whose React signatures clash with Motion's gesture props of
294
458
  * the same name on `motion.*` elements — excluded from `Reveal`'s public API
@@ -304,12 +468,19 @@ export interface BasicPageRevealProps extends Omit<ComponentProps<"div">, Reveal
304
468
  * the one-shot data-arrival entrance.
305
469
  */
306
470
  show?: boolean;
471
+ /**
472
+ * Clip the block while its height animates (the default). Pass `false`
473
+ * for a block whose content must show whole from the first frame — a
474
+ * button with a rim, a shadow — and let it fade in as the space opens.
475
+ */
476
+ clip?: boolean;
307
477
  /**
308
478
  * Which gap the presence variant compensates while collapsing —
309
- * `"stack"` for a Stack block (`gap-10`), `"block"` for an element
479
+ * `"stack"` for a Stack block (`gap-10`), `"fields"` for a field in a
480
+ * `Fields` sheet (`gap-5`), `"block"` for an element
310
481
  * inside a block (`gap-3`). @default "stack"
311
482
  */
312
- gap?: "stack" | "block";
483
+ gap?: "stack" | "block" | "fields";
313
484
  /**
314
485
  * Set when this wraps multiple `Card` rows — the extra element Reveal
315
486
  * needs for `AnimatePresence` sits between them and the card's own
@@ -334,7 +505,7 @@ export interface BasicPageRevealProps extends Omit<ComponentProps<"div">, Reveal
334
505
  * `Footer` grammar): a whole section of the Stack that appears or leaves at
335
506
  * runtime glides open/closed while its neighbours follow.
336
507
  */
337
- declare function Reveal({ show, gap, dividers, className, ...props }: BasicPageRevealProps): import("react").JSX.Element;
508
+ declare function Reveal({ show, clip, gap, dividers, className, ...props }: BasicPageRevealProps): import("react").JSX.Element;
338
509
  export interface BasicPageBreadcrumbsProps extends ComponentProps<"nav"> {
339
510
  /** `Crumb`s, root-most first; the last one is the immediate parent. */
340
511
  children: ReactNode;
@@ -342,23 +513,26 @@ export interface BasicPageBreadcrumbsProps extends ComponentProps<"nav"> {
342
513
  /**
343
514
  * The trail above the title — where this page sits, root-most crumb first,
344
515
  * ending with the immediate parent; the current page is the `Title` below.
345
- * Place inside `Root`, before `Title`. It floats in `Root`'s reserved top
346
- * padding (vertically centered in the 64px zone) instead of taking layout
347
- * space, so `Title` sits at the same position whether or not a page has
348
- * one.
516
+ * Place inside `Root`, before `Title`. It floats in the page's top-left
517
+ * corner instead of taking layout space, and the column reserves a 64px
518
+ * top zone for it, so `Title` sits at the same position whether or not a
519
+ * page has one.
349
520
  *
350
521
  * One form at every depth: `‹ parent / parent / parent` — the chevron opens
351
522
  * the trail (it is the way up), slashes separate the crumbs (they are the
352
523
  * path), one crumb or many. Below `sm` the path collapses to `‹ parent` —
353
524
  * the last crumb alone. Crumbs render through the host's `LinkProvider`.
354
525
  *
355
- * The offsets align the first *label* glyph with the title glyph. Title
356
- * text sits 40px in (`px-5` root gutter + `px-5` title pad); inside a `sm`
357
- * ghost button the label sits 29.75px in (8px icon-side pad + 15.75px
358
- * chevron, 1.125em at the 14px `text-base`, + 4px gap + 2px label-span
359
- * `px-0.5`) — so `left` is the 10.25px difference. `top-4` centers the 32px
360
- * buttons in the 64px reserved zone. The chevron and the ghost hover pills
361
- * hang in the padding — the usual optical alignment for borderless controls.
526
+ * Four crumbs or more, the middle folds: `‹ root / … / parent / parent`,
527
+ * with the folded pages behind the ellipsis as a menu. The trail keeps a
528
+ * width ceiling at any depth, and the fold never touches the tail, so the
529
+ * title morph is unaffected.
530
+ *
531
+ * It sits in the page's top-left corner — `top-4 left-3`, the chevron ink
532
+ * 20px from the edge, the column gutter's width — as chrome of the pane,
533
+ * not of the column: on a wide pane it stays at the corner while the
534
+ * column centers. `top-4` centers the 32px buttons in the 64px reserved
535
+ * zone; the ghost hover pills hang in the corner padding.
362
536
  *
363
537
  * Motion between pages: the tail crumb is the morph partner of the child
364
538
  * page's `Title` (pair their `morphId`s); everything before it holds still.
@@ -393,7 +567,7 @@ export type BasicPageBackProps = BasicPageCrumbProps;
393
567
  * path with `Breadcrumbs` + `Crumb` instead.
394
568
  */
395
569
  declare function Back({ className, ...props }: BasicPageBackProps): import("react").JSX.Element;
396
- export interface BasicPageRowLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "title"> {
570
+ export interface BasicPageRowLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "title" | RevealMotionConflicts> {
397
571
  /** Left-side field name — plain text, or compose with a trailing badge. */
398
572
  label: ReactNode;
399
573
  /** Optional helper under the label. */
@@ -473,6 +647,7 @@ declare function RowLink({ label, description, leading, href, className, childre
473
647
  */
474
648
  export declare const BasicPage: {
475
649
  Root: typeof Root;
650
+ CondenseScope: typeof CondenseScope;
476
651
  Breadcrumbs: typeof Breadcrumbs;
477
652
  Crumb: typeof Crumb;
478
653
  Back: typeof Back;
@@ -493,6 +668,11 @@ export declare const BasicPage: {
493
668
  Value: typeof Value;
494
669
  Alert: typeof Alert;
495
670
  Footer: typeof Footer;
671
+ Form: typeof Form;
672
+ Saved: typeof Saved;
673
+ Fields: typeof Fields;
674
+ Inline: typeof Inline;
675
+ Submit: typeof Submit;
496
676
  Reveal: typeof Reveal;
497
677
  };
498
678
  export {};
@@ -1 +1 @@
1
- export { BasicPage, BASIC_PAGE_CARD, BASIC_PAGE_CALLOUT, BASIC_PAGE_ROW, BASIC_PAGE_ITEM, BASIC_PAGE_ITEM_PANEL, BASIC_PAGE_ITEM_PANEL_DIVIDED, type BasicPageRowProps, type BasicPageRowLinkProps, type BasicPageBackProps, type BasicPageBreadcrumbsProps, type BasicPageCrumbProps, type BasicPageFooterProps, type BasicPageItemPanelProps, } 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 BasicPageRowProps, type BasicPageRowLinkProps, type BasicPageBackProps, type BasicPageBreadcrumbsProps, type BasicPageCrumbProps, type BasicPageFooterProps, type BasicPageFormProps, type BasicPageFormErrors, type BasicPageItemPanelProps, } from './basic-page';
@@ -1,4 +1,5 @@
1
1
  import { AnchorHTMLAttributes, ButtonHTMLAttributes, ComponentProps, FC, ReactNode, Ref } from 'react';
2
+ import { Button } from '../../components/button';
2
3
  /**
3
4
  * Sidebar — Pho's first SECTION: a composed app rail, not a micro component.
4
5
  * It encodes the navigation rail used across Photon surfaces (the Pho docs
@@ -52,9 +53,37 @@ interface RootProps extends ComponentProps<"aside"> {
52
53
  declare function Root({ className, inset, ...props }: RootProps): import("react").JSX.Element;
53
54
  /** Brand slot at the top of the rail — logo, wordmark, workspace switcher. */
54
55
  declare function Header({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
55
- /** The scrollable middle — a stack of `Sidebar.Group`s. */
56
- declare function Nav({ className, ...props }: ComponentProps<"nav">): import("react").JSX.Element;
57
- /** One titled cluster of nav rows: a `GroupLabel` followed by a `List`. */
56
+ /**
57
+ * The rail's search row — an outlined button dressed to `Item` metrics so
58
+ * its label lines up with the rows below, the shortcut at the trailing
59
+ * edge. The press is the Button's own; wire `onClick` (and a global ⌘K)
60
+ * to a `Command.Dialog`.
61
+ */
62
+ declare function Search({ label, kbd, className, ...props }: Omit<ComponentProps<typeof Button>, "children" | "variant" | "size"> & {
63
+ label?: ReactNode;
64
+ kbd?: string;
65
+ }): import("react").JSX.Element;
66
+ /**
67
+ * The scrollable middle — a stack of `Sidebar.Group`s in a `ScrollArea`
68
+ * (overlay scrollbar, edge fade). Pass `scroll={false}` where a parent
69
+ * scrolls the whole rail as one column (a narrow-viewport drawer) — the
70
+ * nav is then a plain stack at its natural height.
71
+ *
72
+ * The nav owns its breathing room toward its neighbors as a resting inset
73
+ * (a scroll view's safe-area padding): 24px above, 16px below by default —
74
+ * rows stand clear of the ends at rest and scroll through the gap, under
75
+ * the edge fade, instead of clipping at a dead margin. `inset` /
76
+ * `insetTop` / `insetBottom` override it; the same values become plain
77
+ * padding when `scroll={false}`, so both modes keep one geometry. A
78
+ * `Header` right before the nav and a `Footer` after it drop their own
79
+ * margins — the gap lives here, not on the neighbors.
80
+ */
81
+ declare function Nav({ scroll, inset, insetTop, insetBottom, className, style, children, ...props }: ComponentProps<"nav"> & {
82
+ scroll?: boolean;
83
+ inset?: number | string;
84
+ insetTop?: number | string;
85
+ insetBottom?: number | string;
86
+ }): import("react").JSX.Element;
58
87
  declare function Group({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
59
88
  /** The cluster's caption — description ink, regular weight. */
60
89
  declare function GroupLabel({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
@@ -151,6 +180,7 @@ declare function AccountRow({ name, avatarSrc, initials, className, ...props }:
151
180
  export declare const Sidebar: {
152
181
  Root: typeof Root;
153
182
  Header: typeof Header;
183
+ Search: typeof Search;
154
184
  Nav: typeof Nav;
155
185
  Group: typeof Group;
156
186
  GroupLabel: typeof GroupLabel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@photon-ai/pho-ui",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Pho Design System — Photon's React component library, built on Base UI",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -36,6 +36,25 @@
36
36
  }
37
37
  }
38
38
 
39
+ @layer base {
40
+ /* Each block surface registers itself, so anything that needs to fade
41
+ into "the background it sits on" (a scroll area's edge wash) reads
42
+ `--pho-surface` and inherits the nearest surface ancestor's color —
43
+ live across themes, no wiring. */
44
+ .bg-pho-page {
45
+ --pho-surface: var(--background-color-pho-page);
46
+ }
47
+ .bg-pho-primary {
48
+ --pho-surface: var(--background-color-pho-primary);
49
+ }
50
+ .bg-pho-secondary {
51
+ --pho-surface: var(--background-color-pho-secondary);
52
+ }
53
+ .bg-pho-inverse {
54
+ --pho-surface: var(--background-color-pho-inverse);
55
+ }
56
+ }
57
+
39
58
  /* True squircle corners (progressive enhancement; falls back to border-radius
40
59
  where `corner-shape` is unsupported). Pair with a `rounded-*` utility. */
41
60
  @utility squircle {