@photon-ai/pho-ui 2.6.0 → 2.7.1

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 (78) hide show
  1. package/dist/chunks/IconChevronDown-CZilB71T.js +11 -0
  2. package/dist/chunks/IconChevronDown-CZilB71T.js.map +1 -0
  3. package/dist/chunks/IconSearch-BKAHkLyX.js +14 -0
  4. package/dist/chunks/IconSearch-BKAHkLyX.js.map +1 -0
  5. package/dist/chunks/animated-height-CCO-Ocoz.js +48 -0
  6. package/dist/chunks/animated-height-CCO-Ocoz.js.map +1 -0
  7. package/dist/chunks/basic-page-BF4jnCa1.js +1373 -0
  8. package/dist/chunks/basic-page-BF4jnCa1.js.map +1 -0
  9. package/dist/chunks/{button-DNNs5RsT.js → button-CdqS_t5a.js} +62 -65
  10. package/dist/chunks/button-CdqS_t5a.js.map +1 -0
  11. package/dist/chunks/checkbox-Cdm08HWG.js +129 -0
  12. package/dist/chunks/checkbox-Cdm08HWG.js.map +1 -0
  13. package/dist/chunks/{choice-card-CunOnY9l.js → choice-card-BVNP1NB6.js} +2 -2
  14. package/dist/chunks/{choice-card-CunOnY9l.js.map → choice-card-BVNP1NB6.js.map} +1 -1
  15. package/dist/chunks/data-table--f6am1O3.js +279 -0
  16. package/dist/chunks/data-table--f6am1O3.js.map +1 -0
  17. package/dist/chunks/{dialog-8SRNi_rv.js → dialog-BxKACOj5.js} +4 -4
  18. package/dist/chunks/{dialog-8SRNi_rv.js.map → dialog-BxKACOj5.js.map} +1 -1
  19. package/dist/chunks/{error-Crs-wqMC.js → error-D0yoFxCv.js} +2 -2
  20. package/dist/chunks/{error-Crs-wqMC.js.map → error-D0yoFxCv.js.map} +1 -1
  21. package/dist/chunks/is-react-component-DSnjtBmo.js +10 -0
  22. package/dist/chunks/is-react-component-DSnjtBmo.js.map +1 -0
  23. package/dist/chunks/link-provider-DXzDQ08N.js +24 -0
  24. package/dist/chunks/link-provider-DXzDQ08N.js.map +1 -0
  25. package/dist/chunks/{scroll-area-Bu7egArU.js → scroll-area-BO-9PMM7.js} +27 -26
  26. package/dist/chunks/scroll-area-BO-9PMM7.js.map +1 -0
  27. package/dist/chunks/sidebar-DVzZsCts.js +223 -0
  28. package/dist/chunks/sidebar-DVzZsCts.js.map +1 -0
  29. package/dist/chunks/skeleton-DwjSl4vC.js +18 -0
  30. package/dist/chunks/skeleton-DwjSl4vC.js.map +1 -0
  31. package/dist/chunks/{toast-DoXaRPIZ.js → toast-iSf6NuAS.js} +43 -45
  32. package/dist/chunks/toast-iSf6NuAS.js.map +1 -0
  33. package/dist/chunks/use-press-pulse-IbNstUT0.js +58 -0
  34. package/dist/chunks/use-press-pulse-IbNstUT0.js.map +1 -0
  35. package/dist/components/button.js +1 -1
  36. package/dist/components/checkbox.js +4 -126
  37. package/dist/components/command.js +54 -57
  38. package/dist/components/command.js.map +1 -1
  39. package/dist/components/data-table.js +11 -0
  40. package/dist/components/dialog.js +1 -1
  41. package/dist/components/error.js +1 -1
  42. package/dist/components/phone-input.js +608 -615
  43. package/dist/components/phone-input.js.map +1 -1
  44. package/dist/components/radio-group.js +2 -2
  45. package/dist/components/scroll-area.js +1 -1
  46. package/dist/components/select.js +35 -39
  47. package/dist/components/select.js.map +1 -1
  48. package/dist/components/skeleton.js +2 -15
  49. package/dist/components/toast.js +1 -1
  50. package/dist/index.js +94 -73
  51. package/dist/motion.js +89 -0
  52. package/dist/motion.js.map +1 -0
  53. package/dist/primitives.js +2 -2
  54. package/dist/sections/basic-page.js +16 -14
  55. package/dist/sections/sidebar.js +1 -1
  56. package/dist/src/components/data-table/data-table.d.ts +227 -0
  57. package/dist/src/components/data-table/index.d.ts +2 -0
  58. package/dist/src/index.d.ts +1 -0
  59. package/dist/src/motion/index.d.ts +149 -0
  60. package/dist/src/sections/basic-page/basic-page.d.ts +47 -7
  61. package/dist/src/sections/basic-page/index.d.ts +1 -0
  62. package/dist/utils.js +13 -12
  63. package/package.json +10 -1
  64. package/dist/chunks/animated-height-C2eQstGy.js +0 -51
  65. package/dist/chunks/animated-height-C2eQstGy.js.map +0 -1
  66. package/dist/chunks/basic-page-DsI1xo6p.js +0 -1295
  67. package/dist/chunks/basic-page-DsI1xo6p.js.map +0 -1
  68. package/dist/chunks/button-DNNs5RsT.js.map +0 -1
  69. package/dist/chunks/link-provider-9TFNyDqO.js +0 -28
  70. package/dist/chunks/link-provider-9TFNyDqO.js.map +0 -1
  71. package/dist/chunks/scroll-area-Bu7egArU.js.map +0 -1
  72. package/dist/chunks/sidebar-DvB-G0BP.js +0 -231
  73. package/dist/chunks/sidebar-DvB-G0BP.js.map +0 -1
  74. package/dist/chunks/toast-DoXaRPIZ.js.map +0 -1
  75. package/dist/chunks/use-press-pulse-8iorQPsh.js +0 -62
  76. package/dist/chunks/use-press-pulse-8iorQPsh.js.map +0 -1
  77. package/dist/components/checkbox.js.map +0 -1
  78. package/dist/components/skeleton.js.map +0 -1
