@jbpark/ui-kit 5.0.0 → 5.2.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 (56) hide show
  1. package/dist/Space.mjs +2 -0
  2. package/dist/Space.mjs.map +1 -1
  3. package/dist/components/atoms/checkbox/checkbox.mjs +11 -8
  4. package/dist/components/atoms/checkbox/checkbox.mjs.map +1 -1
  5. package/dist/components/atoms/radio/radio.mjs +11 -8
  6. package/dist/components/atoms/radio/radio.mjs.map +1 -1
  7. package/dist/components/atoms/skeleton/skeleton.mjs +1 -1
  8. package/dist/components/atoms/skeleton/skeleton.mjs.map +1 -1
  9. package/dist/components/molecules/dropdown.mjs +14 -12
  10. package/dist/components/molecules/dropdown.mjs.map +1 -1
  11. package/dist/components/molecules/menu/item/item.mjs.map +1 -1
  12. package/dist/components/organisms/imperative-stack.mjs +6 -4
  13. package/dist/components/organisms/imperative-stack.mjs.map +1 -1
  14. package/dist/components/organisms/modal.d.mts.map +1 -1
  15. package/dist/components/organisms/modal.mjs +12 -7
  16. package/dist/components/organisms/modal.mjs.map +1 -1
  17. package/dist/components/organisms/toast.d.mts.map +1 -1
  18. package/dist/components/organisms/toast.mjs +3 -1
  19. package/dist/components/organisms/toast.mjs.map +1 -1
  20. package/dist/components/templates/grid/col.d.mts.map +1 -1
  21. package/dist/components/templates/grid/col.mjs +35 -15
  22. package/dist/components/templates/grid/col.mjs.map +1 -1
  23. package/dist/components/templates/grid/row-context.mjs +1 -2
  24. package/dist/components/templates/grid/row-context.mjs.map +1 -1
  25. package/dist/components/templates/grid/row.d.mts.map +1 -1
  26. package/dist/components/templates/grid/row.mjs +2 -9
  27. package/dist/components/templates/grid/row.mjs.map +1 -1
  28. package/dist/components/templates/layout/content.d.mts.map +1 -1
  29. package/dist/components/templates/layout/content.mjs +5 -1
  30. package/dist/components/templates/layout/content.mjs.map +1 -1
  31. package/dist/components/templates/layout/sider.mjs +22 -7
  32. package/dist/components/templates/layout/sider.mjs.map +1 -1
  33. package/dist/components/templates/page-header.d.mts.map +1 -1
  34. package/dist/components/templates/page-header.mjs +3 -1
  35. package/dist/components/templates/page-header.mjs.map +1 -1
  36. package/dist/core/badge.d.mts +1 -1
  37. package/dist/core/button.d.mts +1 -1
  38. package/dist/index.d.mts +2 -1
  39. package/dist/index.mjs +2 -1
  40. package/dist/providers/config/config.d.mts.map +1 -1
  41. package/dist/providers/config/config.mjs +7 -1
  42. package/dist/providers/config/config.mjs.map +1 -1
  43. package/dist/providers/config/context.d.mts.map +1 -1
  44. package/dist/providers/config/context.mjs +4 -1
  45. package/dist/providers/config/context.mjs.map +1 -1
  46. package/dist/providers/config/index.d.mts +2 -1
  47. package/dist/providers/config/registry.d.mts +14 -0
  48. package/dist/providers/config/registry.d.mts.map +1 -0
  49. package/dist/providers/config/registry.mjs +26 -0
  50. package/dist/providers/config/registry.mjs.map +1 -0
  51. package/dist/providers/config/types.d.mts +3 -0
  52. package/dist/providers/config/types.d.mts.map +1 -1
  53. package/dist/providers.d.mts +2 -1
  54. package/dist/providers.mjs +2 -1
  55. package/dist/style.css +40 -0
  56. package/package.json +2 -2
