@photon-ai/pho-ui 4.2.0 → 4.3.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 (30) hide show
  1. package/dist/chunks/{basic-page-C3qjXfBe.js → basic-page-65eFgq8o.js} +407 -407
  2. package/dist/chunks/basic-page-65eFgq8o.js.map +1 -0
  3. package/dist/chunks/card-N-tvFsuV.js +64 -0
  4. package/dist/chunks/card-N-tvFsuV.js.map +1 -0
  5. package/dist/chunks/{command-CTYrSz9a.js → command-ZagVyDx7.js} +2 -2
  6. package/dist/chunks/{command-CTYrSz9a.js.map → command-ZagVyDx7.js.map} +1 -1
  7. package/dist/chunks/date-picker-CZbcNIe-.js +428 -0
  8. package/dist/chunks/date-picker-CZbcNIe-.js.map +1 -0
  9. package/dist/chunks/{dialog-BwfUFn6B.js → dialog-BYiAFetB.js} +4 -4
  10. package/dist/chunks/{dialog-BwfUFn6B.js.map → dialog-BYiAFetB.js.map} +1 -1
  11. package/dist/chunks/{filter-bar-D9lBBr4z.js → filter-bar-DTaLgQr0.js} +2 -2
  12. package/dist/chunks/{filter-bar-D9lBBr4z.js.map → filter-bar-DTaLgQr0.js.map} +1 -1
  13. package/dist/components/card.js +1 -1
  14. package/dist/components/command.js +1 -1
  15. package/dist/components/date-picker.js +1 -1
  16. package/dist/components/dialog.js +1 -1
  17. package/dist/components/filter-bar.js +1 -1
  18. package/dist/index.js +5 -5
  19. package/dist/sections/basic-page.js +1 -1
  20. package/dist/src/components/card/card.d.ts +20 -4
  21. package/dist/src/components/date-picker/date-picker.d.ts +25 -2
  22. package/dist/src/components/date-picker/index.d.ts +1 -1
  23. package/dist/src/index.d.ts +1 -1
  24. package/dist/src/sections/basic-page/basic-page.d.ts +5 -5
  25. package/package.json +1 -1
  26. package/dist/chunks/basic-page-C3qjXfBe.js.map +0 -1
  27. package/dist/chunks/card-DhDwtSi9.js +0 -56
  28. package/dist/chunks/card-DhDwtSi9.js.map +0 -1
  29. package/dist/chunks/date-picker-Ddeo1fNE.js +0 -422
  30. package/dist/chunks/date-picker-Ddeo1fNE.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker-CZbcNIe-.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconCalendar.mjs","../../src/components/date-picker/date-picker.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\": \"M4 7a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M16 3v4\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M8 3v4\", \"key\": \"svg-2\" }], [\"path\", { \"d\": \"M4 11h16\", \"key\": \"svg-3\" }], [\"path\", { \"d\": \"M11 15h1\", \"key\": \"svg-4\" }], [\"path\", { \"d\": \"M12 15v3\", \"key\": \"svg-5\" }]];\nconst IconCalendar = createReactComponent(\"outline\", \"calendar\", \"Calendar\", __iconNode);\n\nexport { __iconNode, IconCalendar as default };\n//# sourceMappingURL=IconCalendar.mjs.map\n","import {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\nimport { IconCalendar } from \"@tabler/icons-react\";\nimport type { DateRange, Matcher, PropsBase } from \"react-day-picker\";\nimport { Calendar } from \"../calendar\";\nimport { Popover } from \"../popover\";\nimport type { InputSize } from \"../input\";\nimport { cn } from \"../../utils/cn\";\n\n/** The trigger wears Input's sizes so the two line up in one form. */\nexport type DatePickerSize = InputSize;\n\n/**\n * How fine the time is asked for, and read back. Omit it for a date alone.\n * The value is always a `Date`; the granularity says which of its parts the\n * viewer sets, and everything below is zeroed.\n */\nexport type DatePickerTime = \"hour\" | \"minute\" | \"second\";\n\n/** `step` for a native time field — the unit it moves and shows. */\nconst TIME_STEP: Record<DatePickerTime, number> = {\n hour: 3600,\n minute: 60,\n second: 1,\n};\n\n// Effective padding matches Input's (12/8px, lg 14/10px); Input reaches it\n// through a 2px wrapper inset it has to compensate for, the trigger directly.\nconst SIZE_PAD: Record<DatePickerSize, string> = {\n // 16px until there is room — a 14px control next to a 16px field looks shrunk.\n sm: \"px-3 py-2 text-md md:text-base\",\n md: \"px-3 py-2 text-md\",\n lg: \"px-3.5 py-2.5 text-md\",\n};\n\nconst SIZE_RADIUS: Record<DatePickerSize, string> = {\n sm: \"rounded-base\",\n md: \"rounded-base\",\n lg: \"squircle rounded-base\",\n};\n\nconst TRIGGER_BASE = cn(\n \"bg-pho-primary ring-pho-primary text-pho-primary relative flex cursor-pointer items-center gap-2 text-left ring-1 ring-inset\",\n \"transition-shadow duration-100 ease-linear focus-visible:outline-none\",\n // Invalid is mid-weight — thicker than the rest hairline, thinner than focus.\n \"data-[invalid]:ring-pho-error-subtle data-[invalid]:ring-[1.5px]\",\n);\n\n// Open or focused, the edge is Input's: the brand ring at 2px in place of the\n// hairline. The popover path focuses the button itself; the native path puts a\n// system field over it, so the ring follows the field inside.\nconst TRIGGER_FIELD = cn(\n \"has-[input:focus-visible]:ring-pho-brand data-[popup-open]:ring-pho-brand has-[input:focus-visible]:ring-2 data-[popup-open]:ring-2\",\n \"data-[invalid]:has-[input:focus-visible]:ring-pho-error data-[invalid]:data-[popup-open]:ring-pho-error\",\n \"has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50\",\n);\n\nconst TRIGGER_NATIVE = cn(\n \"has-[input:focus-visible]:ring-pho-brand has-[input:focus-visible]:ring-2\",\n \"data-[invalid]:has-[input:focus-visible]:ring-pho-error\",\n \"has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50\",\n);\n\n/**\n * A named window in the rail beside the calendar — the Menu row's manners,\n * since that is what a list of choices is.\n */\nconst PRESET = cn(\n \"flex shrink-0 cursor-pointer items-center rounded-sm px-2.5 py-1.5 text-left text-base whitespace-nowrap select-none\",\n \"text-pho-secondary transition-[color,background-color] duration-150 ease-out\",\n \"hover:bg-pho-ghost-hover hover:text-pho-primary\",\n \"outline-pho-brand focus-visible:outline-2 focus-visible:-outline-offset-1\",\n \"sm:w-full\",\n);\n\n/** The one in play. Quiet, like a highlighted menu row — not an action fill. */\nconst PRESET_ON = \"bg-pho-ghost-hover text-pho-primary font-medium\";\n\n/* ------------------------------------------------------------------ words */\n\n/**\n * ICU disagrees with itself about which space belongs before `AM` and around\n * a range dash: Node sends a narrow no-break space and a thin space where\n * Chrome sends ordinary ones. The two strings look identical and are not, so\n * a server-rendered label would fail to hydrate. Flattening every space\n * separator to the ordinary one makes the words the same on both sides.\n */\nconst SPACE_SEPARATORS = /[\\u00a0\\u2000-\\u200a\\u202f\\u205f\\u3000]/g;\nconst flattenSpaces = (words: string) => words.replace(SPACE_SEPARATORS, \" \");\n\n/** The date's parts, all in figures — the shape that is quickest to type. */\nconst NUMERIC_DATE = {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n} as const;\n\n/** The clock, on a 24-hour dial: `15:04` is fewer keystrokes than `3:04 PM`. */\nconst NUMERIC_CLOCK: Record<DatePickerTime, Intl.DateTimeFormatOptions> = {\n hour: { hour: \"2-digit\", minute: \"2-digit\", hourCycle: \"h23\" },\n minute: { hour: \"2-digit\", minute: \"2-digit\", hourCycle: \"h23\" },\n second: {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hourCycle: \"h23\",\n },\n};\n\n/**\n * What sits between the two ends of a span. No spaces around it — the field\n * is tight and the dates are already grouped by their own separators. An en\n * dash rather than a hyphen because a hyphen is one: `2026-09-01-08` in a\n * year-first locale would read as three numbers, `2026-09-01–08` as two dates.\n */\nconst SPAN_DASH = \"\\u2013\";\n\n/** A day whose parts are all different, so the locale's order reads clearly. */\nconst SAMPLE = new Date(2026, 8, 12, 15, 4, 5);\n\nfunction numericFormat(\n locales: Intl.LocalesArgument,\n time: DatePickerTime | undefined,\n) {\n return new Intl.DateTimeFormat(locales, {\n ...NUMERIC_DATE,\n ...(time ? NUMERIC_CLOCK[time] : {}),\n });\n}\n\ntype DatePart = \"year\" | \"month\" | \"day\";\nconst isDatePart = (type: string): type is DatePart =>\n type === \"year\" || type === \"month\" || type === \"day\";\n\n/** Which of year, month and day comes first here, and which comes last. */\nfunction numericOrder(locales: Intl.LocalesArgument): DatePart[] {\n return new Intl.DateTimeFormat(locales, NUMERIC_DATE)\n .formatToParts(SAMPLE)\n .map((part) => part.type)\n .filter(isDatePart);\n}\n\nconst MASK: Record<DatePart, string> = {\n year: \"yyyy\",\n month: \"mm\",\n day: \"dd\",\n};\n\n/**\n * The shape to type, in this locale's own order — `mm/dd/yyyy`,\n * `yyyy-mm-dd`, `dd.mm.yyyy`. Lowercase, the way a browser's own date field\n * writes it, so the two paths read alike.\n */\nexport function dateFieldMask(\n locales?: Intl.LocalesArgument,\n time?: DatePickerTime,\n): string {\n return flattenSpaces(\n numericFormat(locales, time)\n .formatToParts(SAMPLE)\n .map((part) =>\n isDatePart(part.type)\n ? MASK[part.type]\n : part.type === \"hour\"\n ? \"hh\"\n : part.type === \"minute\"\n ? \"mm\"\n : part.type === \"second\"\n ? \"ss\"\n : part.value,\n )\n .join(\"\"),\n );\n}\n\n/**\n * The figures in the field — `09/12/2026`, or `09/10/2026–09/13/2026` for a\n * span, in the viewer's locale. An empty or half-finished range prints just\n * the day that is settled; nothing selected prints nothing. Pass `time` to\n * print the clock too, at the precision that was asked for.\n *\n * Figures rather than words (`Sep 12, 2026`) because the field is typed into:\n * a month's name is the one part of a date nobody wants to spell.\n */\nexport function formatDateLabel(\n value: Date | DateRange | undefined,\n locales?: Intl.LocalesArgument,\n time?: DatePickerTime,\n): string {\n if (value == null) return \"\";\n const format = numericFormat(locales, time);\n if (value instanceof Date) return flattenSpaces(format.format(value));\n if (value.from == null) return \"\";\n if (value.to == null) return flattenSpaces(format.format(value.from));\n // A span of one day is a day: printing it twice says nothing the once did\n // not, and the first click of a range makes exactly that shape.\n if (\n time == null &&\n value.from.getFullYear() === value.to.getFullYear() &&\n value.from.getMonth() === value.to.getMonth() &&\n value.from.getDate() === value.to.getDate()\n ) {\n return flattenSpaces(format.format(value.from));\n }\n return flattenSpaces(joinSpan(format, value.from, value.to, time != null));\n}\n\n/**\n * Both ends of a span, with whatever they say twice said once — a shared\n * year, and a shared month behind it, printed at the end that carries it.\n * `09/01–09/08/2026`, `01.–08.09.2026`, `2026-09-01–08`. A span carrying a\n * clock is printed whole.\n *\n * Joined here rather than by `Intl.formatRange`, which does this in `de-DE`\n * and `sv-SE` and not in `en-US` or `en-GB`, and which drops the padding the\n * single-date format asks for. Whole fields only, taken from whichever end\n * the year sits at, so the half that is dropped is never the half that\n * distinguishes the two dates.\n */\nfunction joinSpan(\n format: Intl.DateTimeFormat,\n from: Date,\n to: Date,\n hasClock: boolean,\n): string {\n const a = format.formatToParts(from);\n const b = format.formatToParts(to);\n const text = (parts: Intl.DateTimeFormatPart[]) =>\n parts.map((part) => part.value).join(\"\");\n\n // With a clock in it there is nothing worth merging: the tail fields are\n // hours and minutes, the saving is a year that would then print after a\n // time, and a trim that lands mid-clock eats one end's `:00`.\n if (hasClock || a.length !== b.length) {\n return `${text(a)}${SPAN_DASH}${text(b)}`;\n }\n const same = (at: number) =>\n a[at]!.type === b[at]!.type && a[at]!.value === b[at]!.value;\n\n // The year leads (`yyyy-mm-dd`): the second date drops the shared head.\n if (a[0]?.type === \"year\") {\n let cut = 0;\n while (cut < a.length && same(cut)) cut += 1;\n // Back off to a field boundary so a half-written number never survives.\n while (cut > 0 && b[cut - 1]!.type !== \"literal\") cut -= 1;\n if (cut > 0 && cut < a.length) {\n return `${text(a)}${SPAN_DASH}${text(b.slice(cut))}`;\n }\n return `${text(a)}${SPAN_DASH}${text(b)}`;\n }\n\n // The year trails (`mm/dd/yyyy`, `dd.mm.yyyy`): the first date drops the\n // shared tail.\n let keep = a.length;\n while (keep > 0 && same(keep - 1)) keep -= 1;\n while (keep < a.length && a[keep]!.type !== \"literal\") keep += 1;\n if (keep > 0 && keep < a.length) {\n return `${text(a.slice(0, keep))}${SPAN_DASH}${text(b)}`;\n }\n return `${text(a)}${SPAN_DASH}${text(b)}`;\n}\n\n/* ------------------------------------------------------- date arithmetic */\n\nconst pad = (n: number) => String(n).padStart(2, \"0\");\n\n/** `YYYY-MM-DD` in the viewer's own zone — never `toISOString`, which is UTC. */\nfunction toDateValue(date: Date): string {\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\nfunction toClockValue(date: Date, time: DatePickerTime): string {\n const hm = `${pad(date.getHours())}:${pad(date.getMinutes())}`;\n return time === \"second\" ? `${hm}:${pad(date.getSeconds())}` : hm;\n}\n\n/** The `datetime-local` spelling of an instant, at the asked-for precision. */\nfunction toDateTimeValue(date: Date, time: DatePickerTime): string {\n return `${toDateValue(date)}T${toClockValue(date, time)}`;\n}\n\n/**\n * Read back a `date` or `datetime-local` field. Parsed part by part rather\n * than handed to `new Date(string)`, which reads a bare `YYYY-MM-DD` as UTC\n * midnight and lands on the day before west of Greenwich.\n */\nfunction fromInputValue(value: string): Date | undefined {\n const match =\n /^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2}))?)?$/.exec(value);\n if (!match) return undefined;\n const [, y, m, d, hh, mm, ss] = match;\n const date = new Date(\n Number(y),\n Number(m) - 1,\n Number(d),\n Number(hh ?? 0),\n Number(mm ?? 0),\n Number(ss ?? 0),\n 0,\n );\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/** A date the calendar could actually show — `Feb 31` rolled over, so no. */\nfunction makeLocalDate(\n shortYear: number,\n month: number,\n day: number,\n clock: number[],\n): Date | undefined {\n // `12/25/26` means 2026, not the year 26 — and `new Date(26, …)` would say\n // 1926. Two figures are this century.\n const year = shortYear < 100 ? 2000 + shortYear : shortYear;\n if (month < 1 || month > 12 || day < 1 || day > 31) return undefined;\n const [hh = 0, mm = 0, ss = 0] = clock;\n if (hh > 23 || mm > 59 || ss > 59) return undefined;\n const date = new Date(year, month - 1, day, hh, mm, ss, 0);\n return date.getMonth() === month - 1 && date.getDate() === day\n ? date\n : undefined;\n}\n\n/**\n * A date out of whatever the viewer typed, read in the same order the field\n * writes it — so what it shows is what it takes back. `yyyy-mm-dd` is read as\n * itself wherever it turns up, since nothing else starts with four figures,\n * and a date spelled out in words still parses so a paste of `Sep 12, 2026`\n * lands. Three numbers at least: the field must not flicker through\n * Decembers on the way to one date.\n */\nfunction parseDateText(\n text: string,\n locales: Intl.LocalesArgument,\n): Date | undefined {\n const trimmed = text.trim();\n if (trimmed === \"\") return undefined;\n\n const numbers = (trimmed.match(/\\d+/g) ?? []).map(Number);\n if (numbers.length >= 3) {\n const clock = numbers.slice(3);\n // `3:04 pm` is not the shape the field writes, but it is a shape people\n // type; move it onto the 24-hour dial the rest of this speaks.\n if (/\\bpm\\b/i.test(trimmed) && clock[0] !== undefined && clock[0] < 12) {\n clock[0] += 12;\n } else if (/\\bam\\b/i.test(trimmed) && clock[0] === 12) {\n clock[0] = 0;\n }\n\n // Four figures up front can only be a year; no locale puts a day or a\n // month there.\n if (/^\\d{4}\\D/.test(trimmed)) {\n const [year, month, day] = numbers;\n return makeLocalDate(year!, month!, day!, clock);\n }\n\n const slots: Partial<Record<DatePart, number>> = {};\n numericOrder(locales).forEach((part, at) => {\n slots[part] = numbers[at];\n });\n if (slots.year != null && slots.month != null && slots.day != null) {\n const made = makeLocalDate(slots.year, slots.month, slots.day, clock);\n if (made) return made;\n }\n }\n\n // Words — a pasted `Sep 12, 2026`. Only worth trying with letters in it and\n // a four-figure year to go with them: `new Date` turns a bare `Sep 12` into\n // this year's, which is a guess the field should not make.\n if (!/[a-z]/i.test(trimmed)) return undefined;\n if (numbers.length < 2 || !/\\b\\d{4}\\b/.test(trimmed)) return undefined;\n const spelled = new Date(trimmed);\n return Number.isNaN(spelled.getTime()) ? undefined : spelled;\n}\n\n/** Zero everything finer than the granularity, so the value means what it says. */\nfunction clampTime(date: Date, time: DatePickerTime | undefined): Date {\n const next = new Date(date);\n next.setMilliseconds(0);\n if (time === \"second\") return next;\n next.setSeconds(0);\n if (time === \"minute\") return next;\n next.setMinutes(0);\n if (time === \"hour\") return next;\n next.setHours(0);\n return next;\n}\n\n/**\n * A value's identity, for telling whether the window on screen is still the\n * one a preset put there. Instants, so a re-render cannot change the answer.\n */\nfunction valueKey(value: Date | DateRange | undefined): string {\n if (value == null) return \"\";\n if (value instanceof Date) return String(value.getTime());\n return `${value.from?.getTime() ?? \"\"}-${value.to?.getTime() ?? \"\"}`;\n}\n\n/** A day from the calendar, wearing the clock the value already carried. */\nfunction withDay(day: Date, keepTimeFrom: Date | undefined): Date {\n const next = new Date(day);\n if (keepTimeFrom) {\n next.setHours(\n keepTimeFrom.getHours(),\n keepTimeFrom.getMinutes(),\n keepTimeFrom.getSeconds(),\n 0,\n );\n }\n return next;\n}\n\nconst startOfMonth = (d: Date) => new Date(d.getFullYear(), d.getMonth(), 1);\nconst endOfMonth = (d: Date) => new Date(d.getFullYear(), d.getMonth() + 1, 0);\n// DayPicker's matchers count calendar days, so a bound carrying a time of day\n// disables nothing extra on the calendar. Widen each to its whole day before\n// handing it to a system picker, which would otherwise enforce the clock too.\nconst startOfDay = (d: Date) =>\n new Date(d.getFullYear(), d.getMonth(), d.getDate());\nconst endOfDay = (d: Date) =>\n new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59, 999);\nconst later = (a: Date | undefined, b: Date) => (a && a > b ? a : b);\nconst earlier = (a: Date | undefined, b: Date) => (a && a < b ? a : b);\n\n/**\n * The only rules a system picker enforces are its first and last day. Returns\n * them, or `null` when the page asked for something the OS cannot express — a\n * weekday rule, a predicate, a hidden set — in which case the calendar, which\n * can enforce it, stays on every device.\n */\nfunction nativeBounds(\n calendarProps: PropsBase | undefined,\n): { min?: Date; max?: Date } | null {\n if (calendarProps?.hidden != null) return null;\n\n let min: Date | undefined;\n let max: Date | undefined;\n const rules: Matcher[] =\n calendarProps?.disabled == null\n ? []\n : Array.isArray(calendarProps.disabled)\n ? calendarProps.disabled\n : [calendarProps.disabled];\n\n for (const rule of rules) {\n if (rule == null || typeof rule !== \"object\" || rule instanceof Date) {\n return null;\n }\n const keys = Object.keys(rule);\n // `{ before }` and `{ after }` alone are the two the OS understands; the\n // pair of them is DayPicker's *interval*, which means the opposite.\n if (keys.length !== 1) return null;\n if (\"before\" in rule && rule.before instanceof Date) {\n min = later(min, startOfDay(rule.before));\n } else if (\"after\" in rule && rule.after instanceof Date) {\n max = earlier(max, endOfDay(rule.after));\n } else {\n return null;\n }\n }\n\n if (calendarProps?.startMonth) {\n min = later(min, startOfMonth(calendarProps.startMonth));\n }\n if (calendarProps?.endMonth) {\n max = earlier(max, endOfDay(endOfMonth(calendarProps.endMonth)));\n }\n return { min, max };\n}\n\n/* --------------------------------------------------------------- devices */\n\nconst COARSE_POINTER = \"(pointer: coarse)\";\n\n/**\n * True where the primary input is a finger. `useSyncExternalStore` so the\n * server and the first client render agree (no match) and the swap happens in\n * the same commit as hydration, rather than as a mismatch.\n */\nfunction useCoarsePointer(): boolean {\n const subscribe = useCallback((notify: () => void) => {\n if (typeof window === \"undefined\" || !window.matchMedia) return () => {};\n const query = window.matchMedia(COARSE_POINTER);\n query.addEventListener(\"change\", notify);\n return () => query.removeEventListener(\"change\", notify);\n }, []);\n\n return useSyncExternalStore(\n subscribe,\n () =>\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(COARSE_POINTER).matches,\n () => false,\n );\n}\n\n/* ------------------------------------------------------------------ props */\n\n/**\n * A window the page offers by name — `Last 7 days` — beside the calendar.\n * Pass a function for anything measured from now, so it is resolved at the\n * click rather than at render.\n */\nexport interface DatePickerPreset<T> {\n label: string;\n value: T | (() => T);\n}\n\n/** Extra about a change — present when the value came from a named window. */\nexport interface DatePickerChangeDetails<T> {\n preset: DatePickerPreset<T>;\n}\n\ninterface DatePickerBaseProps {\n /** Field label (associated for accessibility). */\n label?: ReactNode;\n /** Helper text below the field; rendered in the error color when `invalid`. */\n hint?: ReactNode;\n /**\n * What the field shows until something is chosen.\n * @default the shape to type, in this locale's order (`mm/dd/yyyy`)\n */\n placeholder?: string;\n /** Render the invalid state (error ring + error-colored hint). */\n invalid?: boolean;\n disabled?: boolean;\n /** Marks the label with the required asterisk. */\n required?: boolean;\n /** Size variant. @default \"md\" */\n size?: DatePickerSize;\n /**\n * `fill` takes the column it is in, like every other field. `hug` shrinks\n * to the words it is showing, for a field that sits in a toolbar or beside\n * a title rather than in a form.\n * @default \"fill\"\n */\n width?: \"fill\" | \"hug\";\n /**\n * Ask for a time as well as a day, this fine. `hour` sets the hour and\n * zeroes the rest, `minute` the hour and minute, `second` all three. Omit\n * it and the value is midnight on the chosen day.\n */\n time?: DatePickerTime;\n /** Locale for the trigger's words. Defaults to the viewer's. */\n locales?: Intl.LocalesArgument;\n /**\n * Everything else React DayPicker takes — `disabled` days, `startMonth` /\n * `endMonth`, `numberOfMonths`, `weekStartsOn`, `captionLayout`.\n */\n calendarProps?: PropsBase;\n /** Id for the trigger, if the page needs its own. */\n id?: string;\n /** Class applied to the trigger. */\n className?: string;\n /**\n * Accessible name when there is no visible label — a toolbar control\n * beside a page title, which already says what the field is for.\n */\n \"aria-label\"?: string;\n /**\n * The named window the field should read. A page that already knows the\n * name (`Last 24 hours` in the URL) passes it so a remount, and a rolling\n * window recomputed each render, still write the name rather than the\n * figures. The name drops the moment the value is no longer that window\n * — a day picked by hand, or the page clearing this.\n */\n selectedPreset?: string;\n /**\n * How the popover lines up with the field. A hug field on the right of a\n * header wants `end`, so the calendar grows left instead of off-screen.\n * @default \"start\"\n */\n align?: \"start\" | \"center\" | \"end\";\n}\n\nexport interface DatePickerSingleProps extends DatePickerBaseProps {\n /** @default \"single\" */\n mode?: \"single\";\n value?: Date;\n defaultValue?: Date;\n onValueChange?: (\n value: Date | undefined,\n details?: DatePickerChangeDetails<Date>,\n ) => void;\n /** Named days offered beside the calendar. */\n presets?: DatePickerPreset<Date>[];\n}\n\nexport interface DatePickerRangeProps extends DatePickerBaseProps {\n mode: \"range\";\n value?: DateRange;\n defaultValue?: DateRange;\n onValueChange?: (\n value: DateRange | undefined,\n details?: DatePickerChangeDetails<DateRange>,\n ) => void;\n /** Named windows offered beside the calendar — `Last 7 days`, and so on. */\n presets?: DatePickerPreset<DateRange>[];\n /**\n * Shortest and longest span the viewer may pick, counted in days. A pick\n * that would break either restarts the span from the day just clicked, so\n * the bound is felt rather than explained.\n */\n minDays?: number;\n maxDays?: number;\n}\n\nexport type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps;\n\n/* ------------------------------------------------------------- the clock */\n\n/** One labelled time field — the popover's way of asking for the clock. */\nfunction ClockField({\n label,\n value,\n time,\n disabled,\n onChange,\n}: {\n label: string;\n value: Date | undefined;\n time: DatePickerTime;\n disabled?: boolean;\n onChange: (next: string) => void;\n}) {\n return (\n <>\n <span className=\"text-pho-description text-xs\">{label}</span>\n <label\n className={cn(\n \"bg-pho-primary ring-pho-primary rounded-sm px-2 py-1 ring-1 ring-inset\",\n \"focus-within:ring-pho-brand transition-shadow duration-100 ease-linear focus-within:ring-2\",\n )}\n >\n <input\n type=\"time\"\n step={TIME_STEP[time]}\n disabled={disabled}\n aria-label={label}\n value={value ? toClockValue(value, time) : \"\"}\n onChange={(event) => onChange(event.target.value)}\n className={cn(\n \"text-pho-primary w-full bg-transparent text-base tabular-nums outline-none\",\n // The browser's own clock glyph is off-brand and unstyleable;\n // the field's words are the control.\n \"[&::-webkit-calendar-picker-indicator]:hidden\",\n )}\n />\n </label>\n </>\n );\n}\n\n/* ------------------------------------------------------------ the picker */\n\n/**\n * Date Picker — a field that shows the chosen date and opens a `Calendar` to\n * change it. `mode=\"range\"` picks a span instead of a day; the popover stays\n * open until both ends are down.\n *\n * The value is a `Date` (or a `{ from, to }` range), never a string: pass\n * `value` to control it, `defaultValue` to let it keep its own. Clearing is\n * built in — clicking the chosen day again unsets it.\n *\n * `time` asks for the clock as well, to the hour, the minute, or the second.\n *\n * On a touch device the field hands off to the system picker — the OS wheel or\n * dialog, which people already know — as long as the rules the page set are\n * ones it can enforce. A weekday rule or a predicate keeps the calendar, which\n * can; so does `mode=\"range\"`, which no system picker offers.\n */\nexport function DatePicker(props: DatePickerProps) {\n const {\n mode = \"single\",\n defaultValue,\n onValueChange,\n label,\n hint,\n placeholder,\n invalid,\n disabled,\n required,\n size = \"md\",\n width = \"fill\",\n time,\n locales,\n calendarProps,\n id,\n className,\n selectedPreset,\n align = \"start\",\n \"aria-label\": ariaLabel,\n } = props;\n const presets = props.presets as\n DatePickerPreset<Date | DateRange>[] | undefined;\n // Range-only, and read off the union the same way.\n const { minDays, maxDays } = props as DatePickerRangeProps;\n\n // Presence of the prop, not its value: an empty controlled picker is the\n // normal starting state, so `value === undefined` cannot mean \"uncontrolled\".\n const controlled = \"value\" in props;\n const [ownValue, setOwnValue] = useState<Date | DateRange | undefined>(\n defaultValue,\n );\n const value = controlled ? props.value : ownValue;\n const [open, setOpen] = useState(false);\n // A range takes two clicks, and the first one already reads as a complete\n // one-day range ({ from, to } both set), so the value alone can't say when\n // the question is answered. Count the picks in this opening instead.\n const picks = useRef(0);\n\n // Empty, the field shows the shape to type. A span cannot be typed, so it\n // asks in words instead.\n const fieldPlaceholder =\n placeholder ??\n (mode === \"range\" ? \"Pick a date range\" : dateFieldMask(locales, time));\n\n const generatedId = useId();\n const triggerId = id ?? generatedId;\n const hintId = hint ? `${triggerId}-hint` : undefined;\n const calendarId = `${triggerId}-calendar`;\n\n // Whether the calendar should take the caret as it appears — true only when\n // a key asked for it, so a click leaves the caret in the field.\n const [gridFocus, setGridFocus] = useState(false);\n\n // The field is not a `Popover.Trigger`, so Base UI never routes its own\n // opening through `onOpenChange`: a controlled `open` is written straight\n // into the store. Every way in goes through here instead, or the reset an\n // opening owes — the pick count, the month on screen — silently never runs.\n const openPicker = (focusGrid = false) => {\n if (open) return;\n picks.current = 0;\n setMonth(undefined);\n setGridFocus(focusGrid);\n setOpen(true);\n };\n\n const notify = onValueChange as\n | ((\n v: Date | DateRange | undefined,\n d?: DatePickerChangeDetails<Date | DateRange>,\n ) => void)\n | undefined;\n\n const commit = (\n next: Date | DateRange | undefined,\n details?: DatePickerChangeDetails<Date | DateRange>,\n ) => {\n if (details) {\n setIgnoreSelected(false);\n } else {\n setIgnoreSelected(true);\n setChosen(null);\n }\n if (!controlled) setOwnValue(next);\n // The two modes have disjoint value types, and the union's callback is\n // only ever handed the shape its own mode produces. A second argument\n // is reserved for a named window, so a calendar pick stays a one-arg\n // call — existing listeners keep matching.\n if (details) notify?.(next, details);\n else notify?.(next);\n };\n\n const single = mode === \"single\" ? (value as Date | undefined) : undefined;\n const range = mode === \"range\" ? (value as DateRange | undefined) : undefined;\n // Reopen where the value lives, not on today's month.\n const anchor = single ?? range?.from;\n\n // The field is a text input, so the words in it are the viewer's until they\n // leave: `null` means \"whatever the value says\", anything else is what they\n // typed. Blur, a pick, and closing all hand the field back to the value.\n const [draft, setDraft] = useState<string | null>(null);\n // A preset names the window it set; the name stands only while the value is\n // still the one it produced, so a day picked afterwards drops the name with\n // no bookkeeping.\n const [chosen, setChosen] = useState<{ label: string; key: string } | null>(\n null,\n );\n // `selectedPreset` is the page's name for a rolling window. A hand pick\n // has to drop that name even if the page is a frame late clearing it —\n // otherwise the field still says \"Last 24 hours\" over a day the viewer\n // just chose. A new name from the page (or the same name after a remount)\n // starts honoring it again.\n const [ignoreSelected, setIgnoreSelected] = useState(false);\n useEffect(() => {\n setIgnoreSelected(false);\n }, [selectedPreset]);\n const presetLabel =\n selectedPreset && !ignoreSelected\n ? selectedPreset\n : chosen && chosen.key === valueKey(value)\n ? chosen.label\n : null;\n\n const text = draft ?? presetLabel ?? formatDateLabel(value, locales, time);\n // A typeable field stays wide enough for the shape to type, so it does\n // not jump when a date answers it. A span is read-only — hug the words\n // on screen, not the empty-state sentence sitting underneath.\n const hugChars = Math.max(\n text.length,\n mode === \"range\" ? 0 : fieldPlaceholder.length,\n 1,\n );\n const hugToWords = width === \"hug\" && mode === \"range\";\n\n const pickPreset = (preset: DatePickerPreset<Date | DateRange>) => {\n const next =\n typeof preset.value === \"function\" ? preset.value() : preset.value;\n setChosen({ label: preset.label, key: valueKey(next) });\n setDraft(null);\n commit(next, { preset });\n // A named window is the whole answer, clock included.\n setOpen(false);\n };\n\n // The month on screen follows what is typed, and resets to the value's own\n // month each time the calendar opens. Held from the first render rather than\n // handed over later: DayPicker keeps its own month until the prop arrives,\n // and a calendar that starts uncontrolled would ignore the first jump.\n const [month, setMonth] = useState<Date | undefined>(undefined);\n const [thisMonth] = useState(() => calendarProps?.today ?? new Date());\n const shownMonth =\n month ?? calendarProps?.defaultMonth ?? anchor ?? thisMonth;\n\n const fieldRef = useRef<HTMLDivElement>(null);\n const popupRef = useRef<HTMLDivElement>(null);\n\n const coarse = useCoarsePointer();\n const bounds = nativeBounds(calendarProps);\n // No system picker offers a range, so that mode keeps the calendar; so does\n // a rule the OS cannot enforce.\n const native =\n coarse && mode === \"single\" && bounds != null && !presets?.length;\n\n const face = (\n <>\n <IconCalendar className=\"text-pho-secondary size-4 shrink-0\" />\n <span\n className={cn(\n \"min-w-0 flex-1 truncate\",\n text === \"\" && \"text-pho-placeholder\",\n )}\n >\n {text === \"\" ? fieldPlaceholder : text}\n </span>\n </>\n );\n\n return (\n <div\n className={cn(\n \"flex flex-col gap-1.5\",\n width === \"hug\" ? \"w-fit\" : \"w-full\",\n )}\n >\n {label ? (\n <label\n htmlFor={triggerId}\n className=\"text-pho-secondary flex w-fit cursor-default items-center gap-0.5 text-base font-medium\"\n >\n {label}\n {required ? <span className=\"text-pho-brand\">*</span> : null}\n </label>\n ) : null}\n\n {native ? (\n <div\n data-invalid={invalid || undefined}\n className={cn(\n TRIGGER_BASE,\n TRIGGER_NATIVE,\n width === \"hug\" ? \"w-fit\" : \"w-full\",\n SIZE_PAD[size],\n SIZE_RADIUS[size],\n className,\n )}\n >\n {face}\n {/* The system field lies over the whole control at zero opacity:\n the tap opens the OS picker, the words underneath stay Pho's. */}\n <input\n id={triggerId}\n type={time ? \"datetime-local\" : \"date\"}\n step={time ? TIME_STEP[time] : undefined}\n min={\n bounds?.min\n ? time\n ? toDateTimeValue(clampTime(bounds.min, time), time)\n : toDateValue(bounds.min)\n : undefined\n }\n max={\n bounds?.max\n ? time\n ? toDateTimeValue(clampTime(bounds.max, time), time)\n : toDateValue(bounds.max)\n : undefined\n }\n required={required}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-describedby={hintId}\n value={\n single\n ? time\n ? toDateTimeValue(single, time)\n : toDateValue(single)\n : \"\"\n }\n onChange={(event) => {\n const next = fromInputValue(event.target.value);\n commit(next ? clampTime(next, time) : undefined);\n }}\n className=\"absolute inset-0 size-full cursor-pointer opacity-0\"\n />\n </div>\n ) : (\n <Popover.Root\n open={open}\n onOpenChange={(next, details) => {\n // Clicking in the field is how the viewer reaches the caret, so it\n // opens the calendar and never takes it away again — the field is\n // not a trigger Base UI knows about, so its own presses arrive\n // here as presses from outside.\n if (\n !next &&\n details.reason === \"outside-press\" &&\n details.event.target instanceof Node &&\n fieldRef.current?.contains(details.event.target)\n ) {\n return;\n }\n // Opening is `openPicker`'s job; this only ever hears about\n // closes (Escape, a click outside) and the odd programmatic open.\n if (next) {\n picks.current = 0;\n setMonth(undefined);\n } else {\n setDraft(null);\n setGridFocus(false);\n }\n setOpen(next);\n }}\n >\n <div\n ref={fieldRef}\n data-invalid={invalid || undefined}\n data-popup-open={open || undefined}\n className={cn(\n TRIGGER_BASE,\n TRIGGER_FIELD,\n width === \"hug\" ? \"w-fit\" : \"w-full\",\n SIZE_PAD[size],\n SIZE_RADIUS[size],\n className,\n )}\n >\n <IconCalendar className=\"text-pho-secondary size-4 shrink-0\" />\n <input\n id={triggerId}\n type=\"text\"\n // A span is two dates and a separator; there is nothing\n // sensible to type, so the field only opens the calendar.\n readOnly={mode === \"range\"}\n disabled={disabled}\n required={required}\n placeholder={fieldPlaceholder}\n aria-label={ariaLabel}\n aria-describedby={hintId}\n // The APG's date-picker combobox: a text field that also says\n // what it opens. `textbox` alone does not support `aria-expanded`.\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={open ? calendarId : undefined}\n autoComplete=\"off\"\n spellCheck={false}\n value={text}\n onFocus={() => openPicker()}\n onMouseDown={() => openPicker()}\n onChange={(event) => {\n const typed = event.target.value;\n setDraft(typed);\n if (typed.trim() === \"\") {\n commit(undefined);\n return;\n }\n const parsed = parseDateText(typed, locales);\n if (parsed) {\n commit(clampTime(parsed, time));\n // Follow the words: the calendar shows what was typed.\n setMonth(parsed);\n }\n }}\n onBlur={() => setDraft(null)}\n onKeyDown={(event) => {\n if (event.key === \"Escape\" && open) {\n event.preventDefault();\n setDraft(null);\n setOpen(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n // Hand the caret to the grid, where the arrows mean days.\n const grid = popupRef.current?.querySelector<HTMLElement>(\n \"td[data-day] button[tabindex='0']\",\n );\n if (grid) {\n grid.focus();\n return;\n }\n // Closed: the grid is not mounted yet, so the calendar takes\n // the caret itself as it appears — one press, not two.\n openPicker(true);\n }\n }}\n // Typed fields use `size`, not `field-sizing: content` — that\n // sizes from the current content and ignores `size` outright,\n // so a one-letter draft collapsed the field to 20px against\n // the shape to type. A span cannot be typed, so it hugs the\n // glyphs on screen (`Last 30 minutes`, not sixteen `M`s).\n size={width === \"hug\" && !hugToWords ? hugChars : undefined}\n className={cn(\n \"text-pho-primary placeholder:text-pho-placeholder bg-transparent outline-none\",\n hugToWords\n ? \"field-sizing-content w-auto min-w-min\"\n : width === \"hug\"\n ? \"min-w-0\"\n : \"min-w-0 flex-1\",\n mode === \"range\" && \"cursor-pointer\",\n )}\n />\n </div>\n\n <Popover.Portal>\n <Popover.Positioner anchor={fieldRef} align={align} sideOffset={6}>\n {/* Two months on a phone are taller than the room under the\n field; cap the popup at what Base UI measured and let it\n scroll rather than running off the screen. */}\n <Popover.Popup\n ref={popupRef}\n id={calendarId}\n // The field keeps the caret: the viewer is mid-word, and the\n // calendar is a second way to answer, not a takeover.\n initialFocus={false}\n finalFocus={false}\n className=\"max-h-[var(--available-height)] overflow-y-auto p-3\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n {presets?.length ? (\n // Beside the calendar where there is room, above it on a\n // phone, where a row that scrolls sideways costs no height.\n <div\n // A labelled set of buttons, not a form section.\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role\n role=\"group\"\n aria-label=\"Presets\"\n className={cn(\n \"flex shrink-0 gap-1 overflow-x-auto\",\n \"sm:border-pho-secondary sm:w-36 sm:flex-col sm:gap-0.5 sm:overflow-visible sm:border-r sm:pr-3\",\n )}\n >\n {presets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n aria-pressed={preset.label === presetLabel}\n onClick={() => pickPreset(preset)}\n className={cn(\n PRESET,\n preset.label === presetLabel && PRESET_ON,\n )}\n >\n {preset.label}\n </button>\n ))}\n </div>\n ) : null}\n\n <div>\n {mode === \"range\" ? (\n <Calendar\n {...calendarProps}\n mode=\"range\"\n min={minDays}\n max={maxDays}\n month={shownMonth}\n onMonthChange={setMonth}\n // DayPicker's own prop, not the DOM attribute.\n // oxlint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={gridFocus}\n selected={range}\n onSelect={(next, clicked) => {\n const first = picks.current === 0;\n picks.current += 1;\n // Reopened on a span that is already settled: the first\n // click starts a new one. DayPicker would otherwise drag\n // the nearer end over, so asking for Sep 20 – 25 on top\n // of Sep 1 – 8 would land on Sep 1 – 25.\n if (first && range?.to) {\n const day = clampTime(\n withDay(clicked, time ? range.from : undefined),\n time,\n );\n commit({ from: day, to: new Date(day) });\n setDraft(null);\n return;\n }\n const kept = next && {\n from:\n next.from &&\n clampTime(\n withDay(\n next.from,\n time ? range?.from : undefined,\n ),\n time,\n ),\n to:\n next.to &&\n clampTime(\n withDay(next.to, time ? range?.to : undefined),\n time,\n ),\n };\n commit(kept);\n setDraft(null);\n // Second pick, and the question is answered either way:\n // both ends down, or the same day twice, which DayPicker\n // reads as clearing the span. Unless a time is still to\n // be set, which lives below.\n if (\n !time &&\n picks.current >= 2 &&\n (!kept || (kept.from && kept.to))\n ) {\n setOpen(false);\n }\n }}\n />\n ) : (\n <Calendar\n {...calendarProps}\n mode=\"single\"\n month={shownMonth}\n onMonthChange={setMonth}\n // oxlint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={gridFocus}\n selected={single}\n onSelect={(next) => {\n commit(\n next &&\n clampTime(\n withDay(next, time ? single : undefined),\n time,\n ),\n );\n setDraft(null);\n // The clock is still to be set, and it is below.\n if (!time) setOpen(false);\n }}\n />\n )}\n\n {time ? (\n <div className=\"border-pho-secondary mt-3 grid grid-cols-[auto_1fr] items-center gap-x-3 gap-y-2 border-t pt-3\">\n {mode === \"range\" ? (\n <>\n <ClockField\n label=\"From\"\n value={range?.from}\n time={time}\n onChange={(clock) => {\n if (!range?.from) return;\n const next = fromInputValue(\n `${toDateValue(range.from)}T${clock}`,\n );\n if (next) {\n commit({\n ...range,\n from: clampTime(next, time),\n });\n }\n }}\n disabled={!range?.from}\n />\n <ClockField\n label=\"To\"\n value={range?.to}\n time={time}\n onChange={(clock) => {\n if (!range?.to) return;\n const next = fromInputValue(\n `${toDateValue(range.to)}T${clock}`,\n );\n if (next) {\n commit({\n ...range,\n to: clampTime(next, time),\n });\n }\n }}\n disabled={!range?.to}\n />\n </>\n ) : (\n <ClockField\n label=\"Time\"\n value={single}\n time={time}\n onChange={(clock) => {\n if (!single) return;\n const next = fromInputValue(\n `${toDateValue(single)}T${clock}`,\n );\n if (next) commit(clampTime(next, time));\n }}\n disabled={!single}\n />\n )}\n </div>\n ) : null}\n </div>\n </div>\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n )}\n\n {hint ? (\n <p\n id={hintId}\n className={cn(\n \"text-pho-description text-base\",\n invalid && \"text-pho-error\",\n )}\n >\n {hint}\n </p>\n ) : null}\n </div>\n );\n}\n\nDatePicker.displayName = \"DatePicker\";"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -112,7 +112,7 @@ function K({ icon: t, title: n, description: l, consequences: r, warning: a, act
112
112
  ...u,
113
113
  children: [
114
114
  g && /* @__PURE__ */ o("div", {
115
- className: "flex shrink-0 flex-col gap-1 px-6 pt-6",
115
+ className: "flex shrink-0 flex-col gap-2 px-6 pt-6",
116
116
  children: [
117
117
  t && /* @__PURE__ */ e(B, { children: t }),
118
118
  (n || h) && /* @__PURE__ */ o("div", {
@@ -168,7 +168,7 @@ function L({ icon: t, title: n, description: l, actions: r, showClose: a = !0, c
168
168
  ...c,
169
169
  children: [
170
170
  !!(t || n || l || d) && /* @__PURE__ */ o("div", {
171
- className: "flex shrink-0 flex-col gap-1 px-6 pt-6",
171
+ className: "flex shrink-0 flex-col gap-2 px-6 pt-6",
172
172
  children: [
173
173
  t && /* @__PURE__ */ e(B, { children: t }),
174
174
  (n || d) && /* @__PURE__ */ o("div", {
@@ -217,7 +217,7 @@ function Q({ icon: t, title: n, description: l, actions: r, showClose: a = !0, f
217
217
  className: "flex flex-col gap-5",
218
218
  children: [
219
219
  (t || n || l) && /* @__PURE__ */ o("div", {
220
- className: "flex flex-col gap-1",
220
+ className: "flex flex-col gap-2",
221
221
  children: [
222
222
  t && /* @__PURE__ */ e(B, {
223
223
  size: "lg",
@@ -259,4 +259,4 @@ export {
259
259
  re as t
260
260
  };
261
261
 
262
- //# sourceMappingURL=dialog-BwfUFn6B.js.map
262
+ //# sourceMappingURL=dialog-BYiAFetB.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-BwfUFn6B.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":";;;;;;;;;AA6CA,IAAM,IAAuB,EAC3B,IACF;AAOA,SAAgB,KAA4B;AAC1C,SAAO,EAAW,CAAoB,GAAG,WAAW;AACtD;AAUA,SAAS,EAAK,EAAE,cAAA,GAAc,YAAA,GAAY,GAAG,EAAA,GAAoB;AAC/D,QAAM,CAAC,GAAS,CAAA,IAAc,EAAS,EAAK,GAGtC,IAAa,EAAO,EAAK,GACzB,IAAqB,EAA2B,IAAI;AAG1D,EAAA,EAAA,MAAgB;AACd,QAAK;AACL,aAAA,EAAW,UAAU,EAAmB,SACxC,MAAa;AACX,QAAA,EAAW,UAAU;AAAA,MACvB;AAAA,EACF,GAAG,CAAC,CAAU,CAAC;AAEf,QAAM,IAAmB,EAAA,CACtB,GAAM,MAAiB;AACtB,QAAI,CAAC,KAAQ,EAAW,SAAS;AAC/B,MAAA,EAAa,OAAO;AACpB;AAAA,IACF;AACA,IAAA,IAAe,GAAM,CAAY;AAAA,EACnC,GACA,CAAC,CAAY,CACf,GAEM,IAAe,EAAA,OACZ;AAAA,IACL,SAAA;AAAA,IACA,cAAA,MAAoB;AAClB,MAAA,EAAW,UAAU,IACrB,EAAW,EAAI;AAAA,IACjB;AAAA,IACA,YAAA,MAAkB;AAChB,MAAA,EAAW,UAAU,IACrB,EAAW,EAAK;AAAA,IAClB;AAAA,IACA,OAAA,MAAa,EAAmB,SAAS,MAAM;AAAA,EACjD,IACA,CAAC,CAAO,CACV;AAEA,SACE,gBAAA,EAAC,EAAqB,UAAtB;AAAA,IAA+B,OAAO;AAAA,IACpC,UAAA,gBAAA,EAAC,EAAW,MAAZ;AAAA,MACE,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,GAAI;AAAA,IACL,CAAA;AAAA,EAC4B,CAAA;AAEnC;AAEA,IAAM,IAAU,EAAW,SACrB,IAAS,EAAW,QACpB,IAAQ,EAAW;AAiBzB,SAAS,EAAW,GAA2C;AAC7D,SACE,KAAS,QAAQ,OAAQ,EAA6B,QAAS;AAEnE;AAOA,SAAS,EAAO,EAAE,SAAA,GAAS,SAAA,GAAS,UAAA,GAAU,GAAG,EAAA,GAA4B;AAC3E,QAAM,IAAiB,EAAW,CAAoB,GAChD,CAAC,GAAM,CAAA,IAAW,EAAS,EAAK,GAChC,IAAa,EAAO,EAAI;AAE9B,EAAA,EAAA,OACE,EAAW,UAAU,IACrB,MAAa;AACX,IAAA,EAAW,UAAU;AAAA,EACvB,IACC,CAAC,CAAC;AAEL,WAAS,EAAY,GAA2C;AAC9D,QAAI,KAAQ,EAAS;AACrB,UAAM,IAAS,IAAU,CAAK;AAC9B,QAAI,CAAC,EAAW,CAAM,GAAG;AACvB,MAAA,GAAgB,MAAM;AACtB;AAAA,IACF;AACA,IAAA,EAAQ,EAAI,GACZ,GAAgB,aAAa,GAC7B,EAAO,KAAA,MACC;AACJ,MAAA,GAAgB,WAAW,GACvB,EAAW,WAAS,EAAQ,EAAK,GACrC,GAAgB,MAAM;AAAA,IACxB,GAAA,CACC,MAAmB;AAClB,MAAA,GAAgB,WAAW,GACvB,EAAW,WAAS,EAAQ,EAAK,GAEnC,OAAO,UAAY,OAAA,QAAA,IAAA,aACO,gBAE1B,QAAQ,MAAM,2CAA2C,CAAK;AAAA,IAElE,CACF;AAAA,EACF;AAEA,QAAM,IAAQ,KAAQ;AACtB,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,GAAI;AAAA,IACJ,UAAU,KAAY;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,EACV,CAAA;AAEL;AAEA,SAAS,EAAS,EAChB,WAAA,GACA,GAAG,EAAA,GACuC;AAC1C,SACE,gBAAA,EAAC,EAAW,UAAZ;AAAA,IACE,WAAW,EACT,8EACA,kGACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EAAE,WAAA,GAAW,GAAG,EAAA,GAA+C;AAC5E,SACE,gBAAA,EAAC,EAAW,OAAZ;AAAA,IACE,WAAW,EAET,+LAIA,wEAEA,oDACA,kEACA,+FACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EAAE,WAAA,GAAW,GAAG,EAAA,GAA+C;AAC5E,SACE,gBAAA,EAAC,EAAW,OAAZ;AAAA,IACE,WAAW,EACT,0EACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAY,EACnB,WAAA,GACA,GAAG,EAAA,GAC0C;AAC7C,SACE,gBAAA,EAAC,EAAW,aAAZ;AAAA,IACE,WAAW,EACT,oDACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAOA,SAAS,EAAiB,EACxB,UAAA,GACA,MAAA,IAAO,KAAA,GAIN;AACD,SACE,gBAAA,EAAC,QAAD;AAAA,IACE,eAAA;AAAA,IACA,WAAW,EACT,2BACA,MAAS,OAAO,oBAAoB,gBACtC;AAAA,IAEC,UAAA;AAAA,EACG,CAAA;AAEV;AAkDA,SAAS,EAAQ,EACf,MAAA,GACA,OAAA,GACA,aAAA,GACA,cAAA,GACA,SAAA,GACA,SAAA,GACA,WAAA,IAAY,IACZ,UAAA,GACA,WAAA,GACA,GAAG,EAAA,GACY;AAEf,QAAM,IAAkB,KAAW,QAAQ,GACrC,IAAY,GAAQ,KAAQ,KAAS,KAAe,IACpD,IAAkB,KAAgB,QAAQ,EAAa,SAAS,GAEhE,IAAgB,KAAmB,KAAW,QAAQ,KAAY;AAExE,SACE,gBAAA,EAAC,GAAD,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD,CAAW,CAAA,GACX,gBAAA,EAAC,GAAD;AAAA,IAAkB,WAAA;AAAA,IAAW,GAAI;AAAA,IAAjC,UAAA;AAAA,MACG,KACC,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QAAf,UAAA;AAAA,UACG,KAAQ,gBAAA,EAAC,GAAD,EAAA,UAAmB,EAAuB,CAAA;AAAA,WACjD,KAAS,MAGT,gBAAA,EAAC,OAAD;AAAA,YAAK,WAAU;AAAA,YAAf,UAAA,CACG,IACC,gBAAA,EAAC,GAAD;AAAA,cAAO,WAAW,IAAkB,UAAU;AAAA,cAC3C,UAAA;AAAA,YACI,CAAA,IAEP,gBAAA,EAAC,OAAD;AAAA,cAAK,WAAU;AAAA,cAAe,eAAY;AAAA,YAAQ,CAAA,GAEnD,KACC,gBAAA,EAAC,GAAD,EACE,QACE,gBAAA,EAAC,GAAD,EAAa,WAAU,iDAAkD,CAAA,EAE5E,CAAA,CAEA;AAAA;UAEN,KAAe,gBAAA,EAAC,GAAD,EAAA,UAAc,EAAyB,CAAA;AAAA,QACpD;AAAA;MAEN,KACC,gBAAA,EAAC,EAAW,MAAZ;AAAA,QAAiB,WAAU;AAAA,QAA3B,UAAA,CACE,gBAAA,EAAC,EAAW,UAAZ,EAAA,UACE,gBAAA,EAAC,EAAW,SAAZ;AAAA,UAAoB,WAAU;AAAA,UAA9B,UAAA;AAAA,YACG,KACC,gBAAA,EAAC,MAAD;AAAA,cAAI,WAAU;AAAA,cACX,UAAA,EAAa,IAAA,CAAK,GAAM,MAGvB,gBAAA,EAAC,MAAD;AAAA,gBAEE,WAAU;AAAA,gBAET,UAAA;AAAA,cACC,GAJG,CAIH,CACL;AAAA,YACC,CAAA;AAAA,YAEL,KAAW,QACV,gBAAA,EAAC,KAAD;AAAA,cAAG,WAAU;AAAA,cACV,UAAA;AAAA,YACA,CAAA;AAAA,YAEJ;AAAA,UACiB;AAAA,QACD,CAAA,EAAA,CAAA,GACrB,gBAAA,EAAC,EAAW,WAAZ,EAAA,UACE,gBAAA,EAAC,EAAW,OAAZ,CAAmB,CAAA,EACC,CAAA,CACP;AAAA;MAElB,KAAW,QACV,gBAAA,EAAC,OAAD;AAAA,QACE,WAAW,EACT,0DACA,CAAC,KAAiB,MACpB;AAAA,QAEC,UAAA;AAAA,MACE,CAAA;AAAA,IAEF;AAAA,EACD,CAAA,CAAA,EAAA,CAAA;AAEZ;AAUA,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GACoC;AACvC,SACE,gBAAA,EAAC,EAAW,OAAZ;AAAA,IACE,WAAW,EACT,gJACA,oDACA,sEACA,mGACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAgCA,SAAS,EAAa,EACpB,MAAA,GACA,OAAA,GACA,aAAA,GACA,SAAA,GACA,WAAA,IAAY,IACZ,UAAA,GACA,WAAA,GACA,GAAG,EAAA,GACiB;AAEpB,QAAM,IAAkB,KAAW,QAAQ;AAG3C,SACE,gBAAA,EAAC,GAAD,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD,CAAW,CAAA,GACX,gBAAA,EAAC,GAAD;AAAA,IAAuB,WAAA;AAAA,IAAW,GAAI;AAAA,IAAtC,UAAA;AAAA,MALc,GAAQ,KAAQ,KAAS,KAAe,MAOlD,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QAAf,UAAA;AAAA,UACG,KAAQ,gBAAA,EAAC,GAAD,EAAA,UAAmB,EAAuB,CAAA;AAAA,WACjD,KAAS,MACT,gBAAA,EAAC,OAAD;AAAA,YAAK,WAAU;AAAA,YAAf,UAAA,CACG,IACC,gBAAA,EAAC,GAAD;AAAA,cAAO,WAAW,IAAkB,UAAU;AAAA,cAC3C,UAAA;AAAA,YACI,CAAA,IAEP,gBAAA,EAAC,OAAD;AAAA,cAAK,WAAU;AAAA,cAAe,eAAY;AAAA,YAAQ,CAAA,GAEnD,KACC,gBAAA,EAAC,GAAD,EACE,QACE,gBAAA,EAAC,GAAD,EAAa,WAAU,iDAAkD,CAAA,EAE5E,CAAA,CAEA;AAAA;UAEN,KAAe,gBAAA,EAAC,GAAD,EAAA,UAAc,EAAyB,CAAA;AAAA,QACpD;AAAA;MAEP,gBAAA,EAAC,EAAW,MAAZ;AAAA,QAAiB,WAAU;AAAA,QAA3B,UAAA,CACE,gBAAA,EAAC,EAAW,UAAZ,EAAA,UACE,gBAAA,EAAC,EAAW,SAAZ;AAAA,UAAoB,WAAU;AAAA,UAC3B,UAAA;AAAA,QACiB,CAAA,EACD,CAAA,GACrB,gBAAA,EAAC,EAAW,WAAZ,EAAA,UACE,gBAAA,EAAC,EAAW,OAAZ,CAAmB,CAAA,EACC,CAAA,CACP;AAAA;MAChB,KAAW,QACV,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QACZ,UAAA;AAAA,MACE,CAAA;AAAA,IAEG;AAAA,EACN,CAAA,CAAA,EAAA,CAAA;AAEZ;AASA,SAAS,EAAgB,EACvB,WAAA,GACA,GAAG,EAAA,GACoC;AACvC,SACE,gBAAA,EAAC,EAAW,OAAZ;AAAA,IACE,WAAW,EACT,+DACA,4CACA,kGACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AA2CA,SAAS,EAAkB,EACzB,MAAA,GACA,OAAA,GACA,aAAA,GACA,SAAA,GACA,WAAA,IAAY,IACZ,gBAAA,GACA,UAAA,GACA,WAAA,GACA,GAAG,EAAA,GACsB;AAEzB,QAAM,IAAkB,KAAW,QAAQ;AAE3C,SACE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,IAA4B,WAAA;AAAA,IAAW,GAAI;AAAA,IAA3C,UAAA,CACG,KACC,gBAAA,EAAC,GAAD,EACE,QAAQ,gBAAA,EAAC,GAAD,EAAa,WAAU,2BAA4B,CAAA,EAC5D,CAAA,GAGH,gBAAA,EAAC,OAAD;AAAA,MACE,WAAW,EACT,+DACA,CACF;AAAA,MAIA,UAAA,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QACb,UAAA,gBAAA,EAAC,GAAD;AAAA,UAAgB,WAAU;AAAA,UAA1B,UAAA;AAAA,aACI,KAAQ,KAAS,MACjB,gBAAA,EAAC,OAAD;AAAA,cAAK,WAAU;AAAA,cAAf,UAAA;AAAA,gBACG,KACC,gBAAA,EAAC,GAAD;AAAA,kBAAkB,MAAK;AAAA,kBAAM,UAAA;AAAA,gBAAuB,CAAA;AAAA,gBAErD,KAAS,gBAAA,EAAC,GAAD,EAAA,UAAQ,EAAa,CAAA;AAAA,gBAC9B,KAAe,gBAAA,EAAC,GAAD,EAAA,UAAc,EAAyB,CAAA;AAAA,cACpD;AAAA;YAEN;AAAA,YACA,KAAW,QACV,gBAAA,EAAC,OAAD;AAAA,cAAK,WAAU;AAAA,cACZ,UAAA;AAAA,YACE,CAAA;AAAA,UAEO;AAAA;MACb,CAAA;AAAA,IACF,CAAA,CACU;AAAA,EACX,CAAA,EAAA,CAAA;AAEZ;AAQA,IAAa,KAAS;AAAA,EACpB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,OAAA;AAAA,EACA,aAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,cAAA;AAAA,EACA,mBAAA;AACF"}
1
+ {"version":3,"file":"dialog-BYiAFetB.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-2 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-2 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-2\">\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};"],"mappings":"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"}
@@ -7,7 +7,7 @@ import { t as L } from "./IconSearch-BKAHkLyX.js";
7
7
  import { t as $ } from "./IconX-pZ9vrtSr.js";
8
8
  import { t as g } from "./popover-BhBJO346.js";
9
9
  import { t as w } from "./input-group-fc9_jD4d.js";
10
- import { t as d } from "./command-CTYrSz9a.js";
10
+ import { t as d } from "./command-ZagVyDx7.js";
11
11
  import { useRef as D, useState as T } from "react";
12
12
  import { jsx as a, jsxs as u } from "react/jsx-runtime";
13
13
  var E = [["path", {
@@ -256,4 +256,4 @@ export {
256
256
  O as t
257
257
  };
258
258
 
259
- //# sourceMappingURL=filter-bar-D9lBBr4z.js.map
259
+ //# sourceMappingURL=filter-bar-DTaLgQr0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter-bar-D9lBBr4z.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconPlus.mjs","../../src/components/filter-bar/filter-bar.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\": \"M12 5l0 14\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M5 12l14 0\", \"key\": \"svg-1\" }]];\nconst IconPlus = createReactComponent(\"outline\", \"plus\", \"Plus\", __iconNode);\n\nexport { __iconNode, IconPlus as default };\n//# sourceMappingURL=IconPlus.mjs.map\n","import {\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\nimport { IconCheck, IconPlus, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { Button } from \"../button\";\nimport { Command } from \"../command\";\nimport { InputGroup } from \"../input-group\";\nimport { Popover } from \"../popover\";\nimport { cn } from \"../../utils/cn\";\n\n/**\n * Filter Bar — the row that pins above a log list: a search field for an\n * id, then one chip per filter. A chip with nothing chosen reads\n * `+ Status`; with a value it reads `Status: Failed` and carries its own\n * clear. Each chip opens a small popover: a keyboard-first list of\n * options (with a search field past eight of them), or presets and a\n * from / to pair for a date range.\n *\n * Design notes:\n * - Fully controlled. The page owns `filters` and `search` and hands\n * them back changed; the bar keeps no state but which popover is open.\n * That keeps the query in one place (the URL, a store) and lets the\n * list refetch from it.\n * - Chips are real buttons (the trigger, and the clear beside it), so\n * the bar is one tab stop per control and Escape closes a popover\n * back onto its chip.\n * - No scroll container of its own: chips wrap. `sticky` pins it to the\n * top of the nearest scroll pane on the surface it sits on.\n */\n\nexport interface FilterOption {\n value: string;\n label: string;\n}\n\ninterface FilterDefinitionBase {\n /** The key in `filters` this chip reads and writes. */\n key: string;\n /** The chip's word — \"Status\", \"Event type\". Sentence case. */\n label: string;\n}\n\nexport interface SelectFilterDefinition extends FilterDefinitionBase {\n type?: \"select\";\n options: readonly FilterOption[];\n /** Several values at once (`string[]`); one at a time by default. */\n multiple?: boolean;\n /**\n * A search field above the options. On by default past eight options,\n * off below; say so to override.\n */\n searchable?: boolean;\n /** The search field's placeholder. @default \"Search\" */\n searchPlaceholder?: string;\n}\n\n/** A relative preset for a date-range filter — \"Last 7 days\" is 168 hours. */\nexport interface DateRangePreset {\n label: string;\n hours: number;\n}\n\nexport interface DateRangeFilterDefinition extends FilterDefinitionBase {\n type: \"date-range\";\n /** The relative presets listed above the from / to pair. */\n presets?: readonly DateRangePreset[];\n}\n\nexport type FilterDefinition =\n SelectFilterDefinition | DateRangeFilterDefinition;\n\n/**\n * A date-range value. A preset stores an absolute ISO timestamp in `from`\n * (computed when chosen) and its label in `preset`; the from / to pair\n * stores plain `YYYY-MM-DD` dates. Either side may be open (`null`).\n */\nexport interface DateRangeValue {\n from: string | null;\n to: string | null;\n preset?: string;\n}\n\nexport type FilterValue = string | string[] | DateRangeValue;\n\n/** The page's filter state — one entry per definition key that is set. */\nexport type FilterValues = Record<string, FilterValue | undefined>;\n\n/** The relative presets a date-range chip lists when given none. */\nexport const FILTER_DATE_PRESETS: readonly DateRangePreset[] = [\n { label: \"Last hour\", hours: 1 },\n { label: \"Last 24 hours\", hours: 24 },\n { label: \"Last 7 days\", hours: 24 * 7 },\n { label: \"Last 30 days\", hours: 24 * 30 },\n];\n\n/** Past this many options a select chip shows a search field. */\nconst SEARCHABLE_PAST = 8;\n\n/** Whether a filter value counts as set — an empty string or list does not. */\nexport function isFilterSet(value: FilterValue | undefined): boolean {\n if (value == null) return false;\n if (typeof value === \"string\") return value !== \"\";\n if (Array.isArray(value)) return value.length > 0;\n return value.from != null || value.to != null;\n}\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction formatDay(value: string): string {\n // A plain date is a calendar day: format it in UTC so the day survives\n // every viewer timezone. A timestamp is a moment: format it locally.\n const dateOnly = DATE_ONLY.test(value);\n const date = new Date(dateOnly ? `${value}T00:00:00Z` : value);\n if (Number.isNaN(date.getTime())) return value;\n return new Intl.DateTimeFormat(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n ...(dateOnly ? { timeZone: \"UTC\" } : {}),\n }).format(date);\n}\n\n/** The words a set chip shows after its label. */\nexport function formatFilterValue(\n definition: FilterDefinition,\n value: FilterValue | undefined,\n): string {\n if (!isFilterSet(value) || value == null) return \"\";\n if (definition.type === \"date-range\") {\n const range = value as DateRangeValue;\n if (range.preset) return range.preset;\n if (range.from && range.to) {\n return `${formatDay(range.from)} to ${formatDay(range.to)}`;\n }\n if (range.from) return `From ${formatDay(range.from)}`;\n if (range.to) return `Until ${formatDay(range.to)}`;\n return \"\";\n }\n const labelOf = (item: string) =>\n definition.options.find((option) => option.value === item)?.label ?? item;\n if (Array.isArray(value)) return value.map(labelOf).join(\", \");\n return typeof value === \"string\" ? labelOf(value) : \"\";\n}\n\n/* --------------------------------- chips -------------------------------- */\n\nconst CHIP_TRIGGER =\n \"outline-pho-brand flex h-8 min-w-0 cursor-pointer items-center gap-1.5 rounded-full text-base transition-[color,background-color] duration-100 ease-linear focus-visible:outline-2 focus-visible:-outline-offset-2 [&>svg]:size-4 [&>svg]:shrink-0\";\n\nfunction FilterChip({\n definition,\n value,\n onChange,\n}: {\n definition: FilterDefinition;\n value: FilterValue | undefined;\n onChange: (next: FilterValue | undefined) => void;\n}) {\n const [open, setOpen] = useState(false);\n const focusRef = useRef<HTMLElement | null>(null);\n const set = isFilterSet(value);\n const display = formatFilterValue(definition, value);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <span\n data-filter-chip={definition.key}\n data-set={set || undefined}\n className={cn(\n \"ring-pho-primary inline-flex max-w-full shrink-0 items-stretch rounded-full ring-1 ring-inset\",\n set ? \"bg-pho-secondary\" : \"bg-transparent\",\n )}\n >\n <Popover.Trigger\n aria-label={set ? undefined : `${definition.label} filter`}\n className={cn(\n CHIP_TRIGGER,\n \"hover:bg-pho-ghost-hover\",\n set ? \"pr-1.5 pl-3\" : \"pr-3 pl-2.5\",\n set ? \"rounded-r-none\" : \"\",\n )}\n >\n {set ? null : <IconPlus aria-hidden />}\n {set ? (\n <span className=\"flex min-w-0 items-baseline gap-1\">\n <span className=\"text-pho-description shrink-0\">\n {definition.label}:\n </span>\n <span className=\"text-pho-primary max-w-56 truncate font-medium\">\n {display}\n </span>\n </span>\n ) : (\n <span className=\"text-pho-secondary\">{definition.label}</span>\n )}\n </Popover.Trigger>\n {set ? (\n <button\n type=\"button\"\n aria-label={`Clear ${definition.label.toLowerCase()} filter`}\n onClick={() => onChange(undefined)}\n className={cn(\n CHIP_TRIGGER,\n \"text-pho-secondary hover:bg-pho-ghost-hover hover:text-pho-secondary-hover rounded-l-none pr-2.5 pl-1 [&>svg]:size-3.5\",\n )}\n >\n <IconX aria-hidden />\n </button>\n ) : null}\n </span>\n <Popover.Portal>\n <Popover.Positioner align=\"start\" sideOffset={6}>\n <Popover.Popup\n aria-label={`${definition.label} filter`}\n initialFocus={focusRef}\n className={cn(\n \"w-64 p-0\",\n definition.type === \"date-range\" && \"w-72\",\n )}\n >\n {definition.type === \"date-range\" ? (\n <DateRangePanel\n definition={definition}\n value={value as DateRangeValue | undefined}\n focusRef={focusRef}\n onChange={(next) => {\n onChange(next);\n if (next?.preset) setOpen(false);\n }}\n />\n ) : (\n <OptionsPanel\n definition={definition}\n value={value as string | string[] | undefined}\n focusRef={focusRef}\n onChange={(next) => {\n onChange(next);\n if (!definition.multiple) setOpen(false);\n }}\n />\n )}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nfunction OptionsPanel({\n definition,\n value,\n focusRef,\n onChange,\n}: {\n definition: SelectFilterDefinition;\n value: string | string[] | undefined;\n focusRef: RefObject<HTMLElement | null>;\n onChange: (next: string | string[] | undefined) => void;\n}) {\n const [query, setQuery] = useState(\"\");\n const searchable =\n definition.searchable ?? definition.options.length > SEARCHABLE_PAST;\n const chosen = new Set(\n value == null ? [] : Array.isArray(value) ? value : [value],\n );\n const needle = query.trim().toLowerCase();\n const options = needle\n ? definition.options.filter(\n (option) =>\n option.label.toLowerCase().includes(needle) ||\n option.value.toLowerCase().includes(needle),\n )\n : definition.options;\n const pick = (option: FilterOption) => {\n if (definition.multiple) {\n const next = new Set(chosen);\n if (next.has(option.value)) next.delete(option.value);\n else next.add(option.value);\n // Keep the definition's order, so the chip reads the same way\n // whatever order the values were chosen in.\n const ordered = definition.options\n .map((item) => item.value)\n .filter((item) => next.has(item));\n onChange(ordered.length > 0 ? ordered : undefined);\n return;\n }\n onChange(chosen.has(option.value) ? undefined : option.value);\n };\n return (\n <Command.Root\n label={`${definition.label} options`}\n // Without a search field the list itself takes focus, so the arrow\n // keys work from the first frame.\n ref={(node: HTMLDivElement | null) => {\n if (!searchable) focusRef.current = node;\n }}\n className=\"rounded-base\"\n >\n {searchable ? (\n <Command.InputGroup>\n <IconSearch\n aria-hidden\n className=\"text-pho-description pointer-events-none absolute left-3 size-4\"\n />\n <Command.Input\n ref={(node: HTMLInputElement | null) => {\n focusRef.current = node;\n }}\n value={query}\n onValueChange={setQuery}\n placeholder={definition.searchPlaceholder ?? \"Search\"}\n aria-label={`Search ${definition.label.toLowerCase()} options`}\n className=\"py-2 pr-3 pl-9 text-base\"\n />\n </Command.InputGroup>\n ) : null}\n <Command.List>\n <Command.Empty>Nothing matches.</Command.Empty>\n {options.map((option) => (\n <Command.Item\n key={option.value}\n value={option.value}\n title={option.label}\n aria-checked={chosen.has(option.value)}\n icon={chosen.has(option.value) ? <IconCheck aria-hidden /> : null}\n onSelect={() => pick(option)}\n />\n ))}\n </Command.List>\n </Command.Root>\n );\n}\n\nconst DATE_INPUT =\n \"bg-pho-primary ring-pho-primary text-pho-primary focus-visible:ring-pho-brand w-full min-w-0 rounded-sm px-2 py-1 text-base ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2\";\n\nfunction DateRangePanel({\n definition,\n value,\n focusRef,\n onChange,\n}: {\n definition: DateRangeFilterDefinition;\n value: DateRangeValue | undefined;\n focusRef: RefObject<HTMLElement | null>;\n onChange: (next: DateRangeValue | undefined) => void;\n}) {\n const presets = definition.presets ?? FILTER_DATE_PRESETS;\n // A preset's `from` is a timestamp; the day field shows its date.\n const day = (side: string | null | undefined) =>\n side == null ? \"\" : DATE_ONLY.test(side) ? side : side.slice(0, 10);\n const setSide = (side: \"from\" | \"to\", next: string) => {\n // Editing either day leaves a preset behind: the pair is the value now,\n // and a preset's timestamp becomes the day it fell on.\n const range: DateRangeValue = {\n from: day(value?.from) || null,\n to: day(value?.to) || null,\n [side]: next || null,\n };\n onChange(range.from == null && range.to == null ? undefined : range);\n };\n return (\n <div className=\"flex flex-col\">\n <Command.Root\n label={`${definition.label} presets`}\n ref={(node: HTMLDivElement | null) => {\n focusRef.current = node;\n }}\n className=\"rounded-t-[inherit]\"\n >\n <Command.List>\n {presets.map((preset) => (\n <Command.Item\n key={preset.label}\n value={preset.label}\n title={preset.label}\n aria-checked={value?.preset === preset.label}\n icon={\n value?.preset === preset.label ? (\n <IconCheck aria-hidden />\n ) : null\n }\n onSelect={() =>\n onChange({\n from: new Date(\n Date.now() - preset.hours * 60 * 60 * 1000,\n ).toISOString(),\n to: null,\n preset: preset.label,\n })\n }\n />\n ))}\n </Command.List>\n </Command.Root>\n {/* The day fields stand outside the command list: its arrow-key\n handling would otherwise swallow the native date stepping. */}\n <div className=\"border-pho-secondary grid grid-cols-2 gap-2 border-t p-2\">\n <label className=\"text-pho-description flex min-w-0 flex-col gap-1 text-xs\">\n From\n <input\n type=\"date\"\n value={day(value?.from)}\n max={day(value?.to) || undefined}\n onChange={(event) => setSide(\"from\", event.target.value)}\n className={DATE_INPUT}\n />\n </label>\n <label className=\"text-pho-description flex min-w-0 flex-col gap-1 text-xs\">\n To\n <input\n type=\"date\"\n value={day(value?.to)}\n min={day(value?.from) || undefined}\n onChange={(event) => setSide(\"to\", event.target.value)}\n className={DATE_INPUT}\n />\n </label>\n </div>\n </div>\n );\n}\n\n/* ---------------------------------- bar --------------------------------- */\n\nexport interface FilterBarProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** One chip per definition, in this order. */\n definitions: readonly FilterDefinition[];\n /** The values, keyed by definition key. Absent or empty means unset. */\n filters: FilterValues;\n /** The whole map, changed — set, cleared, or cleared all. */\n onFiltersChange: (next: FilterValues) => void;\n /** The search field's text. The field renders only with `onSearchChange`. */\n search?: string;\n onSearchChange?: (value: string) => void;\n /** A teaching phrase — \"Find an event by id\". @default \"Search\" */\n searchPlaceholder?: string;\n /** The field's accessible name when the placeholder is too short to be one. */\n searchLabel?: string;\n /**\n * Pin the bar to the top of the nearest scroll pane. It paints the\n * surface it sits on (`--pho-surface`) so rows scroll under it.\n */\n sticky?: boolean;\n /** Controls after the chips — a range picker, an export button. */\n children?: ReactNode;\n ref?: Ref<HTMLDivElement>;\n}\n\nexport function FilterBar({\n definitions,\n filters,\n onFiltersChange,\n search,\n onSearchChange,\n searchPlaceholder = \"Search\",\n searchLabel,\n sticky,\n className,\n children,\n ...props\n}: FilterBarProps) {\n const setCount = definitions.filter((definition) =>\n isFilterSet(filters[definition.key]),\n ).length;\n const change = (key: string, next: FilterValue | undefined) => {\n const rest = { ...filters };\n if (next === undefined) delete rest[key];\n else rest[key] = next;\n onFiltersChange(rest);\n };\n return (\n <div\n data-filter-bar=\"\"\n className={cn(\n \"flex min-w-0 flex-wrap items-center gap-2\",\n sticky &&\n \"sticky top-0 z-10 bg-[var(--pho-surface,var(--background-color-pho-page))] py-3\",\n className,\n )}\n {...props}\n >\n {onSearchChange != null ? (\n <InputGroup.Root size=\"sm\" className=\"w-64 max-w-full\">\n <InputGroup.Addon>\n <IconSearch />\n </InputGroup.Addon>\n <InputGroup.Input\n type=\"search\"\n value={search ?? \"\"}\n onChange={(event) => onSearchChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n onSearchChange(\"\");\n }}\n placeholder={searchPlaceholder}\n aria-label={searchLabel ?? searchPlaceholder}\n />\n </InputGroup.Root>\n ) : null}\n {definitions.map((definition) => (\n <FilterChip\n key={definition.key}\n definition={definition}\n value={filters[definition.key]}\n onChange={(next) => change(definition.key, next)}\n />\n ))}\n {setCount > 1 ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n const rest = { ...filters };\n for (const definition of definitions) delete rest[definition.key];\n onFiltersChange(rest);\n }}\n >\n Clear filters\n </Button>\n ) : null}\n {children}\n </div>\n );\n}\n\nFilterBar.displayName = \"FilterBar\";\n"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;;;AASA,IAAM,IAAa,CAAC,CAAC,QAAQ;AAAA,EAAE,GAAK;AAAA,EAAc,KAAO;AAAQ,CAAC,GAAG,CAAC,QAAQ;AAAA,EAAE,GAAK;AAAA,EAAc,KAAO;AAAQ,CAAC,CAAC,GAC9G,IAAW,EAAqB,WAAW,QAAQ,QAAQ,CAAU,GCmF9D,IAAkD;AAAA,EAC7D;AAAA,IAAE,OAAO;AAAA,IAAa,OAAO;AAAA,EAAE;AAAA,EAC/B;AAAA,IAAE,OAAO;AAAA,IAAiB,OAAO;AAAA,EAAG;AAAA,EACpC;AAAA,IAAE,OAAO;AAAA,IAAe,OAAO;AAAA,EAAO;AAAA,EACtC;AAAA,IAAE,OAAO;AAAA,IAAgB,OAAO;AAAA,EAAQ;AAC1C,GAGM,IAAkB;AAGxB,SAAgB,EAAY,GAAyC;AACnE,SAAI,KAAS,OAAa,KACtB,OAAO,KAAU,WAAiB,MAAU,KAC5C,MAAM,QAAQ,CAAK,IAAU,EAAM,SAAS,IACzC,EAAM,QAAQ,QAAQ,EAAM,MAAM;AAC3C;AAEA,IAAM,IAAY;AAElB,SAAS,EAAU,GAAuB;AAGxC,QAAM,IAAW,EAAU,KAAK,CAAK,GAC/B,IAAO,IAAI,KAAK,IAAW,GAAG,CAAA,eAAoB,CAAK;AAC7D,SAAI,OAAO,MAAM,EAAK,QAAQ,CAAC,IAAU,IAClC,IAAI,KAAK,eAAe,SAAS;AAAA,IACtC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,GAAI,IAAW,EAAE,UAAU,MAAM,IAAI,CAAC;AAAA,EACxC,CAAC,EAAE,OAAO,CAAI;AAChB;AAGA,SAAgB,EACd,GACA,GACQ;AACR,MAAI,CAAC,EAAY,CAAK,KAAK,KAAS,KAAM,QAAO;AACjD,MAAI,EAAW,SAAS,cAAc;AACpC,UAAM,IAAQ;AACd,WAAI,EAAM,SAAe,EAAM,SAC3B,EAAM,QAAQ,EAAM,KACf,GAAG,EAAU,EAAM,IAAI,CAAA,OAAQ,EAAU,EAAM,EAAE,CAAA,KAEtD,EAAM,OAAa,QAAQ,EAAU,EAAM,IAAI,CAAA,KAC/C,EAAM,KAAW,SAAS,EAAU,EAAM,EAAE,CAAA,KACzC;AAAA,EACT;AACA,QAAM,IAAA,CAAW,MACf,EAAW,QAAQ,KAAA,CAAM,MAAW,EAAO,UAAU,CAAI,GAAG,SAAS;AACvE,SAAI,MAAM,QAAQ,CAAK,IAAU,EAAM,IAAI,CAAO,EAAE,KAAK,IAAI,IACtD,OAAO,KAAU,WAAW,EAAQ,CAAK,IAAI;AACtD;AAIA,IAAM,IACJ;AAEF,SAAS,EAAW,EAClB,YAAA,GACA,OAAA,GACA,UAAA,EAAA,GAKC;AACD,QAAM,CAAC,GAAM,CAAA,IAAW,EAAS,EAAK,GAChC,IAAW,EAA2B,IAAI,GAC1C,IAAM,EAAY,CAAK,GACvB,IAAU,EAAkB,GAAY,CAAK;AACnD,SACE,gBAAA,EAAC,EAAQ,MAAT;AAAA,IAAoB,MAAA;AAAA,IAAM,cAAc;AAAA,IAAxC,UAAA,CACE,gBAAA,EAAC,QAAD;AAAA,MACE,oBAAkB,EAAW;AAAA,MAC7B,YAAU,KAAO;AAAA,MACjB,WAAW,EACT,iGACA,IAAM,qBAAqB,gBAC7B;AAAA,MANF,UAAA,CAQE,gBAAA,EAAC,EAAQ,SAAT;AAAA,QACE,cAAY,IAAM,SAAY,GAAG,EAAW,KAAA;AAAA,QAC5C,WAAW,EACT,GACA,4BACA,IAAM,gBAAgB,eACtB,IAAM,mBAAmB,EAC3B;AAAA,QAPF,UAAA,CASG,IAAM,OAAO,gBAAA,EAAC,GAAD,EAAU,eAAA,GAAa,CAAA,GACpC,IACC,gBAAA,EAAC,QAAD;AAAA,UAAM,WAAU;AAAA,UAAhB,UAAA,CACE,gBAAA,EAAC,QAAD;AAAA,YAAM,WAAU;AAAA,YAAhB,UAAA,CACG,EAAW,OAAM,GACd;AAAA,UACN,CAAA,GAAA,gBAAA,EAAC,QAAD;AAAA,YAAM,WAAU;AAAA,YACb,UAAA;AAAA,UACG,CAAA,CACF;AAAA,QAEN,CAAA,IAAA,gBAAA,EAAC,QAAD;AAAA,UAAM,WAAU;AAAA,UAAsB,UAAA,EAAW;AAAA,QAAY,CAAA,CAEhD;AAAA,MAChB,CAAA,GAAA,IACC,gBAAA,EAAC,UAAD;AAAA,QACE,MAAK;AAAA,QACL,cAAY,SAAS,EAAW,MAAM,YAAY,CAAA;AAAA,QAClD,SAAA,MAAe,EAAS,MAAS;AAAA,QACjC,WAAW,EACT,GACA,wHACF;AAAA,QAEA,UAAA,gBAAA,EAAC,GAAD,EAAO,eAAA,GAAa,CAAA;AAAA,MACd,CAAA,IACN,IACA;AAAA,IACN,CAAA,GAAA,gBAAA,EAAC,EAAQ,QAAT,EAAA,UACE,gBAAA,EAAC,EAAQ,YAAT;AAAA,MAAoB,OAAM;AAAA,MAAQ,YAAY;AAAA,MAC5C,UAAA,gBAAA,EAAC,EAAQ,OAAT;AAAA,QACE,cAAY,GAAG,EAAW,KAAA;AAAA,QAC1B,cAAc;AAAA,QACd,WAAW,EACT,YACA,EAAW,SAAS,gBAAgB,MACtC;AAAA,QAEC,UAAA,EAAW,SAAS,eACnB,gBAAA,EAAC,GAAD;AAAA,UACc,YAAA;AAAA,UACL,OAAA;AAAA,UACG,UAAA;AAAA,UACV,UAAA,CAAW,MAAS;AAClB,YAAA,EAAS,CAAI,GACT,GAAM,UAAQ,EAAQ,EAAK;AAAA,UACjC;AAAA,QACD,CAAA,IAED,gBAAA,EAAC,GAAD;AAAA,UACc,YAAA;AAAA,UACL,OAAA;AAAA,UACG,UAAA;AAAA,UACV,UAAA,CAAW,MAAS;AAClB,YAAA,EAAS,CAAI,GACR,EAAW,YAAU,EAAQ,EAAK;AAAA,UACzC;AAAA,QACD,CAAA;AAAA,MAEU,CAAA;AAAA,IACG,CAAA,EACN,CAAA,CACJ;AAAA;AAElB;AAEA,SAAS,EAAa,EACpB,YAAA,GACA,OAAA,GACA,UAAA,GACA,UAAA,EAAA,GAMC;AACD,QAAM,CAAC,GAAO,CAAA,IAAY,EAAS,EAAE,GAC/B,IACJ,EAAW,cAAc,EAAW,QAAQ,SAAS,GACjD,IAAS,IAAI,IACjB,KAAS,OAAO,CAAC,IAAI,MAAM,QAAQ,CAAK,IAAI,IAAQ,CAAC,CAAK,CAC5D,GACM,IAAS,EAAM,KAAK,EAAE,YAAY,GAClC,IAAU,IACZ,EAAW,QAAQ,OAAA,CAChB,MACC,EAAO,MAAM,YAAY,EAAE,SAAS,CAAM,KAC1C,EAAO,MAAM,YAAY,EAAE,SAAS,CAAM,CAC9C,IACA,EAAW,SACT,IAAA,CAAQ,MAAyB;AACrC,QAAI,EAAW,UAAU;AACvB,YAAM,IAAO,IAAI,IAAI,CAAM;AAC3B,MAAI,EAAK,IAAI,EAAO,KAAK,IAAG,EAAK,OAAO,EAAO,KAAK,IAC/C,EAAK,IAAI,EAAO,KAAK;AAG1B,YAAM,IAAU,EAAW,QACxB,IAAA,CAAK,MAAS,EAAK,KAAK,EACxB,OAAA,CAAQ,MAAS,EAAK,IAAI,CAAI,CAAC;AAClC,MAAA,EAAS,EAAQ,SAAS,IAAI,IAAU,MAAS;AACjD;AAAA,IACF;AACA,IAAA,EAAS,EAAO,IAAI,EAAO,KAAK,IAAI,SAAY,EAAO,KAAK;AAAA,EAC9D;AACA,SACE,gBAAA,EAAC,EAAQ,MAAT;AAAA,IACE,OAAO,GAAG,EAAW,KAAA;AAAA,IAGrB,KAAA,CAAM,MAAgC;AACpC,MAAK,MAAY,EAAS,UAAU;AAAA,IACtC;AAAA,IACA,WAAU;AAAA,IAPZ,UAAA,CASG,IACC,gBAAA,EAAC,EAAQ,YAAT,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,MACE,eAAA;AAAA,MACA,WAAU;AAAA,IACX,CAAA,GACD,gBAAA,EAAC,EAAQ,OAAT;AAAA,MACE,KAAA,CAAM,MAAkC;AACtC,QAAA,EAAS,UAAU;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,MACP,eAAe;AAAA,MACf,aAAa,EAAW,qBAAqB;AAAA,MAC7C,cAAY,UAAU,EAAW,MAAM,YAAY,CAAA;AAAA,MACnD,WAAU;AAAA,IACX,CAAA,CACiB,EAAA,CAAA,IAClB,MACJ,gBAAA,EAAC,EAAQ,MAAT,EAAA,UAAA,CACE,gBAAA,EAAC,EAAQ,OAAT,EAAA,UAAe,mBAA+B,CAAA,GAC7C,EAAQ,IAAA,CAAK,MACZ,gBAAA,EAAC,EAAQ,MAAT;AAAA,MAEE,OAAO,EAAO;AAAA,MACd,OAAO,EAAO;AAAA,MACd,gBAAc,EAAO,IAAI,EAAO,KAAK;AAAA,MACrC,MAAM,EAAO,IAAI,EAAO,KAAK,IAAI,gBAAA,EAAC,GAAD,EAAW,eAAA,GAAa,CAAA,IAAI;AAAA,MAC7D,UAAA,MAAgB,EAAK,CAAM;AAAA,IAC5B,GANM,EAAO,KAMb,CACF,CACW,EAAA,CAAA,CACF;AAAA;AAElB;AAEA,IAAM,IACJ;AAEF,SAAS,EAAe,EACtB,YAAA,GACA,OAAA,GACA,UAAA,GACA,UAAA,EAAA,GAMC;AACD,QAAM,IAAU,EAAW,WAAW,GAEhC,IAAA,CAAO,MACX,KAAQ,OAAO,KAAK,EAAU,KAAK,CAAI,IAAI,IAAO,EAAK,MAAM,GAAG,EAAE,GAC9D,IAAA,CAAW,GAAqB,MAAiB;AAGrD,UAAM,IAAwB;AAAA,MAC5B,MAAM,EAAI,GAAO,IAAI,KAAK;AAAA,MAC1B,IAAI,EAAI,GAAO,EAAE,KAAK;AAAA,MACrB,CAAA,CAAA,GAAO,KAAQ;AAAA,IAClB;AACA,IAAA,EAAS,EAAM,QAAQ,QAAQ,EAAM,MAAM,OAAO,SAAY,CAAK;AAAA,EACrE;AACA,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,IAAf,UAAA,CACE,gBAAA,EAAC,EAAQ,MAAT;AAAA,MACE,OAAO,GAAG,EAAW,KAAA;AAAA,MACrB,KAAA,CAAM,MAAgC;AACpC,QAAA,EAAS,UAAU;AAAA,MACrB;AAAA,MACA,WAAU;AAAA,MAEV,UAAA,gBAAA,EAAC,EAAQ,MAAT,EAAA,UACG,EAAQ,IAAA,CAAK,MACZ,gBAAA,EAAC,EAAQ,MAAT;AAAA,QAEE,OAAO,EAAO;AAAA,QACd,OAAO,EAAO;AAAA,QACd,gBAAc,GAAO,WAAW,EAAO;AAAA,QACvC,MACE,GAAO,WAAW,EAAO,QACvB,gBAAA,EAAC,GAAD,EAAW,eAAA,GAAa,CAAA,IACtB;AAAA,QAEN,UAAA,MACE,EAAS;AAAA,UACP,OAAM,oBAAI,KACR,KAAK,IAAI,IAAI,EAAO,QAAQ,KAAK,KAAK,GACxC,GAAE,YAAY;AAAA,UACd,IAAI;AAAA,UACJ,QAAQ,EAAO;AAAA,QACjB,CAAC;AAAA,MAEJ,GAlBM,EAAO,KAkBb,CACF,EACW,CAAA;AAAA,IACF,CAAA,GAGd,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,MAAf,UAAA,CACE,gBAAA,EAAC,SAAD;AAAA,QAAO,WAAU;AAAA,QAAjB,UAAA,CAA4E,QAE1E,gBAAA,EAAC,SAAD;AAAA,UACE,MAAK;AAAA,UACL,OAAO,EAAI,GAAO,IAAI;AAAA,UACtB,KAAK,EAAI,GAAO,EAAE,KAAK;AAAA,UACvB,UAAA,CAAW,MAAU,EAAQ,QAAQ,EAAM,OAAO,KAAK;AAAA,UACvD,WAAW;AAAA,QACZ,CAAA,CACI;AAAA,MACP,CAAA,GAAA,gBAAA,EAAC,SAAD;AAAA,QAAO,WAAU;AAAA,QAAjB,UAAA,CAA4E,MAE1E,gBAAA,EAAC,SAAD;AAAA,UACE,MAAK;AAAA,UACL,OAAO,EAAI,GAAO,EAAE;AAAA,UACpB,KAAK,EAAI,GAAO,IAAI,KAAK;AAAA,UACzB,UAAA,CAAW,MAAU,EAAQ,MAAM,EAAM,OAAO,KAAK;AAAA,UACrD,WAAW;AAAA,QACZ,CAAA,CACI;AAAA,MACJ,CAAA,CAAA;AAAA,IACF,CAAA,CAAA;AAAA;AAET;AA+BA,SAAgB,EAAU,EACxB,aAAA,GACA,SAAA,GACA,iBAAA,GACA,QAAA,GACA,gBAAA,GACA,mBAAA,IAAoB,UACpB,aAAA,GACA,QAAA,GACA,WAAA,GACA,UAAA,GACA,GAAG,EAAA,GACc;AACjB,QAAM,IAAW,EAAY,OAAA,CAAQ,MACnC,EAAY,EAAQ,EAAW,GAAA,CAAI,CACrC,EAAE,QACI,IAAA,CAAU,GAAa,MAAkC;AAC7D,UAAM,IAAO,EAAE,GAAG,EAAQ;AAC1B,IAAI,MAAS,SAAW,OAAO,EAAK,CAAA,IAC/B,EAAK,CAAA,IAAO,GACjB,EAAgB,CAAI;AAAA,EACtB;AACA,SACE,gBAAA,EAAC,OAAD;AAAA,IACE,mBAAgB;AAAA,IAChB,WAAW,EACT,6CACA,KACE,mFACF,CACF;AAAA,IACA,GAAI;AAAA,IARN,UAAA;AAAA,MAUG,KAAkB,OACjB,gBAAA,EAAC,EAAW,MAAZ;AAAA,QAAiB,MAAK;AAAA,QAAK,WAAU;AAAA,QAArC,UAAA,CACE,gBAAA,EAAC,EAAW,OAAZ,EAAA,UACE,gBAAA,EAAC,GAAD,CAAa,CAAA,EACG,CAAA,GAClB,gBAAA,EAAC,EAAW,OAAZ;AAAA,UACE,MAAK;AAAA,UACL,OAAO,KAAU;AAAA,UACjB,UAAA,CAAW,MAAU,EAAe,EAAM,OAAO,KAAK;AAAA,UACtD,WAAA,CAAY,MAAU;AACpB,YAAI,EAAM,QAAQ,aAClB,EAAM,eAAe,GACrB,EAAe,EAAE;AAAA,UACnB;AAAA,UACA,aAAa;AAAA,UACb,cAAY,KAAe;AAAA,QAC5B,CAAA,CACc;AAAA,MACf,CAAA,IAAA;AAAA,MACH,EAAY,IAAA,CAAK,MAChB,gBAAA,EAAC,GAAD;AAAA,QAEc,YAAA;AAAA,QACZ,OAAO,EAAQ,EAAW,GAAA;AAAA,QAC1B,UAAA,CAAW,MAAS,EAAO,EAAW,KAAK,CAAI;AAAA,MAChD,GAJM,EAAW,GAIjB,CACF;AAAA,MACA,IAAW,IACV,gBAAA,EAAC,GAAD;AAAA,QACE,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,SAAA,MAAe;AACb,gBAAM,IAAO,EAAE,GAAG,EAAQ;AAC1B,qBAAW,KAAc,EAAa,QAAO,EAAK,EAAW,GAAA;AAC7D,UAAA,EAAgB,CAAI;AAAA,QACtB;AAAA,QACD,UAAA;AAAA,MAEO,CAAA,IACN;AAAA,MACH;AAAA,IACE;AAAA;AAET;AAEA,EAAU,cAAc"}
1
+ {"version":3,"file":"filter-bar-DTaLgQr0.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconPlus.mjs","../../src/components/filter-bar/filter-bar.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\": \"M12 5l0 14\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M5 12l14 0\", \"key\": \"svg-1\" }]];\nconst IconPlus = createReactComponent(\"outline\", \"plus\", \"Plus\", __iconNode);\n\nexport { __iconNode, IconPlus as default };\n//# sourceMappingURL=IconPlus.mjs.map\n","import {\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\nimport { IconCheck, IconPlus, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { Button } from \"../button\";\nimport { Command } from \"../command\";\nimport { InputGroup } from \"../input-group\";\nimport { Popover } from \"../popover\";\nimport { cn } from \"../../utils/cn\";\n\n/**\n * Filter Bar — the row that pins above a log list: a search field for an\n * id, then one chip per filter. A chip with nothing chosen reads\n * `+ Status`; with a value it reads `Status: Failed` and carries its own\n * clear. Each chip opens a small popover: a keyboard-first list of\n * options (with a search field past eight of them), or presets and a\n * from / to pair for a date range.\n *\n * Design notes:\n * - Fully controlled. The page owns `filters` and `search` and hands\n * them back changed; the bar keeps no state but which popover is open.\n * That keeps the query in one place (the URL, a store) and lets the\n * list refetch from it.\n * - Chips are real buttons (the trigger, and the clear beside it), so\n * the bar is one tab stop per control and Escape closes a popover\n * back onto its chip.\n * - No scroll container of its own: chips wrap. `sticky` pins it to the\n * top of the nearest scroll pane on the surface it sits on.\n */\n\nexport interface FilterOption {\n value: string;\n label: string;\n}\n\ninterface FilterDefinitionBase {\n /** The key in `filters` this chip reads and writes. */\n key: string;\n /** The chip's word — \"Status\", \"Event type\". Sentence case. */\n label: string;\n}\n\nexport interface SelectFilterDefinition extends FilterDefinitionBase {\n type?: \"select\";\n options: readonly FilterOption[];\n /** Several values at once (`string[]`); one at a time by default. */\n multiple?: boolean;\n /**\n * A search field above the options. On by default past eight options,\n * off below; say so to override.\n */\n searchable?: boolean;\n /** The search field's placeholder. @default \"Search\" */\n searchPlaceholder?: string;\n}\n\n/** A relative preset for a date-range filter — \"Last 7 days\" is 168 hours. */\nexport interface DateRangePreset {\n label: string;\n hours: number;\n}\n\nexport interface DateRangeFilterDefinition extends FilterDefinitionBase {\n type: \"date-range\";\n /** The relative presets listed above the from / to pair. */\n presets?: readonly DateRangePreset[];\n}\n\nexport type FilterDefinition =\n SelectFilterDefinition | DateRangeFilterDefinition;\n\n/**\n * A date-range value. A preset stores an absolute ISO timestamp in `from`\n * (computed when chosen) and its label in `preset`; the from / to pair\n * stores plain `YYYY-MM-DD` dates. Either side may be open (`null`).\n */\nexport interface DateRangeValue {\n from: string | null;\n to: string | null;\n preset?: string;\n}\n\nexport type FilterValue = string | string[] | DateRangeValue;\n\n/** The page's filter state — one entry per definition key that is set. */\nexport type FilterValues = Record<string, FilterValue | undefined>;\n\n/** The relative presets a date-range chip lists when given none. */\nexport const FILTER_DATE_PRESETS: readonly DateRangePreset[] = [\n { label: \"Last hour\", hours: 1 },\n { label: \"Last 24 hours\", hours: 24 },\n { label: \"Last 7 days\", hours: 24 * 7 },\n { label: \"Last 30 days\", hours: 24 * 30 },\n];\n\n/** Past this many options a select chip shows a search field. */\nconst SEARCHABLE_PAST = 8;\n\n/** Whether a filter value counts as set — an empty string or list does not. */\nexport function isFilterSet(value: FilterValue | undefined): boolean {\n if (value == null) return false;\n if (typeof value === \"string\") return value !== \"\";\n if (Array.isArray(value)) return value.length > 0;\n return value.from != null || value.to != null;\n}\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction formatDay(value: string): string {\n // A plain date is a calendar day: format it in UTC so the day survives\n // every viewer timezone. A timestamp is a moment: format it locally.\n const dateOnly = DATE_ONLY.test(value);\n const date = new Date(dateOnly ? `${value}T00:00:00Z` : value);\n if (Number.isNaN(date.getTime())) return value;\n return new Intl.DateTimeFormat(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n ...(dateOnly ? { timeZone: \"UTC\" } : {}),\n }).format(date);\n}\n\n/** The words a set chip shows after its label. */\nexport function formatFilterValue(\n definition: FilterDefinition,\n value: FilterValue | undefined,\n): string {\n if (!isFilterSet(value) || value == null) return \"\";\n if (definition.type === \"date-range\") {\n const range = value as DateRangeValue;\n if (range.preset) return range.preset;\n if (range.from && range.to) {\n return `${formatDay(range.from)} to ${formatDay(range.to)}`;\n }\n if (range.from) return `From ${formatDay(range.from)}`;\n if (range.to) return `Until ${formatDay(range.to)}`;\n return \"\";\n }\n const labelOf = (item: string) =>\n definition.options.find((option) => option.value === item)?.label ?? item;\n if (Array.isArray(value)) return value.map(labelOf).join(\", \");\n return typeof value === \"string\" ? labelOf(value) : \"\";\n}\n\n/* --------------------------------- chips -------------------------------- */\n\nconst CHIP_TRIGGER =\n \"outline-pho-brand flex h-8 min-w-0 cursor-pointer items-center gap-1.5 rounded-full text-base transition-[color,background-color] duration-100 ease-linear focus-visible:outline-2 focus-visible:-outline-offset-2 [&>svg]:size-4 [&>svg]:shrink-0\";\n\nfunction FilterChip({\n definition,\n value,\n onChange,\n}: {\n definition: FilterDefinition;\n value: FilterValue | undefined;\n onChange: (next: FilterValue | undefined) => void;\n}) {\n const [open, setOpen] = useState(false);\n const focusRef = useRef<HTMLElement | null>(null);\n const set = isFilterSet(value);\n const display = formatFilterValue(definition, value);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <span\n data-filter-chip={definition.key}\n data-set={set || undefined}\n className={cn(\n \"ring-pho-primary inline-flex max-w-full shrink-0 items-stretch rounded-full ring-1 ring-inset\",\n set ? \"bg-pho-secondary\" : \"bg-transparent\",\n )}\n >\n <Popover.Trigger\n aria-label={set ? undefined : `${definition.label} filter`}\n className={cn(\n CHIP_TRIGGER,\n \"hover:bg-pho-ghost-hover\",\n set ? \"pr-1.5 pl-3\" : \"pr-3 pl-2.5\",\n set ? \"rounded-r-none\" : \"\",\n )}\n >\n {set ? null : <IconPlus aria-hidden />}\n {set ? (\n <span className=\"flex min-w-0 items-baseline gap-1\">\n <span className=\"text-pho-description shrink-0\">\n {definition.label}:\n </span>\n <span className=\"text-pho-primary max-w-56 truncate font-medium\">\n {display}\n </span>\n </span>\n ) : (\n <span className=\"text-pho-secondary\">{definition.label}</span>\n )}\n </Popover.Trigger>\n {set ? (\n <button\n type=\"button\"\n aria-label={`Clear ${definition.label.toLowerCase()} filter`}\n onClick={() => onChange(undefined)}\n className={cn(\n CHIP_TRIGGER,\n \"text-pho-secondary hover:bg-pho-ghost-hover hover:text-pho-secondary-hover rounded-l-none pr-2.5 pl-1 [&>svg]:size-3.5\",\n )}\n >\n <IconX aria-hidden />\n </button>\n ) : null}\n </span>\n <Popover.Portal>\n <Popover.Positioner align=\"start\" sideOffset={6}>\n <Popover.Popup\n aria-label={`${definition.label} filter`}\n initialFocus={focusRef}\n className={cn(\n \"w-64 p-0\",\n definition.type === \"date-range\" && \"w-72\",\n )}\n >\n {definition.type === \"date-range\" ? (\n <DateRangePanel\n definition={definition}\n value={value as DateRangeValue | undefined}\n focusRef={focusRef}\n onChange={(next) => {\n onChange(next);\n if (next?.preset) setOpen(false);\n }}\n />\n ) : (\n <OptionsPanel\n definition={definition}\n value={value as string | string[] | undefined}\n focusRef={focusRef}\n onChange={(next) => {\n onChange(next);\n if (!definition.multiple) setOpen(false);\n }}\n />\n )}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nfunction OptionsPanel({\n definition,\n value,\n focusRef,\n onChange,\n}: {\n definition: SelectFilterDefinition;\n value: string | string[] | undefined;\n focusRef: RefObject<HTMLElement | null>;\n onChange: (next: string | string[] | undefined) => void;\n}) {\n const [query, setQuery] = useState(\"\");\n const searchable =\n definition.searchable ?? definition.options.length > SEARCHABLE_PAST;\n const chosen = new Set(\n value == null ? [] : Array.isArray(value) ? value : [value],\n );\n const needle = query.trim().toLowerCase();\n const options = needle\n ? definition.options.filter(\n (option) =>\n option.label.toLowerCase().includes(needle) ||\n option.value.toLowerCase().includes(needle),\n )\n : definition.options;\n const pick = (option: FilterOption) => {\n if (definition.multiple) {\n const next = new Set(chosen);\n if (next.has(option.value)) next.delete(option.value);\n else next.add(option.value);\n // Keep the definition's order, so the chip reads the same way\n // whatever order the values were chosen in.\n const ordered = definition.options\n .map((item) => item.value)\n .filter((item) => next.has(item));\n onChange(ordered.length > 0 ? ordered : undefined);\n return;\n }\n onChange(chosen.has(option.value) ? undefined : option.value);\n };\n return (\n <Command.Root\n label={`${definition.label} options`}\n // Without a search field the list itself takes focus, so the arrow\n // keys work from the first frame.\n ref={(node: HTMLDivElement | null) => {\n if (!searchable) focusRef.current = node;\n }}\n className=\"rounded-base\"\n >\n {searchable ? (\n <Command.InputGroup>\n <IconSearch\n aria-hidden\n className=\"text-pho-description pointer-events-none absolute left-3 size-4\"\n />\n <Command.Input\n ref={(node: HTMLInputElement | null) => {\n focusRef.current = node;\n }}\n value={query}\n onValueChange={setQuery}\n placeholder={definition.searchPlaceholder ?? \"Search\"}\n aria-label={`Search ${definition.label.toLowerCase()} options`}\n className=\"py-2 pr-3 pl-9 text-base\"\n />\n </Command.InputGroup>\n ) : null}\n <Command.List>\n <Command.Empty>Nothing matches.</Command.Empty>\n {options.map((option) => (\n <Command.Item\n key={option.value}\n value={option.value}\n title={option.label}\n aria-checked={chosen.has(option.value)}\n icon={chosen.has(option.value) ? <IconCheck aria-hidden /> : null}\n onSelect={() => pick(option)}\n />\n ))}\n </Command.List>\n </Command.Root>\n );\n}\n\nconst DATE_INPUT =\n \"bg-pho-primary ring-pho-primary text-pho-primary focus-visible:ring-pho-brand w-full min-w-0 rounded-sm px-2 py-1 text-base ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2\";\n\nfunction DateRangePanel({\n definition,\n value,\n focusRef,\n onChange,\n}: {\n definition: DateRangeFilterDefinition;\n value: DateRangeValue | undefined;\n focusRef: RefObject<HTMLElement | null>;\n onChange: (next: DateRangeValue | undefined) => void;\n}) {\n const presets = definition.presets ?? FILTER_DATE_PRESETS;\n // A preset's `from` is a timestamp; the day field shows its date.\n const day = (side: string | null | undefined) =>\n side == null ? \"\" : DATE_ONLY.test(side) ? side : side.slice(0, 10);\n const setSide = (side: \"from\" | \"to\", next: string) => {\n // Editing either day leaves a preset behind: the pair is the value now,\n // and a preset's timestamp becomes the day it fell on.\n const range: DateRangeValue = {\n from: day(value?.from) || null,\n to: day(value?.to) || null,\n [side]: next || null,\n };\n onChange(range.from == null && range.to == null ? undefined : range);\n };\n return (\n <div className=\"flex flex-col\">\n <Command.Root\n label={`${definition.label} presets`}\n ref={(node: HTMLDivElement | null) => {\n focusRef.current = node;\n }}\n className=\"rounded-t-[inherit]\"\n >\n <Command.List>\n {presets.map((preset) => (\n <Command.Item\n key={preset.label}\n value={preset.label}\n title={preset.label}\n aria-checked={value?.preset === preset.label}\n icon={\n value?.preset === preset.label ? (\n <IconCheck aria-hidden />\n ) : null\n }\n onSelect={() =>\n onChange({\n from: new Date(\n Date.now() - preset.hours * 60 * 60 * 1000,\n ).toISOString(),\n to: null,\n preset: preset.label,\n })\n }\n />\n ))}\n </Command.List>\n </Command.Root>\n {/* The day fields stand outside the command list: its arrow-key\n handling would otherwise swallow the native date stepping. */}\n <div className=\"border-pho-secondary grid grid-cols-2 gap-2 border-t p-2\">\n <label className=\"text-pho-description flex min-w-0 flex-col gap-1 text-xs\">\n From\n <input\n type=\"date\"\n value={day(value?.from)}\n max={day(value?.to) || undefined}\n onChange={(event) => setSide(\"from\", event.target.value)}\n className={DATE_INPUT}\n />\n </label>\n <label className=\"text-pho-description flex min-w-0 flex-col gap-1 text-xs\">\n To\n <input\n type=\"date\"\n value={day(value?.to)}\n min={day(value?.from) || undefined}\n onChange={(event) => setSide(\"to\", event.target.value)}\n className={DATE_INPUT}\n />\n </label>\n </div>\n </div>\n );\n}\n\n/* ---------------------------------- bar --------------------------------- */\n\nexport interface FilterBarProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** One chip per definition, in this order. */\n definitions: readonly FilterDefinition[];\n /** The values, keyed by definition key. Absent or empty means unset. */\n filters: FilterValues;\n /** The whole map, changed — set, cleared, or cleared all. */\n onFiltersChange: (next: FilterValues) => void;\n /** The search field's text. The field renders only with `onSearchChange`. */\n search?: string;\n onSearchChange?: (value: string) => void;\n /** A teaching phrase — \"Find an event by id\". @default \"Search\" */\n searchPlaceholder?: string;\n /** The field's accessible name when the placeholder is too short to be one. */\n searchLabel?: string;\n /**\n * Pin the bar to the top of the nearest scroll pane. It paints the\n * surface it sits on (`--pho-surface`) so rows scroll under it.\n */\n sticky?: boolean;\n /** Controls after the chips — a range picker, an export button. */\n children?: ReactNode;\n ref?: Ref<HTMLDivElement>;\n}\n\nexport function FilterBar({\n definitions,\n filters,\n onFiltersChange,\n search,\n onSearchChange,\n searchPlaceholder = \"Search\",\n searchLabel,\n sticky,\n className,\n children,\n ...props\n}: FilterBarProps) {\n const setCount = definitions.filter((definition) =>\n isFilterSet(filters[definition.key]),\n ).length;\n const change = (key: string, next: FilterValue | undefined) => {\n const rest = { ...filters };\n if (next === undefined) delete rest[key];\n else rest[key] = next;\n onFiltersChange(rest);\n };\n return (\n <div\n data-filter-bar=\"\"\n className={cn(\n \"flex min-w-0 flex-wrap items-center gap-2\",\n sticky &&\n \"sticky top-0 z-10 bg-[var(--pho-surface,var(--background-color-pho-page))] py-3\",\n className,\n )}\n {...props}\n >\n {onSearchChange != null ? (\n <InputGroup.Root size=\"sm\" className=\"w-64 max-w-full\">\n <InputGroup.Addon>\n <IconSearch />\n </InputGroup.Addon>\n <InputGroup.Input\n type=\"search\"\n value={search ?? \"\"}\n onChange={(event) => onSearchChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n onSearchChange(\"\");\n }}\n placeholder={searchPlaceholder}\n aria-label={searchLabel ?? searchPlaceholder}\n />\n </InputGroup.Root>\n ) : null}\n {definitions.map((definition) => (\n <FilterChip\n key={definition.key}\n definition={definition}\n value={filters[definition.key]}\n onChange={(next) => change(definition.key, next)}\n />\n ))}\n {setCount > 1 ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n const rest = { ...filters };\n for (const definition of definitions) delete rest[definition.key];\n onFiltersChange(rest);\n }}\n >\n Clear filters\n </Button>\n ) : null}\n {children}\n </div>\n );\n}\n\nFilterBar.displayName = \"FilterBar\";\n"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { n as t, t as a } from "../chunks/card-DhDwtSi9.js";
2
+ import { n as t, t as a } from "../chunks/card-N-tvFsuV.js";
3
3
  export {
4
4
  a as CARD_SURFACE,
5
5
  t as Card
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { n as t, t as a } from "../chunks/command-CTYrSz9a.js";
2
+ import { n as t, t as a } from "../chunks/command-ZagVyDx7.js";
3
3
  export {
4
4
  a as Command,
5
5
  t as useCommandState
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { n as t, t as a } from "../chunks/date-picker-Ddeo1fNE.js";
2
+ import { n as t, t as a } from "../chunks/date-picker-CZbcNIe-.js";
3
3
  export {
4
4
  a as DatePicker,
5
5
  t as formatDateLabel
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { n as i, t as o } from "../chunks/dialog-BwfUFn6B.js";
2
+ import { n as i, t as o } from "../chunks/dialog-BYiAFetB.js";
3
3
  export {
4
4
  o as Dialog,
5
5
  i as useDialogPending
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { i as t, n as e, r as a, t as i } from "../chunks/filter-bar-D9lBBr4z.js";
2
+ import { i as t, n as e, r as a, t as i } from "../chunks/filter-bar-DTaLgQr0.js";
3
3
  export {
4
4
  i as FILTER_DATE_PRESETS,
5
5
  e as FilterBar,
package/dist/index.js CHANGED
@@ -10,21 +10,21 @@ import "./utils.js";
10
10
  import { a as h, c as k, d as v, i as w, l as W, n as x, o as H, r as y, s as z, t as K, u as X } from "./chunks/button-CdqS_t5a.js";
11
11
  import { a as Z, c as j, i as J, l as Q, n as q, o as $, r as aa, s as sa, t as ta } from "./chunks/error-BAQgnde7.js";
12
12
  import { A as oa, B as ea, C as ia, D as Ea, E as Sa, F as _a, I as na, L as ma, M as Ia, N as Ta, O as pa, P as Aa, R as Ra, S as la, T as Ca, V as Ba, _ as fa, a as Na, b as Pa, c as ua, d as La, f as ca, g as Da, h as Oa, i as Va, j as da, k as Ua, l as Ga, m as ba, n as Fa, o as Ma, p as ga, r as ha, s as ka, t as va, u as wa, v as Wa, w as xa, x as Ha, y as ya, z as za } from "./chunks/trace-Hku-rImp.js";
13
- import { n as Xa, t as Ya } from "./chunks/date-picker-Ddeo1fNE.js";
13
+ import { n as Xa, t as Ya } from "./chunks/date-picker-CZbcNIe-.js";
14
14
  import { n as ja, t as Ja } from "./chunks/copy-button-B_B15mEi.js";
15
15
  import { a as qa, c as $a, d as as, i as ss, l as ts, n as rs, o as os, r as es, s as is, t as Es, u as Ss } from "./chunks/sidebar-DRPe5CAh.js";
16
16
  import { t as ns } from "./chunks/input-DjvZoF8v.js";
17
- import { i as Is, n as Ts, r as ps, t as As } from "./chunks/filter-bar-D9lBBr4z.js";
17
+ import { i as Is, n as Ts, r as ps, t as As } from "./chunks/filter-bar-DTaLgQr0.js";
18
18
  import { a as ls } from "./chunks/data-table-BeUwsjmX.js";
19
19
  import { n as Bs, t as fs } from "./chunks/code-block-BuDIo8Q0.js";
20
20
  import { n as Ps, t as us } from "./chunks/stat-hnNqjWVG.js";
21
21
  import { t as cs } from "./chunks/calendar-4OFiCLAv.js";
22
22
  import { t as Os } from "./chunks/close-button-GvqWbLl0.js";
23
23
  import { t as ds } from "./chunks/input-group-fc9_jD4d.js";
24
- import { n as Gs, t as bs } from "./chunks/card-DhDwtSi9.js";
25
- import { n as Ms, t as gs } from "./chunks/dialog-BwfUFn6B.js";
24
+ import { n as Gs, t as bs } from "./chunks/card-N-tvFsuV.js";
25
+ import { n as Ms, t as gs } from "./chunks/dialog-BYiAFetB.js";
26
26
  import { i as ks, n as vs, r as ws, t as Ws } from "./chunks/status-view-C8tabjDu.js";
27
- import { a as Hs, c as ys, d as zs, f as Ks, i as Xs, l as Ys, m as Zs, n as js, o as Js, p as Qs, r as qs, s as $s, t as at, u as st } from "./chunks/basic-page-C3qjXfBe.js";
27
+ import { a as Hs, c as ys, d as zs, f as Ks, i as Xs, l as Ys, m as Zs, n as js, o as Js, p as Qs, r as qs, s as $s, t as at, u as st } from "./chunks/basic-page-65eFgq8o.js";
28
28
  import { i as rt, n as ot, r as et, t as it } from "./chunks/legend-C0mU7dqd.js";
29
29
  import "./components/chart.js";
30
30
  import { t as _t } from "./chunks/bar-chart-DIALC2_z.js";
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { a as s } from "../chunks/data-table-BeUwsjmX.js";
3
- import { a as E, c as a, d as C, f as S, i as I, l as e, m as o, n as B, o as P, p as N, r, s as t, t as D, u as R } from "../chunks/basic-page-C3qjXfBe.js";
3
+ import { a as E, c as a, d as C, f as S, i as I, l as e, m as o, n as B, o as P, p as N, r, s as t, t as D, u as R } from "../chunks/basic-page-65eFgq8o.js";
4
4
  export {
5
5
  D as AUTO_SAVE_DELAY_MS,
6
6
  B as BASIC_PAGE_CALLOUT,