@photon-ai/pho-ui 2.3.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 (51) 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/{dialog-fWS3A3Z-.js → dialog-8SRNi_rv.js} +2 -2
  4. package/dist/chunks/{dialog-fWS3A3Z-.js.map → dialog-8SRNi_rv.js.map} +1 -1
  5. package/dist/chunks/{input-CCd6XK7Z.js → input-DjvZoF8v.js} +45 -41
  6. package/dist/chunks/input-DjvZoF8v.js.map +1 -0
  7. package/dist/chunks/{input-group-5AtpIhC_.js → input-group-fc9_jD4d.js} +44 -38
  8. package/dist/chunks/input-group-fc9_jD4d.js.map +1 -0
  9. package/dist/chunks/kbd-DNI10uy7.js +18 -0
  10. package/dist/chunks/kbd-DNI10uy7.js.map +1 -0
  11. package/dist/chunks/{scroll-area-DkZHKfqH.js → scroll-area-Bu7egArU.js} +40 -26
  12. package/dist/chunks/scroll-area-Bu7egArU.js.map +1 -0
  13. package/dist/chunks/sidebar-DvB-G0BP.js +231 -0
  14. package/dist/chunks/sidebar-DvB-G0BP.js.map +1 -0
  15. package/dist/chunks/toast-DoXaRPIZ.js +167 -0
  16. package/dist/chunks/toast-DoXaRPIZ.js.map +1 -0
  17. package/dist/components/command.js +125 -172
  18. package/dist/components/command.js.map +1 -1
  19. package/dist/components/dialog.js +1 -1
  20. package/dist/components/input-group.js +1 -1
  21. package/dist/components/input.js +1 -1
  22. package/dist/components/kbd.js +2 -15
  23. package/dist/components/phone-input.js +1 -1
  24. package/dist/components/scroll-area.js +3 -2
  25. package/dist/components/toast.js +3 -57
  26. package/dist/index.js +65 -58
  27. package/dist/primitives.js +1 -1
  28. package/dist/sections/basic-page.js +15 -8
  29. package/dist/sections/sidebar.js +1 -1
  30. package/dist/src/components/command/command.d.ts +5 -4
  31. package/dist/src/components/input/input.d.ts +10 -1
  32. package/dist/src/components/input-group/input-group.d.ts +9 -2
  33. package/dist/src/components/scroll-area/index.d.ts +1 -0
  34. package/dist/src/components/scroll-area/scroll-area-edges.d.ts +6 -0
  35. package/dist/src/components/scroll-area/scroll-area.d.ts +15 -2
  36. package/dist/src/components/toast/index.d.ts +1 -1
  37. package/dist/src/components/toast/toast.d.ts +22 -7
  38. package/dist/src/sections/basic-page/basic-page.d.ts +105 -2
  39. package/dist/src/sections/basic-page/index.d.ts +1 -1
  40. package/dist/src/sections/sidebar/sidebar.d.ts +33 -3
  41. package/package.json +1 -1
  42. package/src/styles/pho.css +19 -0
  43. package/dist/chunks/basic-page-BkLG3Ybg.js +0 -942
  44. package/dist/chunks/basic-page-BkLG3Ybg.js.map +0 -1
  45. package/dist/chunks/input-CCd6XK7Z.js.map +0 -1
  46. package/dist/chunks/input-group-5AtpIhC_.js.map +0 -1
  47. package/dist/chunks/scroll-area-DkZHKfqH.js.map +0 -1
  48. package/dist/chunks/sidebar-Dt1F_CEP.js +0 -186
  49. package/dist/chunks/sidebar-Dt1F_CEP.js.map +0 -1
  50. package/dist/components/kbd.js.map +0 -1
  51. package/dist/components/toast.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,73 +1,80 @@
1
1
  "use client";
