@photon-ai/pho-ui 2.0.1 → 2.1.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 (42) hide show
  1. package/dist/chunks/animated-height-C2eQstGy.js +51 -0
  2. package/dist/chunks/animated-height-C2eQstGy.js.map +1 -0
  3. package/dist/chunks/{basic-page-D1zm81YS.js → basic-page-Dfln58iw.js} +152 -151
  4. package/dist/chunks/basic-page-Dfln58iw.js.map +1 -0
  5. package/dist/chunks/choice-card-CunOnY9l.js +17 -0
  6. package/dist/chunks/choice-card-CunOnY9l.js.map +1 -0
  7. package/dist/chunks/dialog-BC23YRUq.js +262 -0
  8. package/dist/chunks/dialog-BC23YRUq.js.map +1 -0
  9. package/dist/chunks/scroll-area-CNZVwe7v.js +152 -0
  10. package/dist/chunks/scroll-area-CNZVwe7v.js.map +1 -0
  11. package/dist/components/checkbox.js +110 -37
  12. package/dist/components/checkbox.js.map +1 -1
  13. package/dist/components/command.js +2 -2
  14. package/dist/components/dialog.js +1 -1
  15. package/dist/components/phone-input.js +754 -752
  16. package/dist/components/phone-input.js.map +1 -1
  17. package/dist/components/radio-group.js +93 -23
  18. package/dist/components/radio-group.js.map +1 -1
  19. package/dist/components/scroll-area.js +2 -40
  20. package/dist/index.js +2 -2
  21. package/dist/primitives.js +1 -1
  22. package/dist/sections/basic-page.js +1 -1
  23. package/dist/src/components/checkbox/check-glyph.d.ts +10 -0
  24. package/dist/src/components/checkbox/checkbox-card.d.ts +21 -0
  25. package/dist/src/components/checkbox/checkbox.d.ts +1 -1
  26. package/dist/src/components/checkbox/index.d.ts +1 -0
  27. package/dist/src/components/phone-input/index.d.ts +1 -1
  28. package/dist/src/components/phone-input/phone-input.d.ts +8 -1
  29. package/dist/src/components/radio-group/index.d.ts +1 -0
  30. package/dist/src/components/radio-group/radio-card.d.ts +20 -0
  31. package/dist/src/components/radio-group/radio-group.d.ts +4 -2
  32. package/dist/src/components/scroll-area/scroll-area-edges.d.ts +9 -0
  33. package/dist/src/components/scroll-area/scroll-area.d.ts +7 -6
  34. package/dist/src/sections/basic-page/basic-page.d.ts +13 -3
  35. package/dist/src/utils/choice-card.d.ts +15 -0
  36. package/package.json +1 -1
  37. package/dist/chunks/animated-height-DhNSac85.js +0 -50
  38. package/dist/chunks/animated-height-DhNSac85.js.map +0 -1
  39. package/dist/chunks/basic-page-D1zm81YS.js.map +0 -1
  40. package/dist/chunks/dialog-Caze1vkf.js +0 -252
  41. package/dist/chunks/dialog-Caze1vkf.js.map +0 -1
  42. package/dist/components/scroll-area.js.map +0 -1
@@ -1,34 +1,104 @@
1
1
  "use client";