@@ -0,0 +1,279 @@
1
+ "use client";
2
+ import { t as m } from "./cn-ChIgwEl3.js";
3
+ import { n as se } from "./link-provider-DXzDQ08N.js";
4
+ import { SPRING_ENTRANCE as ae } from "../motion.js";
5
+ import { t as K } from "./createReactComponent-BqCmnqfX.js";
6
+ import { t as ie } from "./IconChevronDown-CZilB71T.js";
7
+ import { t as ce } from "./IconSearch-BKAHkLyX.js";
8
+ import { t as ue } from "./animated-height-CCO-Ocoz.js";
9
+ import { t as de } from "./skeleton-DwjSl4vC.js";
10
+ import { r as $ } from "./checkbox-Cdm08HWG.js";
11
+ import { Fragment as pe, createContext as V, useContext as q, useEffect as me, useLayoutEffect as Q, useMemo as he, useState as T, useSyncExternalStore as fe } from "react";
12
+ import { Fragment as J, jsx as t, jsxs as p } from "react/jsx-runtime";
13
+ import { FlexRender as F, columnFilteringFeature as ge, createColumnHelper as be, createFilteredRowModel as xe, createSortedRowModel as Se, filterFn_includesString as ve, globalFilteringFeature as ye, rowSelectionFeature as we, rowSortingFeature as Ce, sortFn_alphanumeric as Ne, sortFn_basic as Fe, sortFn_datetime as Re, sortFn_text as ke, tableFeatures as _e, useTable as Me } from "@tanstack/react-table";
14
+ var Ee = [["path", {
15
+ d: "M6 15l6 -6l6 6",
16
+ key: "svg-0"
17
+ }]], Te = K("outline", "chevron-up", "ChevronUp", Ee), Ae = [["path", {
18
+ d: "M8 9l4 -4l4 4",
19
+ key: "svg-0"
20
+ }], ["path", {
21
+ d: "M16 15l-4 4l-4 -4",
22
+ key: "svg-1"
23
+ }]], Ie = K("outline", "selector", "Selector", Ae), Le = _e({
24
+ rowSortingFeature: Ce,
25
+ rowSelectionFeature: we,
26
+ columnFilteringFeature: ge,
27
+ globalFilteringFeature: ye,
28
+ sortedRowModel: Se(),
29
+ filteredRowModel: xe(),
30
+ filterFns: { includesString: ve },
31
+ sortFns: {
32
+ alphanumeric: Ne,
33
+ basic: Fe,
34
+ datetime: Re,
35
+ text: ke
36
+ },
37
+ columnMeta: {}
38
+ });
39
+ function De() {
40
+ return be();
41
+ }
42
+ var ze = De().display({
43
+ id: "select",
44
+ enableSorting: !1,
45
+ header: ({ table: o }) => {
46
+ const l = o.getRowModel().rows, i = l.filter((c) => c.getIsSelected()).length, a = l.length > 0 && i === l.length;
47
+ return /* @__PURE__ */ t($, {
48
+ size: "sm",
49
+ "aria-label": "Select all",
50
+ checked: a,
51
+ indeterminate: i > 0 && !a,
52
+ onCheckedChange: (c) => {
53
+ o.setRowSelection((h) => {
54
+ const f = { ...h };
55
+ for (const x of l) c === !0 ? f[x.id] = !0 : delete f[x.id];
56
+ return f;
57
+ });
58
+ }
59
+ });
60
+ },
61
+ cell: ({ row: o }) => /* @__PURE__ */ t("span", {
62
+ className: "relative z-10 flex",
63
+ children: /* @__PURE__ */ t($, {
64
+ size: "sm",
65
+ "aria-label": "Select row",
66
+ checked: o.getIsSelected(),
67
+ onCheckedChange: (l) => o.toggleSelected(l === !0)
68
+ })
69
+ })
70
+ }), Oe = V(null);
71
+ function ot() {
72
+ let o = {
73
+ api: null,
74
+ adopted: !1
75
+ };
76
+ const l = /* @__PURE__ */ new Set(), i = () => {
77
+ for (const a of l) a();
78
+ };
79
+ return {
80
+ get: () => o,
81
+ subscribe(a) {
82
+ return l.add(a), () => l.delete(a);
83
+ },
84
+ publish(a) {
85
+ o = {
86
+ ...o,
87
+ api: a
88
+ }, i();
89
+ },
90
+ adopt(a) {
91
+ o = {
92
+ ...o,
93
+ adopted: a
94
+ }, i();
95
+ }
96
+ };
97
+ }
98
+ var Ue = V(null), je = () => () => {
99
+ };
100
+ function He({ value: o, onChange: l, className: i, ...a }) {
101
+ return /* @__PURE__ */ p("label", {
102
+ className: m("flex min-w-40 flex-1 items-center gap-2", i),
103
+ children: [/* @__PURE__ */ t(ce, {
104
+ "aria-hidden": !0,
105
+ className: "text-pho-description size-4 shrink-0"
106
+ }), /* @__PURE__ */ t("input", {
107
+ type: "search",
108
+ value: o,
109
+ onChange: (c) => l(c.target.value),
110
+ className: "text-pho-primary placeholder:text-pho-description outline-pho-brand w-full min-w-0 rounded-sm bg-transparent text-sm focus-visible:outline-2 focus-visible:outline-offset-2",
111
+ ...a
112
+ })]
113
+ });
114
+ }
115
+ var Ge = "rounded-base border border-pho-secondary bg-pho-primary", Pe = 5;
116
+ function Be(o, l) {
117
+ const i = o?.id;
118
+ return String(typeof i == "string" || typeof i == "number" ? i : l);
119
+ }
120
+ function rt({ columns: o, data: l, getRowId: i, rowHref: a, current: c, selected: h, onSelectedChange: f, defaultSort: x, sort: A, onSortChange: W, search: S, toolbar: I, group: R, animateHeight: L, loading: b, empty: X = "Nothing here yet.", className: Y, ...Z }) {
121
+ const ee = se(), v = q(Oe), u = S === !0 || typeof S == "string", [g, k] = T(""), y = typeof S == "string" ? S : "Search", d = q(Ue), D = fe(d?.subscribe ?? je, () => d?.get().adopted ?? !1, () => !1);
122
+ Q(() => {
123
+ if (v != null)
124
+ return v(!0), () => v(!1);
125
+ }, [v]);
126
+ const w = h != null || f != null, [te, ne] = T({}), z = h != null ? Object.fromEntries(h.map((e) => [e, !0])) : te, [oe, re] = T(x ?? []), O = A ?? oe, C = Me({
127
+ features: Le,
128
+ columns: w ? [ze, ...o] : o,
129
+ data: l,
130
+ getRowId: i ? (e) => i(e) : Be,
131
+ state: {
132
+ sorting: O,
133
+ ...u ? { globalFilter: g } : {},
134
+ ...w ? { rowSelection: z } : {}
135
+ },
136
+ ...w ? {
137
+ enableRowSelection: !0,
138
+ onRowSelectionChange: (e) => {
139
+ const n = typeof e == "function" ? e(z) : e;
140
+ h == null && ne(n), f?.(Object.keys(n));
141
+ }
142
+ } : {},
143
+ ...u ? {
144
+ onGlobalFilterChange: k,
145
+ globalFilterFn: "includesString"
146
+ } : {},
147
+ onSortingChange: (e) => {
148
+ const n = typeof e == "function" ? e(O) : e;
149
+ A == null && re(n), W?.(n);
150
+ }
151
+ }), N = C.getRowModel().rows, _ = l.length, U = u ? N.length : _;
152
+ Q(() => {
153
+ !u || d == null || d.publish({
154
+ placeholder: y,
155
+ query: g,
156
+ setQuery: k,
157
+ matched: U,
158
+ total: _
159
+ });
160
+ }, [
161
+ u,
162
+ d,
163
+ y,
164
+ g,
165
+ U,
166
+ _
167
+ ]), me(() => {
168
+ if (d != null)
169
+ return () => d.publish(null);
170
+ }, [d]);
171
+ const j = C.getAllLeafColumns().length, H = he(() => b ? Array.from({ length: b === !0 ? Pe : b }) : [], [b]), G = (e) => {
172
+ const n = a?.(e.original), s = c != null && c === e.id;
173
+ return /* @__PURE__ */ t("tr", {
174
+ className: m("relative", n != null && "hover:bg-pho-primary-hover outline-pho-brand transition-colors has-[a:focus-visible]:outline-2 has-[a:focus-visible]:-outline-offset-2", (s || e.getIsSelected()) && "bg-pho-primary-hover"),
175
+ children: e.getAllCells().map((r, E) => {
176
+ const le = r.column.columnDef.meta?.align ?? "start";
177
+ return /* @__PURE__ */ t("td", {
178
+ className: m("text-pho-primary h-12 px-5 align-middle whitespace-nowrap", le === "end" && "text-right tabular-nums"),
179
+ children: E === (w ? 1 : 0) && n != null ? /* @__PURE__ */ t(ee, {
180
+ href: n,
181
+ "aria-current": s ? "page" : void 0,
182
+ className: "outline-none after:absolute after:inset-0 after:content-['']",
183
+ children: /* @__PURE__ */ t(F, { cell: r })
184
+ }) : /* @__PURE__ */ t(F, { cell: r })
185
+ }, r.id);
186
+ })
187
+ }, e.id);
188
+ };
189
+ let M = N, P = [];
190
+ if (R != null) {
191
+ M = [];
192
+ const e = /* @__PURE__ */ new Map(), n = [];
193
+ for (const s of l) {
194
+ const r = R(s);
195
+ r != null && !e.has(r) && (e.set(r, []), n.push(r));
196
+ }
197
+ for (const s of N) {
198
+ const r = R(s.original);
199
+ r == null ? M.push(s) : (e.has(r) || (e.set(r, []), n.push(r)), e.get(r).push(s));
200
+ }
201
+ P = n.map((s) => [s, e.get(s)]).filter(([, s]) => s.length > 0);
202
+ }
203
+ const B = /* @__PURE__ */ p("table", {
204
+ className: "w-full border-collapse text-sm",
205
+ "aria-busy": b ? !0 : void 0,
206
+ children: [/* @__PURE__ */ t("thead", { children: C.getHeaderGroups().map((e) => /* @__PURE__ */ t("tr", { children: e.headers.map((n) => {
207
+ const s = n.column.columnDef.meta?.align ?? "start", r = n.column.getIsSorted(), E = !n.isPlaceholder && n.column.getCanSort();
208
+ return /* @__PURE__ */ t("th", {
209
+ scope: "col",
210
+ colSpan: n.colSpan,
211
+ "aria-sort": r === "asc" ? "ascending" : r === "desc" ? "descending" : void 0,
212
+ className: m("text-pho-description h-10 px-5 text-left align-middle font-normal whitespace-nowrap", s === "end" && "text-right"),
213
+ children: n.isPlaceholder ? null : E ? /* @__PURE__ */ p("button", {
214
+ type: "button",
215
+ onClick: n.column.getToggleSortingHandler(),
216
+ className: m("group/sort outline-pho-brand hover:text-pho-primary -mx-1 inline-flex items-center gap-1 rounded-sm px-1 transition-colors focus-visible:outline-2", s === "end" && "flex-row-reverse", r && "text-pho-primary"),
217
+ children: [/* @__PURE__ */ t(F, { header: n }), /* @__PURE__ */ t($e, { sorted: r })]
218
+ }) : /* @__PURE__ */ t(F, { header: n })
219
+ }, n.id);
220
+ }) }, e.id)) }), /* @__PURE__ */ t("tbody", {
221
+ className: "divide-pho-secondary border-pho-secondary divide-y border-t",
222
+ children: H.length > 0 ? H.map((e, n) => /* @__PURE__ */ t("tr", { children: C.getAllLeafColumns().map((s) => /* @__PURE__ */ t("td", {
223
+ className: "h-12 px-5 align-middle",
224
+ children: /* @__PURE__ */ t(de, { className: m("h-3.5 w-24", s.columnDef.meta?.align === "end" && "ml-auto") })
225
+ }, s.id)) }, n)) : N.length === 0 ? /* @__PURE__ */ t("tr", { children: /* @__PURE__ */ t("td", {
226
+ colSpan: j,
227
+ className: "text-pho-description px-5 py-10 text-center",
228
+ children: u && g !== "" && l.length > 0 ? /* @__PURE__ */ p(J, { children: [
229
+ "Nothing matches “",
230
+ g,
231
+ "”."
232
+ ] }) : X
233
+ }) }) : /* @__PURE__ */ p(J, { children: [M.map(G), P.map(([e, n]) => /* @__PURE__ */ p(pe, { children: [/* @__PURE__ */ t("tr", {
234
+ "data-table-group": "",
235
+ children: /* @__PURE__ */ t("td", {
236
+ colSpan: j,
237
+ className: "bg-pho-page text-pho-description h-9 px-5 align-middle text-xs font-medium",
238
+ children: e
239
+ })
240
+ }), n.map(G)] }, e))] })
241
+ })]
242
+ });
243
+ return /* @__PURE__ */ p("div", {
244
+ "data-data-table": "",
245
+ className: m(Ge, "scroll-mt-12 contain-inline-size", !L && "overflow-x-auto", Y),
246
+ ...Z,
247
+ children: [(I != null || u && !D) && /* @__PURE__ */ p("div", {
248
+ className: "border-pho-secondary flex min-h-11 flex-wrap items-center gap-x-4 gap-y-1 border-b px-5 py-2",
249
+ children: [u && !D && /* @__PURE__ */ t(He, {
250
+ value: g,
251
+ onChange: k,
252
+ placeholder: y,
253
+ "aria-label": y
254
+ }), I]
255
+ }), L ? /* @__PURE__ */ t(ue, {
256
+ transition: ae,
257
+ className: "overflow-x-auto",
258
+ children: B
259
+ }) : B]
260
+ });
261
+ }
262
+ function $e({ sorted: o }) {
263
+ return /* @__PURE__ */ t("span", {
264
+ "aria-hidden": !0,
265
+ className: m("inline-flex shrink-0 [&>svg]:size-3.5", !o && "opacity-0 transition-opacity group-hover/sort:opacity-100 group-focus-visible/sort:opacity-100"),
266
+ children: o === "asc" ? /* @__PURE__ */ t(Te, {}) : o === "desc" ? /* @__PURE__ */ t(ie, {}) : /* @__PURE__ */ t(Ie, {})
267
+ });
268
+ }
269
+ export {
270
+ Ue as a,
271
+ Oe as i,
272
+ rt as n,
273
+ De as o,
274
+ He as r,
275
+ ot as s,
276
+ Ge as t
277
+ };
278
+
279
+ //# sourceMappingURL=data-table--f6am1O3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-table--f6am1O3.js","names":["__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronUp.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconSelector.mjs","../../src/components/data-table/data-table.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.46.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M6 15l6 -6l6 6\", \"key\": \"svg-0\" }]];\nconst IconChevronUp = createReactComponent(\"outline\", \"chevron-up\", \"ChevronUp\", __iconNode);\n\nexport { __iconNode, IconChevronUp as default };\n//# sourceMappingURL=IconChevronUp.mjs.map\n","/**\n * @license @tabler/icons-react v3.46.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M8 9l4 -4l4 4\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M16 15l-4 4l-4 -4\", \"key\": \"svg-1\" }]];\nconst IconSelector = createReactComponent(\"outline\", \"selector\", \"Selector\", __iconNode);\n\nexport { __iconNode, IconSelector as default };\n//# sourceMappingURL=IconSelector.mjs.map\n","import {\n createContext,\n Fragment,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport {\n columnFilteringFeature,\n createColumnHelper,\n createFilteredRowModel,\n createSortedRowModel,\n filterFn_includesString,\n FlexRender,\n globalFilteringFeature,\n rowSelectionFeature,\n rowSortingFeature,\n sortFn_alphanumeric,\n sortFn_basic,\n sortFn_datetime,\n sortFn_text,\n tableFeatures,\n useTable,\n type ColumnDef,\n type RowData,\n type SortingState,\n} from \"@tanstack/react-table\";\nimport {\n IconChevronDown,\n IconChevronUp,\n IconSearch,\n IconSelector,\n} from \"@tabler/icons-react\";\nimport { Skeleton } from \"../skeleton\";\nimport { Checkbox } from \"../checkbox\";\nimport { SPRING_ENTRANCE } from \"../../motion\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\n\n/**\n * DataTable — a table of records with column semantics: sortable headers,\n * aligned cells, rows that are links into a subpage. TanStack Table (v9)\n * does the thinking — column defs, sorting, row identity — and renders\n * nothing; every pixel here is Pho's.\n *\n * Design notes:\n * - The surface is `BasicPage.Card`'s: hairline border, `base` radius, the\n * page's primary fill, hairline rules between rows. A table is a card of\n * rows that happen to line up in columns, so it sits in a page's `Stack`\n * as any card does.\n * - Header cells are description ink at body size — never small caps, never\n * bold. Hierarchy comes from ink alone; the header is a label row, not a\n * banner.\n * - A sortable header is a button inside the cell: the label and its\n * indicator (`IconSelector` at rest, a chevron once sorted). `aria-sort`\n * sits on the `th`.\n * - Rows that navigate stretch one link across the row (the first cell's\n * link, extended with a pseudo-element), so the whole row is one target\n * for pointer and one stop for keyboard. Hover washes the row; the row\n * whose page is open beside the table (`current`) keeps the wash — the\n * same cue `BasicPage.RowLink` gives under `aria-current`.\n * - Numbers align to the end with tabular figures (`meta.align: \"end\"`).\n * - `search` is one box over every column — plain contains matching, and\n * the body says when nothing matches. In a page, `BasicPage.Search` in\n * the section header adopts the box; alone, the table keeps one in a\n * toolbar row inside its frame. Server-side search keeps its own box\n * outside.\n * - A wide table scrolls sideways inside its own frame; the page never does.\n * `contain: inline-size` keeps the table's intrinsic width out of the\n * page's — a host that sizes to content (a scroll area's fit-content\n * pane, a grid's auto column) would otherwise grow to the widest row.\n *\n * Reach for it when a list needs column semantics — sorting, aligned\n * figures, several fields side by side. A list where each row is one\n * label and a chevron stays `BasicPage.RowLink`.\n */\n\n/** Column metadata a `DataTable` understands. */\nexport interface DataTableColumnMeta {\n /** Cell alignment — `end` for figures (right-aligned, tabular). */\n align?: \"start\" | \"end\";\n}\n\n/**\n * The feature set every `DataTable` runs on — sorting with the stock sort\n * functions, the column meta above. Fixed, so column definitions written\n * once fit every table.\n */\nconst features = tableFeatures({\n rowSortingFeature,\n rowSelectionFeature,\n columnFilteringFeature,\n globalFilteringFeature,\n sortedRowModel: createSortedRowModel(),\n filteredRowModel: createFilteredRowModel(),\n filterFns: { includesString: filterFn_includesString },\n sortFns: {\n alphanumeric: sortFn_alphanumeric,\n basic: sortFn_basic,\n datetime: sortFn_datetime,\n text: sortFn_text,\n },\n columnMeta: {} as DataTableColumnMeta,\n});\n\nexport type DataTableFeatures = typeof features;\n\n/** A column definition for a `DataTable` of `TData` rows. */\nexport type DataTableColumn<\n TData extends RowData,\n TValue = unknown,\n> = ColumnDef<DataTableFeatures, TData, TValue>;\n\n/**\n * The column helper, bound to the table's feature set — `accessor`,\n * `display`, `group`, and `columns` to collect them with their types\n * intact.\n *\n * @example\n * const col = createColumns<Request>();\n * const columns = col.columns([\n * col.accessor(\"actor\", { header: \"Actor\" }),\n * col.accessor(\"amount\", { header: \"Amount\", meta: { align: \"end\" } }),\n * ]);\n */\nexport function createColumns<TData extends RowData>() {\n return createColumnHelper<DataTableFeatures, TData>();\n}\n\n/**\n * The leading checkbox column selection adds. The header checkbox works\n * the visible set: everything the search still shows toggles together,\n * while rows selected earlier and then hidden stay selected.\n */\nconst SELECT_COLUMN = createColumns<RowData>().display({\n id: \"select\",\n enableSorting: false,\n header: ({ table }) => {\n const visible = table.getRowModel().rows;\n const chosen = visible.filter((row) => row.getIsSelected()).length;\n const all = visible.length > 0 && chosen === visible.length;\n return (\n <Checkbox\n size=\"sm\"\n aria-label=\"Select all\"\n checked={all}\n indeterminate={chosen > 0 && !all}\n onCheckedChange={(checked) => {\n table.setRowSelection((old) => {\n const next = { ...old };\n for (const row of visible) {\n if (checked === true) next[row.id] = true;\n else delete next[row.id];\n }\n return next;\n });\n }}\n />\n );\n },\n cell: ({ row }) => (\n // Above a row link's stretched overlay — the box stays clickable.\n // `relative` alone makes no stacking context; without `z-10` the\n // overlay's ::after paints later and eats the click.\n <span className=\"relative z-10 flex\">\n <Checkbox\n size=\"sm\"\n aria-label=\"Select row\"\n checked={row.getIsSelected()}\n onCheckedChange={(checked) => row.toggleSelected(checked === true)}\n />\n </span>\n ),\n});\n\nexport interface DataTableProps<TData extends RowData> extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n columns: ReadonlyArray<DataTableColumn<TData, any>>;\n data: ReadonlyArray<TData>;\n /**\n * A row's identity — what `current` is matched against, and what keeps a\n * row itself across sorts. Defaults to the row's `id` field, else its\n * index.\n */\n getRowId?: (row: TData) => string;\n /**\n * Rows that navigate: each row is one link into a subpage, through the\n * host's `LinkProvider`. Beside a `BasicPage.Aside`, the subpage opens\n * next to the table.\n */\n rowHref?: (row: TData) => string;\n /** The row whose page is open (its id) — it keeps the wash. */\n current?: string | null;\n /**\n * Sorting is on for every accessor column (`enableSorting: false` on a\n * column turns it off there). Uncontrolled by default; `defaultSort`\n * seeds it. Pass `sort` with `onSortChange` to own it — the way to sort\n * on the server.\n */\n defaultSort?: SortingState;\n sort?: SortingState;\n onSortChange?: (sort: SortingState) => void;\n /**\n * A search box on the table — `true`, or the placeholder it should\n * show. One box searches every column (a column opts out with\n * `enableGlobalFilter: false`); matching is a plain case-insensitive\n * contains, on the client. With no matches the body says so. When the\n * list doesn't all come down, keep the box outside and ask the server.\n */\n search?: boolean | string;\n /**\n * Controls in the frame's top band — a `BasicPage.Search` first, then a\n * filter or two. The band is part of the table (one surface, a hairline\n * above the header row), so nothing floats over the page and the\n * spacing above and below is the frame's own. A `Search` here adopts\n * the table's box the way a header one does.\n */\n toolbar?: ReactNode;\n /**\n * Row selection: hand either of these and rows grow a leading checkbox\n * column. The header checkbox works the visible set — everything the\n * search still shows — so select-all after a search means what it says;\n * rows selected earlier and then hidden stay selected. `selected` is\n * the selected ids (ids come from `getRowId`; pair with\n * `onSelectedChange` to own the state); `onSelectedChange` alone\n * listens while the table keeps it. The page renders its own bulk\n * actions from the ids — the table only keeps the score.\n */\n selected?: readonly string[];\n onSelectedChange?: (ids: string[]) => void;\n /**\n * File rows into labeled groups: return a label and the row renders\n * under it, `null` and it stays in the main body. Groups follow the\n * main body, in the order their labels first appear in `data`, each\n * under a quiet label row — and only while they have rows, so a group\n * a search empties simply leaves. Sorting orders rows within their\n * group.\n */\n group?: (row: TData) => string | null;\n /**\n * Glide the frame's height when the rows change — a search narrowing,\n * a filter, bones becoming rows. The height follows the content on the\n * page spring instead of jumping; reserve it for tables whose rows\n * change while mounted (same contract as `BasicPage.Card`'s).\n */\n animateHeight?: boolean;\n /** Bones while the rows are on their way — `true` for five, or a count. */\n loading?: boolean | number;\n /** What the body says when there are no rows. */\n empty?: ReactNode;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * A host that sizes itself around tables provides this; each table\n * announces itself while mounted. `BasicPage.Root` runs wide when the\n * page carries one and `width` was left unsaid.\n */\nexport const TableHostContext = createContext<\n ((present: boolean) => void) | null\n>(null);\n\n/** A searchable table's search, published for a header to adopt. */\nexport interface TableSearchApi {\n placeholder: string;\n query: string;\n setQuery: (query: string) => void;\n /** Rows still showing after the current query. */\n matched: number;\n /** Rows in the list, before search. */\n total: number;\n}\n\ninterface TableSearchState {\n api: TableSearchApi | null;\n adopted: boolean;\n}\n\n/**\n * The channel between a searchable table and a `BasicPage.Search` placed\n * in a section header: the table publishes its search (placeholder,\n * query, the setter); a mounted `Search` adopts it, and the table's own\n * box yields. Provided by `BasicPage.Root`; a table outside any page\n * keeps its built-in box. One searchable table per page — a later\n * publisher takes the slot.\n */\nexport interface TableSearchStore {\n get: () => TableSearchState;\n subscribe: (listener: () => void) => () => void;\n publish: (api: TableSearchApi | null) => void;\n adopt: (adopted: boolean) => void;\n}\n\nexport function createTableSearchStore(): TableSearchStore {\n let state: TableSearchState = { api: null, adopted: false };\n const listeners = new Set<() => void>();\n const emit = () => {\n for (const listener of listeners) listener();\n };\n return {\n get: () => state,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n publish(api) {\n state = { ...state, api };\n emit();\n },\n adopt(adopted) {\n state = { ...state, adopted };\n emit();\n },\n };\n}\n\nexport const TableSearchContext = createContext<TableSearchStore | null>(null);\n\nconst subscribeToNothing = () => () => {};\n\nexport interface GhostSearchProps extends Omit<\n ComponentProps<\"input\">,\n \"value\" | \"onChange\" | \"type\" | \"children\"\n> {\n value: string;\n onChange: (value: string) => void;\n}\n\n/**\n * The search's ghost face — a magnifier and a bare field, quiet ink on a\n * text line, no box around it. What a table wears in its own toolbar\n * band; `BasicPage.Search variant=\"ghost\"` is the same face wherever a\n * page wants it. Presentational: hand it the value and the setter.\n */\nexport function GhostSearch({\n value,\n onChange,\n className,\n ...props\n}: GhostSearchProps) {\n return (\n <label className={cn(\"flex min-w-40 flex-1 items-center gap-2\", className)}>\n <IconSearch\n aria-hidden\n className=\"text-pho-description size-4 shrink-0\"\n />\n <input\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className=\"text-pho-primary placeholder:text-pho-description outline-pho-brand w-full min-w-0 rounded-sm bg-transparent text-sm focus-visible:outline-2 focus-visible:outline-offset-2\"\n {...props}\n />\n </label>\n );\n}\n\n/** Same chrome as `BasicPage.Card`, minus its dividers — rows draw their own. */\nconst DATA_TABLE_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-primary\";\n\nconst DEFAULT_BONES = 5;\n\nfunction defaultRowId(row: unknown, index: number): string {\n const id = (row as { id?: unknown } | null)?.id;\n return typeof id === \"string\" || typeof id === \"number\"\n ? String(id)\n : String(index);\n}\n\nfunction DataTable<TData extends RowData>({\n columns,\n data,\n getRowId,\n rowHref,\n current,\n selected,\n onSelectedChange,\n defaultSort,\n sort,\n onSortChange,\n search,\n toolbar,\n group,\n animateHeight,\n loading,\n empty = \"Nothing here yet.\",\n className,\n ...props\n}: DataTableProps<TData>) {\n const Link = useLinkComponent();\n const announce = useContext(TableHostContext);\n const searching = search === true || typeof search === \"string\";\n const [query, setQuery] = useState(\"\");\n const placeholder = typeof search === \"string\" ? search : \"Search\";\n // A `BasicPage.Search` in a section header adopts the box; the table\n // then renders no toolbar of its own.\n const searchStore = useContext(TableSearchContext);\n const adopted = useSyncExternalStore(\n searchStore?.subscribe ?? subscribeToNothing,\n () => searchStore?.get().adopted ?? false,\n () => false,\n );\n useLayoutEffect(() => {\n if (announce == null) return;\n announce(true);\n return () => announce(false);\n }, [announce]);\n const selecting = selected != null || onSelectedChange != null;\n const [ownSelection, setOwnSelection] = useState<Record<string, true>>({});\n const rowSelection: Record<string, true> =\n selected != null\n ? Object.fromEntries(selected.map((id) => [id, true as const]))\n : ownSelection;\n // Sorting mirrors selection: the component always owns a fallback state,\n // so `defaultSort` + `onSortChange` without `sort` still sorts — a custom\n // `onSortingChange` replaces the table's own updater entirely.\n const [ownSort, setOwnSort] = useState<SortingState>(defaultSort ?? []);\n const sorting: SortingState = sort ?? ownSort;\n const table = useTable<DataTableFeatures, TData>({\n features,\n columns: (selecting\n ? [SELECT_COLUMN as DataTableColumn<TData, any>, ...columns]\n : columns) as Array<DataTableColumn<TData, any>>,\n data: data as Array<TData>,\n getRowId: getRowId ? (row) => getRowId(row) : defaultRowId,\n // Keys only when meant: a present-but-undefined slice of `state` reads\n // as \"controlled, with nobody listening\".\n state: {\n sorting,\n ...(searching ? { globalFilter: query } : {}),\n ...(selecting ? { rowSelection } : {}),\n },\n ...(selecting\n ? {\n enableRowSelection: true,\n onRowSelectionChange: (\n updater:\n | Record<string, true>\n | ((old: Record<string, true>) => Record<string, true>),\n ) => {\n const next =\n typeof updater === \"function\" ? updater(rowSelection) : updater;\n if (selected == null) setOwnSelection(next);\n onSelectedChange?.(Object.keys(next));\n },\n }\n : {}),\n ...(searching\n ? {\n onGlobalFilterChange: setQuery,\n globalFilterFn: \"includesString\" as const,\n }\n : {}),\n onSortingChange: (\n updater: SortingState | ((prev: SortingState) => SortingState),\n ) => {\n const next = typeof updater === \"function\" ? updater(sorting) : updater;\n if (sort == null) setOwnSort(next);\n onSortChange?.(next);\n },\n });\n const rows = table.getRowModel().rows;\n const total = data.length;\n const matched = searching ? rows.length : total;\n useLayoutEffect(() => {\n if (!searching || searchStore == null) return;\n searchStore.publish({ placeholder, query, setQuery, matched, total });\n }, [searching, searchStore, placeholder, query, matched, total]);\n useEffect(() => {\n if (searchStore == null) return;\n return () => searchStore.publish(null);\n }, [searchStore]);\n const leafCount = table.getAllLeafColumns().length;\n const bones = useMemo(\n () =>\n loading\n ? Array.from({ length: loading === true ? DEFAULT_BONES : loading })\n : [],\n [loading],\n );\n\n const renderRow = (row: (typeof rows)[number]) => {\n const href = rowHref?.(row.original);\n const isCurrent = current != null && current === row.id;\n return (\n <tr\n key={row.id}\n className={cn(\n \"relative\",\n href != null &&\n \"hover:bg-pho-primary-hover outline-pho-brand transition-colors has-[a:focus-visible]:outline-2 has-[a:focus-visible]:-outline-offset-2\",\n (isCurrent || row.getIsSelected()) && \"bg-pho-primary-hover\",\n )}\n >\n {row.getAllCells().map((cell, index) => {\n const align = cell.column.columnDef.meta?.align ?? \"start\";\n return (\n <td\n key={cell.id}\n className={cn(\n \"text-pho-primary h-12 px-5 align-middle whitespace-nowrap\",\n align === \"end\" && \"text-right tabular-nums\",\n )}\n >\n {/* The link lives in the first data cell; with selection on,\n cell 0 is the checkbox and must stay outside the anchor. */}\n {index === (selecting ? 1 : 0) && href != null ? (\n // The row's one link, stretched over the row; the\n // ring is the row's (`has-[a:focus-visible]`).\n <Link\n href={href}\n aria-current={isCurrent ? \"page\" : undefined}\n className=\"outline-none after:absolute after:inset-0 after:content-['']\"\n >\n <FlexRender cell={cell} />\n </Link>\n ) : (\n <FlexRender cell={cell} />\n )}\n </td>\n );\n })}\n </tr>\n );\n };\n\n // Partition the (sorted, filtered) rows: the main body, then each\n // labeled group in the order labels first appear in `data`.\n let mainRows = rows;\n let groupSections: Array<[string, typeof rows]> = [];\n if (group != null) {\n mainRows = [];\n const byLabel = new Map<string, typeof rows>();\n const order: string[] = [];\n for (const item of data) {\n const label = group(item);\n if (label != null && !byLabel.has(label)) {\n byLabel.set(label, []);\n order.push(label);\n }\n }\n for (const row of rows) {\n const label = group(row.original);\n if (label == null) {\n mainRows.push(row);\n } else {\n if (!byLabel.has(label)) {\n byLabel.set(label, []);\n order.push(label);\n }\n byLabel.get(label)!.push(row);\n }\n }\n groupSections = order\n .map((label) => [label, byLabel.get(label)!] as [string, typeof rows])\n .filter(([, sectionRows]) => sectionRows.length > 0);\n }\n\n const grid = (\n <table\n className=\"w-full border-collapse text-sm\"\n aria-busy={loading ? true : undefined}\n >\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header) => {\n const align = header.column.columnDef.meta?.align ?? \"start\";\n const sorted = header.column.getIsSorted();\n const sortable =\n !header.isPlaceholder && header.column.getCanSort();\n return (\n <th\n key={header.id}\n scope=\"col\"\n colSpan={header.colSpan}\n aria-sort={\n sorted === \"asc\"\n ? \"ascending\"\n : sorted === \"desc\"\n ? \"descending\"\n : undefined\n }\n className={cn(\n \"text-pho-description h-10 px-5 text-left align-middle font-normal whitespace-nowrap\",\n align === \"end\" && \"text-right\",\n )}\n >\n {header.isPlaceholder ? null : sortable ? (\n <button\n type=\"button\"\n onClick={header.column.getToggleSortingHandler()}\n className={cn(\n \"group/sort outline-pho-brand hover:text-pho-primary -mx-1 inline-flex items-center gap-1 rounded-sm px-1 transition-colors focus-visible:outline-2\",\n align === \"end\" && \"flex-row-reverse\",\n sorted && \"text-pho-primary\",\n )}\n >\n <FlexRender header={header} />\n <SortIndicator sorted={sorted} />\n </button>\n ) : (\n <FlexRender header={header} />\n )}\n </th>\n );\n })}\n </tr>\n ))}\n </thead>\n <tbody className=\"divide-pho-secondary border-pho-secondary divide-y border-t\">\n {bones.length > 0 ? (\n bones.map((_, index) => (\n <tr key={index}>\n {table.getAllLeafColumns().map((column) => (\n <td key={column.id} className=\"h-12 px-5 align-middle\">\n <Skeleton\n className={cn(\n \"h-3.5 w-24\",\n column.columnDef.meta?.align === \"end\" && \"ml-auto\",\n )}\n />\n </td>\n ))}\n </tr>\n ))\n ) : rows.length === 0 ? (\n <tr>\n <td\n colSpan={leafCount}\n className=\"text-pho-description px-5 py-10 text-center\"\n >\n {searching && query !== \"\" && data.length > 0 ? (\n <>Nothing matches “{query}”.</>\n ) : (\n empty\n )}\n </td>\n </tr>\n ) : (\n <>\n {mainRows.map(renderRow)}\n {groupSections.map(([label, sectionRows]) => (\n <Fragment key={label}>\n <tr data-table-group=\"\">\n <td\n colSpan={leafCount}\n // A tinted band, not spacing: the wash marks the group\n // off, the height stays compact.\n className=\"bg-pho-page text-pho-description h-9 px-5 align-middle text-xs font-medium\"\n >\n {label}\n </td>\n </tr>\n {sectionRows.map(renderRow)}\n </Fragment>\n ))}\n </>\n )}\n </tbody>\n </table>\n );\n\n return (\n <div\n data-data-table=\"\"\n className={cn(\n DATA_TABLE_SURFACE,\n \"scroll-mt-12 contain-inline-size\",\n !animateHeight && \"overflow-x-auto\",\n className,\n )}\n {...props}\n >\n {(toolbar != null || (searching && !adopted)) && (\n // The toolbar band — table chrome, like the header row: the ghost\n // search on the cells' text line (`px-5`), filters at the end.\n // Quiet ink, no boxes in the box; the hairline below is the only\n // border it brings.\n <div className=\"border-pho-secondary flex min-h-11 flex-wrap items-center gap-x-4 gap-y-1 border-b px-5 py-2\">\n {searching && !adopted && (\n <GhostSearch\n value={query}\n onChange={setQuery}\n placeholder={placeholder}\n aria-label={placeholder}\n />\n )}\n {toolbar}\n </div>\n )}\n {animateHeight ? (\n // The height glides on the page spring while the rows inside swap;\n // sideways scrolling moves onto the measured layer so the frame\n // clips height only.\n <AnimatedHeight\n transition={SPRING_ENTRANCE}\n className=\"overflow-x-auto\"\n >\n {grid}\n </AnimatedHeight>\n ) : (\n grid\n )}\n </div>\n );\n}\n\n/**\n * The sort cue beside a sortable header: the two-way glyph at rest (shown\n * on hover and focus, so a header reads as plain text until it matters), a\n * chevron pointing the way once the column is sorted.\n */\nfunction SortIndicator({ sorted }: { sorted: false | \"asc\" | \"desc\" }) {\n return (\n <span\n aria-hidden\n className={cn(\n \"inline-flex shrink-0 [&>svg]:size-3.5\",\n !sorted &&\n \"opacity-0 transition-opacity group-hover/sort:opacity-100 group-focus-visible/sort:opacity-100\",\n )}\n >\n {sorted === \"asc\" ? (\n <IconChevronUp />\n ) : sorted === \"desc\" ? (\n <IconChevronDown />\n ) : (\n <IconSelector />\n )}\n </span>\n );\n}\n\nexport { DataTable, DATA_TABLE_SURFACE };\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { t as m } from "./cn-ChIgwEl3.js";
3
- import { a as E } from "./button-DNNs5RsT.js";
3
+ import { a as E } from "./button-CdqS_t5a.js";
4
4
  import { t as P } from "./close-button-GvqWbLl0.js";