2
- import { t as s } from "./chunks/cn-ChIgwEl3.js";
3
- import { n as r, r as o, t as E } from "./chunks/link-provider-9TFNyDqO.js";
4
- import { t as i } from "./chunks/resolve-variant-CcD8iG5l.js";
5
- import { n as I, r as n, t as A } from "./chunks/use-press-pulse-8iorQPsh.js";
2
+ import { t as a } from "./chunks/cn-ChIgwEl3.js";
3
+ import { n as r, r as E, t as o } from "./chunks/link-provider-9TFNyDqO.js";
4
+ import { t as S } from "./chunks/resolve-variant-CcD8iG5l.js";
5
+ import { n as A, r as T, t as I } from "./chunks/use-press-pulse-8iorQPsh.js";
6
6
  import "./utils.js";
7
- import { a as e, c as R, d as p, i as B, l as C, n as O, o as P, r as f, s as u, t as D, u as N } from "./chunks/button-DNNs5RsT.js";
8
- import { a as c, c as l, i as V, l as U, n as G, o as d, r as M, s as b, t as g } from "./chunks/error-Crs-wqMC.js";
9
- import { a as F, i as W, n as h, o as Z, r as v, s as w, t as x } from "./chunks/basic-page-BkLG3Ybg.js";
10
- import { a as z, c as Y, i as j, n as q, o as y, r as J, s as K, t as Q } from "./chunks/sidebar-Dt1F_CEP.js";
11
- import { t as $ } from "./chunks/input-CCd6XK7Z.js";
12
- import { t as sa } from "./chunks/close-button-GvqWbLl0.js";
13
- import { t as ra } from "./chunks/input-group-5AtpIhC_.js";
14
- import { n as Ea, t as _a } from "./chunks/card-DSW3Uhag.js";
15
- import { n as Sa, t as Ia } from "./chunks/dialog-fWS3A3Z-.js";
16
- import { i as Aa, n as Ta, r as ma, t as ea } from "./chunks/status-view-C8tabjDu.js";
7
+ import { a as m, c as R, d as B, i as p, l as C, n as O, o as f, r as u, s as N, t as P, u as D } from "./chunks/button-DNNs5RsT.js";
8
+ import { a as V, c, i as l, l as U, n as G, o as d, r as M, s as b, t as g } from "./chunks/error-Crs-wqMC.js";
9
+ import { a as F, c as W, d as h, f as v, i as Z, l as w, m as x, n as H, o as Y, p as z, r as X, s as j, t as q, u as y } from "./chunks/basic-page-c_7Ii5Fr.js";
10
+ import { a as K, c as Q, i as $, n as ss, o as as, r as ts, s as rs, t as Es } from "./chunks/sidebar-DvB-G0BP.js";
11
+ import { t as _s } from "./chunks/input-DjvZoF8v.js";
12
+ import { t as is } from "./chunks/close-button-GvqWbLl0.js";
13
+ import { t as Ts } from "./chunks/input-group-fc9_jD4d.js";
14
+ import { n as ns, t as es } from "./chunks/card-DSW3Uhag.js";
15
+ import { n as Rs, t as Bs } from "./chunks/dialog-8SRNi_rv.js";
16
+ import { i as Cs, n as Os, r as fs, t as us } from "./chunks/status-view-C8tabjDu.js";
17
17
  import "./components/status-view.js";