2
- import { t } from "../chunks/cn-DTiB6ek_.js";
3
- import "react";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
5
- import { Radio as i } from "@base-ui/react/radio";
6
- import { RadioGroup as d } from "@base-ui/react/radio-group";
7
- function l({ className: r, ...e }) {
8
- return /* @__PURE__ */ o(d, {
9
- className: t("flex flex-col gap-3", r),
10
- ...e
2
+ import { t as d } from "../chunks/cn-DTiB6ek_.js";
3
+ import { r as m } from "../chunks/use-press-pulse-8iorQPsh.js";
4
+ import { a as g, n as C, r as R, t as v } from "../chunks/choice-card-CunOnY9l.js";
5
+ import { createContext as x, useContext as N } from "react";
6
+ import { jsx as o, jsxs as h } from "react/jsx-runtime";
7
+ import { motion as c } from "motion/react";
8
+ import { Radio as l } from "@base-ui/react/radio";
9
+ import { RadioGroup as y } from "@base-ui/react/radio-group";
10
+ var b = x(!1);
11
+ function f() {
12
+ return N(b);
13
+ }
14
+ function k({ className: e, disabled: r, ...a }) {
15
+ return /* @__PURE__ */ o(b.Provider, {
16
+ value: !!r,
17
+ children: /* @__PURE__ */ o(y, {
18
+ disabled: r,
19
+ className: d("flex flex-col gap-3", e),
20
+ ...a
21
+ })
11
22
  });
12
23
  }
13
- l.displayName = "RadioGroup";
14
- function c({ className: r, label: e, ...n }) {
15
- const a = /* @__PURE__ */ o(i.Root, {
16
- className: t("outline-pho-brand bg-pho-primary ring-pho-primary flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-full ring-1 transition duration-100 ease-linear ring-inset focus-visible:outline-2 focus-visible:outline-offset-2", "data-[checked]:bg-pho-brand-solid data-[checked]:ring-transparent", "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", r),
17
- ...n,
18
- children: /* @__PURE__ */ o(i.Indicator, { className: "bg-pho-on-brand size-2 rounded-full" })
24
+ k.displayName = "RadioGroup";
25
+ function I({ className: e, label: r, disabled: a, ...i }) {
26
+ const s = f(), { motionProps: p } = m({
27
+ scale: 0.94,
28
+ disabled: !!(a || s)
29
+ }), { onPointerDown: t, ...u } = p, n = /* @__PURE__ */ o(l.Root, {
30
+ disabled: a,
31
+ render: /* @__PURE__ */ o(c.span, {
32
+ ...u,
33
+ onPointerDown: r ? void 0 : t
34
+ }),
35
+ className: d("outline-pho-brand bg-pho-primary ring-pho-primary flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-full ring-1 ring-inset focus-visible:outline-2 focus-visible:outline-offset-2", "transition-[background-color,box-shadow,color,outline-color] duration-150 ease-out", "hover:bg-pho-primary-hover hover:ring-pho-ink group-hover:bg-pho-primary-hover group-hover:ring-pho-ink", "data-[checked]:bg-pho-brand-solid data-[checked]:ring-transparent", "data-[checked]:hover:bg-pho-brand-solid-hover data-[checked]:group-hover:bg-pho-brand-solid-hover", "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", e),
36
+ ...i,
37
+ children: /* @__PURE__ */ o(l.Indicator, {
38
+ render: /* @__PURE__ */ o(c.span, {
39
+ initial: { scale: 0 },
40
+ animate: { scale: 1 },
41
+ transition: g
42
+ }),
43
+ className: "bg-pho-on-brand size-2 rounded-full"
44
+ })
19
45
  });
20
- return e ? /* @__PURE__ */ s("label", {
21
- className: "flex cursor-pointer items-center gap-2 select-none",
22
- children: [a, /* @__PURE__ */ o("span", {
46
+ return r ? /* @__PURE__ */ h("label", {
47
+ className: "group flex cursor-pointer items-center gap-2 select-none",
48
+ onPointerDown: t,
49
+ children: [n, /* @__PURE__ */ o("span", {
23
50
  className: "text-pho-secondary text-base",
24
- children: e
51
+ children: r
25
52
  })]
26
- }) : a;
53
+ }) : n;
54
+ }
55
+ I.displayName = "Radio";
56
+ function _({ title: e, description: r }) {
57
+ return /* @__PURE__ */ h("span", { children: [/* @__PURE__ */ o("span", {
58
+ className: "text-pho-primary block",
59
+ children: e
60
+ }), r ? /* @__PURE__ */ o("span", {
61
+ className: "text-pho-description block",
62
+ children: r
63
+ }) : null] });
64
+ }
65
+ function P({ className: e, title: r, description: a, icon: i, disabled: s, ...p }) {
66
+ const t = f(), { motionProps: u } = m({
67
+ scale: C,
68
+ disabled: !!(s || t),
69
+ transition: R
70
+ }), n = i != null;
71
+ return /* @__PURE__ */ h(l.Root, {
72
+ disabled: s,
73
+ render: /* @__PURE__ */ o(c.span, { ...u }),
74
+ className: d(v, n && "flex-col gap-1.5", e),
75
+ ...p,
76
+ children: [n ? /* @__PURE__ */ o("span", {
77
+ "aria-hidden": !0,
78
+ className: "text-pho-secondary flex size-6 shrink-0 items-center justify-center [&>svg]:size-6",
79
+ children: i
80
+ }) : /* @__PURE__ */ o("span", {
81
+ "aria-hidden": !0,
82
+ className: d("bg-pho-primary ring-pho-primary mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full ring-1 ring-inset", "group-hover:bg-pho-primary-hover group-hover:ring-pho-ink transition-[background-color,box-shadow] duration-150 ease-out", "group-data-[checked]:bg-pho-brand-solid group-data-[checked]:group-hover:bg-pho-brand-solid-hover group-data-[checked]:ring-transparent"),
83
+ children: /* @__PURE__ */ o(l.Indicator, {
84
+ render: /* @__PURE__ */ o(c.span, {
85
+ initial: { scale: 0 },
86
+ animate: { scale: 1 },
87
+ transition: g
88
+ }),
89
+ className: "bg-pho-on-brand size-1.5 rounded-full"
90
+ })
91
+ }), /* @__PURE__ */ o(_, {
92
+ title: r,
93
+ description: a
94
+ })]
95
+ });
27
96
  }
28
- c.displayName = "Radio";
97
+ P.displayName = "RadioCard";
29
98
  export {
30
- c as Radio,
31
- l as RadioGroup
99
+ I as Radio,
100
+ P as RadioCard,
101
+ k as RadioGroup
32
102
  };
33
103
 
34
104
  //# sourceMappingURL=radio-group.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.js","names":[],"sources":["../../src/components/radio-group/radio-group.tsx"],"sourcesContent":["import { type ComponentProps, type ReactNode } from \"react\";\nimport { RadioGroup as BaseRadioGroup } from \"@base-ui/react/radio-group\";\nimport { Radio as BaseRadio } from \"@base-ui/react/radio\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface RadioGroupProps extends Omit<\n ComponentProps<typeof BaseRadioGroup>,\n \"className\"\n> {\n className?: string;\n}\n\n/**\n * Single-choice group built on Base UI `RadioGroup`. Holds `Radio` items;\n * exactly one may be selected. Control with `value` / `onValueChange` or leave\n * uncontrolled with `defaultValue`.\n */\nexport function RadioGroup({ className, ...props }: RadioGroupProps) {\n return (\n <BaseRadioGroup\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n />\n );\n}\n\nRadioGroup.displayName = \"RadioGroup\";\n\nexport interface RadioProps extends Omit<\n ComponentProps<typeof BaseRadio.Root>,\n \"className\"\n> {\n className?: string;\n /** Text rendered beside the dot; the whole row selects this option. */\n label?: ReactNode;\n}\n\n/**\n * A single option within a `RadioGroup`. Requires a `value`; pass `label` for a\n * clickable text row or provide an `aria-label`.\n */\nexport function Radio({ className, label, ...props }: RadioProps) {\n const dot = (\n <BaseRadio.Root\n className={cn(\n \"outline-pho-brand bg-pho-primary ring-pho-primary flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-full ring-1 transition duration-100 ease-linear ring-inset focus-visible:outline-2 focus-visible:outline-offset-2\",\n \"data-[checked]:bg-pho-brand-solid data-[checked]:ring-transparent\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n {/* The indicator only renders when checked, i.e. always on brand-solid —\n on-brand (light-dark(#fff,#000)) keeps the dot visible in dark mode,\n where brand-solid is white. */}\n <BaseRadio.Indicator className=\"bg-pho-on-brand size-2 rounded-full\" />\n </BaseRadio.Root>\n );\n\n if (!label) return dot;\n return (\n <label className=\"flex cursor-pointer items-center gap-2 select-none\">\n {dot}\n <span className=\"text-pho-secondary text-base\">{label}</span>\n </label>\n );\n}\n\nRadio.displayName = \"Radio\";\n"],"mappings":";;;;;;AAiBA,SAAgB,EAAW,EAAE,WAAA,GAAW,GAAG,EAAA,GAA0B;AACnE,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,WAAW,EAAG,uBAAuB,CAAS;AAAA,IAC9C,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,EAAW,cAAc;AAezB,SAAgB,EAAM,EAAE,WAAA,GAAW,OAAA,GAAO,GAAG,EAAA,GAAqB;AAChE,QAAM,IACJ,gBAAA,EAAC,EAAU,MAAX;AAAA,IACE,WAAW,EACT,+OACA,qEACA,iEACA,CACF;AAAA,IACA,GAAI;AAAA,cAKJ,gBAAA,EAAC,EAAU,WAAX,EAAqB,WAAU,sCAAuC,CAAA;AAAA,EACxD,CAAA;AAGlB,SAAK,IAEH,gBAAA,EAAC,SAAD;AAAA,IAAO,WAAU;AAAA,cAAjB,CACG,GACD,gBAAA,EAAC,QAAD;AAAA,MAAM,WAAU;AAAA,gBAAgC;AAAA,IAAY,CAAA,CACvD;AAAA,OALU;AAOrB;AAEA,EAAM,cAAc"}
1
+ {"version":3,"file":"radio-group.js","names":[],"sources":["../../src/components/radio-group/radio-group.tsx","../../src/components/radio-group/radio-card.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n type ComponentProps,\n type ReactNode,\n} from \"react\";\nimport { RadioGroup as BaseRadioGroup } from \"@base-ui/react/radio-group\";\nimport { Radio as BaseRadio } from \"@base-ui/react/radio\";\nimport { motion } from \"motion/react\";\nimport { cn } from \"../../utils/cn\";\nimport { usePressPulse } from \"../../utils/use-press-pulse\";\nimport { CHOICE_INDICATOR_POP_TRANSITION } from \"../../utils/choice-card\";\n\nexport interface RadioGroupProps extends Omit<\n ComponentProps<typeof BaseRadioGroup>,\n \"className\"\n> {\n className?: string;\n}\n\nconst RadioGroupDisabledContext = createContext(false);\n\n/** Group-level `disabled`, so press pulse skips when the group is locked. */\nexport function useRadioGroupDisabled() {\n return useContext(RadioGroupDisabledContext);\n}\n\n/**\n * Single-choice group built on Base UI `RadioGroup`. Holds `Radio` items;\n * exactly one may be selected. Control with `value` / `onValueChange` or leave\n * uncontrolled with `defaultValue`.\n */\nexport function RadioGroup({ className, disabled, ...props }: RadioGroupProps) {\n return (\n <RadioGroupDisabledContext.Provider value={Boolean(disabled)}>\n <BaseRadioGroup\n disabled={disabled}\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n />\n </RadioGroupDisabledContext.Provider>\n );\n}\n\nRadioGroup.displayName = \"RadioGroup\";\n\nexport interface RadioProps extends Omit<\n ComponentProps<typeof BaseRadio.Root>,\n \"className\"\n> {\n className?: string;\n /** Text rendered beside the dot; the whole row selects this option. */\n label?: ReactNode;\n}\n\n/**\n * A single option within a `RadioGroup`. Requires a `value`; pass `label` for a\n * clickable text row or provide an `aria-label`.\n */\nexport function Radio({ className, label, disabled, ...props }: RadioProps) {\n const groupDisabled = useRadioGroupDisabled();\n const { motionProps } = usePressPulse({\n scale: 0.94,\n disabled: Boolean(disabled || groupDisabled),\n });\n // With a label, the whole row is the hit target — press-trigger from there\n // (pointerdown bubbles up from the label text too) so the dot still\n // animates when the text, not the dot itself, is what's clicked.\n const { onPointerDown, ...dotMotionProps } = motionProps;\n\n const dot = (\n <BaseRadio.Root\n disabled={disabled}\n render={\n <motion.span\n {...dotMotionProps}\n onPointerDown={label ? undefined : onPointerDown}\n />\n }\n className={cn(\n \"outline-pho-brand bg-pho-primary ring-pho-primary flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-full ring-1 ring-inset focus-visible:outline-2 focus-visible:outline-offset-2\",\n // Transform stays out — Motion owns the press pulse.\n \"transition-[background-color,box-shadow,color,outline-color] duration-150 ease-out\",\n // group-hover covers hovering the label text, not just the dot itself.\n \"hover:bg-pho-primary-hover hover:ring-pho-ink group-hover:bg-pho-primary-hover group-hover:ring-pho-ink\",\n \"data-[checked]:bg-pho-brand-solid data-[checked]:ring-transparent\",\n \"data-[checked]:hover:bg-pho-brand-solid-hover data-[checked]:group-hover:bg-pho-brand-solid-hover\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n {/* The indicator only renders when checked, i.e. always on brand-solid —\n on-brand (light-dark(#fff,#000)) keeps the dot visible in dark mode,\n where brand-solid is white. Pops in rather than appearing flat. */}\n <BaseRadio.Indicator\n render={\n <motion.span\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={CHOICE_INDICATOR_POP_TRANSITION}\n />\n }\n className=\"bg-pho-on-brand size-2 rounded-full\"\n />\n </BaseRadio.Root>\n );\n\n if (!label) return dot;\n return (\n <label\n className=\"group flex cursor-pointer items-center gap-2 select-none\"\n onPointerDown={onPointerDown}\n >\n {dot}\n <span className=\"text-pho-secondary text-base\">{label}</span>\n </label>\n );\n}\n\nRadio.displayName = \"Radio\";\n","import { type ComponentProps, type ReactNode } from \"react\";\nimport { Radio as BaseRadio } from \"@base-ui/react/radio\";\nimport { motion } from \"motion/react\";\nimport { cn } from \"../../utils/cn\";\nimport { usePressPulse } from \"../../utils/use-press-pulse\";\nimport {\n CHOICE_CARD_BASE,\n CHOICE_CARD_WITH_ICON,\n CHOICE_CARD_PRESS_SCALE,\n CHOICE_CARD_PRESS_TRANSITION,\n CHOICE_INDICATOR_POP_TRANSITION,\n} from \"../../utils/choice-card\";\nimport { useRadioGroupDisabled } from \"./radio-group\";\n\nexport interface RadioCardProps extends Omit<\n ComponentProps<typeof BaseRadio.Root>,\n \"className\" | \"title\"\n> {\n className?: string;\n /** Tile heading. */\n title: ReactNode;\n /** Supporting copy shown below the title. */\n description?: ReactNode;\n /** Glyph stacked above the title. When set, it replaces the radio dot. */\n icon?: ReactNode;\n}\n\nfunction CardCopy({\n title,\n description,\n}: {\n title: ReactNode;\n description?: ReactNode;\n}) {\n return (\n <span>\n <span className=\"text-pho-primary block\">{title}</span>\n {description ? (\n <span className=\"text-pho-description block\">{description}</span>\n ) : null}\n </span>\n );\n}\n\n/**\n * A `Radio` styled as a bordered, selectable tile — title, optional\n * description, and either a stacked icon or the radio dot. The tile *is*\n * the radio (see `usePressPulse`); an inner glyph is decorative.\n */\nexport function RadioCard({\n className,\n title,\n description,\n icon,\n disabled,\n ...props\n}: RadioCardProps) {\n const groupDisabled = useRadioGroupDisabled();\n const { motionProps } = usePressPulse({\n scale: CHOICE_CARD_PRESS_SCALE,\n disabled: Boolean(disabled || groupDisabled),\n transition: CHOICE_CARD_PRESS_TRANSITION,\n });\n const hasIcon = icon != null;\n\n return (\n <BaseRadio.Root\n disabled={disabled}\n render={<motion.span {...motionProps} />}\n className={cn(\n CHOICE_CARD_BASE,\n hasIcon && CHOICE_CARD_WITH_ICON,\n className,\n )}\n {...props}\n >\n {hasIcon ? (\n <span\n aria-hidden\n className=\"text-pho-secondary flex size-6 shrink-0 items-center justify-center [&>svg]:size-6\"\n >\n {icon}\n </span>\n ) : (\n <span\n aria-hidden\n className={cn(\n \"bg-pho-primary ring-pho-primary mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full ring-1 ring-inset\",\n \"group-hover:bg-pho-primary-hover group-hover:ring-pho-ink transition-[background-color,box-shadow] duration-150 ease-out\",\n \"group-data-[checked]:bg-pho-brand-solid group-data-[checked]:group-hover:bg-pho-brand-solid-hover group-data-[checked]:ring-transparent\",\n )}\n >\n <BaseRadio.Indicator\n render={\n <motion.span\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={CHOICE_INDICATOR_POP_TRANSITION}\n />\n }\n className=\"bg-pho-on-brand size-1.5 rounded-full\"\n />\n </span>\n )}\n <CardCopy title={title} description={description} />\n </BaseRadio.Root>\n );\n}\n\nRadioCard.displayName = \"RadioCard\";\n"],"mappings":"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"}
@@ -1,43 +1,5 @@
1
1
  "use client";
2
- import { t as a } from "../chunks/cn-DTiB6ek_.js";
3
- import "react";
4
- import { jsx as e } from "react/jsx-runtime";
5
- import { ScrollArea as t } from "@base-ui/react/scroll-area";
6
- var n = t.Content, l = t.Corner;
7
- function i({ className: o, ...r }) {
8
- return /* @__PURE__ */ e(t.Root, {
9
- className: a("relative overflow-hidden", o),
10
- ...r
11
- });
12
- }
13
- function c({ className: o, ...r }) {
14
- return /* @__PURE__ */ e(t.Viewport, {
15
- className: a("outline-pho-brand h-full w-full overscroll-contain rounded-[inherit] focus-visible:outline-2 focus-visible:-outline-offset-1", o),
16
- ...r
17
- });
18
- }
19
- function s({ className: o, ...r }) {
20
- return /* @__PURE__ */ e(t.Scrollbar, {
21
- className: a("flex touch-none p-0.5 opacity-0 transition-opacity delay-300 select-none", "data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0 data-[scrolling]:duration-0", "data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=vertical]:w-2.5", o),
22
- ...r
23
- });
24
- }
25
- function u({ className: o, ...r }) {
26
- return /* @__PURE__ */ e(t.Thumb, {
27
- className: a("flex-1 rounded-full bg-[var(--border-color-pho-primary)]", o),
28
- ...r
29
- });
30
- }
31
- var h = {
32
- Root: i,
33
- Viewport: c,
34
- Content: n,
35
- Scrollbar: s,
36
- Thumb: u,
37
- Corner: l
38
- };
2
+ import { t as e } from "../chunks/scroll-area-CNZVwe7v.js";
39
3
  export {
40
- h as ScrollArea
4
+ e as ScrollArea
41
5
  };
42
-
43
- //# sourceMappingURL=scroll-area.js.map
package/dist/index.js CHANGED
@@ -6,13 +6,13 @@ import { n as I, r as n, t as A } from "./chunks/use-press-pulse-8iorQPsh.js";
6
6
  import "./utils.js";
7
7
  import { a as e, c as R, d as p, i as B, l as C, n as O, o as P, r as f, s as u, t as D, u as N } from "./chunks/button-X5wsWvRa.js";
8
8
  import { a as c, c as l, i as V, l as U, n as G, o as d, r as M, s as b, t as g } from "./chunks/error-DR6G2LmG.js";
9
- import { a as F, i as W, n as h, o as Z, r as v, s as w, t as x } from "./chunks/basic-page-D1zm81YS.js";
9
+ import { a as F, i as W, n as h, o as Z, r as v, s as w, t as x } from "./chunks/basic-page-Dfln58iw.js";
10
10
  import { a as z, c as Y, i as j, n as q, o as y, r as J, s as K, t as Q } from "./chunks/sidebar-DDJC1MeD.js";
11
11
  import { t as $ } from "./chunks/input-D3XQcC4J.js";
12
12
  import { t as sa } from "./chunks/close-button-xadxp0j8.js";
13
13
  import { t as ra } from "./chunks/input-group-D6dlma8k.js";
14
14
  import { n as Ea, t as _a } from "./chunks/card-9cGnv-VD.js";
15
- import { n as Sa, t as Ia } from "./chunks/dialog-Caze1vkf.js";
15
+ import { n as Sa, t as Ia } from "./chunks/dialog-BC23YRUq.js";
16
16
  import { i as Aa, n as Ta, r as ma, t as ea } from "./chunks/status-view-CcbctPqR.js";
17
17
  import "./components/status-view.js";
18
18
  export {
@@ -43,6 +43,7 @@ import "./primitives/tooltip.js";
43
43
  export * from "@base-ui/react/field";
44
44
  export * from "@base-ui/react/separator";
45
45
  export * from "@base-ui/react/dialog";
46
+ export * from "@base-ui/react/scroll-area";
46
47
  export * from "@base-ui/react/popover";
47
48
  export * from "@base-ui/react/avatar";
48
49
  export * from "@base-ui/react/accordion";
@@ -70,7 +71,6 @@ export * from "@base-ui/react/preview-card";
70
71
  export * from "@base-ui/react/progress";
71
72
  export * from "@base-ui/react/radio";
72
73
  export * from "@base-ui/react/radio-group";
73
- export * from "@base-ui/react/scroll-area";
74
74
  export * from "@base-ui/react/select";
75
75
  export * from "@base-ui/react/slider";
76
76
  export * from "@base-ui/react/switch";
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { a as _, i as E, n as I, o as a, r as s, s as P, t as C } from "../chunks/basic-page-D1zm81YS.js";
2
+ import { a as _, i as E, n as I, o as a, r as s, s as P, t as C } from "../chunks/basic-page-Dfln58iw.js";
3
3
  export {
4
4
  C as BASIC_PAGE_CALLOUT,
5
5
  I as BASIC_PAGE_CARD,
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The checkbox glyph, stroked on rather than popped in solid — same
3
+ * considered-motion spirit as Button's press/wake effects. Re-keyed per
4
+ * state (check vs. dash) so every appearance draws fresh from empty instead
5
+ * of resuming a stroke left mid-way by whatever the glyph showed before.
6
+ */
7
+ export declare function DrawnCheckGlyph({ indeterminate, className, }: {
8
+ indeterminate?: boolean;
9
+ className?: string;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
3
+ export interface CheckboxCardProps extends Omit<ComponentProps<typeof BaseCheckbox.Root>, "className" | "title"> {
4
+ className?: string;
5
+ /** Tile heading. */
6
+ title: ReactNode;
7
+ /** Supporting copy shown below the title. */
8
+ description?: ReactNode;
9
+ /** Glyph stacked above the title. When set, it replaces the checkbox box. */
10
+ icon?: ReactNode;
11
+ }
12
+ /**
13
+ * A `Checkbox` styled as a bordered, selectable tile — title, optional
14
+ * description, and either a stacked icon or the checkbox box. The tile is a
15
+ * `<label>` around the control so clicks (including on the icon/title) are a
16
+ * trusted activation of the hidden input Base UI renders beside the root.
17
+ */
18
+ export declare function CheckboxCard({ className, title, description, icon, disabled, indeterminate, ...props }: CheckboxCardProps): import("react").JSX.Element;
19
+ export declare namespace CheckboxCard {
20
+ var displayName: string;
21
+ }
@@ -18,7 +18,7 @@ export interface CheckboxProps extends Omit<ComponentProps<typeof BaseCheckbox.R
18
18
  * a quick shallow press pulse on pointer-down (always plays out), the
19
19
  * fill/stroke easing between states, and the glyph popping in.
20
20
  */
21
- export declare function Checkbox({ className, label, size, disabled, ...props }: CheckboxProps): import("react").JSX.Element;
21
+ export declare function Checkbox({ className, label, size, disabled, indeterminate, ...props }: CheckboxProps): import("react").JSX.Element;
22
22
  export declare namespace Checkbox {
23
23
  var displayName: string;
24
24
  }
@@ -1,2 +1,3 @@
1
1
  export { Checkbox, type CheckboxProps, type CheckboxSize } from './checkbox';
2
2
  export { CheckboxGroup, type CheckboxGroupProps } from './checkbox-group';
3
+ export { CheckboxCard, type CheckboxCardProps } from './checkbox-card';
@@ -1 +1 @@
1
- export { PhoneInput, type CountryCode, type PhoneInputChangeMeta, type PhoneInputProps, } from './phone-input';
1
+ export { PhoneInput, CountryFlag, type CountryCode, type PhoneInputChangeMeta, type PhoneInputProps, } from './phone-input';
@@ -1,6 +1,11 @@
1
1
  import { InputHTMLAttributes, ReactNode, Ref } from 'react';
2
2
  import { CountryCode } from 'libphonenumber-js/min';
3
3
  import { InputGroupSize } from '../input-group';
4
+ /** 3:2 SVG flag for a libphonenumber country code; null when unknown. */
5
+ export declare function CountryFlag({ country, className, }: {
6
+ country: CountryCode;
7
+ className?: string;
8
+ }): import("react").JSX.Element | null;
4
9
  export type { CountryCode };
5
10
  export interface PhoneInputChangeMeta {
6
11
  country: CountryCode;
@@ -35,13 +40,15 @@ export interface PhoneInputProps extends Omit<InputHTMLAttributes<HTMLInputEleme
35
40
  labelTrailing?: ReactNode;
36
41
  /** Class applied to the Input Group surface. */
37
42
  wrapperClassName?: string;
43
+ /** Node after the number, inside the field surface (e.g. an Edit action). */
44
+ trailing?: ReactNode;
38
45
  ref?: Ref<HTMLInputElement>;
39
46
  }
40
47
  /**
41
48
  * Phone number field — country picker (searchable Combobox) + national number
42
49
  * input on a shared Input Group surface. The committed value is always E.164.
43
50
  */
44
- export declare function PhoneInput({ value, defaultValue, onValueChange, defaultCountry, countries: countriesProp, lockCountry, size, invalid, label, hint, labelTrailing, disabled, required, placeholder, className, wrapperClassName, id, ref, "aria-label": ariaLabel, onKeyDown, ...props }: PhoneInputProps): import("react").JSX.Element;
51
+ export declare function PhoneInput({ value, defaultValue, onValueChange, defaultCountry, countries: countriesProp, lockCountry, size, invalid, label, hint, labelTrailing, disabled, required, placeholder, className, wrapperClassName, trailing, id, ref, "aria-label": ariaLabel, onKeyDown, ...props }: PhoneInputProps): import("react").JSX.Element;
45
52
  export declare namespace PhoneInput {
46
53
  var displayName: string;
47
54
  }
@@ -1 +1,2 @@
1
1
  export { RadioGroup, Radio, type RadioGroupProps, type RadioProps, } from './radio-group';
2
+ export { RadioCard, type RadioCardProps } from './radio-card';
@@ -0,0 +1,20 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ import { Radio as BaseRadio } from '@base-ui/react/radio';
3
+ export interface RadioCardProps extends Omit<ComponentProps<typeof BaseRadio.Root>, "className" | "title"> {
4
+ className?: string;
5
+ /** Tile heading. */
6
+ title: ReactNode;
7
+ /** Supporting copy shown below the title. */
8
+ description?: ReactNode;
9
+ /** Glyph stacked above the title. When set, it replaces the radio dot. */
10
+ icon?: ReactNode;
11
+ }
12
+ /**
13
+ * A `Radio` styled as a bordered, selectable tile — title, optional
14
+ * description, and either a stacked icon or the radio dot. The tile *is*
15
+ * the radio (see `usePressPulse`); an inner glyph is decorative.
16
+ */
17
+ export declare function RadioCard({ className, title, description, icon, disabled, ...props }: RadioCardProps): import("react").JSX.Element;
18
+ export declare namespace RadioCard {
19
+ var displayName: string;
20
+ }
@@ -4,12 +4,14 @@ import { Radio as BaseRadio } from '@base-ui/react/radio';
4
4
  export interface RadioGroupProps extends Omit<ComponentProps<typeof BaseRadioGroup>, "className"> {
5
5
  className?: string;
6
6
  }
7
+ /** Group-level `disabled`, so press pulse skips when the group is locked. */
8
+ export declare function useRadioGroupDisabled(): boolean;
7
9
  /**
8
10
  * Single-choice group built on Base UI `RadioGroup`. Holds `Radio` items;
9
11
  * exactly one may be selected. Control with `value` / `onValueChange` or leave
10
12
  * uncontrolled with `defaultValue`.
11
13
  */
12
- export declare function RadioGroup({ className, ...props }: RadioGroupProps): import("react").JSX.Element;
14
+ export declare function RadioGroup({ className, disabled, ...props }: RadioGroupProps): import("react").JSX.Element;
13
15
  export declare namespace RadioGroup {
14
16
  var displayName: string;
15
17
  }
@@ -22,7 +24,7 @@ export interface RadioProps extends Omit<ComponentProps<typeof BaseRadio.Root>,
22
24
  * A single option within a `RadioGroup`. Requires a `value`; pass `label` for a
23
25
  * clickable text row or provide an `aria-label`.
24
26
  */
25
- export declare function Radio({ className, label, ...props }: RadioProps): import("react").JSX.Element;
27
+ export declare function Radio({ className, label, disabled, ...props }: RadioProps): import("react").JSX.Element;
26
28
  export declare namespace Radio {
27
29
  var displayName: string;
28
30
  }
@@ -0,0 +1,9 @@
1
+ import { Ref } from 'react';
2
+ /** Overlay strip height — a short ramp, not a banner. `h-8` = 32px. */
3
+ export declare const EDGE_CLASS = "pointer-events-none absolute inset-x-0 z-10 h-8";
4
+ export declare const EDGE_REVEAL_PX = 32;
5
+ export declare function paintEdge(node: HTMLDivElement | null, progress: number): void;
6
+ export declare function Edge({ edge, edgeRef, }: {
7
+ edge: "top" | "bottom";
8
+ edgeRef: Ref<HTMLDivElement>;
9
+ }): import("react").JSX.Element;
@@ -4,15 +4,16 @@ import { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';
4
4
  type StyledProps<T extends ElementType> = Omit<ComponentProps<T>, "className"> & {
5
5
  className?: string;
6
6
  };
7
- declare function Root({ className, ...props }: StyledProps<typeof BaseScrollArea.Root>): import("react").JSX.Element;
8
- declare function Viewport({ className, ...props }: StyledProps<typeof BaseScrollArea.Viewport>): import("react").JSX.Element;
7
+ declare function Root({ className, children, ...props }: StyledProps<typeof BaseScrollArea.Root>): import("react").JSX.Element;
8
+ declare function Viewport({ className, ref, ...props }: StyledProps<typeof BaseScrollArea.Viewport>): import("react").JSX.Element;
9
9
  declare function Scrollbar({ className, ...props }: StyledProps<typeof BaseScrollArea.Scrollbar>): import("react").JSX.Element;
10
10
  declare function Thumb({ className, ...props }: StyledProps<typeof BaseScrollArea.Thumb>): import("react").JSX.Element;
11
11
  /**
12
- * Scroll area built on Base UI `ScrollArea` — a region with custom, overlay
13
- * scrollbars that match the design system instead of the native ones. Give
14
- * `ScrollArea.Root` a fixed size; put scrollable content in `Viewport` →
15
- * `Content` and add a `Scrollbar` → `Thumb` per axis.
12
+ * Scroll area built on Base UI `ScrollArea` — a capped region with overlay
13
+ * scrollbars and progressive edge fade. Approaching rows blur (0 → 1px) and
14
+ * wash into the surface; strength tracks scroll distance over one strip
15
+ * height. Give `Root` a fixed size; put content in `Viewport` → `Content`
16
+ * and add a `Scrollbar` → `Thumb` per axis.
16
17
  */
17
18
  export declare const ScrollArea: {
18
19
  Root: typeof Root;
@@ -6,13 +6,13 @@ export declare const BASIC_PAGE_CARD = "rounded-base border border-pho-secondary
6
6
  * Standalone callout surface — featured block (invite form, notice, etc.).
7
7
  * Don't wrap in `Card`; this is the outer chrome.
8
8
  */
9
- export declare const BASIC_PAGE_CALLOUT = "flex flex-col gap-3 rounded-base border border-pho-secondary bg-pho-page p-5";
9
+ export declare const BASIC_PAGE_CALLOUT = "flex min-w-0 flex-col gap-3 rounded-base border border-pho-secondary bg-pho-page p-5";
10
10
  /**
11
11
  * One row — label (+ optional description) left, control right.
12
12
  * `min-h-[4.25rem]` (68px) keeps avatar/control rows from collapsing shorter
13
13
  * than a comfortable touch target.
14
14
  */
15
- export declare const BASIC_PAGE_ROW = "flex min-h-[4.25rem] flex-col gap-3 px-5 py-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6";
15
+ export declare const BASIC_PAGE_ROW = "flex min-h-[4.25rem] min-w-0 flex-col gap-3 px-5 py-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6";
16
16
  /**
17
17
  * One card row that can host subviews. Same padding rhythm as a plain row —
18
18
  * an optional trailing `ItemPanel` breaks out of it on its own.
@@ -82,6 +82,9 @@ export interface BasicPageTitleProps extends ComponentProps<"h1"> {
82
82
  /**
83
83
  * Page title — largest heading on the surface. Plain-text children get a slug
84
84
  * `id` for hash targets (`#profile`); the heading itself is not a link.
85
+ * Long names ellipsize; keep trailing accessories (`Badge`, status) as
86
+ * `shrink-0` siblings of a `min-w-0 truncate` label inside a `flex min-w-0`
87
+ * row so they stay visible.
85
88
  */
86
89
  declare function Title({ id, morphId, enter, className, children, ...props }: BasicPageTitleProps): import("react").JSX.Element;
87
90
  export interface BasicPageStackProps extends Omit<ComponentProps<"div">, RevealMotionConflicts> {
@@ -304,6 +307,13 @@ export interface BasicPageRevealProps extends Omit<ComponentProps<"div">, Reveal
304
307
  * inside a block (`gap-3`). @default "stack"
305
308
  */
306
309
  gap?: "stack" | "block";
310
+ /**
311
+ * Set when this wraps multiple `Card` rows — the extra element Reveal
312
+ * needs for `AnimatePresence` sits between them and the card's own
313
+ * `divide-y`, so the hairlines between the wrapped rows disappear unless
314
+ * this restores them. Leave off for content that isn't a run of rows.
315
+ */
316
+ dividers?: boolean;
307
317
  ref?: Ref<HTMLDivElement>;
308
318
  }
309
319
  /**
@@ -321,7 +331,7 @@ export interface BasicPageRevealProps extends Omit<ComponentProps<"div">, Reveal
321
331
  * `Footer` grammar): a whole section of the Stack that appears or leaves at
322
332
  * runtime glides open/closed while its neighbours follow.
323
333
  */
324
- declare function Reveal({ show, gap, className, ...props }: BasicPageRevealProps): import("react").JSX.Element;
334
+ declare function Reveal({ show, gap, dividers, className, ...props }: BasicPageRevealProps): import("react").JSX.Element;
325
335
  export interface BasicPageBackProps extends Omit<ButtonLinkProps, "variant" | "size" | "shape" | "prefix" | "suffix" | "svgOnly" | "href"> {
326
336
  /** Parent destination — rendered through the host's `LinkProvider`. */
327
337
  href: string;
@@ -0,0 +1,15 @@
1
+ import { Transition } from 'motion/react';
2
+ /**
3
+ * Shared surface for `RadioCard` / `CheckboxCard` — a bordered, selectable
4
+ * tile. Applied to the radio/checkbox root itself so the whole tile is the
5
+ * hit target. Hover fills (`bg-pho-ghost-hover`); selected uses the brand
6
+ * ring. Press feedback lives on this surface (see `usePressPulse`).
7
+ */
8
+ export declare const CHOICE_CARD_BASE = "group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base p-3 text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2";
9
+ /** Stacked icon above the copy — tighter than the checkbox/radio row gap. */
10
+ export declare const CHOICE_CARD_WITH_ICON = "flex-col gap-1.5";
11
+ /** Same press as Select's default trigger — field-sized, not Button's whileTap. */
12
+ export declare const CHOICE_CARD_PRESS_SCALE = 0.98;
13
+ export declare const CHOICE_CARD_PRESS_TRANSITION: Transition;
14
+ /** Selection pop for a radio dot / checkbox glyph — quick and slightly bouncy. */
15
+ export declare const CHOICE_INDICATOR_POP_TRANSITION: Transition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@photon-ai/pho-ui",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Pho Design System — Photon's React component library, built on Base UI",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -1,50 +0,0 @@
1
- "use client";
2
- import { useEffect as h, useRef as d } from "react";
3
- import { jsx as m } from "react/jsx-runtime";
4
- import { animate as g, motion as R, useMotionValue as x, useReducedMotion as y } from "motion/react";
5
- var w = {
6
- type: "spring",
7
- stiffness: 640,
8
- damping: 50
9
- };
10
- function S({ className: p, transition: s, children: v }) {
11
- const i = d(null), c = d(null), t = x("auto"), u = y();
12
- return h(() => {
13
- const o = i.current, n = c.current;
14
- if (!o || !n) return;
15
- let e = null;
16
- const l = new ResizeObserver((b) => {
17
- const f = b[0]?.borderBoxSize?.[0], r = f ? f.blockSize : n.offsetHeight, a = t.get();
18
- if (a === "auto" || u) {
19
- e?.stop(), e = null, o.style.overflow = "", t.set(r);
20
- return;
21
- }
22
- !e && Math.abs(a - r) < 0.5 || (o.style.overflow = "hidden", e?.stop(), e = g(t, r, {
23
- ...s ?? w,
24
- onComplete: () => {
25
- e = null, o.style.overflow = "";
26
- }
27
- }));
28
- });
29
- return l.observe(n), () => {
30
- l.disconnect(), e?.stop();
31
- };
32
- }, [
33
- t,
34
- u,
35
- s
36
- ]), /* @__PURE__ */ m(R.div, {
37
- ref: i,
38
- style: { height: t },
39
- children: /* @__PURE__ */ m("div", {
40
- ref: c,
41
- className: p,
42
- children: v
43
- })
44
- });
45
- }
46
- export {
47
- S as t
48
- };
49
-
50
- //# sourceMappingURL=animated-height-DhNSac85.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"animated-height-DhNSac85.js","names":[],"sources":["../../src/utils/animated-height.tsx"],"sourcesContent":["import { useEffect, useRef, type ReactNode } from \"react\";\nimport {\n animate,\n motion,\n useMotionValue,\n useReducedMotion,\n type ValueAnimationTransition,\n} from \"motion/react\";\n\n/**\n * Height spring for container-size transitions — same feel as the onboarding /\n * invite card and BasicPage footer reveal: quick, critically damped (no\n * overshoot that would flash clipped content).\n */\nconst HEIGHT_SPRING = { type: \"spring\", stiffness: 640, damping: 50 } as const;\n\n/**\n * Animates its own height to follow the measured height of `children`, so\n * content swaps (search filtering, skeleton → data) glide instead of jumping.\n * Honors `prefers-reduced-motion` by snapping height with no spring.\n */\nexport function AnimatedHeight({\n className,\n transition,\n children,\n}: {\n className?: string;\n /** Spring override for the height follow. @default the Command spring */\n transition?: ValueAnimationTransition<number | \"auto\">;\n children: ReactNode;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const height = useMotionValue<number | \"auto\">(\"auto\");\n const reduceMotion = useReducedMotion();\n\n useEffect(() => {\n const container = containerRef.current;\n const content = contentRef.current;\n if (!container || !content) return;\n\n let animation: ReturnType<typeof animate> | null = null;\n\n const observer = new ResizeObserver((entries) => {\n const box = entries[0]?.borderBoxSize?.[0];\n const next = box ? box.blockSize : content.offsetHeight;\n const current = height.get();\n if (current === \"auto\" || reduceMotion) {\n animation?.stop();\n animation = null;\n container.style.overflow = \"\";\n height.set(next);\n return;\n }\n if (!animation && Math.abs(current - next) < 0.5) return;\n container.style.overflow = \"hidden\";\n animation?.stop();\n animation = animate(height, next, {\n ...(transition ?? HEIGHT_SPRING),\n onComplete: () => {\n animation = null;\n container.style.overflow = \"\";\n },\n });\n });\n observer.observe(content);\n\n return () => {\n observer.disconnect();\n animation?.stop();\n };\n }, [height, reduceMotion, transition]);\n\n return (\n <motion.div ref={containerRef} style={{ height }}>\n <div ref={contentRef} className={className}>\n {children}\n </div>\n </motion.div>\n );\n}\n"],"mappings":";;;;AAcA,IAAM,IAAgB;AAAA,EAAE,MAAM;AAAA,EAAU,WAAW;AAAA,EAAK,SAAS;AAAG;AAOpE,SAAgB,EAAe,EAC7B,WAAA,GACA,YAAA,GACA,UAAA,EAAA,GAMC;AACD,QAAM,IAAe,EAAuB,IAAI,GAC1C,IAAa,EAAuB,IAAI,GACxC,IAAS,EAAgC,MAAM,GAC/C,IAAe,EAAiB;AAEtC,SAAA,EAAA,MAAgB;AACd,UAAM,IAAY,EAAa,SACzB,IAAU,EAAW;AAC3B,QAAI,CAAC,KAAa,CAAC,EAAS;AAE5B,QAAI,IAA+C;AAEnD,UAAM,IAAW,IAAI,eAAA,CAAgB,MAAY;AAC/C,YAAM,IAAM,EAAQ,CAAA,GAAI,gBAAgB,CAAA,GAClC,IAAO,IAAM,EAAI,YAAY,EAAQ,cACrC,IAAU,EAAO,IAAI;AAC3B,UAAI,MAAY,UAAU,GAAc;AACtC,QAAA,GAAW,KAAK,GAChB,IAAY,MACZ,EAAU,MAAM,WAAW,IAC3B,EAAO,IAAI,CAAI;AACf;AAAA,MACF;AACA,MAAI,CAAC,KAAa,KAAK,IAAI,IAAU,CAAI,IAAI,QAC7C,EAAU,MAAM,WAAW,UAC3B,GAAW,KAAK,GAChB,IAAY,EAAQ,GAAQ,GAAM;AAAA,QAChC,GAAI,KAAc;AAAA,QAClB,YAAA,MAAkB;AAChB,UAAA,IAAY,MACZ,EAAU,MAAM,WAAW;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,WAAA,EAAS,QAAQ,CAAO,GAExB,MAAa;AACX,MAAA,EAAS,WAAW,GACpB,GAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG;AAAA,IAAC;AAAA,IAAQ;AAAA,IAAc;AAAA,EAAU,CAAC,GAGnC,gBAAA,EAAC,EAAO,KAAR;AAAA,IAAY,KAAK;AAAA,IAAc,OAAO,EAAE,QAAA,EAAO;AAAA,cAC7C,gBAAA,EAAC,OAAD;AAAA,MAAK,KAAK;AAAA,MAAuB,WAAA;AAAA,MAC9B,UAAA;AAAA,IACE,CAAA;AAAA,EACK,CAAA;AAEhB"}