package/dist/Space.mjs CHANGED
@@ -21,6 +21,7 @@ const Space = ({ loading, loader, children, size = "middle", orientation = "hori
21
21
  if (loading) return /* @__PURE__ */ jsx("div", {
22
22
  className: cn(hidden && "hidden", className),
23
23
  style,
24
+ hidden,
24
25
  ...props,
25
26
  children: loader || /* @__PURE__ */ jsx(Skeleton, {})
26
27
  });
@@ -33,6 +34,7 @@ const Space = ({ loading, loader, children, size = "middle", orientation = "hori
33
34
  gridTemplateColumns: grid?.cols ? `repeat(${grid.cols}, minmax(0, 1fr))` : void 0,
34
35
  ...style
35
36
  },
37
+ hidden,
36
38
  ...props,
37
39
  children: Children.map(children, (child, i) => /* @__PURE__ */ jsxs(Fragment$1, { children: [child, split && i < count - 1 && split] }))
38
40
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Space.mjs","names":[],"sources":["../src/components/molecules/space.tsx"],"sourcesContent":["import { Children } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Skeleton from '../atoms/skeleton';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n loading?: boolean;\n loader?: React.ReactNode;\n orientation?: 'horizontal' | 'vertical';\n size?: 'small' | 'middle' | 'large' | number | number[];\n align?: 'start' | 'end' | 'center' | 'baseline';\n wrap?: boolean;\n split?: React.ReactNode;\n grid?: {\n rows?: number;\n cols?: number;\n };\n}\n\nconst sizes: Record<string, number[]> = {\n small: [4, 4],\n middle: [8, 8],\n large: [16, 16],\n};\n\nconst aligns: Record<string, string> = {\n start: 'items-start text-start',\n end: 'items-end text-end',\n center: 'items-center text-center',\n baseline: 'items-baseline text-baseline',\n};\n\nconst Space = ({\n loading,\n loader,\n children,\n size = 'middle',\n orientation = 'horizontal',\n align = 'center',\n wrap = false,\n split,\n className,\n grid,\n hidden,\n style,\n ...props\n}: Props) => {\n const [x, y] =\n typeof size === 'string'\n ? sizes[size] || [0, 0]\n : Array.isArray(size)\n ? size\n : [size, size];\n const count = Children.count(children);\n\n if (loading) {\n return (\n <div\n className={cn(hidden && 'hidden', className)}\n style={style}\n {...props}\n >\n {loader || <Skeleton />}\n </div>\n );\n }\n\n return (\n <div\n className={cn(\n 'flex flex-nowrap',\n orientation === 'horizontal' ? 'flex-row' : 'flex-col',\n wrap && 'flex-wrap',\n aligns[align],\n grid && 'grid',\n hidden && 'hidden',\n className,\n )}\n style={{\n columnGap: x,\n rowGap: y,\n gridTemplateRows: grid?.rows\n ? `repeat(${grid.rows}, minmax(0, 1fr))`\n : undefined,\n gridTemplateColumns: grid?.cols\n ? `repeat(${grid.cols}, minmax(0, 1fr))`\n : undefined,\n ...style,\n }}\n {...props}\n >\n {Children.map(children, (child, i) => (\n <>\n {child}\n {split && i < count - 1 && split}\n </>\n ))}\n </div>\n );\n};\n\nexport default Space;\n"],"mappings":";;;;;;AAoBA,MAAM,QAAkC;CACtC,OAAO,CAAC,GAAG,EAAE;CACb,QAAQ,CAAC,GAAG,EAAE;CACd,OAAO,CAAC,IAAI,GAAG;CAChB;AAED,MAAM,SAAiC;CACrC,OAAO;CACP,KAAK;CACL,QAAQ;CACR,UAAU;CACX;AAED,MAAM,SAAS,EACb,SACA,QACA,UACA,OAAO,UACP,cAAc,cACd,QAAQ,UACR,OAAO,OACP,OACA,WACA,MACA,QACA,OACA,GAAG,YACQ;CACX,MAAM,CAAC,GAAG,KACR,OAAO,SAAS,WACZ,MAAM,SAAS,CAAC,GAAG,EAAE,GACrB,MAAM,QAAQ,KAAK,GACjB,OACA,CAAC,MAAM,KAAK;CACpB,MAAM,QAAQ,SAAS,MAAM,SAAS;AAEtC,KAAI,QACF,QACE,oBAAC;EACC,WAAW,GAAG,UAAU,UAAU,UAAU;EACrC;EACP,GAAI;YAEH,UAAU,oBAAC,aAAW;GACnB;AAIV,QACE,oBAAC;EACC,WAAW,GACT,oBACA,gBAAgB,eAAe,aAAa,YAC5C,QAAQ,aACR,OAAO,QACP,QAAQ,QACR,UAAU,UACV,UACD;EACD,OAAO;GACL,WAAW;GACX,QAAQ;GACR,kBAAkB,MAAM,OACpB,UAAU,KAAK,KAAK,qBACpB;GACJ,qBAAqB,MAAM,OACvB,UAAU,KAAK,KAAK,qBACpB;GACJ,GAAG;GACJ;EACD,GAAI;YAEH,SAAS,IAAI,WAAW,OAAO,MAC9B,8CACG,OACA,SAAS,IAAI,QAAQ,KAAK,SAC1B,CACH;GACE"}
1
+ {"version":3,"file":"Space.mjs","names":[],"sources":["../src/components/molecules/space.tsx"],"sourcesContent":["import { Children } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Skeleton from '../atoms/skeleton';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n loading?: boolean;\n loader?: React.ReactNode;\n orientation?: 'horizontal' | 'vertical';\n size?: 'small' | 'middle' | 'large' | number | number[];\n align?: 'start' | 'end' | 'center' | 'baseline';\n wrap?: boolean;\n split?: React.ReactNode;\n grid?: {\n rows?: number;\n cols?: number;\n };\n}\n\nconst sizes: Record<string, number[]> = {\n small: [4, 4],\n middle: [8, 8],\n large: [16, 16],\n};\n\nconst aligns: Record<string, string> = {\n start: 'items-start text-start',\n end: 'items-end text-end',\n center: 'items-center text-center',\n baseline: 'items-baseline text-baseline',\n};\n\nconst Space = ({\n loading,\n loader,\n children,\n size = 'middle',\n orientation = 'horizontal',\n align = 'center',\n wrap = false,\n split,\n className,\n grid,\n hidden,\n style,\n ...props\n}: Props) => {\n const [x, y] =\n typeof size === 'string'\n ? sizes[size] || [0, 0]\n : Array.isArray(size)\n ? size\n : [size, size];\n const count = Children.count(children);\n\n if (loading) {\n return (\n <div\n className={cn(hidden && 'hidden', className)}\n style={style}\n hidden={hidden}\n {...props}\n >\n {loader || <Skeleton />}\n </div>\n );\n }\n\n return (\n <div\n className={cn(\n 'flex flex-nowrap',\n orientation === 'horizontal' ? 'flex-row' : 'flex-col',\n wrap && 'flex-wrap',\n aligns[align],\n grid && 'grid',\n hidden && 'hidden',\n className,\n )}\n style={{\n columnGap: x,\n rowGap: y,\n gridTemplateRows: grid?.rows\n ? `repeat(${grid.rows}, minmax(0, 1fr))`\n : undefined,\n gridTemplateColumns: grid?.cols\n ? `repeat(${grid.cols}, minmax(0, 1fr))`\n : undefined,\n ...style,\n }}\n hidden={hidden}\n {...props}\n >\n {Children.map(children, (child, i) => (\n <>\n {child}\n {split && i < count - 1 && split}\n </>\n ))}\n </div>\n );\n};\n\nexport default Space;\n"],"mappings":";;;;;;AAoBA,MAAM,QAAkC;CACtC,OAAO,CAAC,GAAG,EAAE;CACb,QAAQ,CAAC,GAAG,EAAE;CACd,OAAO,CAAC,IAAI,GAAG;CAChB;AAED,MAAM,SAAiC;CACrC,OAAO;CACP,KAAK;CACL,QAAQ;CACR,UAAU;CACX;AAED,MAAM,SAAS,EACb,SACA,QACA,UACA,OAAO,UACP,cAAc,cACd,QAAQ,UACR,OAAO,OACP,OACA,WACA,MACA,QACA,OACA,GAAG,YACQ;CACX,MAAM,CAAC,GAAG,KACR,OAAO,SAAS,WACZ,MAAM,SAAS,CAAC,GAAG,EAAE,GACrB,MAAM,QAAQ,KAAK,GACjB,OACA,CAAC,MAAM,KAAK;CACpB,MAAM,QAAQ,SAAS,MAAM,SAAS;AAEtC,KAAI,QACF,QACE,oBAAC;EACC,WAAW,GAAG,UAAU,UAAU,UAAU;EACrC;EACC;EACR,GAAI;YAEH,UAAU,oBAAC,aAAW;GACnB;AAIV,QACE,oBAAC;EACC,WAAW,GACT,oBACA,gBAAgB,eAAe,aAAa,YAC5C,QAAQ,aACR,OAAO,QACP,QAAQ,QACR,UAAU,UACV,UACD;EACD,OAAO;GACL,WAAW;GACX,QAAQ;GACR,kBAAkB,MAAM,OACpB,UAAU,KAAK,KAAK,qBACpB;GACJ,qBAAqB,MAAM,OACvB,UAAU,KAAK,KAAK,qBACpB;GACJ,GAAG;GACJ;EACO;EACR,GAAI;YAEH,SAAS,IAAI,WAAW,OAAO,MAC9B,8CACG,OACA,SAAS,IAAI,QAAQ,KAAK,SAC1B,CACH;GACE"}
@@ -4,9 +4,9 @@ import { cn } from "../../../utils.mjs";
4
4
  import { checkbox_exports } from "../../../core/checkbox.mjs";
5
5
  import { label_exports } from "../../../core/label.mjs";
6
6
  import { Square, SquareCheck } from "lucide-react";
7
- import { useId } from "react";
7
+ import { useId, useRef } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
- import { useControllableState } from "@jbpark/use-hooks";
9
+ import { useControllableState, useKeyPress } from "@jbpark/use-hooks";
10
10
 
11
11
  //#region src/components/atoms/checkbox/checkbox.tsx
12
12
  const { Checkbox: CoreCheckbox } = checkbox_exports;
@@ -24,6 +24,14 @@ const Checkbox = ({ placement = "left", value: _value = "", children, className,
24
24
  if (disabled) return;
25
25
  setChecked(next);
26
26
  };
27
+ const iconTriggerRef = useRef(null);
28
+ useKeyPress(["Enter", "space"], (event) => {
29
+ event.preventDefault();
30
+ onChange(!checked);
31
+ }, {
32
+ target: iconTriggerRef,
33
+ enabled: !!icons && !disabled
34
+ });
27
35
  const renderContent = icons ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
28
36
  /* @__PURE__ */ jsx("input", {
29
37
  id,
@@ -38,6 +46,7 @@ const Checkbox = ({ placement = "left", value: _value = "", children, className,
38
46
  }
39
47
  }),
40
48
  /* @__PURE__ */ jsx("span", {
49
+ ref: iconTriggerRef,
41
50
  role: "checkbox",
42
51
  "aria-checked": checked,
43
52
  "aria-disabled": disabled,
@@ -46,12 +55,6 @@ const Checkbox = ({ placement = "left", value: _value = "", children, className,
46
55
  onClick: () => {
47
56
  onChange(!checked);
48
57
  },
49
- onKeyDown: (e) => {
50
- if (e.key === "Enter" || e.key === " ") {
51
- e.preventDefault();
52
- onChange(!checked);
53
- }
54
- },
55
58
  children: checked ? icons.checked ?? /* @__PURE__ */ jsx(SquareCheck, {}) : icons.unchecked ?? /* @__PURE__ */ jsx(Square, {})
56
59
  }),
57
60
  children && /* @__PURE__ */ jsx("label", {
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.mjs","names":["checkbox","label"],"sources":["../../../../src/components/atoms/checkbox/checkbox.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\nimport { Square, SquareCheck } from 'lucide-react';\n\nimport { checkbox, label } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport { type OptionValue } from './group';\n\nconst { Checkbox: CoreCheckbox } = checkbox;\nconst { Label: CoreLabel } = label;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'onChange'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n disabled?: boolean;\n icons?: Partial<{ checked: React.ReactNode; unchecked: React.ReactNode }>;\n children?: React.ReactNode;\n onChange?: (checked: boolean) => void;\n}\n\nconst Checkbox = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n name,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [checked, setChecked] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const id = useId();\n const itemValue = String(_value);\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n setChecked(next);\n };\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"checkbox\"\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n role=\"checkbox\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n onChange(!checked);\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onChange(!checked);\n }\n }}\n >\n {checked\n ? (icons.checked ?? <SquareCheck />)\n : (icons.unchecked ?? <Square />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : (\n <>\n <CoreCheckbox\n id={id}\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n className={cn(cursorClassName)}\n onCheckedChange={onChange}\n />\n {children && (\n <CoreLabel htmlFor={id} className={cn(cursorClassName, 'text-left')}>\n {children}\n </CoreLabel>\n )}\n </>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center gap-x-2',\n placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,EAAE,UAAU,iBAAiBA;AACnC,MAAM,EAAE,OAAO,cAAcC;AAkB7B,MAAM,YAAY,EAChB,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,MACA,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;EACX,CAAC;CAEF,MAAM,KAAK,OAAO;CAClB,MAAM,YAAY,OAAO,OAAO;CAEhC,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;AAClC,MAAI,SACF;AAGF,aAAW,KAAK;;CAGlB,MAAM,gBAAgB,QACpB;EACE,oBAAC;GACK;GACJ;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;AACb,aAAS,EAAE,OAAO,QAAQ;;IAE5B;EACF,oBAAC;GACC,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,eAAe;AACb,aAAS,CAAC,QAAQ;;GAEpB,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,OAAE,gBAAgB;AAClB,cAAS,CAAC,QAAQ;;;aAIrB,UACI,MAAM,WAAW,oBAAC,gBAAc,GAChC,MAAM,aAAa,oBAAC,WAAS;IAC7B;EACN,YACC,oBAAC;GACC,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,SAAS;GAER;IACK;KAET,GAEH,8CACE,oBAAC;EACK;EACE;EACN,OAAO;EACE;EACC;EACV,WAAW,GAAG,gBAAgB;EAC9B,iBAAiB;GACjB,EACD,YACC,oBAAC;EAAU,SAAS;EAAI,WAAW,GAAG,iBAAiB,YAAY;EAChE;GACS,IAEb;AAGL,QACE,oBAAC;EACC,WAAW,GACT,6BACA,cAAc,WAAW,oBACzB,iBACA,UAED;EACD,GAAI;YAEH;GACG"}
1
+ {"version":3,"file":"checkbox.mjs","names":["checkbox","label"],"sources":["../../../../src/components/atoms/checkbox/checkbox.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useRef } from 'react';\n\nimport { useControllableState, useKeyPress } from '@jbpark/use-hooks';\nimport { Square, SquareCheck } from 'lucide-react';\n\nimport { checkbox, label } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport { type OptionValue } from './group';\n\nconst { Checkbox: CoreCheckbox } = checkbox;\nconst { Label: CoreLabel } = label;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'onChange'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n disabled?: boolean;\n icons?: Partial<{ checked: React.ReactNode; unchecked: React.ReactNode }>;\n children?: React.ReactNode;\n onChange?: (checked: boolean) => void;\n}\n\nconst Checkbox = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n name,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [checked, setChecked] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const id = useId();\n const itemValue = String(_value);\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n setChecked(next);\n };\n\n const iconTriggerRef = useRef<HTMLSpanElement>(null);\n\n useKeyPress(\n ['Enter', 'space'],\n event => {\n event.preventDefault();\n onChange(!checked);\n },\n { target: iconTriggerRef, enabled: !!icons && !disabled },\n );\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"checkbox\"\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n ref={iconTriggerRef}\n role=\"checkbox\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n onChange(!checked);\n }}\n >\n {checked\n ? (icons.checked ?? <SquareCheck />)\n : (icons.unchecked ?? <Square />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : (\n <>\n <CoreCheckbox\n id={id}\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n className={cn(cursorClassName)}\n onCheckedChange={onChange}\n />\n {children && (\n <CoreLabel htmlFor={id} className={cn(cursorClassName, 'text-left')}>\n {children}\n </CoreLabel>\n )}\n </>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center gap-x-2',\n placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,EAAE,UAAU,iBAAiBA;AACnC,MAAM,EAAE,OAAO,cAAcC;AAkB7B,MAAM,YAAY,EAChB,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,MACA,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;EACX,CAAC;CAEF,MAAM,KAAK,OAAO;CAClB,MAAM,YAAY,OAAO,OAAO;CAEhC,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;AAClC,MAAI,SACF;AAGF,aAAW,KAAK;;CAGlB,MAAM,iBAAiB,OAAwB,KAAK;AAEpD,aACE,CAAC,SAAS,QAAQ,GAClB,UAAS;AACP,QAAM,gBAAgB;AACtB,WAAS,CAAC,QAAQ;IAEpB;EAAE,QAAQ;EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;EAAU,CAC1D;CAED,MAAM,gBAAgB,QACpB;EACE,oBAAC;GACK;GACJ;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;AACb,aAAS,EAAE,OAAO,QAAQ;;IAE5B;EACF,oBAAC;GACC,KAAK;GACL,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,eAAe;AACb,aAAS,CAAC,QAAQ;;aAGnB,UACI,MAAM,WAAW,oBAAC,gBAAc,GAChC,MAAM,aAAa,oBAAC,WAAS;IAC7B;EACN,YACC,oBAAC;GACC,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,SAAS;GAER;IACK;KAET,GAEH,8CACE,oBAAC;EACK;EACE;EACN,OAAO;EACE;EACC;EACV,WAAW,GAAG,gBAAgB;EAC9B,iBAAiB;GACjB,EACD,YACC,oBAAC;EAAU,SAAS;EAAI,WAAW,GAAG,iBAAiB,YAAY;EAChE;GACS,IAEb;AAGL,QACE,oBAAC;EACC,WAAW,GACT,6BACA,cAAc,WAAW,oBACzB,iBACA,UAED;EACD,GAAI;YAEH;GACG"}
@@ -5,9 +5,9 @@ import { field_exports } from "../../../core/field.mjs";
5
5
  import { radio_group_exports } from "../../../core/radio-group.mjs";
6
6
  import { RadioGroupContext } from "./context.mjs";
7
7
  import { Circle, CircleCheck } from "lucide-react";
8
- import { useContext, useId } from "react";
8
+ import { useContext, useId, useRef } from "react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import { useControllableState } from "@jbpark/use-hooks";
10
+ import { useControllableState, useKeyPress } from "@jbpark/use-hooks";
11
11
 
12
12
  //#region src/components/atoms/radio/radio.tsx
13
13
  const { RadioGroup: Core, RadioGroupItem: Item } = radio_group_exports;
@@ -27,6 +27,14 @@ const Radio = ({ placement = "left", value: _value = "", children, className, ic
27
27
  if (disabled) return;
28
28
  setChecked(next);
29
29
  };
30
+ const iconTriggerRef = useRef(null);
31
+ useKeyPress(["Enter", "space"], (event) => {
32
+ event.preventDefault();
33
+ onChange(true);
34
+ }, {
35
+ target: iconTriggerRef,
36
+ enabled: !!icons && !disabled
37
+ });
30
38
  const renderField = /* @__PURE__ */ jsxs(Field, {
31
39
  orientation: "horizontal",
32
40
  className: cn("flex gap-2", placement === "right" && "flex-row-reverse"),
@@ -56,6 +64,7 @@ const Radio = ({ placement = "left", value: _value = "", children, className, ic
56
64
  }
57
65
  }),
58
66
  /* @__PURE__ */ jsx("span", {
67
+ ref: iconTriggerRef,
59
68
  role: "radio",
60
69
  "aria-checked": checked,
61
70
  "aria-disabled": disabled,
@@ -64,12 +73,6 @@ const Radio = ({ placement = "left", value: _value = "", children, className, ic
64
73
  onClick: () => {
65
74
  onChange(true);
66
75
  },
67
- onKeyDown: (e) => {
68
- if (e.key === "Enter" || e.key === " ") {
69
- e.preventDefault();
70
- onChange(true);
71
- }
72
- },
73
76
  children: checked ? icons.checked ?? /* @__PURE__ */ jsx(CircleCheck, {}) : icons.unchecked ?? /* @__PURE__ */ jsx(Circle, {})
74
77
  }),
75
78
  children && /* @__PURE__ */ jsx("label", {
@@ -1 +1 @@
1
- {"version":3,"file":"radio.mjs","names":["radio","field"],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"sourcesContent":["'use client';\n\nimport { useContext, useId } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\nimport { Circle, CircleCheck } from 'lucide-react';\n\nimport { field, radio } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport { RadioGroupContext } from './context';\nimport { type OptionValue } from './group';\n\nconst { RadioGroup: Core, RadioGroupItem: Item } = radio;\nconst { Field, FieldLabel } = field;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<typeof Core>,\n 'onChange' | 'value'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n disabled?: boolean;\n /**\n * Id shared by the underlying control and its label. Generated internally\n * when omitted. `RadioGroup` passes a deterministic id so that the group's\n * single Radix root can address each option.\n */\n id?: string;\n icons?: Partial<{ checked: React.ReactNode; unchecked: React.ReactNode }>;\n onChange?: (checked: boolean) => void;\n}\n\nconst Radio = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n id: _id,\n name,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [checked, setChecked] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const generatedId = useId();\n const id = _id ?? generatedId;\n // Radix identifies/submits an item by its `value`, which is separate from\n // `id` (used only for the DOM id/label pairing) — stringified since Radix\n // requires a string, while `OptionValue` also allows number/boolean.\n const itemValue = String(_value);\n const grouped = useContext(RadioGroupContext);\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n setChecked(next);\n };\n\n // When rendered inside a `RadioGroup`, the group owns the single shared\n // `Core` (Radix radiogroup root) so that arrow keys move focus across every\n // option. A standalone `Radio` still has to provide its own root.\n const renderField = (\n <Field\n orientation=\"horizontal\"\n className={cn('flex gap-2', placement === 'right' && 'flex-row-reverse')}\n data-disabled={disabled}\n >\n <Item value={itemValue} id={id} checked={checked} disabled={disabled} />\n <FieldLabel htmlFor={id} className={cursorClassName}>\n {children}\n </FieldLabel>\n </Field>\n );\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"radio\"\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n role=\"radio\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n onChange(true);\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onChange(true);\n }\n }}\n >\n {checked\n ? (icons.checked ?? <CircleCheck />)\n : (icons.unchecked ?? <Circle />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : grouped ? (\n renderField\n ) : (\n <Core\n name={name}\n value={checked ? itemValue : ''}\n onValueChange={() => onChange(true)}\n >\n {renderField}\n </Core>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center',\n icons && placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Radio;\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,EAAE,YAAY,MAAM,gBAAgB,SAASA;AACnD,MAAM,EAAE,OAAO,eAAeC;AAuB9B,MAAM,SAAS,EACb,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,IAAI,KACJ,MACA,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;EACX,CAAC;CAEF,MAAM,cAAc,OAAO;CAC3B,MAAM,KAAK,OAAO;CAIlB,MAAM,YAAY,OAAO,OAAO;CAChC,MAAM,UAAU,WAAW,kBAAkB;CAE7C,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;AAClC,MAAI,SACF;AAGF,aAAW,KAAK;;CAMlB,MAAM,cACJ,qBAAC;EACC,aAAY;EACZ,WAAW,GAAG,cAAc,cAAc,WAAW,mBAAmB;EACxE,iBAAe;aAEf,oBAAC;GAAK,OAAO;GAAe;GAAa;GAAmB;IAAY,EACxE,oBAAC;GAAW,SAAS;GAAI,WAAW;GACjC;IACU;GACP;CAGV,MAAM,gBAAgB,QACpB;EACE,oBAAC;GACK;GACJ;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;AACb,aAAS,EAAE,OAAO,QAAQ;;IAE5B;EACF,oBAAC;GACC,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,eAAe;AACb,aAAS,KAAK;;GAEhB,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,OAAE,gBAAgB;AAClB,cAAS,KAAK;;;aAIjB,UACI,MAAM,WAAW,oBAAC,gBAAc,GAChC,MAAM,aAAa,oBAAC,WAAS;IAC7B;EACN,YACC,oBAAC;GACC,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,SAAS;GAER;IACK;KAET,GACD,UACF,cAEA,oBAAC;EACO;EACN,OAAO,UAAU,YAAY;EAC7B,qBAAqB,SAAS,KAAK;YAElC;GACI;AAGT,QACE,oBAAC;EACC,WAAW,GACT,qBACA,SAAS,cAAc,WAAW,oBAClC,iBACA,UAED;EACD,GAAI;YAEH;GACG"}
1
+ {"version":3,"file":"radio.mjs","names":["radio","field"],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"sourcesContent":["'use client';\n\nimport { useContext, useId, useRef } from 'react';\n\nimport { useControllableState, useKeyPress } from '@jbpark/use-hooks';\nimport { Circle, CircleCheck } from 'lucide-react';\n\nimport { field, radio } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport { RadioGroupContext } from './context';\nimport { type OptionValue } from './group';\n\nconst { RadioGroup: Core, RadioGroupItem: Item } = radio;\nconst { Field, FieldLabel } = field;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<typeof Core>,\n 'onChange' | 'value'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n disabled?: boolean;\n /**\n * Id shared by the underlying control and its label. Generated internally\n * when omitted. `RadioGroup` passes a deterministic id so that the group's\n * single Radix root can address each option.\n */\n id?: string;\n icons?: Partial<{ checked: React.ReactNode; unchecked: React.ReactNode }>;\n onChange?: (checked: boolean) => void;\n}\n\nconst Radio = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n id: _id,\n name,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [checked, setChecked] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const generatedId = useId();\n const id = _id ?? generatedId;\n // Radix identifies/submits an item by its `value`, which is separate from\n // `id` (used only for the DOM id/label pairing) — stringified since Radix\n // requires a string, while `OptionValue` also allows number/boolean.\n const itemValue = String(_value);\n const grouped = useContext(RadioGroupContext);\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n setChecked(next);\n };\n\n const iconTriggerRef = useRef<HTMLSpanElement>(null);\n\n useKeyPress(\n ['Enter', 'space'],\n event => {\n event.preventDefault();\n onChange(true);\n },\n { target: iconTriggerRef, enabled: !!icons && !disabled },\n );\n\n // When rendered inside a `RadioGroup`, the group owns the single shared\n // `Core` (Radix radiogroup root) so that arrow keys move focus across every\n // option. A standalone `Radio` still has to provide its own root.\n const renderField = (\n <Field\n orientation=\"horizontal\"\n className={cn('flex gap-2', placement === 'right' && 'flex-row-reverse')}\n data-disabled={disabled}\n >\n <Item value={itemValue} id={id} checked={checked} disabled={disabled} />\n <FieldLabel htmlFor={id} className={cursorClassName}>\n {children}\n </FieldLabel>\n </Field>\n );\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"radio\"\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n ref={iconTriggerRef}\n role=\"radio\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n onChange(true);\n }}\n >\n {checked\n ? (icons.checked ?? <CircleCheck />)\n : (icons.unchecked ?? <Circle />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : grouped ? (\n renderField\n ) : (\n <Core\n name={name}\n value={checked ? itemValue : ''}\n onValueChange={() => onChange(true)}\n >\n {renderField}\n </Core>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center',\n icons && placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Radio;\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,EAAE,YAAY,MAAM,gBAAgB,SAASA;AACnD,MAAM,EAAE,OAAO,eAAeC;AAuB9B,MAAM,SAAS,EACb,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,IAAI,KACJ,MACA,UAAU,kBAAkB,IAC5B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;EACX,CAAC;CAEF,MAAM,cAAc,OAAO;CAC3B,MAAM,KAAK,OAAO;CAIlB,MAAM,YAAY,OAAO,OAAO;CAChC,MAAM,UAAU,WAAW,kBAAkB;CAE7C,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;AAClC,MAAI,SACF;AAGF,aAAW,KAAK;;CAGlB,MAAM,iBAAiB,OAAwB,KAAK;AAEpD,aACE,CAAC,SAAS,QAAQ,GAClB,UAAS;AACP,QAAM,gBAAgB;AACtB,WAAS,KAAK;IAEhB;EAAE,QAAQ;EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;EAAU,CAC1D;CAKD,MAAM,cACJ,qBAAC;EACC,aAAY;EACZ,WAAW,GAAG,cAAc,cAAc,WAAW,mBAAmB;EACxE,iBAAe;aAEf,oBAAC;GAAK,OAAO;GAAe;GAAa;GAAmB;IAAY,EACxE,oBAAC;GAAW,SAAS;GAAI,WAAW;GACjC;IACU;GACP;CAGV,MAAM,gBAAgB,QACpB;EACE,oBAAC;GACK;GACJ;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;AACb,aAAS,EAAE,OAAO,QAAQ;;IAE5B;EACF,oBAAC;GACC,KAAK;GACL,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,eAAe;AACb,aAAS,KAAK;;aAGf,UACI,MAAM,WAAW,oBAAC,gBAAc,GAChC,MAAM,aAAa,oBAAC,WAAS;IAC7B;EACN,YACC,oBAAC;GACC,WAAW,GAAG,iBAAiB,YAAY,aAAa;GACxD,SAAS;GAER;IACK;KAET,GACD,UACF,cAEA,oBAAC;EACO;EACN,OAAO,UAAU,YAAY;EAC7B,qBAAqB,SAAS,KAAK;YAElC;GACI;AAGT,QACE,oBAAC;EACC,WAAW,GACT,qBACA,SAAS,cAAc,WAAW,oBAClC,iBACA,UAED;EACD,GAAI;YAEH;GACG"}
@@ -22,6 +22,7 @@ const Skeleton = ({ active = true, loading = true, avatar, size = "default", dir
22
22
  role: "status",
23
23
  "aria-label": locale.loading ?? DEFAULT_LOCALE.loading,
24
24
  className: cn("flex items-center gap-3", className),
25
+ style,
25
26
  ...props,
26
27
  children: [avatar && /* @__PURE__ */ jsx(Core, { className: cn("h-12 w-12", "rounded-xl", !active && "animate-none", classNames.avatar) }), /* @__PURE__ */ jsx("div", {
27
28
  className: cn("flex grow", direction === "vertical" && "flex-col", classNames.wrapper),
@@ -32,7 +33,6 @@ const Skeleton = ({ active = true, loading = true, avatar, size = "default", dir
32
33
  return /* @__PURE__ */ jsx(Core, {
33
34
  className: cn("rounded-md", !active && "animate-none", SIZES[size], classNames.item),
34
35
  style: {
35
- ...style,
36
36
  width: itemWidth,
37
37
  height: itemHeight
38
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton.mjs","names":["skeleton"],"sources":["../../../../src/components/atoms/skeleton/skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { skeleton } from '@repo/ui/core';\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nconst { Skeleton: Core } = skeleton;\n\nconst getValueAtIndex = <T,>(value: T | T[], index: number) => {\n return Array.isArray(value) ? (value[index] ?? value[0]) : value;\n};\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n active?: boolean;\n loading?: boolean;\n avatar?: boolean;\n size?: 'default' | 'small' | 'large';\n count?: number;\n gap?: number;\n direction?: 'horizontal' | 'vertical';\n width?: string | number | (string | number)[];\n height?: string | number | (string | number)[];\n classNames?: {\n wrapper?: string;\n avatar?: string;\n item?: string;\n };\n}\n\nconst SIZES = {\n small: 'w-48 h-4',\n default: 'w-60 h-6',\n large: 'w-72 h-8',\n};\n\nconst Skeleton = ({\n active = true,\n loading = true,\n avatar,\n size = 'default',\n direction = 'vertical',\n count = 1,\n gap = 6,\n className,\n classNames = {},\n style,\n width,\n height,\n children,\n ...props\n}: Props) => {\n const { locale } = useConfig();\n\n // Not wrapping `children` here (unlike Spin's overlay mode) — Skeleton\n // is meant to swap in arbitrary real content once loading finishes,\n // which can include elements with strict parent requirements (e.g. a\n // `<tr>`), so adding a wrapper div could produce invalid markup.\n // `className`/`style`/rest props only ever describe the skeleton's own\n // placeholder markup, so there's nothing for them to apply to here.\n if (!loading) {\n return children ?? null;\n }\n\n return (\n <div\n role=\"status\"\n aria-label={locale.loading ?? DEFAULT_LOCALE.loading}\n className={cn('flex items-center gap-3', className)}\n {...props}\n >\n {avatar && (\n <Core\n className={cn(\n 'h-12 w-12',\n 'rounded-xl',\n !active && 'animate-none',\n classNames.avatar,\n )}\n />\n )}\n <div\n className={cn(\n 'flex grow',\n direction === 'vertical' && 'flex-col',\n classNames.wrapper,\n )}\n style={{\n gap,\n }}\n >\n {Array.from({ length: count }).map((_, index) => {\n const itemWidth = getValueAtIndex(width, index);\n const itemHeight = getValueAtIndex(height, index);\n\n return (\n <Core\n key={index}\n className={cn(\n 'rounded-md',\n !active && 'animate-none',\n SIZES[size],\n classNames.item,\n //\n )}\n style={{\n ...style,\n width: itemWidth,\n height: itemHeight,\n }}\n />\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default Skeleton;\n"],"mappings":";;;;;;;;AAMA,MAAM,EAAE,UAAU,SAASA;AAE3B,MAAM,mBAAuB,OAAgB,UAAkB;AAC7D,QAAO,MAAM,QAAQ,MAAM,GAAI,MAAM,UAAU,MAAM,KAAM;;AAoB7D,MAAM,QAAQ;CACZ,OAAO;CACP,SAAS;CACT,OAAO;CACR;AAED,MAAM,YAAY,EAChB,SAAS,MACT,UAAU,MACV,QACA,OAAO,WACP,YAAY,YACZ,QAAQ,GACR,MAAM,GACN,WACA,aAAa,EAAE,EACf,OACA,OACA,QACA,UACA,GAAG,YACQ;CACX,MAAM,EAAE,WAAW,WAAW;AAQ9B,KAAI,CAAC,QACH,QAAO,YAAY;AAGrB,QACE,qBAAC;EACC,MAAK;EACL,cAAY,OAAO,WAAW,eAAe;EAC7C,WAAW,GAAG,2BAA2B,UAAU;EACnD,GAAI;aAEH,UACC,oBAAC,QACC,WAAW,GACT,aACA,cACA,CAAC,UAAU,gBACX,WAAW,OACZ,GACD,EAEJ,oBAAC;GACC,WAAW,GACT,aACA,cAAc,cAAc,YAC5B,WAAW,QACZ;GACD,OAAO,EACL,KACD;aAEA,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,UAAU;IAC/C,MAAM,YAAY,gBAAgB,OAAO,MAAM;IAC/C,MAAM,aAAa,gBAAgB,QAAQ,MAAM;AAEjD,WACE,oBAAC;KAEC,WAAW,GACT,cACA,CAAC,UAAU,gBACX,MAAM,OACN,WAAW,KAEZ;KACD,OAAO;MACL,GAAG;MACH,OAAO;MACP,QAAQ;MACT;OAZI,MAaL;KAEJ;IACE;GACF"}
1
+ {"version":3,"file":"skeleton.mjs","names":["skeleton"],"sources":["../../../../src/components/atoms/skeleton/skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { skeleton } from '@repo/ui/core';\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nconst { Skeleton: Core } = skeleton;\n\nconst getValueAtIndex = <T,>(value: T | T[], index: number) => {\n return Array.isArray(value) ? (value[index] ?? value[0]) : value;\n};\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n active?: boolean;\n loading?: boolean;\n avatar?: boolean;\n size?: 'default' | 'small' | 'large';\n count?: number;\n gap?: number;\n direction?: 'horizontal' | 'vertical';\n width?: string | number | (string | number)[];\n height?: string | number | (string | number)[];\n classNames?: {\n wrapper?: string;\n avatar?: string;\n item?: string;\n };\n}\n\nconst SIZES = {\n small: 'w-48 h-4',\n default: 'w-60 h-6',\n large: 'w-72 h-8',\n};\n\nconst Skeleton = ({\n active = true,\n loading = true,\n avatar,\n size = 'default',\n direction = 'vertical',\n count = 1,\n gap = 6,\n className,\n classNames = {},\n style,\n width,\n height,\n children,\n ...props\n}: Props) => {\n const { locale } = useConfig();\n\n // Not wrapping `children` here (unlike Spin's overlay mode) — Skeleton\n // is meant to swap in arbitrary real content once loading finishes,\n // which can include elements with strict parent requirements (e.g. a\n // `<tr>`), so adding a wrapper div could produce invalid markup.\n // `className`/`style`/rest props only ever describe the skeleton's own\n // placeholder markup, so there's nothing for them to apply to here.\n if (!loading) {\n return children ?? null;\n }\n\n return (\n <div\n role=\"status\"\n aria-label={locale.loading ?? DEFAULT_LOCALE.loading}\n className={cn('flex items-center gap-3', className)}\n style={style}\n {...props}\n >\n {avatar && (\n <Core\n className={cn(\n 'h-12 w-12',\n 'rounded-xl',\n !active && 'animate-none',\n classNames.avatar,\n )}\n />\n )}\n <div\n className={cn(\n 'flex grow',\n direction === 'vertical' && 'flex-col',\n classNames.wrapper,\n )}\n style={{\n gap,\n }}\n >\n {Array.from({ length: count }).map((_, index) => {\n const itemWidth = getValueAtIndex(width, index);\n const itemHeight = getValueAtIndex(height, index);\n\n return (\n <Core\n key={index}\n className={cn(\n 'rounded-md',\n !active && 'animate-none',\n SIZES[size],\n classNames.item,\n //\n )}\n style={{\n width: itemWidth,\n height: itemHeight,\n }}\n />\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default Skeleton;\n"],"mappings":";;;;;;;;AAMA,MAAM,EAAE,UAAU,SAASA;AAE3B,MAAM,mBAAuB,OAAgB,UAAkB;AAC7D,QAAO,MAAM,QAAQ,MAAM,GAAI,MAAM,UAAU,MAAM,KAAM;;AAoB7D,MAAM,QAAQ;CACZ,OAAO;CACP,SAAS;CACT,OAAO;CACR;AAED,MAAM,YAAY,EAChB,SAAS,MACT,UAAU,MACV,QACA,OAAO,WACP,YAAY,YACZ,QAAQ,GACR,MAAM,GACN,WACA,aAAa,EAAE,EACf,OACA,OACA,QACA,UACA,GAAG,YACQ;CACX,MAAM,EAAE,WAAW,WAAW;AAQ9B,KAAI,CAAC,QACH,QAAO,YAAY;AAGrB,QACE,qBAAC;EACC,MAAK;EACL,cAAY,OAAO,WAAW,eAAe;EAC7C,WAAW,GAAG,2BAA2B,UAAU;EAC5C;EACP,GAAI;aAEH,UACC,oBAAC,QACC,WAAW,GACT,aACA,cACA,CAAC,UAAU,gBACX,WAAW,OACZ,GACD,EAEJ,oBAAC;GACC,WAAW,GACT,aACA,cAAc,cAAc,YAC5B,WAAW,QACZ;GACD,OAAO,EACL,KACD;aAEA,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,UAAU;IAC/C,MAAM,YAAY,gBAAgB,OAAO,MAAM;IAC/C,MAAM,aAAa,gBAAgB,QAAQ,MAAM;AAEjD,WACE,oBAAC;KAEC,WAAW,GACT,cACA,CAAC,UAAU,gBACX,MAAM,OACN,WAAW,KAEZ;KACD,OAAO;MACL,OAAO;MACP,QAAQ;MACT;OAXI,MAYL;KAEJ;IACE;GACF"}
@@ -4,7 +4,7 @@ import { cn } from "../../utils.mjs";
4
4
  import Menu from "./menu/menu.mjs";
5
5
  import { useId, useRef } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import { useControllableState } from "@jbpark/use-hooks";
7
+ import { useControllableState, useKeyPress } from "@jbpark/use-hooks";
8
8
  import { AnimatePresence, motion } from "motion/react";
9
9
 
10
10
  //#region src/components/molecules/dropdown.tsx
@@ -17,6 +17,17 @@ const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange
17
17
  const isClickTrigger = trigger === "click";
18
18
  const menuId = useId();
19
19
  const containerRef = useRef(null);
20
+ const triggerRef = useRef(null);
21
+ useKeyPress("esc", () => {
22
+ onOpenChange(false);
23
+ }, { target: triggerRef });
24
+ useKeyPress(["Enter", "space"], (event) => {
25
+ event.preventDefault();
26
+ onOpenChange(!open);
27
+ }, {
28
+ target: triggerRef,
29
+ enabled: isClickTrigger
30
+ });
20
31
  return /* @__PURE__ */ jsxs("div", {
21
32
  ...props,
22
33
  ref: containerRef,
@@ -32,6 +43,7 @@ const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange
32
43
  onOpenChange(false);
33
44
  },
34
45
  children: [/* @__PURE__ */ jsx("div", {
46
+ ref: triggerRef,
35
47
  role: isClickTrigger ? "button" : void 0,
36
48
  tabIndex: isClickTrigger ? 0 : void 0,
37
49
  "aria-haspopup": "menu",
@@ -48,19 +60,9 @@ const Dropdown = ({ children, menu, trigger = "hover", open: _open, onOpenChange
48
60
  onBlur: (e) => {
49
61
  if (!containerRef.current?.contains(e.relatedTarget)) onOpenChange(false);
50
62
  },
51
- onKeyDown: (e) => {
52
- if (e.key === "Escape") {
53
- onOpenChange(false);
54
- return;
55
- }
56
- if (isClickTrigger && (e.key === "Enter" || e.key === " ")) {
57
- e.preventDefault();
58
- onOpenChange(!open);
59
- }
60
- },
61
63
  children
62
64
  }), /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(motion.div, {
63
- className: cn("absolute top-full pt-2"),
65
+ className: cn("absolute top-full z-50 pt-2"),
64
66
  initial: {
65
67
  opacity: 0,
66
68
  y: -10
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../src/components/molecules/dropdown.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useRef } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Menu, { MenuProps } from './menu';\n\ntype ChangeEventHandler = (open: boolean) => void;\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n open?: boolean;\n trigger?: 'hover' | 'click';\n menu?: MenuProps;\n onOpenChange?: ChangeEventHandler;\n}\n\nconst Dropdown = ({\n children,\n menu,\n trigger = 'hover',\n open: _open,\n onOpenChange: _onOpenChange = () => {},\n className,\n onMouseEnter,\n onMouseLeave,\n ...props\n}: Props) => {\n const [open, onOpenChange] = useControllableState<boolean>({\n value: _open,\n defaultValue: false,\n onChange: _onOpenChange,\n });\n\n const isClickTrigger = trigger === 'click';\n const menuId = useId();\n const containerRef = useRef<HTMLDivElement>(null);\n\n return (\n <div\n {...props}\n ref={containerRef}\n className={cn(\n 'relative',\n 'inline-block cursor-pointer',\n className,\n //\n )}\n onMouseEnter={event => {\n onMouseEnter?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onMouseLeave={event => {\n onMouseLeave?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(false);\n }}\n >\n <div\n role={isClickTrigger ? 'button' : undefined}\n tabIndex={isClickTrigger ? 0 : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n onClick={() => {\n if (!isClickTrigger) {\n return;\n }\n onOpenChange(!open);\n }}\n onFocus={() => {\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onBlur={e => {\n // Without this check, moving focus from the trigger into the\n // menu itself (e.g. via Tab) closed the dropdown before the\n // user could ever reach it — the mouse path avoided the same\n // bug only by way of onMouseDown's preventDefault below, which\n // does nothing for keyboard focus. Mirrors the containment\n // check menu/item/item.tsx already uses for the same reason.\n if (!containerRef.current?.contains(e.relatedTarget as Node)) {\n onOpenChange(false);\n }\n }}\n onKeyDown={e => {\n if (e.key === 'Escape') {\n onOpenChange(false);\n return;\n }\n if (isClickTrigger && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onOpenChange(!open);\n }\n }}\n >\n {children}\n </div>\n <AnimatePresence>\n {open && (\n <motion.div\n className={cn(\n 'absolute top-full pt-2',\n //\n )}\n initial={{ opacity: 0, y: -10 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -10 }}\n transition={{ duration: 0.1 }}\n >\n <Menu\n {...menu}\n id={menuId}\n onMouseDown={e => {\n e.preventDefault();\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n};\n\nexport default Dropdown;\n"],"mappings":";;;;;;;;;;AAoBA,MAAM,YAAY,EAChB,UACA,MACA,UAAU,SACV,MAAM,OACN,cAAc,sBAAsB,IACpC,WACA,cACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,MAAM,gBAAgB,qBAA8B;EACzD,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;CAEF,MAAM,iBAAiB,YAAY;CACnC,MAAM,SAAS,OAAO;CACtB,MAAM,eAAe,OAAuB,KAAK;AAEjD,QACE,qBAAC;EACC,GAAI;EACJ,KAAK;EACL,WAAW,GACT,YACA,+BACA,UAED;EACD,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,KAAK;;EAEpB,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,MAAM;;aAGrB,oBAAC;GACC,MAAM,iBAAiB,WAAW;GAClC,UAAU,iBAAiB,IAAI;GAC/B,iBAAc;GACd,iBAAe;GACf,iBAAe,OAAO,SAAS;GAC/B,eAAe;AACb,QAAI,CAAC,eACH;AAEF,iBAAa,CAAC,KAAK;;GAErB,eAAe;AACb,QAAI,eACF;AAEF,iBAAa,KAAK;;GAEpB,SAAQ,MAAK;AAOX,QAAI,CAAC,aAAa,SAAS,SAAS,EAAE,cAAsB,CAC1D,cAAa,MAAM;;GAGvB,YAAW,MAAK;AACd,QAAI,EAAE,QAAQ,UAAU;AACtB,kBAAa,MAAM;AACnB;;AAEF,QAAI,mBAAmB,EAAE,QAAQ,WAAW,EAAE,QAAQ,MAAM;AAC1D,OAAE,gBAAgB;AAClB,kBAAa,CAAC,KAAK;;;GAItB;IACG,EACN,oBAAC,6BACE,QACC,oBAAC,OAAO;GACN,WAAW,GACT,yBAED;GACD,SAAS;IAAE,SAAS;IAAG,GAAG;IAAK;GAC/B,SAAS;IAAE,SAAS;IAAG,GAAG;IAAG;GAC7B,MAAM;IAAE,SAAS;IAAG,GAAG;IAAK;GAC5B,YAAY,EAAE,UAAU,IAAK;aAE7B,oBAAC;IACC,GAAI;IACJ,IAAI;IACJ,cAAa,MAAK;AAChB,OAAE,gBAAgB;;KAEpB;IACS,GAEC;GACd"}
1
+ {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../src/components/molecules/dropdown.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useRef } from 'react';\n\nimport { useControllableState, useKeyPress } from '@jbpark/use-hooks';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport Menu, { MenuProps } from './menu';\n\ntype ChangeEventHandler = (open: boolean) => void;\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n open?: boolean;\n trigger?: 'hover' | 'click';\n menu?: MenuProps;\n onOpenChange?: ChangeEventHandler;\n}\n\nconst Dropdown = ({\n children,\n menu,\n trigger = 'hover',\n open: _open,\n onOpenChange: _onOpenChange = () => {},\n className,\n onMouseEnter,\n onMouseLeave,\n ...props\n}: Props) => {\n const [open, onOpenChange] = useControllableState<boolean>({\n value: _open,\n defaultValue: false,\n onChange: _onOpenChange,\n });\n\n const isClickTrigger = trigger === 'click';\n const menuId = useId();\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n\n useKeyPress(\n 'esc',\n () => {\n onOpenChange(false);\n },\n { target: triggerRef },\n );\n\n useKeyPress(\n ['Enter', 'space'],\n event => {\n event.preventDefault();\n onOpenChange(!open);\n },\n { target: triggerRef, enabled: isClickTrigger },\n );\n\n return (\n <div\n {...props}\n ref={containerRef}\n className={cn(\n 'relative',\n 'inline-block cursor-pointer',\n className,\n //\n )}\n onMouseEnter={event => {\n onMouseEnter?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onMouseLeave={event => {\n onMouseLeave?.(event);\n if (isClickTrigger) {\n return;\n }\n onOpenChange(false);\n }}\n >\n <div\n ref={triggerRef}\n role={isClickTrigger ? 'button' : undefined}\n tabIndex={isClickTrigger ? 0 : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n onClick={() => {\n if (!isClickTrigger) {\n return;\n }\n onOpenChange(!open);\n }}\n onFocus={() => {\n if (isClickTrigger) {\n return;\n }\n onOpenChange(true);\n }}\n onBlur={e => {\n // Without this check, moving focus from the trigger into the\n // menu itself (e.g. via Tab) closed the dropdown before the\n // user could ever reach it — the mouse path avoided the same\n // bug only by way of onMouseDown's preventDefault below, which\n // does nothing for keyboard focus. Mirrors the containment\n // check menu/item/item.tsx already uses for the same reason.\n if (!containerRef.current?.contains(e.relatedTarget as Node)) {\n onOpenChange(false);\n }\n }}\n >\n {children}\n </div>\n <AnimatePresence>\n {open && (\n <motion.div\n className={cn(\n 'absolute top-full z-50 pt-2',\n //\n )}\n initial={{ opacity: 0, y: -10 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -10 }}\n transition={{ duration: 0.1 }}\n >\n <Menu\n {...menu}\n id={menuId}\n onMouseDown={e => {\n e.preventDefault();\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n};\n\nexport default Dropdown;\n"],"mappings":";;;;;;;;;;AAoBA,MAAM,YAAY,EAChB,UACA,MACA,UAAU,SACV,MAAM,OACN,cAAc,sBAAsB,IACpC,WACA,cACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,MAAM,gBAAgB,qBAA8B;EACzD,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;CAEF,MAAM,iBAAiB,YAAY;CACnC,MAAM,SAAS,OAAO;CACtB,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,aAAa,OAAuB,KAAK;AAE/C,aACE,aACM;AACJ,eAAa,MAAM;IAErB,EAAE,QAAQ,YAAY,CACvB;AAED,aACE,CAAC,SAAS,QAAQ,GAClB,UAAS;AACP,QAAM,gBAAgB;AACtB,eAAa,CAAC,KAAK;IAErB;EAAE,QAAQ;EAAY,SAAS;EAAgB,CAChD;AAED,QACE,qBAAC;EACC,GAAI;EACJ,KAAK;EACL,WAAW,GACT,YACA,+BACA,UAED;EACD,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,KAAK;;EAEpB,eAAc,UAAS;AACrB,kBAAe,MAAM;AACrB,OAAI,eACF;AAEF,gBAAa,MAAM;;aAGrB,oBAAC;GACC,KAAK;GACL,MAAM,iBAAiB,WAAW;GAClC,UAAU,iBAAiB,IAAI;GAC/B,iBAAc;GACd,iBAAe;GACf,iBAAe,OAAO,SAAS;GAC/B,eAAe;AACb,QAAI,CAAC,eACH;AAEF,iBAAa,CAAC,KAAK;;GAErB,eAAe;AACb,QAAI,eACF;AAEF,iBAAa,KAAK;;GAEpB,SAAQ,MAAK;AAOX,QAAI,CAAC,aAAa,SAAS,SAAS,EAAE,cAAsB,CAC1D,cAAa,MAAM;;GAItB;IACG,EACN,oBAAC,6BACE,QACC,oBAAC,OAAO;GACN,WAAW,GACT,8BAED;GACD,SAAS;IAAE,SAAS;IAAG,GAAG;IAAK;GAC/B,SAAS;IAAE,SAAS;IAAG,GAAG;IAAG;GAC7B,MAAM;IAAE,SAAS;IAAG,GAAG;IAAK;GAC5B,YAAY,EAAE,UAAU,IAAK;aAE7B,oBAAC;IACC,GAAI;IACJ,IAAI;IACJ,cAAa,MAAK;AAChB,OAAE,gBAAgB;;KAEpB;IACS,GAEC;GACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"item.mjs","names":[],"sources":["../../../../../src/components/molecules/menu/item/item.tsx"],"sourcesContent":["'use client';\n\nimport { useRef, useState } from 'react';\n\nimport { ChevronDown } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { MENU_CLASSNAMES, MenuItem, Props } from '../menu';\nimport Label from './label';\n\ninterface ItemProps extends Props, MenuItem {\n itemKey: React.Key;\n keyPath: React.Key[];\n root?: boolean;\n index: number;\n}\nconst OFFSET: [number, number] = [8, 8];\nconst INLINE_OFFSET = 16;\n\nconst STYLES = {\n hover: {\n classes: ['hover:underline', 'hover:underline-offset-8'],\n },\n open: {\n classes: ['underline', 'underline-offset-8'],\n },\n} as const;\n\nconst getItemClasses = (\n root: boolean,\n isHorizontal: boolean,\n isInline: boolean,\n hasChildren: boolean,\n customClasses?: string,\n) =>\n cn(\n 'px-4 py-2',\n 'cursor-pointer',\n 'whitespace-nowrap',\n root && isHorizontal ? 'inline-flex' : 'flex',\n ...(root\n ? [\n 'h-full',\n 'rounded-none border-transparent',\n hasChildren && 'hover:border-current',\n isHorizontal ? 'border-b-2' : 'border-r-2',\n isInline && 'border-none',\n ]\n : ['rounded-md', ...STYLES.hover.classes]),\n customClasses,\n );\n\nconst Item = ({\n itemKey,\n keyPath,\n root = false,\n index,\n mode,\n label,\n children,\n selectionMap,\n classNames,\n styles,\n offset = OFFSET,\n inlineOffset = INLINE_OFFSET,\n onClick,\n onSelect,\n ...props\n}: ItemProps) => {\n const [open, setOpen] = useState<boolean>(false);\n\n const itemRef = useRef<HTMLLIElement | null>(null);\n\n const isHorizontal = mode === 'horizontal';\n const isInline = mode === 'inline';\n\n const [left, top] = offset;\n\n const selected = selectionMap?.get(itemKey) ?? false;\n\n const item = {\n ...props,\n label,\n key: itemKey,\n children,\n };\n\n const itemClassNames = getItemClasses(\n root,\n isHorizontal,\n isInline,\n !!children?.length,\n root ? classNames?.rootItem : classNames?.item,\n );\n\n const handleSelect = (domEvent: React.SyntheticEvent) => {\n domEvent.stopPropagation();\n\n if (isInline) {\n setOpen(!open);\n }\n\n const params = {\n domEvent,\n key: itemKey,\n keyPath,\n item,\n };\n\n onClick?.(params);\n\n if (!selected) {\n onSelect?.(params);\n }\n };\n\n // Roving tabindex (WAI-ARIA menu pattern): only the first item in each\n // menu/submenu level is a Tab stop (below); arrow keys move real DOM\n // focus between sibling <li>s within that same level, which is what\n // ends up mattering for actual keyboard use even though — unlike a\n // fully state-tracked implementation — focus resets to the first item\n // if the user Tabs out and back in rather than resuming where they left\n // off.\n const handleKeyDown = (domEvent: React.KeyboardEvent) => {\n if (domEvent.key === 'Enter' || domEvent.key === ' ') {\n domEvent.preventDefault();\n handleSelect(domEvent);\n return;\n }\n\n if (domEvent.key === 'Escape') {\n if (children?.length && open) {\n domEvent.stopPropagation();\n setOpen(false);\n }\n return;\n }\n\n const isNext = isHorizontal\n ? domEvent.key === 'ArrowRight'\n : domEvent.key === 'ArrowDown';\n const isPrev = isHorizontal\n ? domEvent.key === 'ArrowLeft'\n : domEvent.key === 'ArrowUp';\n\n if (!isNext && !isPrev) {\n return;\n }\n\n domEvent.preventDefault();\n const sibling = isNext\n ? itemRef.current?.nextElementSibling\n : itemRef.current?.previousElementSibling;\n sibling?.querySelector<HTMLElement>('[role=\"menuitem\"]')?.focus();\n };\n\n const childrenContainerClassNames = cn(\n isInline ? 'relative overflow-hidden' : 'absolute min-w-[200px]',\n !isInline && root && isHorizontal\n ? 'left-0 top-full pt-2 pl-0'\n : !isInline\n ? 'left-full top-0 pl-2 pt-0'\n : 'pl-4',\n );\n\n const childrenContainerStyle = isInline\n ? {\n paddingLeft: inlineOffset,\n }\n : root && isHorizontal\n ? {\n paddingTop: top,\n }\n : {\n paddingLeft: left,\n };\n\n return (\n <li\n ref={itemRef}\n role=\"none\"\n className={cn(\n 'group',\n 'relative',\n root && isHorizontal ? 'inline-block' : 'block',\n )}\n onMouseEnter={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onMouseLeave={() => {\n if (isInline) {\n return;\n }\n setOpen(false);\n }}\n onFocus={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onBlur={e => {\n if (isInline) {\n return;\n }\n if (!itemRef.current?.contains(e.relatedTarget as Node)) {\n setOpen(false);\n }\n }}\n >\n <div\n role=\"menuitem\"\n tabIndex={index === 0 ? 0 : -1}\n aria-expanded={children?.length ? open : undefined}\n aria-haspopup={children?.length ? 'menu' : undefined}\n aria-current={selected ? true : undefined}\n className={cn(\n itemClassNames,\n ...(selected\n ? root\n ? ['border-current']\n : [...STYLES.open.classes, ...STYLES.hover.classes]\n : root && !!children?.length\n ? ['group-hover:border-current']\n : []),\n //\n )}\n style={root ? styles?.rootItem : styles?.item}\n onClick={handleSelect}\n onKeyDown={handleKeyDown}\n >\n <div\n className={cn(\n 'w-full',\n 'inline-flex items-center justify-between',\n //\n )}\n >\n <Label className={cn(classNames?.label)} style={styles?.label}>\n {label}\n </Label>\n {!root && !isInline && !!children?.length && (\n <ChevronDown className={cn('-rotate-90')} />\n )}\n {isInline && !!children?.length && (\n <ChevronDown\n className={cn(\n 'transition-all',\n open ? '-rotate-180' : 'rotate-0',\n )}\n />\n )}\n </div>\n </div>\n <AnimatePresence>\n {!!children?.length && open && (\n <motion.div\n className={cn(\n childrenContainerClassNames,\n //\n )}\n style={childrenContainerStyle}\n initial={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n animate={isInline ? { height: 'auto', opacity: 1 } : { opacity: 1 }}\n exit={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <ul\n role=\"menu\"\n className={cn(\n MENU_CLASSNAMES,\n isInline && 'shadow-none',\n classNames?.subMenu,\n //\n )}\n style={styles?.subMenu}\n >\n {children.map((child, childIndex) => (\n <Item\n {...child}\n key={child.key}\n itemKey={child.key}\n keyPath={[...keyPath, child.key]}\n index={childIndex}\n selectionMap={selectionMap}\n mode={mode}\n classNames={classNames}\n styles={styles}\n offset={offset}\n inlineOffset={inlineOffset}\n onClick={onClick}\n onSelect={onSelect}\n />\n ))}\n </ul>\n </motion.div>\n )}\n </AnimatePresence>\n </li>\n );\n};\n\nexport default Item;\n"],"mappings":"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"}
1
+ {"version":3,"file":"item.mjs","names":[],"sources":["../../../../../src/components/molecules/menu/item/item.tsx"],"sourcesContent":["'use client';\n\nimport { useRef, useState } from 'react';\n\nimport { ChevronDown } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { MENU_CLASSNAMES, MenuItem, Props } from '../menu';\nimport Label from './label';\n\ninterface ItemProps extends Props, MenuItem {\n itemKey: React.Key;\n keyPath: React.Key[];\n root?: boolean;\n index: number;\n}\nconst OFFSET: [number, number] = [8, 8];\nconst INLINE_OFFSET = 16;\n\nconst STYLES = {\n hover: {\n classes: ['hover:underline', 'hover:underline-offset-8'],\n },\n open: {\n classes: ['underline', 'underline-offset-8'],\n },\n} as const;\n\nconst getItemClasses = (\n root: boolean,\n isHorizontal: boolean,\n isInline: boolean,\n hasChildren: boolean,\n customClasses?: string,\n) =>\n cn(\n 'px-4 py-2',\n 'cursor-pointer',\n 'whitespace-nowrap',\n root && isHorizontal ? 'inline-flex' : 'flex',\n ...(root\n ? [\n 'h-full',\n 'rounded-none border-transparent',\n hasChildren && 'hover:border-current',\n isHorizontal ? 'border-b-2' : 'border-r-2',\n isInline && 'border-none',\n ]\n : ['rounded-md', ...STYLES.hover.classes]),\n customClasses,\n );\n\nconst Item = ({\n itemKey,\n keyPath,\n root = false,\n index,\n mode,\n label,\n children,\n selectionMap,\n classNames,\n styles,\n offset = OFFSET,\n inlineOffset = INLINE_OFFSET,\n onClick,\n onSelect,\n ...props\n}: ItemProps) => {\n const [open, setOpen] = useState<boolean>(false);\n\n const itemRef = useRef<HTMLLIElement | null>(null);\n\n const isHorizontal = mode === 'horizontal';\n const isInline = mode === 'inline';\n\n const [left, top] = offset;\n\n const selected = selectionMap?.get(itemKey) ?? false;\n\n const item = {\n ...props,\n label,\n key: itemKey,\n children,\n };\n\n const itemClassNames = getItemClasses(\n root,\n isHorizontal,\n isInline,\n !!children?.length,\n root ? classNames?.rootItem : classNames?.item,\n );\n\n const handleSelect = (domEvent: React.SyntheticEvent) => {\n domEvent.stopPropagation();\n\n if (isInline) {\n setOpen(!open);\n }\n\n const params = {\n domEvent,\n key: itemKey,\n keyPath,\n item,\n };\n\n onClick?.(params);\n\n if (!selected) {\n onSelect?.(params);\n }\n };\n\n // Roving tabindex (WAI-ARIA menu pattern): only the first item in each\n // menu/submenu level is a Tab stop (below); arrow keys move real DOM\n // focus between sibling <li>s within that same level, which is what\n // ends up mattering for actual keyboard use even though — unlike a\n // fully state-tracked implementation — focus resets to the first item\n // if the user Tabs out and back in rather than resuming where they left\n // off.\n //\n // Deliberately not `useKeyPress` (unlike dropdown.tsx's trigger and\n // radio.tsx/checkbox.tsx's icon mode, #229's action item 5): that hook\n // is a static combo -> handler binding, one listener per combo. This\n // handler is a single stateful branch — Enter/Space select, Escape\n // conditionally closes a submenu and stops the event from also closing\n // an ancestor Dropdown, and the arrow-key branch reads `itemRef` at\n // fire time to focus a *sibling* `<li>`. Splitting that into 3-4\n // separate useKeyPress calls (each its own listener) per menu item\n // wouldn't fix a bug — the existing logic is already correct — it would\n // just multiply listeners across every item in a menu for no benefit.\n const handleKeyDown = (domEvent: React.KeyboardEvent) => {\n if (domEvent.key === 'Enter' || domEvent.key === ' ') {\n domEvent.preventDefault();\n handleSelect(domEvent);\n return;\n }\n\n if (domEvent.key === 'Escape') {\n if (children?.length && open) {\n domEvent.stopPropagation();\n setOpen(false);\n }\n return;\n }\n\n const isNext = isHorizontal\n ? domEvent.key === 'ArrowRight'\n : domEvent.key === 'ArrowDown';\n const isPrev = isHorizontal\n ? domEvent.key === 'ArrowLeft'\n : domEvent.key === 'ArrowUp';\n\n if (!isNext && !isPrev) {\n return;\n }\n\n domEvent.preventDefault();\n const sibling = isNext\n ? itemRef.current?.nextElementSibling\n : itemRef.current?.previousElementSibling;\n sibling?.querySelector<HTMLElement>('[role=\"menuitem\"]')?.focus();\n };\n\n const childrenContainerClassNames = cn(\n isInline ? 'relative overflow-hidden' : 'absolute min-w-[200px]',\n !isInline && root && isHorizontal\n ? 'left-0 top-full pt-2 pl-0'\n : !isInline\n ? 'left-full top-0 pl-2 pt-0'\n : 'pl-4',\n );\n\n const childrenContainerStyle = isInline\n ? {\n paddingLeft: inlineOffset,\n }\n : root && isHorizontal\n ? {\n paddingTop: top,\n }\n : {\n paddingLeft: left,\n };\n\n return (\n <li\n ref={itemRef}\n role=\"none\"\n className={cn(\n 'group',\n 'relative',\n root && isHorizontal ? 'inline-block' : 'block',\n )}\n onMouseEnter={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onMouseLeave={() => {\n if (isInline) {\n return;\n }\n setOpen(false);\n }}\n onFocus={() => {\n if (isInline) {\n return;\n }\n setOpen(true);\n }}\n onBlur={e => {\n if (isInline) {\n return;\n }\n if (!itemRef.current?.contains(e.relatedTarget as Node)) {\n setOpen(false);\n }\n }}\n >\n <div\n role=\"menuitem\"\n tabIndex={index === 0 ? 0 : -1}\n aria-expanded={children?.length ? open : undefined}\n aria-haspopup={children?.length ? 'menu' : undefined}\n aria-current={selected ? true : undefined}\n className={cn(\n itemClassNames,\n ...(selected\n ? root\n ? ['border-current']\n : [...STYLES.open.classes, ...STYLES.hover.classes]\n : root && !!children?.length\n ? ['group-hover:border-current']\n : []),\n //\n )}\n style={root ? styles?.rootItem : styles?.item}\n onClick={handleSelect}\n onKeyDown={handleKeyDown}\n >\n <div\n className={cn(\n 'w-full',\n 'inline-flex items-center justify-between',\n //\n )}\n >\n <Label className={cn(classNames?.label)} style={styles?.label}>\n {label}\n </Label>\n {!root && !isInline && !!children?.length && (\n <ChevronDown className={cn('-rotate-90')} />\n )}\n {isInline && !!children?.length && (\n <ChevronDown\n className={cn(\n 'transition-all',\n open ? '-rotate-180' : 'rotate-0',\n )}\n />\n )}\n </div>\n </div>\n <AnimatePresence>\n {!!children?.length && open && (\n <motion.div\n className={cn(\n childrenContainerClassNames,\n //\n )}\n style={childrenContainerStyle}\n initial={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n animate={isInline ? { height: 'auto', opacity: 1 } : { opacity: 1 }}\n exit={isInline ? { height: 0, opacity: 0 } : { opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <ul\n role=\"menu\"\n className={cn(\n MENU_CLASSNAMES,\n isInline && 'shadow-none',\n classNames?.subMenu,\n //\n )}\n style={styles?.subMenu}\n >\n {children.map((child, childIndex) => (\n <Item\n {...child}\n key={child.key}\n itemKey={child.key}\n keyPath={[...keyPath, child.key]}\n index={childIndex}\n selectionMap={selectionMap}\n mode={mode}\n classNames={classNames}\n styles={styles}\n offset={offset}\n inlineOffset={inlineOffset}\n onClick={onClick}\n onSelect={onSelect}\n />\n ))}\n </ul>\n </motion.div>\n )}\n </AnimatePresence>\n </li>\n );\n};\n\nexport default Item;\n"],"mappings":";;;;;;;;;;;AAkBA,MAAM,SAA2B,CAAC,GAAG,EAAE;AACvC,MAAM,gBAAgB;AAEtB,MAAM,SAAS;CACb,OAAO,EACL,SAAS,CAAC,mBAAmB,2BAA2B,EACzD;CACD,MAAM,EACJ,SAAS,CAAC,aAAa,qBAAqB,EAC7C;CACF;AAED,MAAM,kBACJ,MACA,cACA,UACA,aACA,kBAEA,GACE,aACA,kBACA,qBACA,QAAQ,eAAe,gBAAgB,QACvC,GAAI,OACA;CACE;CACA;CACA,eAAe;CACf,eAAe,eAAe;CAC9B,YAAY;CACb,GACD,CAAC,cAAc,GAAG,OAAO,MAAM,QAAQ,EAC3C,cACD;AAEH,MAAM,QAAQ,EACZ,SACA,SACA,OAAO,OACP,OACA,MACA,OACA,UACA,cACA,YACA,QACA,SAAS,QACT,eAAe,eACf,SACA,UACA,GAAG,YACY;CACf,MAAM,CAAC,MAAM,WAAW,SAAkB,MAAM;CAEhD,MAAM,UAAU,OAA6B,KAAK;CAElD,MAAM,eAAe,SAAS;CAC9B,MAAM,WAAW,SAAS;CAE1B,MAAM,CAAC,MAAM,OAAO;CAEpB,MAAM,WAAW,cAAc,IAAI,QAAQ,IAAI;CAE/C,MAAM,OAAO;EACX,GAAG;EACH;EACA,KAAK;EACL;EACD;CAED,MAAM,iBAAiB,eACrB,MACA,cACA,UACA,CAAC,CAAC,UAAU,QACZ,OAAO,YAAY,WAAW,YAAY,KAC3C;CAED,MAAM,gBAAgB,aAAmC;AACvD,WAAS,iBAAiB;AAE1B,MAAI,SACF,SAAQ,CAAC,KAAK;EAGhB,MAAM,SAAS;GACb;GACA,KAAK;GACL;GACA;GACD;AAED,YAAU,OAAO;AAEjB,MAAI,CAAC,SACH,YAAW,OAAO;;CAsBtB,MAAM,iBAAiB,aAAkC;AACvD,MAAI,SAAS,QAAQ,WAAW,SAAS,QAAQ,KAAK;AACpD,YAAS,gBAAgB;AACzB,gBAAa,SAAS;AACtB;;AAGF,MAAI,SAAS,QAAQ,UAAU;AAC7B,OAAI,UAAU,UAAU,MAAM;AAC5B,aAAS,iBAAiB;AAC1B,YAAQ,MAAM;;AAEhB;;EAGF,MAAM,SAAS,eACX,SAAS,QAAQ,eACjB,SAAS,QAAQ;EACrB,MAAM,SAAS,eACX,SAAS,QAAQ,cACjB,SAAS,QAAQ;AAErB,MAAI,CAAC,UAAU,CAAC,OACd;AAGF,WAAS,gBAAgB;AAIzB,GAHgB,SACZ,QAAQ,SAAS,qBACjB,QAAQ,SAAS,yBACZ,cAA2B,sBAAoB,EAAE,OAAO;;CAGnE,MAAM,8BAA8B,GAClC,WAAW,6BAA6B,0BACxC,CAAC,YAAY,QAAQ,eACjB,8BACA,CAAC,WACC,8BACA,OACP;CAED,MAAM,yBAAyB,WAC3B,EACE,aAAa,cACd,GACD,QAAQ,eACN,EACE,YAAY,KACb,GACD,EACE,aAAa,MACd;AAEP,QACE,qBAAC;EACC,KAAK;EACL,MAAK;EACL,WAAW,GACT,SACA,YACA,QAAQ,eAAe,iBAAiB,QACzC;EACD,oBAAoB;AAClB,OAAI,SACF;AAEF,WAAQ,KAAK;;EAEf,oBAAoB;AAClB,OAAI,SACF;AAEF,WAAQ,MAAM;;EAEhB,eAAe;AACb,OAAI,SACF;AAEF,WAAQ,KAAK;;EAEf,SAAQ,MAAK;AACX,OAAI,SACF;AAEF,OAAI,CAAC,QAAQ,SAAS,SAAS,EAAE,cAAsB,CACrD,SAAQ,MAAM;;aAIlB,oBAAC;GACC,MAAK;GACL,UAAU,UAAU,IAAI,IAAI;GAC5B,iBAAe,UAAU,SAAS,OAAO;GACzC,iBAAe,UAAU,SAAS,SAAS;GAC3C,gBAAc,WAAW,OAAO;GAChC,WAAW,GACT,gBACA,GAAI,WACA,OACE,CAAC,iBAAiB,GAClB,CAAC,GAAG,OAAO,KAAK,SAAS,GAAG,OAAO,MAAM,QAAQ,GACnD,QAAQ,CAAC,CAAC,UAAU,SAClB,CAAC,6BAA6B,GAC9B,EAAE,CAET;GACD,OAAO,OAAO,QAAQ,WAAW,QAAQ;GACzC,SAAS;GACT,WAAW;aAEX,qBAAC;IACC,WAAW,GACT,UACA,2CAED;;KAED,oBAAC;MAAM,WAAW,GAAG,YAAY,MAAM;MAAE,OAAO,QAAQ;gBACrD;OACK;KACP,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,UAAU,UACjC,oBAAC,eAAY,WAAW,GAAG,aAAa,GAAI;KAE7C,YAAY,CAAC,CAAC,UAAU,UACvB,oBAAC,eACC,WAAW,GACT,kBACA,OAAO,gBAAgB,WACxB,GACD;;KAEA;IACF,EACN,oBAAC,6BACE,CAAC,CAAC,UAAU,UAAU,QACrB,oBAAC,OAAO;GACN,WAAW,GACT,4BAED;GACD,OAAO;GACP,SAAS,WAAW;IAAE,QAAQ;IAAG,SAAS;IAAG,GAAG,EAAE,SAAS,GAAG;GAC9D,SAAS,WAAW;IAAE,QAAQ;IAAQ,SAAS;IAAG,GAAG,EAAE,SAAS,GAAG;GACnE,MAAM,WAAW;IAAE,QAAQ;IAAG,SAAS;IAAG,GAAG,EAAE,SAAS,GAAG;GAC3D,YAAY,EAAE,UAAU,IAAK;aAE7B,oBAAC;IACC,MAAK;IACL,WAAW,GACT,iBACA,YAAY,eACZ,YAAY,QAEb;IACD,OAAO,QAAQ;cAEd,SAAS,KAAK,OAAO,eACpB,8BAAC;KACC,GAAI;KACJ,KAAK,MAAM;KACX,SAAS,MAAM;KACf,SAAS,CAAC,GAAG,SAAS,MAAM,IAAI;KAChC,OAAO;KACO;KACR;KACM;KACJ;KACA;KACM;KACL;KACC;MACV,CACF;KACC;IACM,GAEC;GACf"}
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
 
3
+ import { ConfigSnapshotProvider, getRootConfigValue } from "../../providers/config/registry.mjs";
3
4
  import { useEffect, useState } from "react";
4
- import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
5
+ import { jsx } from "react/jsx-runtime";
5
6
  import { v4 } from "uuid";
6
7
  import { createRoot } from "react-dom/client";
7
8
 
@@ -22,9 +23,10 @@ function createImperativeStack({ createRootElement, StackItem }) {
22
23
  }
23
24
  return state;
24
25
  };
26
+ const resolveContainer = (container) => container || getRootConfigValue()?.getContainer() || document.body;
25
27
  const getRootElement = (container) => {
26
28
  if (!isBrowser) return null;
27
- const targetContainer = container || document.body;
29
+ const targetContainer = resolveContainer(container);
28
30
  let rootEl = rootElements.get(targetContainer);
29
31
  if (!rootEl) {
30
32
  rootEl = createRootElement();
@@ -43,14 +45,14 @@ function createImperativeStack({ createRootElement, StackItem }) {
43
45
  };
44
46
  }, [container]);
45
47
  const { stack } = getContainerState(container);
46
- return /* @__PURE__ */ jsx(Fragment$1, { children: stack.map(({ id, ...props }) => /* @__PURE__ */ jsx(StackItem, {
48
+ return /* @__PURE__ */ jsx(ConfigSnapshotProvider, { children: stack.map(({ id, ...props }) => /* @__PURE__ */ jsx(StackItem, {
47
49
  id,
48
50
  ...props
49
51
  }, id)) });
50
52
  };
51
53
  const render = (props) => {
52
54
  if (!isBrowser) return;
53
- const targetContainer = props.container || document.body;
55
+ const targetContainer = resolveContainer(props.container);
54
56
  const rootElement = getRootElement(targetContainer);
55
57
  if (!reactRoots.has(targetContainer)) {
56
58
  const root = createRoot(rootElement);
@@ -1 +1 @@
1
- {"version":3,"file":"imperative-stack.mjs","names":["uuid"],"sources":["../../../src/components/organisms/imperative-stack.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport { v4 as uuid } from 'uuid';\n\n// Shared machinery behind Modal.info/success/error/warning/confirm and\n// Toast.info/success/error/warning — both used to independently\n// reimplement ~120 near-identical lines of this (container-scoped stack,\n// a React root per container, imperative render/destroy). The only parts\n// that actually differ between the two are the DOM node their stack\n// mounts into (position/ARIA) and which component renders each stack\n// entry — everything else here is generic over that.\n\nexport const isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState<TProps> = {\n stack: (TProps & { id: string })[];\n update: (() => void) | null;\n};\n\nexport interface ImperativeStack<\n TProps extends { id?: string; container?: HTMLElement },\n> {\n render: (props: TProps) => string | undefined;\n destroy: (id?: string) => void;\n getRootElement: (container?: HTMLElement) => HTMLElement | null;\n}\n\nexport interface ImperativeStackOptions<\n TProps extends { id?: string; container?: HTMLElement },\n> {\n /** Creates the DOM node this stack's React root mounts into — not yet\n * attached to the document; the factory appends it to the target\n * container itself. Called once per distinct container. */\n createRootElement: () => HTMLElement;\n /** Renders one stack entry — typically each caller's \"Static<Thing>\"\n * component, which owns its own createPortal(..., getRootElement()). */\n StackItem: React.ComponentType<TProps & { id: string }>;\n}\n\nexport function createImperativeStack<\n TProps extends { id?: string; container?: HTMLElement },\n>({\n createRootElement,\n StackItem,\n}: ImperativeStackOptions<TProps>): ImperativeStack<TProps> {\n const containerStates = new Map<HTMLElement, ContainerState<TProps>>();\n const rootElements = new WeakMap<HTMLElement, HTMLElement>();\n const reactRoots = new Map<HTMLElement, Root>();\n\n const getContainerState = (\n container: HTMLElement,\n ): ContainerState<TProps> => {\n let state = containerStates.get(container);\n\n if (!state) {\n state = { stack: [], update: null };\n containerStates.set(container, state);\n }\n\n return state;\n };\n\n const getRootElement = (container?: HTMLElement): HTMLElement | null => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = container || document.body;\n let rootEl = rootElements.get(targetContainer);\n\n if (!rootEl) {\n rootEl = createRootElement();\n targetContainer.appendChild(rootEl);\n rootElements.set(targetContainer, rootEl);\n }\n\n return rootEl;\n };\n\n const StackRenderer = ({ container }: { container: HTMLElement }) => {\n const [, forceUpdate] = useState({});\n\n useEffect(() => {\n const state = getContainerState(container);\n state.update = () => forceUpdate({});\n return () => {\n state.update = null;\n };\n }, [container]);\n\n const { stack } = getContainerState(container);\n\n return (\n <>\n {stack.map(({ id, ...props }) => (\n <StackItem key={id} id={id} {...(props as TProps)} />\n ))}\n </>\n );\n };\n\n const render = (props: TProps): string | undefined => {\n if (!isBrowser) {\n return;\n }\n\n const targetContainer = props.container || document.body;\n const rootElement = getRootElement(targetContainer)!;\n\n if (!reactRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n reactRoots.set(targetContainer, root);\n root.render(<StackRenderer container={targetContainer} />);\n }\n\n const state = getContainerState(targetContainer);\n const id = props.id || uuid();\n state.stack.push({ ...props, id });\n state.update?.();\n\n return id;\n };\n\n const destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n reactRoots.forEach((root, container) => {\n root.unmount();\n rootElements.get(container)?.remove();\n rootElements.delete(container);\n });\n reactRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(item => item.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(item => item.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n reactRoots.get(container)?.unmount();\n reactRoots.delete(container);\n containerStates.delete(container);\n rootElements.get(container)?.remove();\n rootElements.delete(container);\n }\n });\n };\n\n return { render, destroy, getRootElement };\n}\n"],"mappings":";;;;;;;;AAeA,MAAa,YACX,OAAO,WAAW,eAAe,OAAO,aAAa;AA2BvD,SAAgB,sBAEd,EACA,mBACA,aAC0D;CAC1D,MAAM,kCAAkB,IAAI,KAA0C;CACtE,MAAM,+BAAe,IAAI,SAAmC;CAC5D,MAAM,6BAAa,IAAI,KAAwB;CAE/C,MAAM,qBACJ,cAC2B;EAC3B,IAAI,QAAQ,gBAAgB,IAAI,UAAU;AAE1C,MAAI,CAAC,OAAO;AACV,WAAQ;IAAE,OAAO,EAAE;IAAE,QAAQ;IAAM;AACnC,mBAAgB,IAAI,WAAW,MAAM;;AAGvC,SAAO;;CAGT,MAAM,kBAAkB,cAAgD;AACtE,MAAI,CAAC,UACH,QAAO;EAGT,MAAM,kBAAkB,aAAa,SAAS;EAC9C,IAAI,SAAS,aAAa,IAAI,gBAAgB;AAE9C,MAAI,CAAC,QAAQ;AACX,YAAS,mBAAmB;AAC5B,mBAAgB,YAAY,OAAO;AACnC,gBAAa,IAAI,iBAAiB,OAAO;;AAG3C,SAAO;;CAGT,MAAM,iBAAiB,EAAE,gBAA4C;EACnE,MAAM,GAAG,eAAe,SAAS,EAAE,CAAC;AAEpC,kBAAgB;GACd,MAAM,QAAQ,kBAAkB,UAAU;AAC1C,SAAM,eAAe,YAAY,EAAE,CAAC;AACpC,gBAAa;AACX,UAAM,SAAS;;KAEhB,CAAC,UAAU,CAAC;EAEf,MAAM,EAAE,UAAU,kBAAkB,UAAU;AAE9C,SACE,4CACG,MAAM,KAAK,EAAE,IAAI,GAAG,YACnB,oBAAC;GAAuB;GAAI,GAAK;KAAjB,GAAqC,CACrD,GACD;;CAIP,MAAM,UAAU,UAAsC;AACpD,MAAI,CAAC,UACH;EAGF,MAAM,kBAAkB,MAAM,aAAa,SAAS;EACpD,MAAM,cAAc,eAAe,gBAAgB;AAEnD,MAAI,CAAC,WAAW,IAAI,gBAAgB,EAAE;GACpC,MAAM,OAAO,WAAW,YAAY;AACpC,cAAW,IAAI,iBAAiB,KAAK;AACrC,QAAK,OAAO,oBAAC,iBAAc,WAAW,kBAAmB,CAAC;;EAG5D,MAAM,QAAQ,kBAAkB,gBAAgB;EAChD,MAAM,KAAK,MAAM,MAAMA,IAAM;AAC7B,QAAM,MAAM,KAAK;GAAE,GAAG;GAAO;GAAI,CAAC;AAClC,QAAM,UAAU;AAEhB,SAAO;;CAGT,MAAM,WAAW,OAAgB;AAC/B,MAAI,CAAC,IAAI;AACP,mBAAgB,SAAQ,UAAS;AAC/B,UAAM,QAAQ,EAAE;AAChB,UAAM,UAAU;KAChB;AACF,cAAW,SAAS,MAAM,cAAc;AACtC,SAAK,SAAS;AACd,iBAAa,IAAI,UAAU,EAAE,QAAQ;AACrC,iBAAa,OAAO,UAAU;KAC9B;AACF,cAAW,OAAO;AAClB,mBAAgB,OAAO;AACvB;;AAGF,kBAAgB,SAAS,OAAO,cAAc;AAC5C,OAAI,CAAC,MAAM,MAAM,MAAK,SAAQ,KAAK,OAAO,GAAG,CAC3C;AAGF,SAAM,QAAQ,MAAM,MAAM,QAAO,SAAQ,KAAK,OAAO,GAAG;AACxD,SAAM,UAAU;AAEhB,OAAI,CAAC,MAAM,MAAM,QAAQ;AACvB,eAAW,IAAI,UAAU,EAAE,SAAS;AACpC,eAAW,OAAO,UAAU;AAC5B,oBAAgB,OAAO,UAAU;AACjC,iBAAa,IAAI,UAAU,EAAE,QAAQ;AACrC,iBAAa,OAAO,UAAU;;IAEhC;;AAGJ,QAAO;EAAE;EAAQ;EAAS;EAAgB"}
1
+ {"version":3,"file":"imperative-stack.mjs","names":["uuid"],"sources":["../../../src/components/organisms/imperative-stack.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Root, createRoot } from 'react-dom/client';\n\nimport { v4 as uuid } from 'uuid';\n\nimport { ConfigSnapshotProvider, getRootConfigValue } from '@repo/ui/providers';\n\n// Shared machinery behind Modal.info/success/error/warning/confirm and\n// Toast.info/success/error/warning — both used to independently\n// reimplement ~120 near-identical lines of this (container-scoped stack,\n// a React root per container, imperative render/destroy). The only parts\n// that actually differ between the two are the DOM node their stack\n// mounts into (position/ARIA) and which component renders each stack\n// entry — everything else here is generic over that.\n\nexport const isBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\ntype ContainerState<TProps> = {\n stack: (TProps & { id: string })[];\n update: (() => void) | null;\n};\n\nexport interface ImperativeStack<\n TProps extends { id?: string; container?: HTMLElement },\n> {\n render: (props: TProps) => string | undefined;\n destroy: (id?: string) => void;\n getRootElement: (container?: HTMLElement) => HTMLElement | null;\n}\n\nexport interface ImperativeStackOptions<\n TProps extends { id?: string; container?: HTMLElement },\n> {\n /** Creates the DOM node this stack's React root mounts into — not yet\n * attached to the document; the factory appends it to the target\n * container itself. Called once per distinct container. */\n createRootElement: () => HTMLElement;\n /** Renders one stack entry — typically each caller's \"Static<Thing>\"\n * component, which owns its own createPortal(..., getRootElement()). */\n StackItem: React.ComponentType<TProps & { id: string }>;\n}\n\nexport function createImperativeStack<\n TProps extends { id?: string; container?: HTMLElement },\n>({\n createRootElement,\n StackItem,\n}: ImperativeStackOptions<TProps>): ImperativeStack<TProps> {\n const containerStates = new Map<HTMLElement, ContainerState<TProps>>();\n const rootElements = new WeakMap<HTMLElement, HTMLElement>();\n const reactRoots = new Map<HTMLElement, Root>();\n\n const getContainerState = (\n container: HTMLElement,\n ): ContainerState<TProps> => {\n let state = containerStates.get(container);\n\n if (!state) {\n state = { stack: [], update: null };\n containerStates.set(container, state);\n }\n\n return state;\n };\n\n // Shared by `render` and `getRootElement` so both agree on the same\n // target container whenever the caller doesn't pass one explicitly — the\n // stack's React root (created once, in `render`) and the DOM node a\n // `StackItem` (e.g. StaticToast) later portals into (calling\n // `getRootElement` again with the same, possibly-undefined `container`)\n // would otherwise resolve two different containers here, splitting the\n // React tree (correctly under the root Config, via ConfigSnapshotProvider\n // above) from the actual visible DOM (silently back under `document.body`,\n // outside the Config's themed wrapper — undoing this fix's whole point).\n const resolveContainer = (container?: HTMLElement): HTMLElement =>\n container || getRootConfigValue()?.getContainer() || document.body;\n\n const getRootElement = (container?: HTMLElement): HTMLElement | null => {\n if (!isBrowser) {\n return null;\n }\n\n const targetContainer = resolveContainer(container);\n let rootEl = rootElements.get(targetContainer);\n\n if (!rootEl) {\n rootEl = createRootElement();\n targetContainer.appendChild(rootEl);\n rootElements.set(targetContainer, rootEl);\n }\n\n return rootEl;\n };\n\n const StackRenderer = ({ container }: { container: HTMLElement }) => {\n const [, forceUpdate] = useState({});\n\n useEffect(() => {\n const state = getContainerState(container);\n state.update = () => forceUpdate({});\n return () => {\n state.update = null;\n };\n }, [container]);\n\n const { stack } = getContainerState(container);\n\n return (\n <ConfigSnapshotProvider>\n {stack.map(({ id, ...props }) => (\n <StackItem key={id} id={id} {...(props as TProps)} />\n ))}\n </ConfigSnapshotProvider>\n );\n };\n\n const render = (props: TProps): string | undefined => {\n if (!isBrowser) {\n return;\n }\n\n // An explicit `container` prop always wins (it may be chosen for\n // layout reasons unrelated to theming); otherwise mount into the root\n // Config's own themed wrapper element (if one renders — see\n // `needsWrapper` in config.tsx) so CSS custom properties and the\n // `.dark` class cascade to this stack via normal DOM inheritance, not\n // just `document.body` sitting as an unthemed sibling of it.\n const targetContainer = resolveContainer(props.container);\n const rootElement = getRootElement(targetContainer)!;\n\n if (!reactRoots.has(targetContainer)) {\n const root = createRoot(rootElement);\n reactRoots.set(targetContainer, root);\n root.render(<StackRenderer container={targetContainer} />);\n }\n\n const state = getContainerState(targetContainer);\n const id = props.id || uuid();\n state.stack.push({ ...props, id });\n state.update?.();\n\n return id;\n };\n\n const destroy = (id?: string) => {\n if (!id) {\n containerStates.forEach(state => {\n state.stack = [];\n state.update?.();\n });\n reactRoots.forEach((root, container) => {\n root.unmount();\n rootElements.get(container)?.remove();\n rootElements.delete(container);\n });\n reactRoots.clear();\n containerStates.clear();\n return;\n }\n\n containerStates.forEach((state, container) => {\n if (!state.stack.some(item => item.id === id)) {\n return;\n }\n\n state.stack = state.stack.filter(item => item.id !== id);\n state.update?.();\n\n if (!state.stack.length) {\n reactRoots.get(container)?.unmount();\n reactRoots.delete(container);\n containerStates.delete(container);\n rootElements.get(container)?.remove();\n rootElements.delete(container);\n }\n });\n };\n\n return { render, destroy, getRootElement };\n}\n"],"mappings":";;;;;;;;;AAiBA,MAAa,YACX,OAAO,WAAW,eAAe,OAAO,aAAa;AA2BvD,SAAgB,sBAEd,EACA,mBACA,aAC0D;CAC1D,MAAM,kCAAkB,IAAI,KAA0C;CACtE,MAAM,+BAAe,IAAI,SAAmC;CAC5D,MAAM,6BAAa,IAAI,KAAwB;CAE/C,MAAM,qBACJ,cAC2B;EAC3B,IAAI,QAAQ,gBAAgB,IAAI,UAAU;AAE1C,MAAI,CAAC,OAAO;AACV,WAAQ;IAAE,OAAO,EAAE;IAAE,QAAQ;IAAM;AACnC,mBAAgB,IAAI,WAAW,MAAM;;AAGvC,SAAO;;CAYT,MAAM,oBAAoB,cACxB,aAAa,oBAAoB,EAAE,cAAc,IAAI,SAAS;CAEhE,MAAM,kBAAkB,cAAgD;AACtE,MAAI,CAAC,UACH,QAAO;EAGT,MAAM,kBAAkB,iBAAiB,UAAU;EACnD,IAAI,SAAS,aAAa,IAAI,gBAAgB;AAE9C,MAAI,CAAC,QAAQ;AACX,YAAS,mBAAmB;AAC5B,mBAAgB,YAAY,OAAO;AACnC,gBAAa,IAAI,iBAAiB,OAAO;;AAG3C,SAAO;;CAGT,MAAM,iBAAiB,EAAE,gBAA4C;EACnE,MAAM,GAAG,eAAe,SAAS,EAAE,CAAC;AAEpC,kBAAgB;GACd,MAAM,QAAQ,kBAAkB,UAAU;AAC1C,SAAM,eAAe,YAAY,EAAE,CAAC;AACpC,gBAAa;AACX,UAAM,SAAS;;KAEhB,CAAC,UAAU,CAAC;EAEf,MAAM,EAAE,UAAU,kBAAkB,UAAU;AAE9C,SACE,oBAAC,oCACE,MAAM,KAAK,EAAE,IAAI,GAAG,YACnB,oBAAC;GAAuB;GAAI,GAAK;KAAjB,GAAqC,CACrD,GACqB;;CAI7B,MAAM,UAAU,UAAsC;AACpD,MAAI,CAAC,UACH;EASF,MAAM,kBAAkB,iBAAiB,MAAM,UAAU;EACzD,MAAM,cAAc,eAAe,gBAAgB;AAEnD,MAAI,CAAC,WAAW,IAAI,gBAAgB,EAAE;GACpC,MAAM,OAAO,WAAW,YAAY;AACpC,cAAW,IAAI,iBAAiB,KAAK;AACrC,QAAK,OAAO,oBAAC,iBAAc,WAAW,kBAAmB,CAAC;;EAG5D,MAAM,QAAQ,kBAAkB,gBAAgB;EAChD,MAAM,KAAK,MAAM,MAAMA,IAAM;AAC7B,QAAM,MAAM,KAAK;GAAE,GAAG;GAAO;GAAI,CAAC;AAClC,QAAM,UAAU;AAEhB,SAAO;;CAGT,MAAM,WAAW,OAAgB;AAC/B,MAAI,CAAC,IAAI;AACP,mBAAgB,SAAQ,UAAS;AAC/B,UAAM,QAAQ,EAAE;AAChB,UAAM,UAAU;KAChB;AACF,cAAW,SAAS,MAAM,cAAc;AACtC,SAAK,SAAS;AACd,iBAAa,IAAI,UAAU,EAAE,QAAQ;AACrC,iBAAa,OAAO,UAAU;KAC9B;AACF,cAAW,OAAO;AAClB,mBAAgB,OAAO;AACvB;;AAGF,kBAAgB,SAAS,OAAO,cAAc;AAC5C,OAAI,CAAC,MAAM,MAAM,MAAK,SAAQ,KAAK,OAAO,GAAG,CAC3C;AAGF,SAAM,QAAQ,MAAM,MAAM,QAAO,SAAQ,KAAK,OAAO,GAAG;AACxD,SAAM,UAAU;AAEhB,OAAI,CAAC,MAAM,MAAM,QAAQ;AACvB,eAAW,IAAI,UAAU,EAAE,SAAS;AACpC,eAAW,OAAO,UAAU;AAC5B,oBAAgB,OAAO,UAAU;AACjC,iBAAa,IAAI,UAAU,EAAE,QAAQ;AACrC,iBAAa,OAAO,UAAU;;IAEhC;;AAGJ,QAAO;EAAE;EAAQ;EAAS;EAAgB"}
@@ -1 +1 @@
1
- {"version":3,"file":"modal.d.mts","names":[],"sources":["../../../src/components/organisms/modal.tsx"],"mappings":";;;;UAgCiB,KAAA;EACf,IAAA;EACA,YAAA;EACA,QAAA;IAGM,SAAA,GAAY,KAAA,CAAM,SAAA;IAClB,QAAA;EAAA;EAEN,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,OAAA,GAAU,KAAA,CAAM,SAAA;EAChB,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,UAAA;IACE,IAAA;IACA,MAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,MAAA;EACA,UAAA;EACA,SAAA,GAAY,WAAA;EACZ,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,IAAA;EACA,QAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,IAAA;EACA,EAAA;EACA,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,SAAA,GAAY,WAAA;AAAA;AAAA,cAGR,KAAA;EAAA;;;;;;;;;;;;;;;;;;KAkBH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA;;;cAoMa,WAAA;iBAEG,WAAA;eAEF,WAAA;iBAEE,WAAA;iBAEA,WAAA;AAAA"}
1
+ {"version":3,"file":"modal.d.mts","names":[],"sources":["../../../src/components/organisms/modal.tsx"],"mappings":";;;;UAiCiB,KAAA;EACf,IAAA;EACA,YAAA;EACA,QAAA;IAGM,SAAA,GAAY,KAAA,CAAM,SAAA;IAClB,QAAA;EAAA;EAEN,SAAA,GAAY,KAAA,CAAM,SAAA;EAClB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,OAAA,GAAU,KAAA,CAAM,SAAA;EAChB,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,UAAA;IACE,IAAA;IACA,MAAA;IACA,IAAA;IACA,MAAA;EAAA;EAEF,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,MAAA;EACA,UAAA;EACA,SAAA,GAAY,WAAA;EACZ,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,IAAA;EACA,QAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,IAAA;EACA,EAAA;EACA,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,SAAA,GAAY,WAAA;AAAA;AAAA,cAGR,KAAA;EAAA;;;;;;;;;;;;;;;;;;KAkBH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA;;;cA4Ma,WAAA;iBAEG,WAAA;eAEF,WAAA;iBAEE,WAAA;iBAEA,WAAA;AAAA"}
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../utils.mjs";
4
+ import { DEFAULT_LOCALE, useConfig } from "../../providers/config/context.mjs";
4
5
  import { dialog_exports } from "../../core/dialog.mjs";
5
6
  import Button from "../../Button.mjs";
6
7
  import { createImperativeStack, isBrowser } from "./imperative-stack.mjs";
@@ -11,7 +12,8 @@ import { createPortal } from "react-dom";
11
12
 
12
13
  //#region src/components/organisms/modal.tsx
13
14
  const { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } = dialog_exports;
14
- const Modal = ({ open = false, maskClosable = false, closable = false, closeIcon, className, classNames, style, title, content, footer, container, children, okText = "OK", cancelText = "Cancel", onOk, onCancel, ...props }) => {
15
+ const Modal = ({ open = false, maskClosable = false, closable = false, closeIcon, className, classNames, style, title, content, footer, container, children, okText, cancelText, onOk, onCancel, ...props }) => {
16
+ const { locale } = useConfig();
15
17
  if (typeof window === "undefined") return null;
16
18
  return /* @__PURE__ */ jsx(Dialog, {
17
19
  open,
@@ -45,11 +47,11 @@ const Modal = ({ open = false, maskClosable = false, closable = false, closeIcon
45
47
  className: cn("flex-row justify-end gap-x-2", classNames?.footer),
46
48
  children: footer || /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
47
49
  onClick: onOk,
48
- children: okText
50
+ children: okText ?? locale.ok ?? DEFAULT_LOCALE.ok
49
51
  }), /* @__PURE__ */ jsx(Button, {
50
52
  variant: "outlined",
51
53
  onClick: onCancel,
52
- children: cancelText
54
+ children: cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel
53
55
  })] })
54
56
  })
55
57
  ]
@@ -63,8 +65,11 @@ const STATIC_ICONS = {
63
65
  warning: /* @__PURE__ */ jsx(OctagonAlert, { className: "text-yellow-400" }),
64
66
  confirm: /* @__PURE__ */ jsx(CircleQuestionMark, {})
65
67
  };
66
- const StaticModal = ({ id, type, title, content, okText = "OK", cancelText = "Cancel", container, icon, onOk, onCancel, ...props }) => {
68
+ const StaticModal = ({ id, type, title, content, okText, cancelText, container, icon, onOk, onCancel, ...props }) => {
69
+ const { locale } = useConfig();
67
70
  const [open, setOpen] = useState(true);
71
+ const resolvedOkText = okText ?? locale.ok ?? DEFAULT_LOCALE.ok;
72
+ const resolvedCancelText = cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel;
68
73
  const closeModal = (callback) => {
69
74
  callback?.();
70
75
  setOpen(false);
@@ -78,16 +83,16 @@ const StaticModal = ({ id, type, title, content, okText = "OK", cancelText = "Ca
78
83
  variant: "outlined",
79
84
  className: "col-span-2",
80
85
  onClick: () => closeModal(onCancel),
81
- children: cancelText
86
+ children: resolvedCancelText
82
87
  }), /* @__PURE__ */ jsx(Button, {
83
88
  className: "col-span-3",
84
89
  onClick: () => closeModal(onOk),
85
- children: okText
90
+ children: resolvedOkText
86
91
  })]
87
92
  }) : /* @__PURE__ */ jsx(Button, {
88
93
  className: cn("grow"),
89
94
  onClick: () => closeModal(onOk),
90
- children: okText
95
+ children: resolvedOkText
91
96
  });
92
97
  if (!isBrowser) return null;
93
98
  return createPortal(/* @__PURE__ */ jsx(Modal, {
@@ -1 +1 @@
1
- {"version":3,"file":"modal.mjs","names":["dialog"],"sources":["../../../src/components/organisms/modal.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n Check,\n CircleQuestionMark,\n Info,\n OctagonAlert,\n OctagonX,\n} from 'lucide-react';\n\nimport { dialog } from '@repo/ui/core';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\nimport {\n type ImperativeStack,\n createImperativeStack,\n isBrowser,\n} from './imperative-stack';\n\nconst {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} = dialog;\n\nexport interface Props {\n open?: boolean;\n maskClosable?: boolean;\n closable?:\n | boolean\n | {\n closeIcon?: React.ReactNode;\n disabled?: boolean;\n };\n closeIcon?: React.ReactNode;\n title?: React.ReactNode;\n content?: React.ReactNode;\n footer?: React.ReactNode;\n className?: string;\n classNames?: {\n mask?: string;\n header?: string;\n body?: string;\n footer?: string;\n };\n style?: React.CSSProperties;\n okText?: string;\n cancelText?: string;\n container?: HTMLElement;\n children?: React.ReactNode;\n onOk?: () => void;\n onCancel?: () => void;\n}\n\ninterface StaticProps extends Props {\n type?: 'info' | 'success' | 'error' | 'warning' | 'confirm';\n id?: string;\n icon?: React.ReactNode;\n container?: HTMLElement;\n}\n\nconst Modal = ({\n open = false,\n maskClosable = false,\n closable = false,\n closeIcon,\n className,\n classNames,\n style,\n title,\n content,\n footer,\n container,\n children,\n okText = 'OK',\n cancelText = 'Cancel',\n onOk,\n onCancel,\n ...props\n}: Props) => {\n if (typeof window === 'undefined') {\n return null;\n }\n\n return (\n <Dialog\n open={open}\n onOpenChange={(open: boolean) => {\n if (!open) {\n onCancel?.();\n }\n }}\n {...props}\n >\n <DialogContent\n className={cn(\n 'rounded-lg p-4 max-sm:max-w-[80%]',\n 'border-none outline-none',\n className,\n )}\n classNames={{\n ...classNames,\n mask: cn('bg-black/60', classNames?.mask),\n }}\n style={style}\n closable={closable}\n closeIcon={closeIcon}\n container={container}\n onPointerDownOutside={event => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n >\n {/**\n * @todo [Dialog & AlertDialog] fix: can't get id correctly in shadow dom\n * @see https://github.com/radix-ui/primitives/pull/3384\n **/}\n <DialogHeader\n className={cn(\n classNames?.header,\n !title && 'hidden',\n //\n )}\n >\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription className=\"hidden\" />\n </DialogHeader>\n <div className={cn('break-all', classNames?.body)}>\n {children ?? content}\n </div>\n {footer !== null && (\n <DialogFooter\n className={cn('flex-row justify-end gap-x-2', classNames?.footer)}\n >\n {footer || (\n <>\n <Button onClick={onOk}>{okText}</Button>\n <Button variant=\"outlined\" onClick={onCancel}>\n {cancelText}\n </Button>\n </>\n )}\n </DialogFooter>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nconst STATIC_ICONS = {\n info: <Info className=\"text-blue-400\" />,\n success: <Check className=\"text-green-400\" />,\n error: <OctagonX className=\"text-red-400\" />,\n warning: <OctagonAlert className=\"text-yellow-400\" />,\n confirm: <CircleQuestionMark />,\n};\n\nconst StaticModal = ({\n id,\n type,\n title,\n content,\n okText = 'OK',\n cancelText = 'Cancel',\n container,\n icon,\n onOk,\n onCancel,\n ...props\n}: StaticProps & { id: string }): React.ReactPortal | null => {\n const [open, setOpen] = useState(true);\n\n const closeModal = (callback?: () => void) => {\n callback?.();\n setOpen(false);\n setTimeout(() => {\n modalStack.destroy(id);\n }, 200);\n };\n\n const footer =\n type === 'confirm' ? (\n <div className=\"grid w-full grid-cols-5 gap-x-2\">\n <Button\n variant=\"outlined\"\n className=\"col-span-2\"\n onClick={() => closeModal(onCancel)}\n >\n {cancelText}\n </Button>\n <Button className=\"col-span-3\" onClick={() => closeModal(onOk)}>\n {okText}\n </Button>\n </div>\n ) : (\n <Button\n className={cn(\n 'grow',\n //\n )}\n onClick={() => closeModal(onOk)}\n >\n {okText}\n </Button>\n );\n\n if (!isBrowser) {\n return null;\n }\n\n return createPortal(\n <Modal\n open={open}\n footer={footer}\n className={cn(\n 'z-10000',\n 'box-content w-100',\n 'rounded-3xl p-4',\n 'gap-y-0',\n )}\n classNames={{\n mask: 'z-10000 bg-black/[.6]',\n body: cn(\n 'text-black-70 whitespace-pre-wrap text-center',\n content && 'mt-3',\n ),\n footer: 'mt-9',\n }}\n title={\n <p\n className={cn(\n 'text-center text-lg leading-normal whitespace-pre-wrap',\n 'flex items-center justify-center gap-x-2',\n //\n )}\n >\n {icon || (type && STATIC_ICONS[type])}\n {title}\n </p>\n }\n container={container}\n onCancel={() => closeModal(onCancel)}\n {...props}\n >\n {content}\n </Modal>,\n modalStack.getRootElement(container)!,\n );\n};\n\n// No `role`/`aria-modal` here — this element is only a mount point for the\n// imperative stack, not the dialog itself. Radix already renders its own\n// `role=\"dialog\"`/`aria-modal=\"true\"` on the actual `DialogContent` via\n// portal once a modal is open. Setting it here as well would (a) leave\n// `aria-modal=\"true\"` on the page permanently, even with zero modals open,\n// hiding the rest of the document from screen readers, and (b) duplicate\n// Radix's own dialog role once one is open.\nconst modalStack: ImperativeStack<StaticProps> =\n createImperativeStack<StaticProps>({\n createRootElement: () => {\n const el = document.createElement('div');\n el.style.zIndex = '10000';\n el.style.position = 'absolute';\n return el;\n },\n StackItem: StaticModal,\n });\n\nModal.destroy = modalStack.destroy;\n\nModal.destroyAll = () => {\n modalStack.destroy();\n};\n\nModal.info = (props: StaticProps) =>\n modalStack.render({ type: 'info', ...props });\nModal.success = (props: StaticProps) =>\n modalStack.render({ type: 'success', ...props });\nModal.error = (props: StaticProps) =>\n modalStack.render({ type: 'error', ...props });\nModal.warning = (props: StaticProps) =>\n modalStack.render({ type: 'warning', ...props });\nModal.confirm = (props: StaticProps) =>\n modalStack.render({ type: 'confirm', ...props });\n\nexport default Modal;\n"],"mappings":"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"}
1
+ {"version":3,"file":"modal.mjs","names":["dialog"],"sources":["../../../src/components/organisms/modal.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n Check,\n CircleQuestionMark,\n Info,\n OctagonAlert,\n OctagonX,\n} from 'lucide-react';\n\nimport { dialog } from '@repo/ui/core';\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\nimport {\n type ImperativeStack,\n createImperativeStack,\n isBrowser,\n} from './imperative-stack';\n\nconst {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} = dialog;\n\nexport interface Props {\n open?: boolean;\n maskClosable?: boolean;\n closable?:\n | boolean\n | {\n closeIcon?: React.ReactNode;\n disabled?: boolean;\n };\n closeIcon?: React.ReactNode;\n title?: React.ReactNode;\n content?: React.ReactNode;\n footer?: React.ReactNode;\n className?: string;\n classNames?: {\n mask?: string;\n header?: string;\n body?: string;\n footer?: string;\n };\n style?: React.CSSProperties;\n okText?: string;\n cancelText?: string;\n container?: HTMLElement;\n children?: React.ReactNode;\n onOk?: () => void;\n onCancel?: () => void;\n}\n\ninterface StaticProps extends Props {\n type?: 'info' | 'success' | 'error' | 'warning' | 'confirm';\n id?: string;\n icon?: React.ReactNode;\n container?: HTMLElement;\n}\n\nconst Modal = ({\n open = false,\n maskClosable = false,\n closable = false,\n closeIcon,\n className,\n classNames,\n style,\n title,\n content,\n footer,\n container,\n children,\n okText,\n cancelText,\n onOk,\n onCancel,\n ...props\n}: Props) => {\n const { locale } = useConfig();\n\n if (typeof window === 'undefined') {\n return null;\n }\n\n return (\n <Dialog\n open={open}\n onOpenChange={(open: boolean) => {\n if (!open) {\n onCancel?.();\n }\n }}\n {...props}\n >\n <DialogContent\n className={cn(\n 'rounded-lg p-4 max-sm:max-w-[80%]',\n 'border-none outline-none',\n className,\n )}\n classNames={{\n ...classNames,\n mask: cn('bg-black/60', classNames?.mask),\n }}\n style={style}\n closable={closable}\n closeIcon={closeIcon}\n container={container}\n onPointerDownOutside={event => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n >\n {/**\n * @todo [Dialog & AlertDialog] fix: can't get id correctly in shadow dom\n * @see https://github.com/radix-ui/primitives/pull/3384\n **/}\n <DialogHeader\n className={cn(\n classNames?.header,\n !title && 'hidden',\n //\n )}\n >\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription className=\"hidden\" />\n </DialogHeader>\n <div className={cn('break-all', classNames?.body)}>\n {children ?? content}\n </div>\n {footer !== null && (\n <DialogFooter\n className={cn('flex-row justify-end gap-x-2', classNames?.footer)}\n >\n {footer || (\n <>\n <Button onClick={onOk}>\n {okText ?? locale.ok ?? DEFAULT_LOCALE.ok}\n </Button>\n <Button variant=\"outlined\" onClick={onCancel}>\n {cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel}\n </Button>\n </>\n )}\n </DialogFooter>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nconst STATIC_ICONS = {\n info: <Info className=\"text-blue-400\" />,\n success: <Check className=\"text-green-400\" />,\n error: <OctagonX className=\"text-red-400\" />,\n warning: <OctagonAlert className=\"text-yellow-400\" />,\n confirm: <CircleQuestionMark />,\n};\n\nconst StaticModal = ({\n id,\n type,\n title,\n content,\n okText,\n cancelText,\n container,\n icon,\n onOk,\n onCancel,\n ...props\n}: StaticProps & { id: string }): React.ReactPortal | null => {\n const { locale } = useConfig();\n const [open, setOpen] = useState(true);\n const resolvedOkText = okText ?? locale.ok ?? DEFAULT_LOCALE.ok;\n const resolvedCancelText =\n cancelText ?? locale.cancel ?? DEFAULT_LOCALE.cancel;\n\n const closeModal = (callback?: () => void) => {\n callback?.();\n setOpen(false);\n setTimeout(() => {\n modalStack.destroy(id);\n }, 200);\n };\n\n const footer =\n type === 'confirm' ? (\n <div className=\"grid w-full grid-cols-5 gap-x-2\">\n <Button\n variant=\"outlined\"\n className=\"col-span-2\"\n onClick={() => closeModal(onCancel)}\n >\n {resolvedCancelText}\n </Button>\n <Button className=\"col-span-3\" onClick={() => closeModal(onOk)}>\n {resolvedOkText}\n </Button>\n </div>\n ) : (\n <Button\n className={cn(\n 'grow',\n //\n )}\n onClick={() => closeModal(onOk)}\n >\n {resolvedOkText}\n </Button>\n );\n\n if (!isBrowser) {\n return null;\n }\n\n return createPortal(\n <Modal\n open={open}\n footer={footer}\n className={cn(\n 'z-10000',\n 'box-content w-100',\n 'rounded-3xl p-4',\n 'gap-y-0',\n )}\n classNames={{\n mask: 'z-10000 bg-black/[.6]',\n body: cn(\n 'text-black-70 whitespace-pre-wrap text-center',\n content && 'mt-3',\n ),\n footer: 'mt-9',\n }}\n title={\n <p\n className={cn(\n 'text-center text-lg leading-normal whitespace-pre-wrap',\n 'flex items-center justify-center gap-x-2',\n //\n )}\n >\n {icon || (type && STATIC_ICONS[type])}\n {title}\n </p>\n }\n container={container}\n onCancel={() => closeModal(onCancel)}\n {...props}\n >\n {content}\n </Modal>,\n modalStack.getRootElement(container)!,\n );\n};\n\n// No `role`/`aria-modal` here — this element is only a mount point for the\n// imperative stack, not the dialog itself. Radix already renders its own\n// `role=\"dialog\"`/`aria-modal=\"true\"` on the actual `DialogContent` via\n// portal once a modal is open. Setting it here as well would (a) leave\n// `aria-modal=\"true\"` on the page permanently, even with zero modals open,\n// hiding the rest of the document from screen readers, and (b) duplicate\n// Radix's own dialog role once one is open.\nconst modalStack: ImperativeStack<StaticProps> =\n createImperativeStack<StaticProps>({\n createRootElement: () => {\n const el = document.createElement('div');\n el.style.zIndex = '10000';\n el.style.position = 'absolute';\n return el;\n },\n StackItem: StaticModal,\n });\n\nModal.destroy = modalStack.destroy;\n\nModal.destroyAll = () => {\n modalStack.destroy();\n};\n\nModal.info = (props: StaticProps) =>\n modalStack.render({ type: 'info', ...props });\nModal.success = (props: StaticProps) =>\n modalStack.render({ type: 'success', ...props });\nModal.error = (props: StaticProps) =>\n modalStack.render({ type: 'error', ...props });\nModal.warning = (props: StaticProps) =>\n modalStack.render({ type: 'warning', ...props });\nModal.confirm = (props: StaticProps) =>\n modalStack.render({ type: 'confirm', ...props });\n\nexport default Modal;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.mts","names":[],"sources":["../../../src/components/organisms/toast.tsx"],"mappings":";;;KAiBK,SAAA;AAAA,UAEY,KAAA;EACf,IAAA,GAAO,SAAA;EACP,KAAA,EAAO,KAAA,CAAM,SAAA;EACb,WAAA,GAAc,KAAA,CAAM,SAAA;EACpB,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,QAAA;EACA,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,OAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,EAAA;EACA,QAAA;EACA,SAAA,GAAY,WAAA;AAAA;AAAA,cAUR,KAAA;EAAA;;;;;;;;;KASH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA;;;cA+Ga,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;iBAEtB,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;eAE3B,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;iBAEvB,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;AAAA;AAAA,KAR5C,cAAA,GAAiB,IAAA,CAAK,WAAA"}
1
+ {"version":3,"file":"toast.d.mts","names":[],"sources":["../../../src/components/organisms/toast.tsx"],"mappings":";;;KAkBK,SAAA;AAAA,UAEY,KAAA;EACf,IAAA,GAAO,SAAA;EACP,KAAA,EAAO,KAAA,CAAM,SAAA;EACb,WAAA,GAAc,KAAA,CAAM,SAAA;EACpB,IAAA,GAAO,KAAA,CAAM,SAAA;EACb,QAAA;EACA,MAAA,GAAS,KAAA,CAAM,SAAA;EACf,SAAA;EACA,OAAA;AAAA;AAAA,UAGQ,WAAA,SAAoB,KAAA;EAC5B,EAAA;EACA,QAAA;EACA,SAAA,GAAY,WAAA;AAAA;AAAA,cAUR,KAAA;EAAA;;;;;;;;;KASH,KAAA,GAAK,kBAAA,CAAA,GAAA,CAAA,OAAA;;;cAoHa,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;iBAEtB,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;eAE3B,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;iBAEvB,KAAA,CAAM,SAAA,EAAS,KAAA,GAAU,cAAA;AAAA;AAAA,KAR5C,cAAA,GAAiB,IAAA,CAAK,WAAA"}