18
18
  export {
19
- x as BASIC_PAGE_CALLOUT,
20
- h as BASIC_PAGE_CARD,
21
- v as BASIC_PAGE_ITEM,
22
- W as BASIC_PAGE_ITEM_PANEL,
23
- F as BASIC_PAGE_ITEM_PANEL_DIVIDED,
24
- Z as BASIC_PAGE_ROW,
25
- D as BUTTON_COLORS,
19
+ q as AUTO_SAVE_DELAY_MS,
20
+ H as BASIC_PAGE_CALLOUT,
21
+ X as BASIC_PAGE_CARD,
22
+ Z as BASIC_PAGE_ITEM,
23
+ F as BASIC_PAGE_ITEM_PANEL,
24
+ Y as BASIC_PAGE_ITEM_PANEL_DIVIDED,
25
+ j as BASIC_PAGE_ROW,
26
+ P as BUTTON_COLORS,
26
27
  O as BUTTON_SHAPES,
27
- f as BUTTON_SIZES,
28
- B as BUTTON_VARIANTS,
29
- w as BasicPage,
30
- e as Button,
31
- P as ButtonLink,
32
- _a as CARD_SURFACE,
33
- A as CONTROL_PRESS_SCALE,
34
- I as CONTROL_PRESS_SPRING,
35
- Ea as Card,
36
- sa as CloseButton,
37
- Ia as Dialog,
38
- u as EFFECT_BUTTON_SIZES,
28
+ u as BUTTON_SIZES,
29
+ p as BUTTON_VARIANTS,
30
+ W as BasicPage,
31
+ m as Button,
32
+ f as ButtonLink,
33
+ es as CARD_SURFACE,
34
+ w as CONDENSE_BAR_ENTER,
35
+ y as CONDENSE_BAR_RISE_PX,
36
+ h as CONDENSE_BAR_TRAVEL,
37
+ I as CONTROL_PRESS_SCALE,
38
+ A as CONTROL_PRESS_SPRING,
39
+ ns as Card,
40
+ is as CloseButton,
41
+ Bs as Dialog,
42
+ N as EFFECT_BUTTON_SIZES,
39
43
  R as EffectButton,
40
44
  C as EffectButtonLink,
41
45
  g as Error,
42
46
  G as ErrorView,
43
47
  M as GENERIC_ERROR_TITLE,
44
- $ as Input,
45
- ra as InputGroup,
46
- E as LinkProvider,
47
- Q as SIDEBAR_HEADER_INSET,
48
- q as SIDEBAR_ITEM,
49
- J as SIDEBAR_ITEM_ACTIVE,
50
- j as SIDEBAR_ITEM_INACTIVE,
51
- z as SIDEBAR_ROOT,
52
- y as SIDEBAR_ROOT_BASE,
53
- K as SIDEBAR_ROOT_INSET,
54
- ea as STATUS_VIEW,
55
- Ta as STATUS_VIEW_COPY,
56
- ma as STATUS_VIEW_SIZES,
57
- Y as Sidebar,
58
- Aa as StatusView,
59
- N as buttonVariants,
60
- V as capitalizeFirst,
61
- s as cn,
62
- c as describeError,
63
- p as effectButtonVariants,
48
+ _s as Input,
49
+ Ts as InputGroup,
50
+ o as LinkProvider,
51
+ Es as SIDEBAR_HEADER_INSET,
52
+ ss as SIDEBAR_ITEM,
53
+ ts as SIDEBAR_ITEM_ACTIVE,
54
+ $ as SIDEBAR_ITEM_INACTIVE,
55
+ K as SIDEBAR_ROOT,
56
+ as as SIDEBAR_ROOT_BASE,
57
+ rs as SIDEBAR_ROOT_INSET,
58
+ us as STATUS_VIEW,
59
+ Os as STATUS_VIEW_COPY,
60
+ fs as STATUS_VIEW_SIZES,
61
+ Q as Sidebar,
62
+ Cs as StatusView,
63
+ D as buttonVariants,
64
+ l as capitalizeFirst,
65
+ a as cn,
66
+ V as describeError,
67
+ B as effectButtonVariants,
68
+ v as formToasts,
64
69
  d as httpReasonPhrase,
65
70
  b as httpStatusExplanation,
66
- l as isProblem,
67
- o as isReactComponent,
71
+ c as isProblem,
72
+ E as isReactComponent,
68
73
  U as parseProblem,
69
- i as resolveVariant,
70
- Sa as useDialogPending,
74
+ S as resolveVariant,
75
+ z as useAutoSave,
76
+ x as useCondense,
77
+ Rs as useDialogPending,
71
78
  r as useLinkComponent,
72
- n as usePressPulse
79
+ T as usePressPulse
73
80
  };
@@ -48,6 +48,7 @@ export * from "@base-ui/react/popover";
48
48
  export * from "@base-ui/react/avatar";
49
49
  export * from "@base-ui/react/form";
50
50
  export * from "@base-ui/react/menu";
51
+ export * from "@base-ui/react/toast";
51
52
  export * from "@base-ui/react/accordion";
52
53
  export * from "@base-ui/react/alert-dialog";
53
54
  export * from "@base-ui/react/autocomplete";
@@ -75,7 +76,6 @@ export * from "@base-ui/react/select";
75
76
  export * from "@base-ui/react/slider";
76
77
  export * from "@base-ui/react/switch";