5
- import { t as I } from "./animated-height-C2eQstGy.js";
6
- import { t as p } from "./scroll-area-Bu7egArU.js";
5
+ import { t as I } from "./animated-height-CCO-Ocoz.js";
6
+ import { t as p } from "./scroll-area-BO-9PMM7.js";
7
7
  import { createContext as _, useCallback as F, useContext as D, useEffect as j, useMemo as O, useRef as C, useState as T } from "react";
8
8
  import { jsx as e, jsxs as o } from "react/jsx-runtime";
9
9
  import { Dialog as f } from "@base-ui/react/dialog";
@@ -259,4 +259,4 @@ export {
259
259
  re as t
260
260
  };
261
261
 
262
- //# sourceMappingURL=dialog-8SRNi_rv.js.map
262
+ //# sourceMappingURL=dialog-BxKACOj5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-8SRNi_rv.js","names":[],"sources":["../../src/components/dialog/dialog.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from \"react\";\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { ScrollArea } from \"../scroll-area\";\nimport { Button, type ButtonProps } from \"../button/button\";\nimport { CloseButton } from \"../button/close-button\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\n/* ========================== Async pending context ========================== */\n\n/** Imperative actions exposed by Base UI's `actionsRef`. */\ninterface RootActions {\n unmount: () => void;\n close: () => void;\n}\n\ninterface DialogPendingContextValue {\n /** True while a `Dialog.Action` promise is in flight. */\n pending: boolean;\n beginPending: () => void;\n endPending: () => void;\n /** Close the dialog imperatively (used by `Dialog.Action` on resolve). */\n close: () => void;\n}\n\nconst DialogPendingContext = createContext<DialogPendingContextValue | null>(\n null,\n);\n\n/**\n * Whether the surrounding dialog has a `Dialog.Action` promise in flight —\n * use it to disable secondary actions (Cancel etc.) while work is pending.\n * Returns `false` outside a `Dialog.Root`.\n */\nexport function useDialogPending(): boolean {\n return useContext(DialogPendingContext)?.pending ?? false;\n}\n\ntype RootProps = ComponentProps<typeof BaseDialog.Root>;\n\n/**\n * `Dialog.Root` with async awareness: while a `Dialog.Action` promise is\n * pending, every close request (outside press, Escape, `Dialog.Close`) is\n * cancelled so the dialog stays open until the work settles. Props pass\n * through to Base UI's `Dialog.Root` unchanged.\n */\nfunction Root({ onOpenChange, actionsRef, ...props }: RootProps) {\n const [pending, setPending] = useState(false);\n // Guard reads a ref so a resolve → close() in the same tick isn't blocked\n // by a not-yet-flushed state update.\n const pendingRef = useRef(false);\n const internalActionsRef = useRef<RootActions | null>(null);\n\n // Keep a caller-supplied actionsRef working alongside our internal one.\n useEffect(() => {\n if (!actionsRef) return;\n actionsRef.current = internalActionsRef.current;\n return () => {\n actionsRef.current = null;\n };\n }, [actionsRef]);\n\n const handleOpenChange = useCallback<NonNullable<RootProps[\"onOpenChange\"]>>(\n (open, eventDetails) => {\n if (!open && pendingRef.current) {\n eventDetails.cancel();\n return;\n }\n onOpenChange?.(open, eventDetails);\n },\n [onOpenChange],\n );\n\n const contextValue = useMemo<DialogPendingContextValue>(\n () => ({\n pending,\n beginPending: () => {\n pendingRef.current = true;\n setPending(true);\n },\n endPending: () => {\n pendingRef.current = false;\n setPending(false);\n },\n close: () => internalActionsRef.current?.close(),\n }),\n [pending],\n );\n\n return (\n <DialogPendingContext.Provider value={contextValue}>\n <BaseDialog.Root\n actionsRef={internalActionsRef}\n onOpenChange={handleOpenChange}\n {...props}\n />\n </DialogPendingContext.Provider>\n );\n}\n\nconst Trigger = BaseDialog.Trigger;\nconst Portal = BaseDialog.Portal;\nconst Close = BaseDialog.Close;\n\n/* ============================== Dialog.Action ============================== */\n\nexport interface DialogActionProps extends Omit<ButtonProps, \"onClick\"> {\n /**\n * Confirm handler. Return a promise to keep the dialog open while it runs:\n * the button shows `loading`, all dismissal is locked, and the dialog\n * closes when the promise resolves. On rejection the dialog stays open —\n * surface errors inside the handler. A non-promise return closes\n * immediately, like `Dialog.Close`.\n */\n onClick?: (\n event: ReactMouseEvent<HTMLButtonElement>,\n ) => void | Promise<unknown>;\n}\n\nfunction isThenable(value: unknown): value is Promise<unknown> {\n return (\n value != null && typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * The confirm button of an action row, with native promise support — a\n * `Button` that runs its (possibly async) `onClick` and closes the dialog\n * when the work settles successfully.\n */\nfunction Action({ onClick, loading, disabled, ...props }: DialogActionProps) {\n const pendingContext = useContext(DialogPendingContext);\n const [busy, setBusy] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n function handleClick(event: ReactMouseEvent<HTMLButtonElement>) {\n if (busy || loading) return;\n const result = onClick?.(event);\n if (!isThenable(result)) {\n pendingContext?.close();\n return;\n }\n setBusy(true);\n pendingContext?.beginPending();\n result.then(\n () => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n pendingContext?.close();\n },\n (error: unknown) => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.error(\"Dialog.Action: async onClick rejected —\", error);\n }\n },\n );\n }\n\n const inert = busy || loading;\n return (\n <Button\n {...props}\n disabled={disabled || inert}\n loading={inert}\n onClick={handleClick}\n />\n );\n}\n\nfunction Backdrop({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Backdrop>) {\n return (\n <BaseDialog.Backdrop\n className={cn(\n \"bg-pho-overlay fixed inset-0 z-50 transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n // Floating layer: bg-pho-primary + border-pho-secondary hairline, elevation kept.\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg border outline-none\",\n // Global height cap — the inset panel's footprint (inset-4 /\n // sm:inset-8). A flex column so the body region can shrink and\n // scroll while header and actions stay pinned.\n \"flex max-h-[calc(100dvh-2rem)] flex-col sm:max-h-[calc(100dvh-4rem)]\",\n // Opacity + scale only — leave translate centering alone (no transition-all).\n \"transition-[opacity,scale] duration-200 ease-out\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Title({ className, ...props }: StyledProps<typeof BaseDialog.Title>) {\n return (\n <BaseDialog.Title\n className={cn(\n \"text-pho-primary font-display text-display-sm font-medium text-balance\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Description({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Description>) {\n return (\n <BaseDialog.Description\n className={cn(\n \"text-pho-description text-display-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Header icon chrome: secondary ink, a hair of extra air before the title.\n * Panel dialogs use 32px (`size-8`); fullscreen gates step up to 48px\n * (`size-12`) so the glyph reads at viewport scale.\n */\nfunction DialogHeaderIcon({\n children,\n size = \"md\",\n}: {\n children: ReactNode;\n size?: \"md\" | \"lg\";\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"text-pho-secondary mb-1\",\n size === \"lg\" ? \"[&>svg]:size-12\" : \"[&>svg]:size-8\",\n )}\n >\n {children}\n </span>\n );\n}\n\ninterface ContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /**\n * Decorative icon above the title — typically a Tabler outline icon.\n * Rendered aria-hidden in secondary ink at 32px (`[&>svg]:size-8`). Pass a\n * styled node to override the ink; the size is owned by the slot.\n */\n icon?: ReactNode;\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Consequence bullets rendered as a list at the top of the body — one item\n * per outcome (what is deleted, what survives, who loses access). Use on\n * destructive confirms where the one-line description undersells the\n * impact; keep each item to a single short sentence. Wrap the load-bearing\n * figure in `<strong>` (\"<strong>3 members</strong> lose access\") — the\n * list styles it (secondary ink, medium weight); no classes needed.\n */\n consequences?: ReactNode[];\n /**\n * Final cautionary line under `consequences` — error ink at description\n * size (e.g. \"It cannot be undone. Please be certain.\"). Reserve it for\n * irreversible actions; keep it short.\n */\n warning?: ReactNode;\n /**\n * Footer action row (Cancel / Confirm, etc.). Iron rule: when `actions` is\n * set, the header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience panel: renders the portal, backdrop, and styled popup with an\n * optional header (title/description + close) and optional action row. For\n * full control, compose the parts directly (`Dialog.Portal` /\n * `Dialog.Backdrop` / `Dialog.Popup`).\n */\nfunction Content({\n icon,\n title,\n description,\n consequences,\n warning,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: ContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(icon || title || description || showCloseButton);\n const hasConsequences = consequences != null && consequences.length > 0;\n // The scrollable middle region — actions stay pinned below it.\n const hasScrollBody = hasConsequences || warning != null || children != null;\n\n return (\n <Portal>\n <Backdrop />\n <Popup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex shrink-0 flex-col gap-1 px-6 pt-6\">\n {icon && <DialogHeaderIcon>{icon}</DialogHeaderIcon>}\n {(title || showCloseButton) && (\n // Title row height = title only. Close is out of flow, centered\n // on the row, and may paint outside it (no clip, no stretch).\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {hasScrollBody && (\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content className=\"flex flex-col gap-5 px-6 py-5\">\n {hasConsequences && (\n <ul className=\"text-pho-description text-md [&_strong]:text-pho-secondary space-y-1 [&_strong]:font-medium\">\n {consequences.map((item, index) => (\n // Hand-drawn marker: a 4px dot on the first line's center —\n // quieter than the browser disc, ink tracks the text.\n <li\n key={index}\n className=\"relative pl-4 before:absolute before:top-2.5 before:left-1 before:size-1 before:rounded-full before:bg-current\"\n >\n {item}\n </li>\n ))}\n </ul>\n )}\n {warning != null && (\n <p className=\"text-pho-error text-display-xs font-medium\">\n {warning}\n </p>\n )}\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n )}\n {actions != null && (\n <div\n className={cn(\n \"flex shrink-0 items-center justify-end gap-2 px-6 pb-5\",\n !hasScrollBody && \"pt-5\",\n )}\n >\n {actions}\n </div>\n )}\n </Popup>\n </Portal>\n );\n}\n\n/* =========================== Dialog.InsetContent =========================== */\n\n/**\n * Near-fullscreen popup — the viewport minus a breathing ring, floating over\n * a backdrop (the page stays visible through the gap, so it dims like any\n * floating layer). Still a card: border, elevation, rounded corners; the\n * scale gesture stays but shrinks to 98% — at this size 95% reads like a jump.\n */\nfunction InsetPopup({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed inset-4 z-50 flex flex-col overflow-hidden rounded-lg border outline-none sm:inset-8\",\n \"transition-[opacity,scale] duration-200 ease-out\",\n \"data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0 data-[ending-style]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface InsetContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /** Decorative icon above the title — same treatment as `Content`. */\n icon?: ReactNode;\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Bottom action row. Iron rule as `Content`: when `actions` is set, the\n * header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience near-fullscreen panel: header pinned on top, body filling and\n * scrolling on its own, optional action row pinned at the bottom. Sits\n * between `Content` (a focused card) and `FullscreenContent` (a page\n * takeover): use it for roomy working surfaces — pickers, editors, previews —\n * that still want the page peeking through an edge.\n */\nfunction InsetContent({\n icon,\n title,\n description,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: InsetContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(icon || title || description || showCloseButton);\n\n return (\n <Portal>\n <Backdrop />\n <InsetPopup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex shrink-0 flex-col gap-1 px-6 pt-6\">\n {icon && <DialogHeaderIcon>{icon}</DialogHeaderIcon>}\n {(title || showCloseButton) && (\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content className=\"px-6 py-5\">\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n {actions != null && (\n <div className=\"flex shrink-0 items-center justify-end gap-2 px-6 pb-5\">\n {actions}\n </div>\n )}\n </InsetPopup>\n </Portal>\n );\n}\n\n/* ========================= Dialog.FullscreenContent ======================== */\n\n/**\n * Full-viewport popup — a page-surface takeover instead of a floating card.\n * No backdrop: the popup itself is the layer. Fade only; scale is a floating-\n * card gesture and reads wrong at viewport size.\n */\nfunction FullscreenPopup({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n \"bg-pho-page fixed inset-0 z-50 overflow-y-auto outline-none\",\n \"transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface FullscreenContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /**\n * Decorative icon above the title — same chrome as `Content`, but 48px\n * (`size-12`) for viewport-scale gates.\n */\n icon?: ReactNode;\n /** Heading of the takeover. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Action row under the body. Iron rule as `Content`: when `actions` is set,\n * the corner close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Corner close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n /**\n * Classes on the viewport-centering frame (the `min-h-full` flex host).\n * Use to drop the default optical `pb-20` when the stack grows (e.g. a\n * captcha) so true center stays put: `frameClassName=\"pb-6\"`.\n */\n frameClassName?: string;\n children?: ReactNode;\n}\n\n/**\n * Convenience full-screen panel: the whole viewport becomes the dialog, with\n * a centered column at the standalone-flow width (28rem — the same measure as\n * onboarding / invite cards). Column height follows its content through\n * `AnimatedHeight` (same spring as the Card shell), so step swaps — phone →\n * OTP → captcha — glide instead of jumping. Use for gates the visitor must\n * deal with before the page behind makes sense (e.g. binding a phone number);\n * prefer `Content` for everything conversational.\n */\nfunction FullscreenContent({\n icon,\n title,\n description,\n actions,\n showClose = true,\n frameClassName,\n children,\n className,\n ...props\n}: FullscreenContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a corner X.\n const showCloseButton = actions == null && showClose;\n\n return (\n <Portal>\n <FullscreenPopup className={className} {...props}>\n {showCloseButton && (\n <Close\n render={<CloseButton className=\"fixed top-4 right-4 z-10\" />}\n />\n )}\n {/* Default `pb-20` optically lifts the column above true center. */}\n <div\n className={cn(\n \"flex min-h-full items-center justify-center px-6 pt-6 pb-20\",\n frameClassName,\n )}\n >\n {/* Width stays on the outer host; AnimatedHeight measures the\n section stack and springs its own height on content changes. */}\n <div className=\"w-full max-w-md\">\n <AnimatedHeight className=\"flex flex-col gap-5\">\n {(icon || title || description) && (\n <div className=\"flex flex-col gap-1\">\n {icon && (\n <DialogHeaderIcon size=\"lg\">{icon}</DialogHeaderIcon>\n )}\n {title && <Title>{title}</Title>}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {children}\n {actions != null && (\n <div className=\"flex items-center justify-end gap-2\">\n {actions}\n </div>\n )}\n </AnimatedHeight>\n </div>\n </div>\n </FullscreenPopup>\n </Portal>\n );\n}\n\n/**\n * Modal dialog built on Base UI `Dialog`. Controlled or uncontrolled via\n * `Dialog.Root` (`open` / `onOpenChange` / `defaultOpen`). `Dialog.Action`\n * adds native promise support: an async confirm keeps the dialog open and\n * undismissable until the work resolves.\n */\nexport const Dialog = {\n Root,\n Trigger,\n Portal,\n Backdrop,\n Popup,\n InsetPopup,\n FullscreenPopup,\n Title,\n Description,\n Close,\n Action,\n Content,\n InsetContent,\n FullscreenContent,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"dialog-BxKACOj5.js","names":[],"sources":["../../src/components/dialog/dialog.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from \"react\";\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { ScrollArea } from \"../scroll-area\";\nimport { Button, type ButtonProps } from \"../button/button\";\nimport { CloseButton } from \"../button/close-button\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\n/* ========================== Async pending context ========================== */\n\n/** Imperative actions exposed by Base UI's `actionsRef`. */\ninterface RootActions {\n unmount: () => void;\n close: () => void;\n}\n\ninterface DialogPendingContextValue {\n /** True while a `Dialog.Action` promise is in flight. */\n pending: boolean;\n beginPending: () => void;\n endPending: () => void;\n /** Close the dialog imperatively (used by `Dialog.Action` on resolve). */\n close: () => void;\n}\n\nconst DialogPendingContext = createContext<DialogPendingContextValue | null>(\n null,\n);\n\n/**\n * Whether the surrounding dialog has a `Dialog.Action` promise in flight —\n * use it to disable secondary actions (Cancel etc.) while work is pending.\n * Returns `false` outside a `Dialog.Root`.\n */\nexport function useDialogPending(): boolean {\n return useContext(DialogPendingContext)?.pending ?? false;\n}\n\ntype RootProps = ComponentProps<typeof BaseDialog.Root>;\n\n/**\n * `Dialog.Root` with async awareness: while a `Dialog.Action` promise is\n * pending, every close request (outside press, Escape, `Dialog.Close`) is\n * cancelled so the dialog stays open until the work settles. Props pass\n * through to Base UI's `Dialog.Root` unchanged.\n */\nfunction Root({ onOpenChange, actionsRef, ...props }: RootProps) {\n const [pending, setPending] = useState(false);\n // Guard reads a ref so a resolve → close() in the same tick isn't blocked\n // by a not-yet-flushed state update.\n const pendingRef = useRef(false);\n const internalActionsRef = useRef<RootActions | null>(null);\n\n // Keep a caller-supplied actionsRef working alongside our internal one.\n useEffect(() => {\n if (!actionsRef) return;\n actionsRef.current = internalActionsRef.current;\n return () => {\n actionsRef.current = null;\n };\n }, [actionsRef]);\n\n const handleOpenChange = useCallback<NonNullable<RootProps[\"onOpenChange\"]>>(\n (open, eventDetails) => {\n if (!open && pendingRef.current) {\n eventDetails.cancel();\n return;\n }\n onOpenChange?.(open, eventDetails);\n },\n [onOpenChange],\n );\n\n const contextValue = useMemo<DialogPendingContextValue>(\n () => ({\n pending,\n beginPending: () => {\n pendingRef.current = true;\n setPending(true);\n },\n endPending: () => {\n pendingRef.current = false;\n setPending(false);\n },\n close: () => internalActionsRef.current?.close(),\n }),\n [pending],\n );\n\n return (\n <DialogPendingContext.Provider value={contextValue}>\n <BaseDialog.Root\n actionsRef={internalActionsRef}\n onOpenChange={handleOpenChange}\n {...props}\n />\n </DialogPendingContext.Provider>\n );\n}\n\nconst Trigger = BaseDialog.Trigger;\nconst Portal = BaseDialog.Portal;\nconst Close = BaseDialog.Close;\n\n/* ============================== Dialog.Action ============================== */\n\nexport interface DialogActionProps extends Omit<ButtonProps, \"onClick\"> {\n /**\n * Confirm handler. Return a promise to keep the dialog open while it runs:\n * the button shows `loading`, all dismissal is locked, and the dialog\n * closes when the promise resolves. On rejection the dialog stays open —\n * surface errors inside the handler. A non-promise return closes\n * immediately, like `Dialog.Close`.\n */\n onClick?: (\n event: ReactMouseEvent<HTMLButtonElement>,\n ) => void | Promise<unknown>;\n}\n\nfunction isThenable(value: unknown): value is Promise<unknown> {\n return (\n value != null && typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * The confirm button of an action row, with native promise support — a\n * `Button` that runs its (possibly async) `onClick` and closes the dialog\n * when the work settles successfully.\n */\nfunction Action({ onClick, loading, disabled, ...props }: DialogActionProps) {\n const pendingContext = useContext(DialogPendingContext);\n const [busy, setBusy] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n function handleClick(event: ReactMouseEvent<HTMLButtonElement>) {\n if (busy || loading) return;\n const result = onClick?.(event);\n if (!isThenable(result)) {\n pendingContext?.close();\n return;\n }\n setBusy(true);\n pendingContext?.beginPending();\n result.then(\n () => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n pendingContext?.close();\n },\n (error: unknown) => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.error(\"Dialog.Action: async onClick rejected —\", error);\n }\n },\n );\n }\n\n const inert = busy || loading;\n return (\n <Button\n {...props}\n disabled={disabled || inert}\n loading={inert}\n onClick={handleClick}\n />\n );\n}\n\nfunction Backdrop({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Backdrop>) {\n return (\n <BaseDialog.Backdrop\n className={cn(\n \"bg-pho-overlay fixed inset-0 z-50 transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n // Floating layer: bg-pho-primary + border-pho-secondary hairline, elevation kept.\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg border outline-none\",\n // Global height cap — the inset panel's footprint (inset-4 /\n // sm:inset-8). A flex column so the body region can shrink and\n // scroll while header and actions stay pinned.\n \"flex max-h-[calc(100dvh-2rem)] flex-col sm:max-h-[calc(100dvh-4rem)]\",\n // Opacity + scale only — leave translate centering alone (no transition-all).\n \"transition-[opacity,scale] duration-200 ease-out\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Title({ className, ...props }: StyledProps<typeof BaseDialog.Title>) {\n return (\n <BaseDialog.Title\n className={cn(\n \"text-pho-primary font-display text-display-sm font-medium text-balance\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Description({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Description>) {\n return (\n <BaseDialog.Description\n className={cn(\n \"text-pho-description text-display-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Header icon chrome: secondary ink, a hair of extra air before the title.\n * Panel dialogs use 32px (`size-8`); fullscreen gates step up to 48px\n * (`size-12`) so the glyph reads at viewport scale.\n */\nfunction DialogHeaderIcon({\n children,\n size = \"md\",\n}: {\n children: ReactNode;\n size?: \"md\" | \"lg\";\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"text-pho-secondary mb-1\",\n size === \"lg\" ? \"[&>svg]:size-12\" : \"[&>svg]:size-8\",\n )}\n >\n {children}\n </span>\n );\n}\n\ninterface ContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /**\n * Decorative icon above the title — typically a Tabler outline icon.\n * Rendered aria-hidden in secondary ink at 32px (`[&>svg]:size-8`). Pass a\n * styled node to override the ink; the size is owned by the slot.\n */\n icon?: ReactNode;\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Consequence bullets rendered as a list at the top of the body — one item\n * per outcome (what is deleted, what survives, who loses access). Use on\n * destructive confirms where the one-line description undersells the\n * impact; keep each item to a single short sentence. Wrap the load-bearing\n * figure in `<strong>` (\"<strong>3 members</strong> lose access\") — the\n * list styles it (secondary ink, medium weight); no classes needed.\n */\n consequences?: ReactNode[];\n /**\n * Final cautionary line under `consequences` — error ink at description\n * size (e.g. \"It cannot be undone. Please be certain.\"). Reserve it for\n * irreversible actions; keep it short.\n */\n warning?: ReactNode;\n /**\n * Footer action row (Cancel / Confirm, etc.). Iron rule: when `actions` is\n * set, the header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience panel: renders the portal, backdrop, and styled popup with an\n * optional header (title/description + close) and optional action row. For\n * full control, compose the parts directly (`Dialog.Portal` /\n * `Dialog.Backdrop` / `Dialog.Popup`).\n */\nfunction Content({\n icon,\n title,\n description,\n consequences,\n warning,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: ContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(icon || title || description || showCloseButton);\n const hasConsequences = consequences != null && consequences.length > 0;\n // The scrollable middle region — actions stay pinned below it.\n const hasScrollBody = hasConsequences || warning != null || children != null;\n\n return (\n <Portal>\n <Backdrop />\n <Popup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex shrink-0 flex-col gap-1 px-6 pt-6\">\n {icon && <DialogHeaderIcon>{icon}</DialogHeaderIcon>}\n {(title || showCloseButton) && (\n // Title row height = title only. Close is out of flow, centered\n // on the row, and may paint outside it (no clip, no stretch).\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {hasScrollBody && (\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content className=\"flex flex-col gap-5 px-6 py-5\">\n {hasConsequences && (\n <ul className=\"text-pho-description text-md [&_strong]:text-pho-secondary space-y-1 [&_strong]:font-medium\">\n {consequences.map((item, index) => (\n // Hand-drawn marker: a 4px dot on the first line's center —\n // quieter than the browser disc, ink tracks the text.\n <li\n key={index}\n className=\"relative pl-4 before:absolute before:top-2.5 before:left-1 before:size-1 before:rounded-full before:bg-current\"\n >\n {item}\n </li>\n ))}\n </ul>\n )}\n {warning != null && (\n <p className=\"text-pho-error text-display-xs font-medium\">\n {warning}\n </p>\n )}\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n )}\n {actions != null && (\n <div\n className={cn(\n \"flex shrink-0 items-center justify-end gap-2 px-6 pb-5\",\n !hasScrollBody && \"pt-5\",\n )}\n >\n {actions}\n </div>\n )}\n </Popup>\n </Portal>\n );\n}\n\n/* =========================== Dialog.InsetContent =========================== */\n\n/**\n * Near-fullscreen popup — the viewport minus a breathing ring, floating over\n * a backdrop (the page stays visible through the gap, so it dims like any\n * floating layer). Still a card: border, elevation, rounded corners; the\n * scale gesture stays but shrinks to 98% — at this size 95% reads like a jump.\n */\nfunction InsetPopup({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed inset-4 z-50 flex flex-col overflow-hidden rounded-lg border outline-none sm:inset-8\",\n \"transition-[opacity,scale] duration-200 ease-out\",\n \"data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0 data-[ending-style]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface InsetContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /** Decorative icon above the title — same treatment as `Content`. */\n icon?: ReactNode;\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Bottom action row. Iron rule as `Content`: when `actions` is set, the\n * header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience near-fullscreen panel: header pinned on top, body filling and\n * scrolling on its own, optional action row pinned at the bottom. Sits\n * between `Content` (a focused card) and `FullscreenContent` (a page\n * takeover): use it for roomy working surfaces — pickers, editors, previews —\n * that still want the page peeking through an edge.\n */\nfunction InsetContent({\n icon,\n title,\n description,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: InsetContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(icon || title || description || showCloseButton);\n\n return (\n <Portal>\n <Backdrop />\n <InsetPopup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex shrink-0 flex-col gap-1 px-6 pt-6\">\n {icon && <DialogHeaderIcon>{icon}</DialogHeaderIcon>}\n {(title || showCloseButton) && (\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content className=\"px-6 py-5\">\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n {actions != null && (\n <div className=\"flex shrink-0 items-center justify-end gap-2 px-6 pb-5\">\n {actions}\n </div>\n )}\n </InsetPopup>\n </Portal>\n );\n}\n\n/* ========================= Dialog.FullscreenContent ======================== */\n\n/**\n * Full-viewport popup — a page-surface takeover instead of a floating card.\n * No backdrop: the popup itself is the layer. Fade only; scale is a floating-\n * card gesture and reads wrong at viewport size.\n */\nfunction FullscreenPopup({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n \"bg-pho-page fixed inset-0 z-50 overflow-y-auto outline-none\",\n \"transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface FullscreenContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /**\n * Decorative icon above the title — same chrome as `Content`, but 48px\n * (`size-12`) for viewport-scale gates.\n */\n icon?: ReactNode;\n /** Heading of the takeover. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Action row under the body. Iron rule as `Content`: when `actions` is set,\n * the corner close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Corner close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n /**\n * Classes on the viewport-centering frame (the `min-h-full` flex host).\n * Use to drop the default optical `pb-20` when the stack grows (e.g. a\n * captcha) so true center stays put: `frameClassName=\"pb-6\"`.\n */\n frameClassName?: string;\n children?: ReactNode;\n}\n\n/**\n * Convenience full-screen panel: the whole viewport becomes the dialog, with\n * a centered column at the standalone-flow width (28rem — the same measure as\n * onboarding / invite cards). Column height follows its content through\n * `AnimatedHeight` (same spring as the Card shell), so step swaps — phone →\n * OTP → captcha — glide instead of jumping. Use for gates the visitor must\n * deal with before the page behind makes sense (e.g. binding a phone number);\n * prefer `Content` for everything conversational.\n */\nfunction FullscreenContent({\n icon,\n title,\n description,\n actions,\n showClose = true,\n frameClassName,\n children,\n className,\n ...props\n}: FullscreenContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a corner X.\n const showCloseButton = actions == null && showClose;\n\n return (\n <Portal>\n <FullscreenPopup className={className} {...props}>\n {showCloseButton && (\n <Close\n render={<CloseButton className=\"fixed top-4 right-4 z-10\" />}\n />\n )}\n {/* Default `pb-20` optically lifts the column above true center. */}\n <div\n className={cn(\n \"flex min-h-full items-center justify-center px-6 pt-6 pb-20\",\n frameClassName,\n )}\n >\n {/* Width stays on the outer host; AnimatedHeight measures the\n section stack and springs its own height on content changes. */}\n <div className=\"w-full max-w-md\">\n <AnimatedHeight className=\"flex flex-col gap-5\">\n {(icon || title || description) && (\n <div className=\"flex flex-col gap-1\">\n {icon && (\n <DialogHeaderIcon size=\"lg\">{icon}</DialogHeaderIcon>\n )}\n {title && <Title>{title}</Title>}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {children}\n {actions != null && (\n <div className=\"flex items-center justify-end gap-2\">\n {actions}\n </div>\n )}\n </AnimatedHeight>\n </div>\n </div>\n </FullscreenPopup>\n </Portal>\n );\n}\n\n/**\n * Modal dialog built on Base UI `Dialog`. Controlled or uncontrolled via\n * `Dialog.Root` (`open` / `onOpenChange` / `defaultOpen`). `Dialog.Action`\n * adds native promise support: an async confirm keeps the dialog open and\n * undismissable until the work resolves.\n */\nexport const Dialog = {\n Root,\n Trigger,\n Portal,\n Backdrop,\n Popup,\n InsetPopup,\n FullscreenPopup,\n Title,\n Description,\n Close,\n Action,\n Content,\n InsetContent,\n FullscreenContent,\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { t as h } from "./cn-ChIgwEl3.js";
3
- import { a as x, o as R } from "./button-DNNs5RsT.js";
3
+ import { a as x, o as R } from "./button-CdqS_t5a.js";
4
4
  import { t as C } from "./createReactComponent-BqCmnqfX.js";
5
5
  import { t as S } from "./IconInfoCircle-L0zfhg7R.js";
6
6
  import { t as g } from "./IconAlertCircleFilled-VxKU8TYK.js";
@@ -249,4 +249,4 @@ export {
249
249
  M as t
250
250
  };
251
251
 
252
- //# sourceMappingURL=error-Crs-wqMC.js.map
252
+ //# sourceMappingURL=error-D0yoFxCv.js.map