77
78
  export * from "@base-ui/react/tabs";
78
- export * from "@base-ui/react/toast";
79
79
  export * from "@base-ui/react/toggle";
80
80
  export * from "@base-ui/react/toggle-group";
81
81
  export * from "@base-ui/react/toolbar";
@@ -1,11 +1,18 @@
1
1
  "use client";
2
- import { a as _, i as E, n as I, o as a, r as s, s as P, t as C } from "../chunks/basic-page-BkLG3Ybg.js";
2
+ import { a as A, c as E, d as s, f as a, i as S, l as C, m as I, n as B, o as P, p as e, r as N, s as o, t as D, u as R } from "../chunks/basic-page-c_7Ii5Fr.js";
3
3
  export {
4
- C as BASIC_PAGE_CALLOUT,
5
- I as BASIC_PAGE_CARD,
6
- s as BASIC_PAGE_ITEM,
7
- E as BASIC_PAGE_ITEM_PANEL,
8
- _ as BASIC_PAGE_ITEM_PANEL_DIVIDED,
9
- a as BASIC_PAGE_ROW,
10
- P as BasicPage
4
+ D as AUTO_SAVE_DELAY_MS,
5
+ B as BASIC_PAGE_CALLOUT,
6
+ N as BASIC_PAGE_CARD,
7
+ S as BASIC_PAGE_ITEM,
8
+ A as BASIC_PAGE_ITEM_PANEL,
9
+ P as BASIC_PAGE_ITEM_PANEL_DIVIDED,
10
+ o as BASIC_PAGE_ROW,
11
+ E as BasicPage,
12
+ C as CONDENSE_BAR_ENTER,
13
+ R as CONDENSE_BAR_RISE_PX,
14
+ s as CONDENSE_BAR_TRAVEL,
15
+ a as formToasts,
16
+ e as useAutoSave,
17
+ I as useCondense
11
18
  };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { a as I, c as _, i as A, n as R, o as S, r as a, s, t as T } from "../chunks/sidebar-Dt1F_CEP.js";
2
+ import { a as I, c as _, i as A, n as R, o as S, r as a, s, t as T } from "../chunks/sidebar-DvB-G0BP.js";
3
3
  export {
4
4
  T as SIDEBAR_HEADER_INSET,
5
5
  R as SIDEBAR_ITEM,
@@ -1,7 +1,7 @@
1
1
  import { ComponentProps, ReactNode } from 'react';
2
2
  import { Command as CommandPrimitive, useCommandState } from 'cmdk';
3
3
  import { Dialog as PhoDialog } from '../dialog';
4
- declare function Root({ className, children, ...props }: ComponentProps<typeof CommandPrimitive>): import("react").JSX.Element;
4
+ declare function Root({ shouldFilter, className, children, ...props }: ComponentProps<typeof CommandPrimitive>): import("react").JSX.Element;
5
5
  /**
6
6
  * The input row — a bottom hairline separates it from the list. Position
7
7
  * leading icons absolutely and pad the input (`pl-9`), mirroring
@@ -89,9 +89,10 @@ declare function Dialog({ open, onOpenChange, label, className, children, ...pro
89
89
  /**
90
90
  * Command menu built on `cmdk` — a filterable list of actions driven from a
91
91
  * single input, keyboard-first. Compose inline (`Command.Root`) or as a
92
- * ⌘K-style modal palette (`Command.Dialog`, which owns the overlay). By
93
- * default cmdk filters and ranks items for you; pass `shouldFilter={false}`
94
- * to render your own result set (e.g. hierarchy-preserving navigation).
92
+ * ⌘K-style modal palette (`Command.Dialog`, which owns the overlay).
93
+ * Filtering is yours by default — filter in render so the rows' diff can
94
+ * glide; pass `shouldFilter` to hand matching and ranking to cmdk (its
95
+ * imperative reorder skips the animation).
95
96
  *
96
97
  * Rows share one layout via `Command.Item` `level` — idle
97
98
  * `item` → `subitem` → `subsubitem`, or flat `result` while searching.
@@ -15,6 +15,15 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
15
15
  }>;
16
16
  /** Node rendered at the right edge of the label row (e.g. "Forgot?"). */
17
17
  labelTrailing?: ReactNode;
18
+ /**
19
+ * Quiet word or glyph inside the field at its trailing edge (an
20
+ * auto-save's `Saved`, a live character count). Non-interactive overlay:
21
+ * it never takes the pointer, the invalid icon takes the corner over
22
+ * it, and the input reserves nothing — content that shows only
23
+ * sometimes brings its own surface wash (as `Saved` does) so long text
24
+ * fades beneath it instead of colliding.
25
+ */
26
+ trailing?: ReactNode;
18
27
  /** Class applied to the input wrapper. */
19
28
  wrapperClassName?: string;
20
29
  ref?: Ref<HTMLInputElement>;
@@ -24,7 +33,7 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
24
33
  * Pho's bordered surface, leading icon, invalid state, and a built-in password
25
34
  * reveal toggle.
26
35
  */
27
- export declare function Input({ label, hint, size, invalid, icon: Icon, labelTrailing, disabled, required, type, className, wrapperClassName, id, ref, ...props }: InputProps): import("react").JSX.Element;
36
+ export declare function Input({ label, hint, size, invalid, icon: Icon, labelTrailing, trailing, disabled, required, type, className, wrapperClassName, id, ref, ...props }: InputProps): import("react").JSX.Element;
28
37
  export declare namespace Input {
29
38
  var displayName: string;
30
39
  }
@@ -1,4 +1,4 @@
1
- import { ComponentProps, ElementType, HTMLAttributes, InputHTMLAttributes, Ref } from 'react';
1
+ import { ComponentProps, ElementType, HTMLAttributes, InputHTMLAttributes, Ref, ReactNode } from 'react';
2
2
  import { Separator as BaseSeparator } from '@base-ui/react/separator';
3
3
  /** Override Base UI's `string | (state) => string` className with plain string. */
4
4
  type StyledProps<T extends ElementType> = Omit<ComponentProps<T>, "className"> & {
@@ -20,6 +20,13 @@ export interface InputGroupRootProps extends HTMLAttributes<HTMLDivElement> {
20
20
  */
21
21
  declare function Root({ size, invalid, className, onPointerDown, ref, ...props }: InputGroupRootProps): import("react").JSX.Element;
22
22
  export interface InputGroupInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size"> {
23
+ /**
24
+ * Quiet word or glyph over the control's trailing edge, before the
25
+ * addons (an auto-save's `Saved`). Non-interactive overlay; content
26
+ * that shows only sometimes brings its own surface wash so long text
27
+ * fades beneath it. Reserves nothing.
28
+ */
29
+ trailing?: ReactNode;
23
30
  ref?: Ref<HTMLInputElement>;
24
31
  }
25
32
  /**
@@ -27,7 +34,7 @@ export interface InputGroupInputProps extends Omit<InputHTMLAttributes<HTMLInput
27
34
  * `Field.Root` it picks up the label and description wiring automatically;
28
35
  * standalone it behaves as a plain `<input>` (pass `aria-label` then).
29
36
  */
30
- declare function GroupInput({ className, ref, ...props }: InputGroupInputProps): import("react").JSX.Element;
37
+ declare function GroupInput({ className, trailing, ref, ...props }: InputGroupInputProps): import("react").JSX.Element;
31
38
  /**
32
39
  * Inline content beside the control — prefix/suffix text, an icon, a `Kbd`
33
40
  * hint, or a small button. Text and icons render in the secondary tone so the
@@ -1 +1,2 @@
1
1
  export { ScrollArea } from './scroll-area';
2
+ export { BLUR_MAX_PX } from './scroll-area-edges';
@@ -2,6 +2,12 @@ import { Ref } from 'react';
2
2
  /** Overlay strip height — a short ramp, not a banner. `h-8` = 32px. */
3
3
  export declare const EDGE_CLASS = "pointer-events-none absolute inset-x-0 z-10 h-8";
4
4
  export declare const EDGE_REVEAL_PX = 32;
5
+ /**
6
+ * The system's one blur strength. The edge fade peaks here, and a motion
7
+ * that softens (a scope swap, a bar title) borrows the same value, so
8
+ * every soft focus in the product is the same soft focus.
9
+ */
10
+ export declare const BLUR_MAX_PX = 1;
5
11
  export declare function paintEdge(node: HTMLDivElement | null, progress: number): void;
6
12
  export declare function Edge({ edge, edgeRef, surface, className, }: {
7
13
  edge: "top" | "bottom";
@@ -1,9 +1,22 @@
1
- import { ComponentProps, ElementType } from 'react';
1
+ import { ComponentProps, ElementType, Ref } from 'react';
2
2
  import { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';
3
3
  /** Override Base UI's `string | (state) => string` className with plain string. */
4
4
  type StyledProps<T extends ElementType> = Omit<ComponentProps<T>, "className"> & {
5
5
  className?: string;
6
6
  };
7
+ /**
8
+ * The scrolled content. `inset` is a resting inset in the scroll axis —
9
+ * like a scroll view's safe-area padding: the content stands clear of the
10
+ * edges at rest but scrolls past them to the true edge, and the scrollbar
11
+ * and edge fade stay on `Root`'s edges. `insetTop` / `insetBottom` set the
12
+ * ends separately (they win over `inset`).
13
+ */
14
+ declare function Content({ inset, insetTop, insetBottom, style, ref, ...props }: ComponentProps<typeof BaseScrollArea.Content> & {
15
+ inset?: number | string;
16
+ insetTop?: number | string;
17
+ insetBottom?: number | string;
18
+ ref?: Ref<HTMLDivElement>;
19
+ }): import("react").JSX.Element;
7
20
  declare function Root({ className, children, ...props }: StyledProps<typeof BaseScrollArea.Root>): import("react").JSX.Element;
8
21
  declare function Viewport({ className, ref, ...props }: StyledProps<typeof BaseScrollArea.Viewport>): import("react").JSX.Element;
9
22
  declare function Scrollbar({ className, ...props }: StyledProps<typeof BaseScrollArea.Scrollbar>): import("react").JSX.Element;
@@ -18,7 +31,7 @@ declare function Thumb({ className, ...props }: StyledProps<typeof BaseScrollAre
18
31
  export declare const ScrollArea: {
19
32
  Root: typeof Root;
20
33
  Viewport: typeof Viewport;
21
- Content: import('react').ForwardRefExoticComponent<Omit<import('@base-ui/react').ScrollAreaContentProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
34
+ Content: typeof Content;
22
35
  Scrollbar: typeof Scrollbar;
23
36
  Thumb: typeof Thumb;
24
37
  Corner: import('react').ForwardRefExoticComponent<Omit<import('@base-ui/react').ScrollAreaCornerProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
@@ -1 +1 @@
1
- export { Toast } from './toast';
1
+ export { Toast, Toasty } from './toast';
@@ -1,4 +1,4 @@
1
- import { ComponentProps, ElementType } from 'react';
1
+ import { ComponentProps, ElementType, ReactNode } from 'react';
2
2
  import { Toast as BaseToast } from '@base-ui/react/toast';
3
3
  /** Override Base UI's `string | (state) => string` className with plain string. */
4
4
  type StyledProps<T extends ElementType> = Omit<ComponentProps<T>, "className"> & {
@@ -11,12 +11,27 @@ declare function Title({ className, ...props }: StyledProps<typeof BaseToast.Tit
11
11
  declare function Description({ className, ...props }: StyledProps<typeof BaseToast.Description>): import("react").JSX.Element;
12
12
  declare function Close({ className, ...props }: StyledProps<typeof BaseToast.Close>): import("react").JSX.Element;
13
13
  /**
14
- * Toast built on Base UI `Toast` — a transient, non-blocking notification.
15
- * Wrap your app in `Toast.Provider`, render a `Toast.Portal` → `Viewport` that
16
- * maps `useToastManager().toasts` to `Toast.Root`s, then call
17
- * `useToastManager().add({ title, description })` to show one. Use a toast for
18
- * confirmation of a background action; for a choice the user must make, use
19
- * `Dialog`.
14
+ * Toasty — the whole toast system in one wrapper, Kumo-shaped: provider,
15
+ * portal, viewport, and the stacked card list with status variants. Wrap
16
+ * the app once and call `Toast.useToastManager().add({ title, type })`
17
+ * from any child; pass a `toastManager` from `createToastManager()` so
18
+ * code outside the tree (a form's auto-save, a query cache) can speak
19
+ * through the same lane. `manager.promise` shows loading → success/error
20
+ * with the matching glyphs.
21
+ */
22
+ export declare function Toasty({ children, toastManager, }: {
23
+ children?: ReactNode;
24
+ toastManager?: ComponentProps<typeof BaseToast.Provider>["toastManager"];
25
+ }): import("react").JSX.Element;
26
+ /**
27
+ * Toast built on Base UI `Toast` — transient, non-blocking notifications
28
+ * in a sonner-style stack, styled after Cloudflare's Kumo: at rest the
29
+ * cards collapse into a peek (12px rise and −10% scale per depth, words
30
+ * hidden behind the front card), expand into a true list with a 12px gap
31
+ * on hover or focus, swipe to dismiss, three visible at most. `type`
32
+ * (`success` / `error` / `warning` / `info` / `loading`) tints hairline,
33
+ * glyph, and title together. Reach for `Toasty` unless you need to
34
+ * compose the parts yourself.
20
35
  */
21
36
  export declare const Toast: {
22
37
  Provider: import('react').FC<import('@base-ui/react').ToastProviderProps>;
@@ -72,6 +72,66 @@ export interface BasicPageRootProps extends ComponentProps<"div"> {
72
72
  condense?: boolean;
73
73
  }
74
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;
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;
75
135
  export interface BasicPageTitleProps extends ComponentProps<"h1"> {
76
136
  /**
77
137
  * Shared-element key. Pair with the same `morphId` on the subpage's
@@ -283,9 +343,36 @@ export interface BasicPageAlertProps extends Omit<ComponentProps<"div">, "childr
283
343
  * instead.
284
344
  */
285
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>;
286
362
  /** Field errors keyed by `name`, the shape Base UI `Form` maps onto fields. */
287
363
  export type BasicPageFormErrors = Record<string, string | string[]>;
288
- export interface BasicPageFormProps<Values extends Record<string, unknown> = Record<string, unknown>> extends Omit<ComponentProps<typeof FormElement>, "onFormSubmit" | "errors" | "action"> {
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;
289
376
  /**
290
377
  * The save. Receives the field values keyed by `name`, after native
291
378
  * validation passed. Resolve to finish; return `{ errors }` to put
@@ -315,7 +402,21 @@ export interface BasicPageFormProps<Values extends Record<string, unknown> = Rec
315
402
  * its footer is one block; a form that spans several blocks goes around
316
403
  * the `Stack` instead, and the blocks keep the Stack's rhythm.
317
404
  */
318
- declare function Form<Values extends Record<string, unknown>>({ action, errors: initialErrors, className, children, onChange, ...props }: BasicPageFormProps<Values>): import("react").JSX.Element;
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;
319
420
  /**
320
421
  * The form card: labelled fields stacked, label above control, one rhythm
321
422
  * (`gap-5`). Where a `Card` of `Row`s is a table of settings, this is a
@@ -546,6 +647,7 @@ declare function RowLink({ label, description, leading, href, className, childre
546
647
  */
547
648
  export declare const BasicPage: {
548
649
  Root: typeof Root;
650
+ CondenseScope: typeof CondenseScope;
549
651
  Breadcrumbs: typeof Breadcrumbs;
550
652
  Crumb: typeof Crumb;
551
653
  Back: typeof Back;
@@ -567,6 +669,7 @@ export declare const BasicPage: {
567
669
  Alert: typeof Alert;
568
670
  Footer: typeof Footer;
569
671
  Form: typeof Form;
672
+ Saved: typeof Saved;
570
673
  Fields: typeof Fields;
571
674
  Inline: typeof Inline;
572
675
  Submit: typeof Submit;
@@ -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 BasicPageRootProps, type BasicPageRowProps, type BasicPageRowLinkProps, type BasicPageBackProps, type BasicPageBreadcrumbsProps, type BasicPageCrumbProps, type BasicPageFooterProps, type BasicPageFormProps, type BasicPageFormErrors, 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.3.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 {