@jbpark/ui-kit 9.1.1 → 10.0.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 (112) hide show
  1. package/README.ko.md +18 -17
  2. package/README.md +18 -17
  3. package/dist/Button.d.mts +1 -1
  4. package/dist/Button.d.mts.map +1 -1
  5. package/dist/Button.mjs +4 -5
  6. package/dist/Button.mjs.map +1 -1
  7. package/dist/Tag.d.mts.map +1 -1
  8. package/dist/Tag.mjs.map +1 -1
  9. package/dist/components/atoms/checkbox/checkbox.mjs.map +1 -1
  10. package/dist/components/atoms/option-group.mjs.map +1 -1
  11. package/dist/components/atoms/popover.d.mts +3 -1
  12. package/dist/components/atoms/popover.d.mts.map +1 -1
  13. package/dist/components/atoms/popover.mjs +10 -111
  14. package/dist/components/atoms/popover.mjs.map +1 -1
  15. package/dist/components/atoms/progress.mjs +3 -4
  16. package/dist/components/atoms/progress.mjs.map +1 -1
  17. package/dist/components/atoms/radio/context.mjs +2 -2
  18. package/dist/components/atoms/radio/context.mjs.map +1 -1
  19. package/dist/components/atoms/radio/group.mjs +6 -6
  20. package/dist/components/atoms/radio/group.mjs.map +1 -1
  21. package/dist/components/atoms/radio/radio.d.mts +2 -5
  22. package/dist/components/atoms/radio/radio.d.mts.map +1 -1
  23. package/dist/components/atoms/radio/radio.mjs +0 -1
  24. package/dist/components/atoms/radio/radio.mjs.map +1 -1
  25. package/dist/components/atoms/rich-text-editor/content-classes.mjs +1 -1
  26. package/dist/components/atoms/rich-text-editor/content-classes.mjs.map +1 -1
  27. package/dist/components/atoms/rich-text-editor/rich-text-editor.mjs +1 -1
  28. package/dist/components/atoms/rich-text-editor/rich-text-editor.mjs.map +1 -1
  29. package/dist/components/atoms/rich-text-editor/toolbar-button.mjs.map +1 -1
  30. package/dist/components/atoms/rich-text-editor/toolbar-presets.mjs.map +1 -1
  31. package/dist/components/atoms/rich-text-editor/toolbar.mjs +1 -1
  32. package/dist/components/atoms/rich-text-editor/toolbar.mjs.map +1 -1
  33. package/dist/components/atoms/select.mjs +5 -1
  34. package/dist/components/atoms/select.mjs.map +1 -1
  35. package/dist/components/atoms/slider/slider.mjs.map +1 -1
  36. package/dist/components/atoms/switch.d.mts +1 -1
  37. package/dist/components/atoms/switch.d.mts.map +1 -1
  38. package/dist/components/atoms/switch.mjs +3 -3
  39. package/dist/components/atoms/switch.mjs.map +1 -1
  40. package/dist/components/molecules/collapse.mjs +3 -10
  41. package/dist/components/molecules/collapse.mjs.map +1 -1
  42. package/dist/components/organisms/drawer.d.mts +1 -2
  43. package/dist/components/organisms/drawer.d.mts.map +1 -1
  44. package/dist/components/organisms/drawer.mjs +5 -7
  45. package/dist/components/organisms/drawer.mjs.map +1 -1
  46. package/dist/components/organisms/modal.d.mts.map +1 -1
  47. package/dist/components/organisms/modal.mjs +1 -3
  48. package/dist/components/organisms/modal.mjs.map +1 -1
  49. package/dist/components/templates/container.d.mts +4 -3
  50. package/dist/components/templates/container.d.mts.map +1 -1
  51. package/dist/components/templates/container.mjs +10 -6
  52. package/dist/components/templates/container.mjs.map +1 -1
  53. package/dist/components/templates/index.d.mts +13 -0
  54. package/dist/components/templates/layout/content.d.mts +4 -3
  55. package/dist/components/templates/layout/content.d.mts.map +1 -1
  56. package/dist/components/templates/layout/content.mjs +14 -9
  57. package/dist/components/templates/layout/content.mjs.map +1 -1
  58. package/dist/core/accordion.d.mts +1 -1
  59. package/dist/core/accordion.mjs +12 -12
  60. package/dist/core/accordion.mjs.map +1 -1
  61. package/dist/core/badge.d.mts +5 -17
  62. package/dist/core/badge.d.mts.map +1 -1
  63. package/dist/core/badge.mjs +12 -21
  64. package/dist/core/badge.mjs.map +1 -1
  65. package/dist/core/button.d.mts +7 -6
  66. package/dist/core/button.d.mts.map +1 -1
  67. package/dist/core/button.mjs +4 -4
  68. package/dist/core/button.mjs.map +1 -1
  69. package/dist/core/calendar.mjs +2 -1
  70. package/dist/core/calendar.mjs.map +1 -1
  71. package/dist/core/checkbox.d.mts +1 -1
  72. package/dist/core/checkbox.mjs +14 -14
  73. package/dist/core/checkbox.mjs.map +1 -1
  74. package/dist/core/dialog.d.mts +1 -1
  75. package/dist/core/dialog.mjs +25 -33
  76. package/dist/core/dialog.mjs.map +1 -1
  77. package/dist/core/drawer.d.mts +1 -1
  78. package/dist/core/drawer.mjs +45 -46
  79. package/dist/core/drawer.mjs.map +1 -1
  80. package/dist/core/label.d.mts +1 -2
  81. package/dist/core/label.mjs +1 -3
  82. package/dist/core/label.mjs.map +1 -1
  83. package/dist/core/popover.d.mts +1 -1
  84. package/dist/core/popover.mjs +42 -37
  85. package/dist/core/popover.mjs.map +1 -1
  86. package/dist/core/progress.d.mts +1 -1
  87. package/dist/core/progress.mjs +7 -10
  88. package/dist/core/progress.mjs.map +1 -1
  89. package/dist/core/radio-group.d.mts +3 -7
  90. package/dist/core/radio-group.mjs +14 -13
  91. package/dist/core/radio-group.mjs.map +1 -1
  92. package/dist/core/select.d.mts +7 -3
  93. package/dist/core/select.d.mts.map +1 -1
  94. package/dist/core/select.mjs +60 -56
  95. package/dist/core/select.mjs.map +1 -1
  96. package/dist/core/separator.d.mts +1 -1
  97. package/dist/core/separator.mjs +6 -5
  98. package/dist/core/separator.mjs.map +1 -1
  99. package/dist/core/slider.d.mts +1 -1
  100. package/dist/core/slider.mjs +38 -27
  101. package/dist/core/slider.mjs.map +1 -1
  102. package/dist/core/switch.d.mts +1 -1
  103. package/dist/core/switch.mjs +15 -15
  104. package/dist/core/switch.mjs.map +1 -1
  105. package/dist/index.d.mts +1 -0
  106. package/dist/lib/z-layers.mjs +4 -6
  107. package/dist/lib/z-layers.mjs.map +1 -1
  108. package/dist/providers/config/config.mjs +2 -2
  109. package/dist/providers/config/config.mjs.map +1 -1
  110. package/dist/style.css +327 -462
  111. package/package.json +7 -20
  112. package/dist/core/radio-group.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"progress.mjs","names":["progress"],"sources":["../../../src/components/atoms/progress.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport { progress } from '../../core';\n\nconst { Progress: Core } = progress;\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n value: number;\n direction?: 'horizontal' | 'vertical';\n classNames?: {\n background?: string;\n bar?: string;\n };\n}\n\nconst Progress = ({\n value,\n className,\n direction = 'horizontal',\n classNames,\n ...props\n}: Props) => {\n const isHorizontal = direction === 'horizontal';\n const dimension = isHorizontal ? 'width' : 'height';\n const normalizedValue = Number.isFinite(value)\n ? Math.min(100, Math.max(0, value))\n : 0;\n\n return (\n <Core\n {...props}\n value={normalizedValue}\n className={cn(\n isHorizontal ? 'h-4 w-full' : 'flex h-full w-4 flex-col justify-end',\n className,\n classNames?.background,\n //\n )}\n barClassName={cn('flex-none', classNames?.bar)}\n barStyle={{\n transform: 'none',\n [dimension]: `${normalizedValue}%`,\n //\n }}\n />\n );\n};\n\nexport default Progress;\n"],"mappings":";;;;AAIA,MAAM,EAAE,UAAU,SAASA;AAW3B,MAAM,YAAY,EAChB,OACA,WACA,YAAY,cACZ,YACA,GAAG,YACQ;CACX,MAAM,eAAe,cAAc;CACnC,MAAM,YAAY,eAAe,UAAU;CAC3C,MAAM,kBAAkB,OAAO,SAAS,KAAK,IACzC,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,IAChC;CAEJ,OACE,oBAAC,MAAD;EACE,GAAI;EACJ,OAAO;EACP,WAAW,GACT,eAAe,eAAe,wCAC9B,WACA,YAAY,UAEd;EACA,cAAc,GAAG,aAAa,YAAY,GAAG;EAC7C,UAAU;GACR,WAAW;IACV,YAAY,GAAG,gBAAgB;EAElC;CACD,CAAA;AAEL"}
1
+ {"version":3,"file":"progress.mjs","names":["progress"],"sources":["../../../src/components/atoms/progress.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport { progress } from '../../core';\n\nconst { Progress: Core } = progress;\n\nexport interface Props extends React.ComponentPropsWithoutRef<'div'> {\n value: number;\n direction?: 'horizontal' | 'vertical';\n classNames?: {\n background?: string;\n bar?: string;\n };\n}\n\nconst Progress = ({\n value,\n className,\n direction = 'horizontal',\n classNames,\n ...props\n}: Props) => {\n const isHorizontal = direction === 'horizontal';\n const normalizedValue = Number.isFinite(value)\n ? Math.min(100, Math.max(0, value))\n : 0;\n\n return (\n <Core\n {...props}\n value={normalizedValue}\n className={cn(\n isHorizontal ? 'h-4 w-full' : 'flex h-full w-4 flex-col justify-end',\n className,\n classNames?.background,\n //\n )}\n barClassName={cn('flex-none', classNames?.bar)}\n barStyle={\n isHorizontal\n ? { width: `${normalizedValue}%` }\n : { width: '100%', height: `${normalizedValue}%` }\n }\n />\n );\n};\n\nexport default Progress;\n"],"mappings":";;;;AAIA,MAAM,EAAE,UAAU,SAASA;AAW3B,MAAM,YAAY,EAChB,OACA,WACA,YAAY,cACZ,YACA,GAAG,YACQ;CACX,MAAM,eAAe,cAAc;CACnC,MAAM,kBAAkB,OAAO,SAAS,KAAK,IACzC,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,IAChC;CAEJ,OACE,oBAAC,MAAD;EACE,GAAI;EACJ,OAAO;EACP,WAAW,GACT,eAAe,eAAe,wCAC9B,WACA,YAAY,UAEd;EACA,cAAc,GAAG,aAAa,YAAY,GAAG;EAC7C,UACE,eACI,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAC/B;GAAE,OAAO;GAAQ,QAAQ,GAAG,gBAAgB;EAAG;CAEtD,CAAA;AAEL"}
@@ -5,8 +5,8 @@ import { createContext } from "react";
5
5
  * Internal only — not exported from the package entry points.
6
6
  *
7
7
  * `true` when a `Radio` is rendered inside a `RadioGroup` that already owns a
8
- * single shared `RadioGroupPrimitive.Root`. In that case each `Radio` renders
9
- * only its `RadioGroupItem` so that Radix can manage roving focus (arrow-key
8
+ * single shared Base UI `RadioGroup` root. In that case each `Radio` renders
9
+ * only its `RadioGroupItem` so that Base UI can manage roving focus (arrow-key
10
10
  * navigation) across every option of the group.
11
11
  *
12
12
  * `false` (default) means the `Radio` is standalone and has to wrap itself in
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":[],"sources":["../../../../src/components/atoms/radio/context.tsx"],"sourcesContent":["'use client';\n\nimport { createContext } from 'react';\n\n/**\n * Internal only — not exported from the package entry points.\n *\n * `true` when a `Radio` is rendered inside a `RadioGroup` that already owns a\n * single shared `RadioGroupPrimitive.Root`. In that case each `Radio` renders\n * only its `RadioGroupItem` so that Radix can manage roving focus (arrow-key\n * navigation) across every option of the group.\n *\n * `false` (default) means the `Radio` is standalone and has to wrap itself in\n * its own `Root` to stay functional.\n */\nexport const RadioGroupContext = createContext(false);\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAa,oBAAoB,cAAc,KAAK"}
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../../../src/components/atoms/radio/context.tsx"],"sourcesContent":["'use client';\n\nimport { createContext } from 'react';\n\n/**\n * Internal only — not exported from the package entry points.\n *\n * `true` when a `Radio` is rendered inside a `RadioGroup` that already owns a\n * single shared Base UI `RadioGroup` root. In that case each `Radio` renders\n * only its `RadioGroupItem` so that Base UI can manage roving focus (arrow-key\n * navigation) across every option of the group.\n *\n * `false` (default) means the `Radio` is standalone and has to wrap itself in\n * its own `Root` to stay functional.\n */\nexport const RadioGroupContext = createContext(false);\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAa,oBAAoB,cAAc,KAAK"}
@@ -4,10 +4,10 @@ import { radio_group_exports } from "../../../core/radio-group.mjs";
4
4
  import Button from "../../../Button.mjs";
5
5
  import { normalizeOptions, warnOnDuplicateOptionValues } from "../option-group.mjs";
6
6
  import { RadioGroupContext } from "./context.mjs";
7
- import Radio from "./radio.mjs";
7
+ import Radio$1 from "./radio.mjs";
8
8
  import { useId } from "react";
9
9
  import { jsx } from "react/jsx-runtime";
10
- import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
10
+ import { Radio } from "@base-ui/react/radio";
11
11
  import { useControllableState } from "@jbpark/use-hooks";
12
12
  //#region src/components/atoms/radio/group.tsx
13
13
  const { RadioGroup: Core } = radio_group_exports;
@@ -39,19 +39,19 @@ const RadioGroup = ({ orientation = "horizontal", placement = "left", className,
39
39
  const checked = value === item.value;
40
40
  return /* @__PURE__ */ jsx("li", {
41
41
  className: cn("m-0 flex", classNames?.wrapper),
42
- children: isButton ? /* @__PURE__ */ jsx(RadioGroupPrimitive.Item, {
43
- asChild: true,
42
+ children: isButton ? /* @__PURE__ */ jsx(Radio.Root, {
44
43
  "data-slot": "radio-group-item",
45
44
  value: String(item.value),
46
45
  disabled: disabled || item.disabled,
47
- children: /* @__PURE__ */ jsx(Button, {
46
+ nativeButton: true,
47
+ render: /* @__PURE__ */ jsx(Button, {
48
48
  variant: checked ? buttonStyle : "outlined",
49
49
  size,
50
50
  disabled: disabled || item.disabled,
51
51
  className: cn("rounded-none border", checked && (buttonStyle === "outlined" ? "border-primary" : "border-transparent"), index === 0 && (orientation === "vertical" ? "rounded-t-lg" : "rounded-l-lg"), index === options.length - 1 && (orientation === "vertical" ? "rounded-b-lg" : "rounded-r-lg")),
52
52
  children: item.label
53
53
  })
54
- }) : /* @__PURE__ */ jsx(Radio, {
54
+ }) : /* @__PURE__ */ jsx(Radio$1, {
55
55
  id: getOptionId(index),
56
56
  placement,
57
57
  className: cn(classNames?.item),
@@ -1 +1 @@
1
- {"version":3,"file":"group.mjs","names":["radio"],"sources":["../../../../src/components/atoms/radio/group.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { radio } from '../../../core';\nimport Button from '../button';\nimport {\n type Option,\n type OptionGroupClassNames,\n type OptionValue,\n type Options,\n normalizeOptions,\n warnOnDuplicateOptionValues,\n} from '../option-group';\nimport { RadioGroupContext } from './context';\nimport Radio from './radio';\n\nconst { RadioGroup: Core } = radio;\n\nexport type { OptionValue };\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'ul'>,\n 'onChange' | 'defaultValue' | 'value'\n> {\n options?: Options;\n orientation?: 'vertical' | 'horizontal';\n placement?: 'left' | 'right';\n classNames?: OptionGroupClassNames;\n defaultValue?: OptionValue;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n optionType?: 'default' | 'button';\n buttonStyle?: 'solid' | 'outlined';\n size?: 'small' | 'middle' | 'large';\n disabled?: boolean;\n onChange?: (value: OptionValue) => void;\n}\n\nconst RadioGroup = ({\n orientation = 'horizontal',\n placement = 'left',\n className,\n classNames = {},\n options: _options = [],\n name,\n optionType = 'default',\n buttonStyle = 'solid',\n size,\n disabled,\n defaultValue,\n value: _value,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [value, setValue] = useControllableState<OptionValue>({\n value: _value,\n defaultValue,\n onChange: _onChange,\n });\n\n const options: Option[] = normalizeOptions(_options);\n warnOnDuplicateOptionValues(options, 'Radio.Group');\n\n const isButton = optionType === 'button';\n\n const onChange = (checked: boolean, optionValue: OptionValue) => {\n if (!checked) {\n return;\n }\n setValue(optionValue);\n };\n\n // A single Radix radiogroup root owns every option so that arrow keys move\n // focus across the whole group. `id` stays index-derived (for DOM\n // id/label pairing), but Radix itself now addresses/submits items by\n // their real (stringified) `value` — see radio.tsx.\n const baseId = useId();\n const getOptionId = (index: number) => `${baseId}-${index}`;\n const checkedItemValue = value === undefined ? '' : String(value);\n\n const onValueChange = (itemValue: string) => {\n const item = options.find(option => String(option.value) === itemValue);\n\n if (!item) {\n return;\n }\n\n onChange(true, item.value);\n };\n\n const list = (\n <ul\n {...props}\n className={cn(\n 'm-0 flex list-none gap-4 p-0',\n className,\n orientation === 'vertical' && 'flex-col',\n isButton && 'gap-0',\n )}\n >\n {options.map((item: Option, index) => {\n const checked = value === item.value;\n\n return (\n <li\n key={`${index}-${String(item.value)}`}\n // `m-0` completes the list reset the `ul` above starts (#253):\n // without preflight, hosts that style prose lists still reach the\n // items — Docusaurus/Infima's `.markdown li + li` gives every item\n // but the first a `margin-top`, which in horizontal orientation\n // drops options 2..n by that much and stretches the first one,\n // making it look misaligned.\n className={cn('m-0 flex', classNames?.wrapper)}\n >\n {isButton ? (\n // `asChild` gives the Button real radio semantics (role,\n // aria-checked, roving tabindex, arrow-key nav, click/keyboard\n // selection via the shared Core's onValueChange below) instead\n // of a plain list of buttons with none of that. Uses the Radix\n // primitive directly (not `core/RadioGroupItem`) so that core\n // stays upstream-verbatim with no `asChild` branch (#361); the\n // `data-slot` matches what the default item emits.\n <RadioGroupPrimitive.Item\n asChild\n data-slot=\"radio-group-item\"\n value={String(item.value)}\n disabled={disabled || item.disabled}\n >\n <Button\n variant={checked ? buttonStyle : 'outlined'}\n size={size}\n disabled={disabled || item.disabled}\n className={cn(\n // The `solid` variant (the checked item, by default)\n // renders no border at all while `outlined` (every\n // unchecked item) renders a 1px one — reserving the\n // border unconditionally keeps every option's box the\n // same size regardless of which variant it's in.\n 'rounded-none border',\n checked &&\n (buttonStyle === 'outlined'\n ? 'border-primary'\n : 'border-transparent'),\n index === 0 &&\n (orientation === 'vertical'\n ? 'rounded-t-lg'\n : 'rounded-l-lg'),\n index === options.length - 1 &&\n (orientation === 'vertical'\n ? 'rounded-b-lg'\n : 'rounded-r-lg'),\n )}\n >\n {item.label}\n </Button>\n </RadioGroupPrimitive.Item>\n ) : (\n <Radio\n id={getOptionId(index)}\n placement={placement}\n className={cn(classNames?.item)}\n value={item.value}\n checked={checked}\n disabled={disabled || item.disabled}\n onChange={checked => onChange(checked, item.value)}\n >\n {item.label}\n </Radio>\n )}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <RadioGroupContext.Provider value={true}>\n <Core\n className=\"block\"\n name={name}\n value={checkedItemValue}\n onValueChange={onValueChange}\n >\n {list}\n </Core>\n </RadioGroupContext.Provider>\n );\n};\n\nexport default RadioGroup;\n"],"mappings":";;;;;;;;;;;;AAsBA,MAAM,EAAE,YAAY,SAASA;AAuB7B,MAAM,cAAc,EAClB,cAAc,cACd,YAAY,QACZ,WACA,aAAa,CAAC,GACd,SAAS,WAAW,CAAC,GACrB,MACA,aAAa,WACb,cAAc,SACd,MACA,UACA,cACA,OAAO,QACP,UAAU,kBAAkB,CAAC,GAC7B,GAAG,YACQ;CACX,MAAM,CAAC,OAAO,YAAY,qBAAkC;EAC1D,OAAO;EACP;EACA,UAAU;CACZ,CAAC;CAED,MAAM,UAAoB,iBAAiB,QAAQ;CACnD,4BAA4B,SAAS,aAAa;CAElD,MAAM,WAAW,eAAe;CAEhC,MAAM,YAAY,SAAkB,gBAA6B;EAC/D,IAAI,CAAC,SACH;EAEF,SAAS,WAAW;CACtB;CAMA,MAAM,SAAS,MAAM;CACrB,MAAM,eAAe,UAAkB,GAAG,OAAO,GAAG;CACpD,MAAM,mBAAmB,UAAU,KAAA,IAAY,KAAK,OAAO,KAAK;CAEhE,MAAM,iBAAiB,cAAsB;EAC3C,MAAM,OAAO,QAAQ,MAAK,WAAU,OAAO,OAAO,KAAK,MAAM,SAAS;EAEtE,IAAI,CAAC,MACH;EAGF,SAAS,MAAM,KAAK,KAAK;CAC3B;CAEA,MAAM,OACJ,oBAAC,MAAD;EACE,GAAI;EACJ,WAAW,GACT,gCACA,WACA,gBAAgB,cAAc,YAC9B,YAAY,OACd;EAEC,UAAA,QAAQ,KAAK,MAAc,UAAU;GACpC,MAAM,UAAU,UAAU,KAAK;GAE/B,OACE,oBAAC,MAAD;IAQE,WAAW,GAAG,YAAY,YAAY,OAAO;IAE5C,UAAA,WAQC,oBAAC,oBAAoB,MAArB;KACE,SAAA;KACA,aAAU;KACV,OAAO,OAAO,KAAK,KAAK;KACxB,UAAU,YAAY,KAAK;KAE3B,UAAA,oBAAC,QAAD;MACE,SAAS,UAAU,cAAc;MAC3B;MACN,UAAU,YAAY,KAAK;MAC3B,WAAW,GAMT,uBACA,YACG,gBAAgB,aACb,mBACA,uBACN,UAAU,MACP,gBAAgB,aACb,iBACA,iBACN,UAAU,QAAQ,SAAS,MACxB,gBAAgB,aACb,iBACA,eACR;MAEC,UAAA,KAAK;KACA,CAAA;IACgB,CAAA,IAE1B,oBAAC,OAAD;KACE,IAAI,YAAY,KAAK;KACV;KACX,WAAW,GAAG,YAAY,IAAI;KAC9B,OAAO,KAAK;KACH;KACT,UAAU,YAAY,KAAK;KAC3B,WAAU,YAAW,SAAS,SAAS,KAAK,KAAK;KAEhD,UAAA,KAAK;IACD,CAAA;GAEP,GAhEG,GAAG,MAAM,GAAG,OAAO,KAAK,KAAK,GAgEhC;EAER,CAAC;CACC,CAAA;CAGN,OACE,oBAAC,kBAAkB,UAAnB;EAA4B,OAAO;EACjC,UAAA,oBAAC,MAAD;GACE,WAAU;GACJ;GACN,OAAO;GACQ;GAEd,UAAA;EACG,CAAA;CACoB,CAAA;AAEhC"}
1
+ {"version":3,"file":"group.mjs","names":["radio","RadioPrimitive","Radio"],"sources":["../../../../src/components/atoms/radio/group.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\n\nimport { Radio as RadioPrimitive } from '@base-ui/react/radio';\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { radio } from '../../../core';\nimport Button from '../button';\nimport {\n type Option,\n type OptionGroupClassNames,\n type OptionValue,\n type Options,\n normalizeOptions,\n warnOnDuplicateOptionValues,\n} from '../option-group';\nimport { RadioGroupContext } from './context';\nimport Radio from './radio';\n\nconst { RadioGroup: Core } = radio;\n\nexport type { OptionValue };\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'ul'>,\n 'onChange' | 'defaultValue' | 'value'\n> {\n options?: Options;\n orientation?: 'vertical' | 'horizontal';\n placement?: 'left' | 'right';\n classNames?: OptionGroupClassNames;\n defaultValue?: OptionValue;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n optionType?: 'default' | 'button';\n buttonStyle?: 'solid' | 'outlined';\n size?: 'small' | 'middle' | 'large';\n disabled?: boolean;\n onChange?: (value: OptionValue) => void;\n}\n\nconst RadioGroup = ({\n orientation = 'horizontal',\n placement = 'left',\n className,\n classNames = {},\n options: _options = [],\n name,\n optionType = 'default',\n buttonStyle = 'solid',\n size,\n disabled,\n defaultValue,\n value: _value,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [value, setValue] = useControllableState<OptionValue>({\n value: _value,\n defaultValue,\n onChange: _onChange,\n });\n\n const options: Option[] = normalizeOptions(_options);\n warnOnDuplicateOptionValues(options, 'Radio.Group');\n\n const isButton = optionType === 'button';\n\n const onChange = (checked: boolean, optionValue: OptionValue) => {\n if (!checked) {\n return;\n }\n setValue(optionValue);\n };\n\n // A single Base UI RadioGroup root owns every option so that arrow keys\n // move focus across the whole group. `id` stays index-derived (for DOM\n // id/label pairing), but Base UI itself addresses/submits items by their\n // real (stringified) `value` — see radio.tsx.\n const baseId = useId();\n const getOptionId = (index: number) => `${baseId}-${index}`;\n const checkedItemValue = value === undefined ? '' : String(value);\n\n const onValueChange = (itemValue: string) => {\n const item = options.find(option => String(option.value) === itemValue);\n\n if (!item) {\n return;\n }\n\n onChange(true, item.value);\n };\n\n const list = (\n <ul\n {...props}\n className={cn(\n 'm-0 flex list-none gap-4 p-0',\n className,\n orientation === 'vertical' && 'flex-col',\n isButton && 'gap-0',\n )}\n >\n {options.map((item: Option, index) => {\n const checked = value === item.value;\n\n return (\n <li\n key={`${index}-${String(item.value)}`}\n // `m-0` completes the list reset the `ul` above starts (#253):\n // without preflight, hosts that style prose lists still reach the\n // items — Docusaurus/Infima's `.markdown li + li` gives every item\n // but the first a `margin-top`, which in horizontal orientation\n // drops options 2..n by that much and stretches the first one,\n // making it look misaligned.\n className={cn('m-0 flex', classNames?.wrapper)}\n >\n {isButton ? (\n // `render` gives the Button real radio semantics (role,\n // aria-checked, roving tabindex, arrow-key nav, click/keyboard\n // selection via the shared Core's onValueChange below) instead\n // of a plain list of buttons with none of that. Base UI has no\n // `asChild`; its `render` prop merges the primitive's props onto\n // the Button element. Uses the Radio primitive directly (not\n // `core/RadioGroupItem`) so the core stays a plain default item;\n // the `data-slot` matches what that item emits.\n <RadioPrimitive.Root\n data-slot=\"radio-group-item\"\n value={String(item.value)}\n disabled={disabled || item.disabled}\n // The Button below renders a real `<button>`, so tell Base UI\n // it's a native button — otherwise `useButton` synthesises\n // Enter/Space activation for a non-native element and would\n // double-handle keyboard selection.\n nativeButton\n render={\n <Button\n variant={checked ? buttonStyle : 'outlined'}\n size={size}\n disabled={disabled || item.disabled}\n className={cn(\n // The `solid` variant (the checked item, by default)\n // renders no border at all while `outlined` (every\n // unchecked item) renders a 1px one — reserving the\n // border unconditionally keeps every option's box the\n // same size regardless of which variant it's in.\n 'rounded-none border',\n checked &&\n (buttonStyle === 'outlined'\n ? 'border-primary'\n : 'border-transparent'),\n index === 0 &&\n (orientation === 'vertical'\n ? 'rounded-t-lg'\n : 'rounded-l-lg'),\n index === options.length - 1 &&\n (orientation === 'vertical'\n ? 'rounded-b-lg'\n : 'rounded-r-lg'),\n )}\n >\n {item.label}\n </Button>\n }\n />\n ) : (\n <Radio\n id={getOptionId(index)}\n placement={placement}\n className={cn(classNames?.item)}\n value={item.value}\n checked={checked}\n disabled={disabled || item.disabled}\n onChange={checked => onChange(checked, item.value)}\n >\n {item.label}\n </Radio>\n )}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <RadioGroupContext.Provider value={true}>\n <Core\n className=\"block\"\n name={name}\n value={checkedItemValue}\n onValueChange={onValueChange}\n >\n {list}\n </Core>\n </RadioGroupContext.Provider>\n );\n};\n\nexport default RadioGroup;\n"],"mappings":";;;;;;;;;;;;AAsBA,MAAM,EAAE,YAAY,SAASA;AAuB7B,MAAM,cAAc,EAClB,cAAc,cACd,YAAY,QACZ,WACA,aAAa,CAAC,GACd,SAAS,WAAW,CAAC,GACrB,MACA,aAAa,WACb,cAAc,SACd,MACA,UACA,cACA,OAAO,QACP,UAAU,kBAAkB,CAAC,GAC7B,GAAG,YACQ;CACX,MAAM,CAAC,OAAO,YAAY,qBAAkC;EAC1D,OAAO;EACP;EACA,UAAU;CACZ,CAAC;CAED,MAAM,UAAoB,iBAAiB,QAAQ;CACnD,4BAA4B,SAAS,aAAa;CAElD,MAAM,WAAW,eAAe;CAEhC,MAAM,YAAY,SAAkB,gBAA6B;EAC/D,IAAI,CAAC,SACH;EAEF,SAAS,WAAW;CACtB;CAMA,MAAM,SAAS,MAAM;CACrB,MAAM,eAAe,UAAkB,GAAG,OAAO,GAAG;CACpD,MAAM,mBAAmB,UAAU,KAAA,IAAY,KAAK,OAAO,KAAK;CAEhE,MAAM,iBAAiB,cAAsB;EAC3C,MAAM,OAAO,QAAQ,MAAK,WAAU,OAAO,OAAO,KAAK,MAAM,SAAS;EAEtE,IAAI,CAAC,MACH;EAGF,SAAS,MAAM,KAAK,KAAK;CAC3B;CAEA,MAAM,OACJ,oBAAC,MAAD;EACE,GAAI;EACJ,WAAW,GACT,gCACA,WACA,gBAAgB,cAAc,YAC9B,YAAY,OACd;EAEC,UAAA,QAAQ,KAAK,MAAc,UAAU;GACpC,MAAM,UAAU,UAAU,KAAK;GAE/B,OACE,oBAAC,MAAD;IAQE,WAAW,GAAG,YAAY,YAAY,OAAO;IAE5C,UAAA,WASC,oBAACC,MAAe,MAAhB;KACE,aAAU;KACV,OAAO,OAAO,KAAK,KAAK;KACxB,UAAU,YAAY,KAAK;KAK3B,cAAA;KACA,QACE,oBAAC,QAAD;MACE,SAAS,UAAU,cAAc;MAC3B;MACN,UAAU,YAAY,KAAK;MAC3B,WAAW,GAMT,uBACA,YACG,gBAAgB,aACb,mBACA,uBACN,UAAU,MACP,gBAAgB,aACb,iBACA,iBACN,UAAU,QAAQ,SAAS,MACxB,gBAAgB,aACb,iBACA,eACR;MAEC,UAAA,KAAK;KACA,CAAA;IAEX,CAAA,IAED,oBAACC,SAAD;KACE,IAAI,YAAY,KAAK;KACV;KACX,WAAW,GAAG,YAAY,IAAI;KAC9B,OAAO,KAAK;KACH;KACT,UAAU,YAAY,KAAK;KAC3B,WAAU,YAAW,SAAS,SAAS,KAAK,KAAK;KAEhD,UAAA,KAAK;IACD,CAAA;GAEP,GAtEG,GAAG,MAAM,GAAG,OAAO,KAAK,KAAK,GAsEhC;EAER,CAAC;CACC,CAAA;CAGN,OACE,oBAAC,kBAAkB,UAAnB;EAA4B,OAAO;EACjC,UAAA,oBAAC,MAAD;GACE,WAAU;GACJ;GACN,OAAO;GACQ;GAEd,UAAA;EACG,CAAA;CACoB,CAAA;AAEhC"}
@@ -1,9 +1,6 @@
1
- import { RadioGroup } from "../../../core/radio-group.mjs";
2
- import "../../../core/index.mjs";
3
1
  import { OptionValue } from "../option-group.mjs";
4
2
  //#region src/components/atoms/radio/radio.d.ts
5
- declare const Core: typeof RadioGroup;
6
- interface Props extends Omit<React.ComponentPropsWithoutRef<typeof Core>, 'onChange' | 'value'> {
3
+ interface Props extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange'> {
7
4
  placement?: 'left' | 'right';
8
5
  defaultChecked?: boolean;
9
6
  checked?: boolean;
@@ -14,7 +11,7 @@ interface Props extends Omit<React.ComponentPropsWithoutRef<typeof Core>, 'onCha
14
11
  /**
15
12
  * Id shared by the underlying control and its label. Generated internally
16
13
  * when omitted. `RadioGroup` passes a deterministic id so that the group's
17
- * single Radix root can address each option.
14
+ * single Base UI root can address each option.
18
15
  */
19
16
  id?: string;
20
17
  icons?: Partial<{
@@ -1 +1 @@
1
- {"version":3,"file":"radio.d.mts","names":[],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"mappings":";;;;cAaoB,aAAI;UAGP,cAAc,KAC7B,MAAM,gCAAgC;EAGtC;EACA;EACA;EACA,QAAQ;;EAER;EACA;;;;;;EAMA;EACA,QAAQ;IAAU,SAAS,MAAM;IAAW,WAAW,MAAM;;EAC7D,YAAY;;cAGR,UAAS,WAAA,OAAA,QAAA,UAAA,WAAA,OAAA,UAAA,gBAAA,SAAA,UAAA,IAAA,KAAA,MAAA,UAAA,cAAA,SAaZ,0BAAK,IAAA"}
1
+ {"version":3,"file":"radio.d.mts","names":[],"sources":["../../../../src/components/atoms/radio/radio.tsx"],"mappings":";;UAoBiB,cAAc,KAC7B,MAAM;EAGN;EACA;EACA;EACA,QAAQ;;EAER;EACA;;;;;;EAMA;EACA,QAAQ;IAAU,SAAS,MAAM;IAAW,WAAW,MAAM;;EAC7D,YAAY;;cAGR,UAAS,WAAA,OAAA,QAAA,UAAA,WAAA,OAAA,UAAA,gBAAA,SAAA,UAAA,IAAA,KAAA,MAAA,UAAA,cAAA,SAaZ,0BAAK,IAAA"}
@@ -40,7 +40,6 @@ const Radio = ({ placement = "left", value: _value = "", children, className, ic
40
40
  children: [/* @__PURE__ */ jsx(Item, {
41
41
  value: itemValue,
42
42
  id,
43
- checked,
44
43
  disabled
45
44
  }), /* @__PURE__ */ jsx(FieldLabel, {
46
45
  htmlFor: id,
@@ -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, useRef } from 'react';\n\nimport { useControllableState, useKeyPress } from '@jbpark/use-hooks';\nimport { Circle, CircleCheck } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { field, radio } from '../../../core';\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,CAAC,GAC7B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;CACZ,CAAC;CAED,MAAM,cAAc,MAAM;CAC1B,MAAM,KAAK,OAAO;CAIlB,MAAM,YAAY,OAAO,MAAM;CAC/B,MAAM,UAAU,WAAW,iBAAiB;CAE5C,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;EAClC,IAAI,UACF;EAGF,WAAW,IAAI;CACjB;CAEA,MAAM,iBAAiB,OAAwB,IAAI;CAEnD,YACE,CAAC,SAAS,OAAO,IACjB,UAAS;EACP,MAAM,eAAe;EACrB,SAAS,IAAI;CACf,GACA;EAAE,QAAQ;EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;CAAS,CAC1D;CAKA,MAAM,cACJ,qBAAC,OAAD;EACE,aAAY;EACZ,WAAW,GAAG,cAAc,cAAc,WAAW,kBAAkB;EACvE,iBAAe;EAHjB,UAAA,CAKE,oBAAC,MAAD;GAAM,OAAO;GAAe;GAAa;GAAmB;EAAW,CAAA,GACvE,oBAAC,YAAD;GAAY,SAAS;GAAI,WAAW;GACjC;EACS,CAAA,CACP;;CAGT,MAAM,gBAAgB,QACpB,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,SAAD;GACM;GACJ,QAAA;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;IACb,SAAS,EAAE,OAAO,OAAO;GAC3B;EACD,CAAA;EACD,oBAAC,QAAD;GACE,KAAK;GACL,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,eAAe;IACb,SAAS,IAAI;GACf;GAEC,UAAA,UACI,MAAM,WAAW,oBAAC,aAAD,CAAc,CAAA,IAC/B,MAAM,aAAa,oBAAC,QAAD,CAAS,CAAA;EAC7B,CAAA;EACL,YACC,oBAAC,SAAD;GACE,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,SAAS;GAER;EACI,CAAA;CAET,EAAA,CAAA,IACA,UACF,cAEA,oBAAC,MAAD;EACQ;EACN,OAAO,UAAU,YAAY;EAC7B,qBAAqB,SAAS,IAAI;EAEjC,UAAA;CACG,CAAA;CAGR,OACE,oBAAC,OAAD;EACE,WAAW,GACT,qBACA,SAAS,cAAc,WAAW,oBAClC,iBACA,SAEF;EACA,GAAI;EAEH,UAAA;CACE,CAAA;AAET"}
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 { cn } from '@repo/ui/utils';\n\nimport { field, radio } from '../../../core';\nimport { RadioGroupContext } from './context';\nimport { type OptionValue } from './group';\n\nconst { RadioGroup: Core, RadioGroupItem: Item } = radio;\nconst { Field, FieldLabel } = field;\n\n// Spreads onto the wrapper `<div>`, so the host props are div-based. (Base UI's\n// `RadioGroup` — `Core` here — types `style`/`className` as state callbacks,\n// which a native `<div>` can't take; the meaningful control props below are\n// re-declared explicitly anyway.)\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 /**\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 Base UI 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 // Base UI identifies/submits an item by its `value`, which is separate\n // from `id` (used only for the DOM id/label pairing) — stringified since\n // the group value is a string, while `OptionValue` also allows\n // 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` (Base UI RadioGroup root) so that arrow keys move focus across\n // every 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} 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;AA2B9B,MAAM,SAAS,EACb,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,IAAI,KACJ,MACA,UAAU,kBAAkB,CAAC,GAC7B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;CACZ,CAAC;CAED,MAAM,cAAc,MAAM;CAC1B,MAAM,KAAK,OAAO;CAKlB,MAAM,YAAY,OAAO,MAAM;CAC/B,MAAM,UAAU,WAAW,iBAAiB;CAE5C,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;EAClC,IAAI,UACF;EAGF,WAAW,IAAI;CACjB;CAEA,MAAM,iBAAiB,OAAwB,IAAI;CAEnD,YACE,CAAC,SAAS,OAAO,IACjB,UAAS;EACP,MAAM,eAAe;EACrB,SAAS,IAAI;CACf,GACA;EAAE,QAAQ;EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;CAAS,CAC1D;CAKA,MAAM,cACJ,qBAAC,OAAD;EACE,aAAY;EACZ,WAAW,GAAG,cAAc,cAAc,WAAW,kBAAkB;EACvE,iBAAe;EAHjB,UAAA,CAKE,oBAAC,MAAD;GAAM,OAAO;GAAe;GAAc;EAAW,CAAA,GACrD,oBAAC,YAAD;GAAY,SAAS;GAAI,WAAW;GACjC;EACS,CAAA,CACP;;CAGT,MAAM,gBAAgB,QACpB,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,SAAD;GACM;GACJ,QAAA;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;IACb,SAAS,EAAE,OAAO,OAAO;GAC3B;EACD,CAAA;EACD,oBAAC,QAAD;GACE,KAAK;GACL,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,eAAe;IACb,SAAS,IAAI;GACf;GAEC,UAAA,UACI,MAAM,WAAW,oBAAC,aAAD,CAAc,CAAA,IAC/B,MAAM,aAAa,oBAAC,QAAD,CAAS,CAAA;EAC7B,CAAA;EACL,YACC,oBAAC,SAAD;GACE,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,SAAS;GAER;EACI,CAAA;CAET,EAAA,CAAA,IACA,UACF,cAEA,oBAAC,MAAD;EACQ;EACN,OAAO,UAAU,YAAY;EAC7B,qBAAqB,SAAS,IAAI;EAEjC,UAAA;CACG,CAAA;CAGR,OACE,oBAAC,OAAD;EACE,WAAW,GACT,qBACA,SAAS,cAAc,WAAW,oBAClC,iBACA,SAEF;EACA,GAAI;EAEH,UAAA;CACE,CAAA;AAET"}
@@ -1,6 +1,6 @@
1
1
  import { cn } from "../../../utils.mjs";
2
2
  //#region src/components/atoms/rich-text-editor/content-classes.ts
3
- const RICH_TEXT_CONTENT_CLASSES = cn("[&_.tiptap]:outline-none", "[&_.tiptap>*:first-child]:mt-0", "[&_.tiptap_h1]:mt-6", "[&_.tiptap_h1]:mb-2", "[&_.tiptap_h1]:text-2xl", "[&_.tiptap_h1]:font-bold", "[&_.tiptap_h2]:mt-5", "[&_.tiptap_h2]:mb-2", "[&_.tiptap_h2]:text-xl", "[&_.tiptap_h2]:font-bold", "[&_.tiptap_h3]:mt-4", "[&_.tiptap_h3]:mb-2", "[&_.tiptap_h3]:text-lg", "[&_.tiptap_h3]:font-semibold", "[&_.tiptap_h4]:mt-3", "[&_.tiptap_h4]:mb-1", "[&_.tiptap_h4]:text-base", "[&_.tiptap_h4]:font-semibold", "[&_.tiptap_ul]:my-2", "[&_.tiptap_ul]:list-disc", "[&_.tiptap_ul]:pl-5", "[&_.tiptap_ol]:my-2", "[&_.tiptap_ol]:list-decimal", "[&_.tiptap_ol]:pl-5", "[&_.tiptap_li]:my-1", "[&_.tiptap_blockquote]:my-2", "[&_.tiptap_blockquote]:border-l-2", "[&_.tiptap_blockquote]:border-gray-300", "[&_.tiptap_blockquote]:pl-3", "[&_.tiptap_blockquote]:text-gray-600", "[&_.tiptap_blockquote]:italic", "[&_.tiptap_pre]:overflow-x-auto", "[&_.tiptap_pre]:my-2", "[&_.tiptap_pre]:rounded", "[&_.tiptap_pre]:bg-gray-900", "[&_.tiptap_pre]:p-3", "[&_.tiptap_pre]:font-mono", "[&_.tiptap_pre]:text-sm", "[&_.tiptap_pre]:text-gray-100", "[&_.tiptap_pre_code]:bg-transparent", "[&_.tiptap_pre_code]:p-0", "[&_.tiptap_pre_code]:text-inherit", "[&_.tiptap_code]:rounded", "[&_.tiptap_code]:bg-gray-100", "[&_.tiptap_code]:px-1", "[&_.tiptap_code]:py-0.5", "[&_.tiptap_code]:font-mono", "[&_.tiptap_code]:text-[0.85em]", "[&_.tiptap_hr]:my-4", "[&_.tiptap_hr]:border-gray-200", "[&_.tiptap_a]:text-blue-600", "[&_.tiptap_a]:underline", "[&_.tiptap_a]:underline-offset-2", "[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:float-left", "[&_.tiptap_p.is-editor-empty:first-child::before]:h-0", "[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400", "[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]");
3
+ const RICH_TEXT_CONTENT_CLASSES = cn("[&_.tiptap]:outline-none", "[&_.tiptap>*:first-child]:mt-0", "[&_.tiptap_h1]:mt-6", "[&_.tiptap_h1]:mb-2", "[&_.tiptap_h1]:text-2xl", "[&_.tiptap_h1]:font-bold", "[&_.tiptap_h2]:mt-5", "[&_.tiptap_h2]:mb-2", "[&_.tiptap_h2]:text-xl", "[&_.tiptap_h2]:font-bold", "[&_.tiptap_h3]:mt-4", "[&_.tiptap_h3]:mb-2", "[&_.tiptap_h3]:text-lg", "[&_.tiptap_h3]:font-semibold", "[&_.tiptap_h4]:mt-3", "[&_.tiptap_h4]:mb-1", "[&_.tiptap_h4]:text-base", "[&_.tiptap_h4]:font-semibold", "[&_.tiptap_ul]:my-2", "[&_.tiptap_ul]:list-disc", "[&_.tiptap_ul]:pl-5", "[&_.tiptap_ol]:my-2", "[&_.tiptap_ol]:list-decimal", "[&_.tiptap_ol]:pl-5", "[&_.tiptap_li]:my-1", "[&_.tiptap_blockquote]:my-2", "[&_.tiptap_blockquote]:border-l-2", "[&_.tiptap_blockquote]:border-border", "[&_.tiptap_blockquote]:pl-3", "[&_.tiptap_blockquote]:text-muted-foreground", "[&_.tiptap_blockquote]:italic", "[&_.tiptap_pre]:overflow-x-auto", "[&_.tiptap_pre]:my-2", "[&_.tiptap_pre]:rounded", "[&_.tiptap_pre]:bg-foreground", "[&_.tiptap_pre]:p-3", "[&_.tiptap_pre]:font-mono", "[&_.tiptap_pre]:text-sm", "[&_.tiptap_pre]:text-background", "[&_.tiptap_pre_code]:bg-transparent", "[&_.tiptap_pre_code]:p-0", "[&_.tiptap_pre_code]:text-inherit", "[&_.tiptap_code]:rounded", "[&_.tiptap_code]:bg-muted", "[&_.tiptap_code]:px-1", "[&_.tiptap_code]:py-0.5", "[&_.tiptap_code]:font-mono", "[&_.tiptap_code]:text-[0.85em]", "[&_.tiptap_hr]:my-4", "[&_.tiptap_hr]:border-border", "[&_.tiptap_a]:underline", "[&_.tiptap_a]:underline-offset-2", "[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:float-left", "[&_.tiptap_p.is-editor-empty:first-child::before]:h-0", "[&_.tiptap_p.is-editor-empty:first-child::before]:text-muted-foreground", "[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]");
4
4
  //#endregion
5
5
  export { RICH_TEXT_CONTENT_CLASSES };
6
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"content-classes.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/content-classes.ts"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\n// The package ships no global Tailwind preflight (see src/globals.css), and a\n// host that runs its own preflight (most do) resets bare h1-h6/ul/ol/blockquote\n// to look like plain text. Since the toolbar can now produce all of these\n// nodes, they need their own scoped typography here or toggling them would be\n// visibly a no-op. Selectors are written out per Tailwind utility (not built\n// via string interpolation) because v4 only extracts class candidates that\n// appear as literal strings in source (see popover.tsx's arrow-class comment).\nexport const RICH_TEXT_CONTENT_CLASSES = cn(\n '[&_.tiptap]:outline-none',\n // Every block element (p/h1/ul/blockquote/...) carries its own UA top\n // margin — without this, the first one stacks on top of the box's own\n // py-2, doubling the padding visually.\n '[&_.tiptap>*:first-child]:mt-0',\n\n '[&_.tiptap_h1]:mt-6',\n '[&_.tiptap_h1]:mb-2',\n '[&_.tiptap_h1]:text-2xl',\n '[&_.tiptap_h1]:font-bold',\n '[&_.tiptap_h2]:mt-5',\n '[&_.tiptap_h2]:mb-2',\n '[&_.tiptap_h2]:text-xl',\n '[&_.tiptap_h2]:font-bold',\n '[&_.tiptap_h3]:mt-4',\n '[&_.tiptap_h3]:mb-2',\n '[&_.tiptap_h3]:text-lg',\n '[&_.tiptap_h3]:font-semibold',\n '[&_.tiptap_h4]:mt-3',\n '[&_.tiptap_h4]:mb-1',\n '[&_.tiptap_h4]:text-base',\n '[&_.tiptap_h4]:font-semibold',\n\n '[&_.tiptap_ul]:my-2',\n '[&_.tiptap_ul]:list-disc',\n '[&_.tiptap_ul]:pl-5',\n '[&_.tiptap_ol]:my-2',\n '[&_.tiptap_ol]:list-decimal',\n '[&_.tiptap_ol]:pl-5',\n '[&_.tiptap_li]:my-1',\n\n '[&_.tiptap_blockquote]:my-2',\n '[&_.tiptap_blockquote]:border-l-2',\n '[&_.tiptap_blockquote]:border-gray-300',\n '[&_.tiptap_blockquote]:pl-3',\n '[&_.tiptap_blockquote]:text-gray-600',\n '[&_.tiptap_blockquote]:italic',\n\n // A long unwrapped code line would otherwise blow out the box width.\n '[&_.tiptap_pre]:overflow-x-auto',\n '[&_.tiptap_pre]:my-2',\n '[&_.tiptap_pre]:rounded',\n '[&_.tiptap_pre]:bg-gray-900',\n '[&_.tiptap_pre]:p-3',\n '[&_.tiptap_pre]:font-mono',\n '[&_.tiptap_pre]:text-sm',\n '[&_.tiptap_pre]:text-gray-100',\n // Reset the inline `code` treatment below when it's nested inside `pre`,\n // so a code block doesn't get a second (redundant) chip background.\n '[&_.tiptap_pre_code]:bg-transparent',\n '[&_.tiptap_pre_code]:p-0',\n '[&_.tiptap_pre_code]:text-inherit',\n '[&_.tiptap_code]:rounded',\n '[&_.tiptap_code]:bg-gray-100',\n '[&_.tiptap_code]:px-1',\n '[&_.tiptap_code]:py-0.5',\n '[&_.tiptap_code]:font-mono',\n '[&_.tiptap_code]:text-[0.85em]',\n\n '[&_.tiptap_hr]:my-4',\n '[&_.tiptap_hr]:border-gray-200',\n\n '[&_.tiptap_a]:text-blue-600',\n '[&_.tiptap_a]:underline',\n '[&_.tiptap_a]:underline-offset-2',\n\n '[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:float-left',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:h-0',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]',\n);\n"],"mappings":";;AASA,MAAa,4BAA4B,GACvC,4BAIA,kCAEA,uBACA,uBACA,2BACA,4BACA,uBACA,uBACA,0BACA,4BACA,uBACA,uBACA,0BACA,gCACA,uBACA,uBACA,4BACA,gCAEA,uBACA,4BACA,uBACA,uBACA,+BACA,uBACA,uBAEA,+BACA,qCACA,0CACA,+BACA,wCACA,iCAGA,mCACA,wBACA,2BACA,+BACA,uBACA,6BACA,2BACA,iCAGA,uCACA,4BACA,qCACA,4BACA,gCACA,yBACA,2BACA,8BACA,kCAEA,uBACA,kCAEA,+BACA,2BACA,oCAEA,yEACA,gEACA,yDACA,mEACA,oFACF"}
1
+ {"version":3,"file":"content-classes.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/content-classes.ts"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\n// The package ships no global Tailwind preflight (see src/globals.css), and a\n// host that runs its own preflight (most do) resets bare h1-h6/ul/ol/blockquote\n// to look like plain text. Since the toolbar can now produce all of these\n// nodes, they need their own scoped typography here or toggling them would be\n// visibly a no-op. Selectors are written out per Tailwind utility (not built\n// via string interpolation) because v4 only extracts class candidates that\n// appear as literal strings in source (see popover.tsx's arrow-class comment).\n//\n// Colours resolve from the theme tokens in globals.css, never from a fixed\n// palette step: a literal `bg-gray-100` renders the same in both schemes, so\n// the editor stayed a white card on a dark page. `bg-foreground`/\n// `text-background` on `pre` is deliberate — it is the one block that wants to\n// invert against the surface, and inverting the tokens keeps it legible in\n// either scheme without a `dark:` override.\nexport const RICH_TEXT_CONTENT_CLASSES = cn(\n '[&_.tiptap]:outline-none',\n // Every block element (p/h1/ul/blockquote/...) carries its own UA top\n // margin — without this, the first one stacks on top of the box's own\n // py-2, doubling the padding visually.\n '[&_.tiptap>*:first-child]:mt-0',\n\n '[&_.tiptap_h1]:mt-6',\n '[&_.tiptap_h1]:mb-2',\n '[&_.tiptap_h1]:text-2xl',\n '[&_.tiptap_h1]:font-bold',\n '[&_.tiptap_h2]:mt-5',\n '[&_.tiptap_h2]:mb-2',\n '[&_.tiptap_h2]:text-xl',\n '[&_.tiptap_h2]:font-bold',\n '[&_.tiptap_h3]:mt-4',\n '[&_.tiptap_h3]:mb-2',\n '[&_.tiptap_h3]:text-lg',\n '[&_.tiptap_h3]:font-semibold',\n '[&_.tiptap_h4]:mt-3',\n '[&_.tiptap_h4]:mb-1',\n '[&_.tiptap_h4]:text-base',\n '[&_.tiptap_h4]:font-semibold',\n\n '[&_.tiptap_ul]:my-2',\n '[&_.tiptap_ul]:list-disc',\n '[&_.tiptap_ul]:pl-5',\n '[&_.tiptap_ol]:my-2',\n '[&_.tiptap_ol]:list-decimal',\n '[&_.tiptap_ol]:pl-5',\n '[&_.tiptap_li]:my-1',\n\n '[&_.tiptap_blockquote]:my-2',\n '[&_.tiptap_blockquote]:border-l-2',\n '[&_.tiptap_blockquote]:border-border',\n '[&_.tiptap_blockquote]:pl-3',\n '[&_.tiptap_blockquote]:text-muted-foreground',\n '[&_.tiptap_blockquote]:italic',\n\n // A long unwrapped code line would otherwise blow out the box width.\n '[&_.tiptap_pre]:overflow-x-auto',\n '[&_.tiptap_pre]:my-2',\n '[&_.tiptap_pre]:rounded',\n '[&_.tiptap_pre]:bg-foreground',\n '[&_.tiptap_pre]:p-3',\n '[&_.tiptap_pre]:font-mono',\n '[&_.tiptap_pre]:text-sm',\n '[&_.tiptap_pre]:text-background',\n // Reset the inline `code` treatment below when it's nested inside `pre`,\n // so a code block doesn't get a second (redundant) chip background.\n '[&_.tiptap_pre_code]:bg-transparent',\n '[&_.tiptap_pre_code]:p-0',\n '[&_.tiptap_pre_code]:text-inherit',\n '[&_.tiptap_code]:rounded',\n '[&_.tiptap_code]:bg-muted',\n '[&_.tiptap_code]:px-1',\n '[&_.tiptap_code]:py-0.5',\n '[&_.tiptap_code]:font-mono',\n '[&_.tiptap_code]:text-[0.85em]',\n\n '[&_.tiptap_hr]:my-4',\n '[&_.tiptap_hr]:border-border',\n\n // No colour: this theme's `--primary` is achromatic (near-black in light,\n // near-white in dark), so `text-primary` would render the link at almost the\n // body colour and buy nothing. `Typography.Link` reaches the same conclusion\n // and styles links with the underline alone — match it.\n '[&_.tiptap_a]:underline',\n '[&_.tiptap_a]:underline-offset-2',\n\n '[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:float-left',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:h-0',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:text-muted-foreground',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]',\n);\n"],"mappings":";;AAgBA,MAAa,4BAA4B,GACvC,4BAIA,kCAEA,uBACA,uBACA,2BACA,4BACA,uBACA,uBACA,0BACA,4BACA,uBACA,uBACA,0BACA,gCACA,uBACA,uBACA,4BACA,gCAEA,uBACA,4BACA,uBACA,uBACA,+BACA,uBACA,uBAEA,+BACA,qCACA,wCACA,+BACA,gDACA,iCAGA,mCACA,wBACA,2BACA,iCACA,uBACA,6BACA,2BACA,mCAGA,uCACA,4BACA,qCACA,4BACA,6BACA,yBACA,2BACA,8BACA,kCAEA,uBACA,gCAMA,2BACA,oCAEA,yEACA,gEACA,yDACA,2EACA,oFACF"}
@@ -36,7 +36,7 @@ const RichTextEditor = ({ value = "", placeholder = "Enter text...", className,
36
36
  }, [value, editor]);
37
37
  return /* @__PURE__ */ jsxs("div", {
38
38
  "data-slot": "rich-text-editor",
39
- className: cn("rounded border border-gray-200 bg-white text-sm text-gray-800", className),
39
+ className: cn("border-input bg-background text-foreground rounded border text-sm", className),
40
40
  children: [showToolbar && editor && /* @__PURE__ */ jsx(Toolbar, {
41
41
  editor,
42
42
  presets,
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-editor.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { TextStyleKit } from '@tiptap/extension-text-style';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { RICH_TEXT_CONTENT_CLASSES } from './content-classes';\nimport Toolbar from './toolbar';\nimport { DEFAULT_TOOLBAR_PRESETS } from './toolbar-presets';\nimport type { ToolbarItem, ToolbarPreset } from './types';\n\nexport interface Props {\n value?: string;\n placeholder?: string;\n className?: string;\n classNames?: {\n toolbar?: string;\n content?: string;\n };\n /**\n * `true` shows every built-in preset; an array shows only the listed\n * presets, in the given order. Omitted or `false` renders no toolbar,\n * matching the original (toolbar-less) output.\n */\n toolbar?: boolean | ToolbarPreset[];\n /** Extra buttons appended after the built-in presets. */\n toolbarItems?: ToolbarItem[];\n onChange?: (value: string) => void;\n}\n\nconst RichTextEditor = ({\n value = '',\n placeholder = 'Enter text...',\n className,\n classNames,\n toolbar = false,\n toolbarItems,\n onChange,\n}: Props) => {\n const presets = toolbar === true ? DEFAULT_TOOLBAR_PRESETS : toolbar || [];\n const showToolbar = presets.length > 0 || (toolbarItems?.length ?? 0) > 0;\n\n const editor = useEditor({\n // SSR renders every exported component without effects running, so the\n // editor must not touch the DOM during that first pass — deferring\n // creation to mount keeps `renderToStaticMarkup` from throwing.\n immediatelyRender: false,\n extensions: [\n StarterKit,\n Placeholder.configure({ placeholder }),\n TextStyleKit.configure({\n fontFamily: false,\n lineHeight: false,\n backgroundColor: false,\n }),\n ],\n content: value,\n onBlur: ({ editor: e }) => {\n onChange?.(e.getHTML());\n },\n // @tiptap/react v3 only re-renders on selection/transaction changes when\n // explicitly opted in — the toolbar's isActive()/getAttributes() reads\n // need that to reflect the caret position live.\n shouldRerenderOnTransaction: showToolbar,\n });\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const current = editor.getHTML();\n\n if (current !== value) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }, [value, editor]);\n\n return (\n <div\n data-slot=\"rich-text-editor\"\n className={cn(\n 'rounded border border-gray-200 bg-white text-sm text-gray-800',\n className,\n //\n )}\n >\n {showToolbar && editor && (\n <Toolbar\n editor={editor}\n presets={presets}\n items={toolbarItems}\n className={classNames?.toolbar}\n />\n )}\n <div\n data-slot=\"rich-text-editor-content\"\n className={cn(\n 'min-h-20 px-3 py-2',\n RICH_TEXT_CONTENT_CLASSES,\n classNames?.content,\n //\n )}\n >\n <EditorContent editor={editor} />\n </div>\n </div>\n );\n};\n\nexport default RichTextEditor;\n"],"mappings":";;;;;;;;;;;;AAmCA,MAAM,kBAAkB,EACtB,QAAQ,IACR,cAAc,iBACd,WACA,YACA,UAAU,OACV,cACA,eACW;CACX,MAAM,UAAU,YAAY,OAAO,0BAA0B,WAAW,CAAC;CACzE,MAAM,cAAc,QAAQ,SAAS,MAAM,cAAc,UAAU,KAAK;CAExE,MAAM,SAAS,UAAU;EAIvB,mBAAmB;EACnB,YAAY;GACV;GACA,YAAY,UAAU,EAAE,YAAY,CAAC;GACrC,aAAa,UAAU;IACrB,YAAY;IACZ,YAAY;IACZ,iBAAiB;GACnB,CAAC;EACH;EACA,SAAS;EACT,SAAS,EAAE,QAAQ,QAAQ;GACzB,WAAW,EAAE,QAAQ,CAAC;EACxB;EAIA,6BAA6B;CAC/B,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,QACH;EAKF,IAFgB,OAAO,QAEb,MAAM,OACd,OAAO,SAAS,WAAW,OAAO,EAAE,YAAY,MAAM,CAAC;CAE3D,GAAG,CAAC,OAAO,MAAM,CAAC;CAElB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,iEACA,SAEF;EANF,UAAA,CAQG,eAAe,UACd,oBAAC,SAAD;GACU;GACC;GACT,OAAO;GACP,WAAW,YAAY;EACxB,CAAA,GAEH,oBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,sBACA,2BACA,YAAY,OAEd;GAEA,UAAA,oBAAC,eAAD,EAAuB,OAAS,CAAA;EAC7B,CAAA,CACF;;AAET"}
1
+ {"version":3,"file":"rich-text-editor.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { TextStyleKit } from '@tiptap/extension-text-style';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { RICH_TEXT_CONTENT_CLASSES } from './content-classes';\nimport Toolbar from './toolbar';\nimport { DEFAULT_TOOLBAR_PRESETS } from './toolbar-presets';\nimport type { ToolbarItem, ToolbarPreset } from './types';\n\nexport interface Props {\n value?: string;\n placeholder?: string;\n className?: string;\n classNames?: {\n toolbar?: string;\n content?: string;\n };\n /**\n * `true` shows every built-in preset; an array shows only the listed\n * presets, in the given order. Omitted or `false` renders no toolbar,\n * matching the original (toolbar-less) output.\n */\n toolbar?: boolean | ToolbarPreset[];\n /** Extra buttons appended after the built-in presets. */\n toolbarItems?: ToolbarItem[];\n onChange?: (value: string) => void;\n}\n\nconst RichTextEditor = ({\n value = '',\n placeholder = 'Enter text...',\n className,\n classNames,\n toolbar = false,\n toolbarItems,\n onChange,\n}: Props) => {\n const presets = toolbar === true ? DEFAULT_TOOLBAR_PRESETS : toolbar || [];\n const showToolbar = presets.length > 0 || (toolbarItems?.length ?? 0) > 0;\n\n const editor = useEditor({\n // SSR renders every exported component without effects running, so the\n // editor must not touch the DOM during that first pass — deferring\n // creation to mount keeps `renderToStaticMarkup` from throwing.\n immediatelyRender: false,\n extensions: [\n StarterKit,\n Placeholder.configure({ placeholder }),\n TextStyleKit.configure({\n fontFamily: false,\n lineHeight: false,\n backgroundColor: false,\n }),\n ],\n content: value,\n onBlur: ({ editor: e }) => {\n onChange?.(e.getHTML());\n },\n // @tiptap/react v3 only re-renders on selection/transaction changes when\n // explicitly opted in — the toolbar's isActive()/getAttributes() reads\n // need that to reflect the caret position live.\n shouldRerenderOnTransaction: showToolbar,\n });\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const current = editor.getHTML();\n\n if (current !== value) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }, [value, editor]);\n\n return (\n <div\n data-slot=\"rich-text-editor\"\n className={cn(\n 'border-input bg-background text-foreground rounded border text-sm',\n className,\n //\n )}\n >\n {showToolbar && editor && (\n <Toolbar\n editor={editor}\n presets={presets}\n items={toolbarItems}\n className={classNames?.toolbar}\n />\n )}\n <div\n data-slot=\"rich-text-editor-content\"\n className={cn(\n 'min-h-20 px-3 py-2',\n RICH_TEXT_CONTENT_CLASSES,\n classNames?.content,\n //\n )}\n >\n <EditorContent editor={editor} />\n </div>\n </div>\n );\n};\n\nexport default RichTextEditor;\n"],"mappings":";;;;;;;;;;;;AAmCA,MAAM,kBAAkB,EACtB,QAAQ,IACR,cAAc,iBACd,WACA,YACA,UAAU,OACV,cACA,eACW;CACX,MAAM,UAAU,YAAY,OAAO,0BAA0B,WAAW,CAAC;CACzE,MAAM,cAAc,QAAQ,SAAS,MAAM,cAAc,UAAU,KAAK;CAExE,MAAM,SAAS,UAAU;EAIvB,mBAAmB;EACnB,YAAY;GACV;GACA,YAAY,UAAU,EAAE,YAAY,CAAC;GACrC,aAAa,UAAU;IACrB,YAAY;IACZ,YAAY;IACZ,iBAAiB;GACnB,CAAC;EACH;EACA,SAAS;EACT,SAAS,EAAE,QAAQ,QAAQ;GACzB,WAAW,EAAE,QAAQ,CAAC;EACxB;EAIA,6BAA6B;CAC/B,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,QACH;EAKF,IAFgB,OAAO,QAEb,MAAM,OACd,OAAO,SAAS,WAAW,OAAO,EAAE,YAAY,MAAM,CAAC;CAE3D,GAAG,CAAC,OAAO,MAAM,CAAC;CAElB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,qEACA,SAEF;EANF,UAAA,CAQG,eAAe,UACd,oBAAC,SAAD;GACU;GACC;GACT,OAAO;GACP,WAAW,YAAY;EACxB,CAAA,GAEH,oBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,sBACA,2BACA,YAAY,OAEd;GAEA,UAAA,oBAAC,eAAD,EAAuB,OAAS,CAAA;EAC7B,CAAA,CACF;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"toolbar-button.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar-button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Button, { type Props as ButtonProps } from '../button';\n\nexport interface ToolbarButtonProps extends Omit<\n ButtonProps,\n 'type' | 'shape' | 'size'\n> {\n active?: boolean;\n}\n\nconst ToolbarButton = ({ active, className, ...props }: ToolbarButtonProps) => (\n <Button\n // Spread first: when this button sits inside a `Popover` trigger\n // (`asChild`), Radix injects its own native `type=\"button\"` onto us for\n // form-submit safety — that's a different `type` than Button's own\n // antd-style color/variant switch, and if it landed after these three,\n // it would silently override `type=\"text\"` and fall through to the\n // `outlined` variant's border.\n {...props}\n type=\"text\"\n size=\"small\"\n shape=\"default\"\n aria-pressed={active}\n className={cn(active && 'bg-accent', className)}\n />\n);\n\nexport default ToolbarButton;\n"],"mappings":";;;;AAWA,MAAM,iBAAiB,EAAE,QAAQ,WAAW,GAAG,YAC7C,oBAAC,QAAD;CAOE,GAAI;CACJ,MAAK;CACL,MAAK;CACL,OAAM;CACN,gBAAc;CACd,WAAW,GAAG,UAAU,aAAa,SAAS;AAC/C,CAAA"}
1
+ {"version":3,"file":"toolbar-button.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar-button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Button, { type Props as ButtonProps } from '../button';\n\nexport interface ToolbarButtonProps extends Omit<\n ButtonProps,\n 'type' | 'shape' | 'size'\n> {\n active?: boolean;\n}\n\nconst ToolbarButton = ({ active, className, ...props }: ToolbarButtonProps) => (\n <Button\n // Spread first so composition props cannot override Button's antd-style\n // color/variant switch below.\n {...props}\n type=\"text\"\n size=\"small\"\n shape=\"default\"\n aria-pressed={active}\n className={cn(active && 'bg-accent', className)}\n />\n);\n\nexport default ToolbarButton;\n"],"mappings":";;;;AAWA,MAAM,iBAAiB,EAAE,QAAQ,WAAW,GAAG,YAC7C,oBAAC,QAAD;CAGE,GAAI;CACJ,MAAK;CACL,MAAK;CACL,OAAM;CACN,gBAAc;CACd,WAAW,GAAG,UAAU,aAAa,SAAS;AAC/C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"toolbar-presets.mjs","names":["LinkIcon"],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar-presets.tsx"],"sourcesContent":["'use client';\n\nimport { type ReactNode, useState } from 'react';\n\nimport type { Editor } from '@tiptap/core';\nimport {\n Bold,\n Code,\n Code2,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n Quote,\n Redo2,\n Strikethrough,\n Underline,\n Undo2,\n} from 'lucide-react';\n\nimport Button from '../button';\nimport ColorPicker from '../color-picker';\nimport Input from '../input';\nimport Popover from '../popover';\nimport Select from '../select';\nimport ToolbarButton from './toolbar-button';\nimport type { ToolbarPreset } from './types';\n\nconst FONT_SIZE_OPTIONS = [\n { label: '12', value: '12px' },\n { label: '14', value: '14px' },\n { label: '16', value: '16px' },\n { label: '18', value: '18px' },\n { label: '24', value: '24px' },\n { label: '32', value: '32px' },\n];\n\nconst HEADING_LEVELS = [1, 2, 3, 4] as const;\n\nconst HEADING_OPTIONS = [\n { label: 'Paragraph', value: 'paragraph' },\n ...HEADING_LEVELS.map(level => ({\n label: `Heading ${level}`,\n value: String(level),\n })),\n];\n\n// Owns its own open/href state, so it has to be a real component (not a\n// plain render function like the other presets) for the hooks below to be\n// valid.\nconst LinkControl = ({ editor }: { editor: Editor }) => {\n const [open, setOpen] = useState(false);\n const [href, setHref] = useState('');\n\n const apply = () => {\n const next = href.trim();\n\n if (next) {\n editor\n .chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: next })\n .run();\n } else {\n editor.chain().focus().unsetLink().run();\n }\n setOpen(false);\n };\n\n return (\n <Popover\n placement=\"bottom\"\n open={open}\n onOpenChange={next => {\n if (next) {\n setHref(editor.getAttributes('link').href ?? '');\n }\n setOpen(next);\n }}\n content={\n <div className=\"flex items-center gap-2\">\n <Input\n value={href}\n placeholder=\"https://\"\n className=\"w-48\"\n onChange={e => setHref(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.preventDefault();\n apply();\n }\n }}\n />\n <Button size=\"small\" onClick={apply}>\n Apply\n </Button>\n </div>\n }\n >\n <ToolbarButton\n icon={<LinkIcon />}\n aria-label=\"Link\"\n active={editor.isActive('link')}\n />\n </Popover>\n );\n};\n\nexport const TOOLBAR_PRESET_RENDERERS: Record<\n ToolbarPreset,\n (editor: Editor) => ReactNode\n> = {\n undo: editor => (\n <ToolbarButton\n key=\"undo\"\n icon={<Undo2 />}\n aria-label=\"Undo\"\n disabled={!editor.can().undo()}\n onClick={() => editor.chain().focus().undo().run()}\n />\n ),\n redo: editor => (\n <ToolbarButton\n key=\"redo\"\n icon={<Redo2 />}\n aria-label=\"Redo\"\n disabled={!editor.can().redo()}\n onClick={() => editor.chain().focus().redo().run()}\n />\n ),\n heading: editor => {\n const activeLevel = HEADING_LEVELS.find(level =>\n editor.isActive('heading', { level }),\n );\n\n return (\n <Select\n key=\"heading\"\n className=\"h-6 w-28\"\n placeholder=\"Style\"\n options={HEADING_OPTIONS}\n value={activeLevel ? String(activeLevel) : 'paragraph'}\n // No `.focus()` here — the Select is still open when this fires,\n // and refocusing the editor mid-selection dismisses it early (same\n // class of bug as the color picker below).\n onChange={value =>\n value === 'paragraph'\n ? editor.chain().setParagraph().run()\n : editor\n .chain()\n .setHeading({ level: Number(value) as 1 | 2 | 3 | 4 })\n .run()\n }\n />\n );\n },\n bold: editor => (\n <ToolbarButton\n key=\"bold\"\n icon={<Bold />}\n aria-label=\"Bold\"\n active={editor.isActive('bold')}\n onClick={() => editor.chain().focus().toggleBold().run()}\n />\n ),\n italic: editor => (\n <ToolbarButton\n key=\"italic\"\n icon={<Italic />}\n aria-label=\"Italic\"\n active={editor.isActive('italic')}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n />\n ),\n underline: editor => (\n <ToolbarButton\n key=\"underline\"\n icon={<Underline />}\n aria-label=\"Underline\"\n active={editor.isActive('underline')}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n />\n ),\n strike: editor => (\n <ToolbarButton\n key=\"strike\"\n icon={<Strikethrough />}\n aria-label=\"Strikethrough\"\n active={editor.isActive('strike')}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n />\n ),\n code: editor => (\n <ToolbarButton\n key=\"code\"\n icon={<Code />}\n aria-label=\"Inline code\"\n active={editor.isActive('code')}\n onClick={() => editor.chain().focus().toggleCode().run()}\n />\n ),\n bulletList: editor => (\n <ToolbarButton\n key=\"bulletList\"\n icon={<List />}\n aria-label=\"Bullet list\"\n active={editor.isActive('bulletList')}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n />\n ),\n orderedList: editor => (\n <ToolbarButton\n key=\"orderedList\"\n icon={<ListOrdered />}\n aria-label=\"Ordered list\"\n active={editor.isActive('orderedList')}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n />\n ),\n blockquote: editor => (\n <ToolbarButton\n key=\"blockquote\"\n icon={<Quote />}\n aria-label=\"Blockquote\"\n active={editor.isActive('blockquote')}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n />\n ),\n codeBlock: editor => (\n <ToolbarButton\n key=\"codeBlock\"\n icon={<Code2 />}\n aria-label=\"Code block\"\n active={editor.isActive('codeBlock')}\n onClick={() => editor.chain().focus().toggleCodeBlock().run()}\n />\n ),\n horizontalRule: editor => (\n <ToolbarButton\n key=\"horizontalRule\"\n icon={<Minus />}\n aria-label=\"Horizontal rule\"\n onClick={() => editor.chain().focus().setHorizontalRule().run()}\n />\n ),\n link: editor => <LinkControl key=\"link\" editor={editor} />,\n fontSize: editor => (\n <Select\n key=\"fontSize\"\n className=\"h-6 w-20\"\n placeholder=\"Size\"\n options={FONT_SIZE_OPTIONS}\n value={editor.getAttributes('textStyle').fontSize ?? undefined}\n // No `.focus()` — see the `heading` preset above.\n onChange={value => editor.chain().setFontSize(value).run()}\n />\n ),\n color: editor => (\n <ColorPicker\n key=\"color\"\n value={editor.getAttributes('textStyle').color || '#000000'}\n // No `.focus()`: react-colorful fires `onChange` continuously while\n // dragging, and refocusing the editor on every tick moves DOM focus\n // out from under the still-open popover, which Radix reads as an\n // outside interaction and dismisses immediately (ui-kit reported\n // symptom: \"picker closes as soon as you try to change the color\").\n // The mark still applies to the stored selection without it.\n onChange={value => editor.chain().setColor(value).run()}\n />\n ),\n};\n\nexport const DEFAULT_TOOLBAR_PRESETS: ToolbarPreset[] = [\n 'undo',\n 'redo',\n 'heading',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'code',\n 'bulletList',\n 'orderedList',\n 'blockquote',\n 'codeBlock',\n 'horizontalRule',\n 'link',\n 'fontSize',\n 'color',\n];\n"],"mappings":"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"}
1
+ {"version":3,"file":"toolbar-presets.mjs","names":["LinkIcon"],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar-presets.tsx"],"sourcesContent":["'use client';\n\nimport { type ReactNode, useState } from 'react';\n\nimport type { Editor } from '@tiptap/core';\nimport {\n Bold,\n Code,\n Code2,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n Quote,\n Redo2,\n Strikethrough,\n Underline,\n Undo2,\n} from 'lucide-react';\n\nimport Button from '../button';\nimport ColorPicker from '../color-picker';\nimport Input from '../input';\nimport Popover from '../popover';\nimport Select from '../select';\nimport ToolbarButton from './toolbar-button';\nimport type { ToolbarPreset } from './types';\n\nconst FONT_SIZE_OPTIONS = [\n { label: '12', value: '12px' },\n { label: '14', value: '14px' },\n { label: '16', value: '16px' },\n { label: '18', value: '18px' },\n { label: '24', value: '24px' },\n { label: '32', value: '32px' },\n];\n\nconst HEADING_LEVELS = [1, 2, 3, 4] as const;\n\nconst HEADING_OPTIONS = [\n { label: 'Paragraph', value: 'paragraph' },\n ...HEADING_LEVELS.map(level => ({\n label: `Heading ${level}`,\n value: String(level),\n })),\n];\n\n// Owns its own open/href state, so it has to be a real component (not a\n// plain render function like the other presets) for the hooks below to be\n// valid.\nconst LinkControl = ({ editor }: { editor: Editor }) => {\n const [open, setOpen] = useState(false);\n const [href, setHref] = useState('');\n\n const apply = () => {\n const next = href.trim();\n\n if (next) {\n editor\n .chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: next })\n .run();\n } else {\n editor.chain().focus().unsetLink().run();\n }\n setOpen(false);\n };\n\n return (\n <Popover\n placement=\"bottom\"\n open={open}\n onOpenChange={next => {\n if (next) {\n setHref(editor.getAttributes('link').href ?? '');\n }\n setOpen(next);\n }}\n content={\n <div className=\"flex items-center gap-2\">\n <Input\n value={href}\n placeholder=\"https://\"\n className=\"w-48\"\n onChange={e => setHref(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.preventDefault();\n apply();\n }\n }}\n />\n <Button size=\"small\" onClick={apply}>\n Apply\n </Button>\n </div>\n }\n >\n <ToolbarButton\n icon={<LinkIcon />}\n aria-label=\"Link\"\n active={editor.isActive('link')}\n />\n </Popover>\n );\n};\n\nexport const TOOLBAR_PRESET_RENDERERS: Record<\n ToolbarPreset,\n (editor: Editor) => ReactNode\n> = {\n undo: editor => (\n <ToolbarButton\n key=\"undo\"\n icon={<Undo2 />}\n aria-label=\"Undo\"\n disabled={!editor.can().undo()}\n onClick={() => editor.chain().focus().undo().run()}\n />\n ),\n redo: editor => (\n <ToolbarButton\n key=\"redo\"\n icon={<Redo2 />}\n aria-label=\"Redo\"\n disabled={!editor.can().redo()}\n onClick={() => editor.chain().focus().redo().run()}\n />\n ),\n heading: editor => {\n const activeLevel = HEADING_LEVELS.find(level =>\n editor.isActive('heading', { level }),\n );\n\n return (\n <Select\n key=\"heading\"\n className=\"h-6 w-28\"\n placeholder=\"Style\"\n options={HEADING_OPTIONS}\n value={activeLevel ? String(activeLevel) : 'paragraph'}\n // No `.focus()` here — the Select is still open when this fires,\n // and refocusing the editor mid-selection dismisses it early (same\n // class of bug as the color picker below).\n onChange={value =>\n value === 'paragraph'\n ? editor.chain().setParagraph().run()\n : editor\n .chain()\n .setHeading({ level: Number(value) as 1 | 2 | 3 | 4 })\n .run()\n }\n />\n );\n },\n bold: editor => (\n <ToolbarButton\n key=\"bold\"\n icon={<Bold />}\n aria-label=\"Bold\"\n active={editor.isActive('bold')}\n onClick={() => editor.chain().focus().toggleBold().run()}\n />\n ),\n italic: editor => (\n <ToolbarButton\n key=\"italic\"\n icon={<Italic />}\n aria-label=\"Italic\"\n active={editor.isActive('italic')}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n />\n ),\n underline: editor => (\n <ToolbarButton\n key=\"underline\"\n icon={<Underline />}\n aria-label=\"Underline\"\n active={editor.isActive('underline')}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n />\n ),\n strike: editor => (\n <ToolbarButton\n key=\"strike\"\n icon={<Strikethrough />}\n aria-label=\"Strikethrough\"\n active={editor.isActive('strike')}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n />\n ),\n code: editor => (\n <ToolbarButton\n key=\"code\"\n icon={<Code />}\n aria-label=\"Inline code\"\n active={editor.isActive('code')}\n onClick={() => editor.chain().focus().toggleCode().run()}\n />\n ),\n bulletList: editor => (\n <ToolbarButton\n key=\"bulletList\"\n icon={<List />}\n aria-label=\"Bullet list\"\n active={editor.isActive('bulletList')}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n />\n ),\n orderedList: editor => (\n <ToolbarButton\n key=\"orderedList\"\n icon={<ListOrdered />}\n aria-label=\"Ordered list\"\n active={editor.isActive('orderedList')}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n />\n ),\n blockquote: editor => (\n <ToolbarButton\n key=\"blockquote\"\n icon={<Quote />}\n aria-label=\"Blockquote\"\n active={editor.isActive('blockquote')}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n />\n ),\n codeBlock: editor => (\n <ToolbarButton\n key=\"codeBlock\"\n icon={<Code2 />}\n aria-label=\"Code block\"\n active={editor.isActive('codeBlock')}\n onClick={() => editor.chain().focus().toggleCodeBlock().run()}\n />\n ),\n horizontalRule: editor => (\n <ToolbarButton\n key=\"horizontalRule\"\n icon={<Minus />}\n aria-label=\"Horizontal rule\"\n onClick={() => editor.chain().focus().setHorizontalRule().run()}\n />\n ),\n link: editor => <LinkControl key=\"link\" editor={editor} />,\n fontSize: editor => (\n <Select\n key=\"fontSize\"\n className=\"h-6 w-20\"\n placeholder=\"Size\"\n options={FONT_SIZE_OPTIONS}\n value={editor.getAttributes('textStyle').fontSize ?? undefined}\n // No `.focus()` — see the `heading` preset above.\n onChange={value => editor.chain().setFontSize(value).run()}\n />\n ),\n color: editor => (\n <ColorPicker\n key=\"color\"\n value={editor.getAttributes('textStyle').color || '#000000'}\n // No `.focus()`: react-colorful fires `onChange` continuously while\n // dragging, and refocusing the editor on every tick moves DOM focus\n // out from under the still-open popover, which Base UI reads as an\n // outside interaction and dismisses immediately (ui-kit reported\n // symptom: \"picker closes as soon as you try to change the color\").\n // The mark still applies to the stored selection without it.\n onChange={value => editor.chain().setColor(value).run()}\n />\n ),\n};\n\nexport const DEFAULT_TOOLBAR_PRESETS: ToolbarPreset[] = [\n 'undo',\n 'redo',\n 'heading',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'code',\n 'bulletList',\n 'orderedList',\n 'blockquote',\n 'codeBlock',\n 'horizontalRule',\n 'link',\n 'fontSize',\n 'color',\n];\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  const Toolbar = ({ editor, presets, items, className }) => {
7
7
  return /* @__PURE__ */ jsxs("div", {
8
8
  "data-slot": "rich-text-editor-toolbar",
9
- className: cn("flex flex-wrap items-center gap-1 border-b border-gray-200 px-2 py-1", className),
9
+ className: cn("border-input flex flex-wrap items-center gap-1 border-b px-2 py-1", className),
10
10
  children: [presets.map((preset) => TOOLBAR_PRESET_RENDERERS[preset](editor)), items?.map((item) => /* @__PURE__ */ jsx(ToolbarButton, {
11
11
  icon: item.icon,
12
12
  "aria-label": item.label,
@@ -1 +1 @@
1
- {"version":3,"file":"toolbar.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core';\n\nimport { cn } from '@repo/ui/utils';\n\nimport ToolbarButton from './toolbar-button';\nimport { TOOLBAR_PRESET_RENDERERS } from './toolbar-presets';\nimport type { ToolbarItem, ToolbarPreset } from './types';\n\nexport interface ToolbarProps {\n editor: Editor;\n presets: ToolbarPreset[];\n items?: ToolbarItem[];\n className?: string;\n}\n\nconst Toolbar = ({ editor, presets, items, className }: ToolbarProps) => {\n return (\n <div\n data-slot=\"rich-text-editor-toolbar\"\n className={cn(\n 'flex flex-wrap items-center gap-1 border-b border-gray-200 px-2 py-1',\n className,\n //\n )}\n >\n {presets.map(preset => TOOLBAR_PRESET_RENDERERS[preset](editor))}\n {items?.map(item => (\n <ToolbarButton\n key={item.key}\n icon={item.icon}\n aria-label={item.label}\n active={item.isActive?.(editor)}\n onClick={() => item.onClick(editor)}\n />\n ))}\n </div>\n );\n};\n\nexport default Toolbar;\n"],"mappings":";;;;;AAeA,MAAM,WAAW,EAAE,QAAQ,SAAS,OAAO,gBAA8B;CACvE,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,wEACA,SAEF;EANF,UAAA,CAQG,QAAQ,KAAI,WAAU,yBAAyB,OAAO,CAAC,MAAM,CAAC,GAC9D,OAAO,KAAI,SACV,oBAAC,eAAD;GAEE,MAAM,KAAK;GACX,cAAY,KAAK;GACjB,QAAQ,KAAK,WAAW,MAAM;GAC9B,eAAe,KAAK,QAAQ,MAAM;EACnC,GALM,KAAK,GAKX,CACF,CACE;;AAET"}
1
+ {"version":3,"file":"toolbar.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core';\n\nimport { cn } from '@repo/ui/utils';\n\nimport ToolbarButton from './toolbar-button';\nimport { TOOLBAR_PRESET_RENDERERS } from './toolbar-presets';\nimport type { ToolbarItem, ToolbarPreset } from './types';\n\nexport interface ToolbarProps {\n editor: Editor;\n presets: ToolbarPreset[];\n items?: ToolbarItem[];\n className?: string;\n}\n\nconst Toolbar = ({ editor, presets, items, className }: ToolbarProps) => {\n return (\n <div\n data-slot=\"rich-text-editor-toolbar\"\n className={cn(\n 'border-input flex flex-wrap items-center gap-1 border-b px-2 py-1',\n className,\n //\n )}\n >\n {presets.map(preset => TOOLBAR_PRESET_RENDERERS[preset](editor))}\n {items?.map(item => (\n <ToolbarButton\n key={item.key}\n icon={item.icon}\n aria-label={item.label}\n active={item.isActive?.(editor)}\n onClick={() => item.onClick(editor)}\n />\n ))}\n </div>\n );\n};\n\nexport default Toolbar;\n"],"mappings":";;;;;AAeA,MAAM,WAAW,EAAE,QAAQ,SAAS,OAAO,gBAA8B;CACvE,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,qEACA,SAEF;EANF,UAAA,CAQG,QAAQ,KAAI,WAAU,yBAAyB,OAAO,CAAC,MAAM,CAAC,GAC9D,OAAO,KAAI,SACV,oBAAC,eAAD;GAEE,MAAM,KAAK;GACX,cAAY,KAAK;GACjB,QAAQ,KAAK,WAAW,MAAM;GAC9B,eAAe,KAAK,QAAQ,MAAM;EACnC,GALM,KAAK,GAKX,CACF,CACE;;AAET"}
@@ -8,8 +8,12 @@ const isGroup = (option) => {
8
8
  return "options" in option && Array.isArray(option.options);
9
9
  };
10
10
  const Select = ({ className, placeholder, options, onChange, ...props }) => {
11
+ const items = options?.flatMap((option) => isGroup(option) ? option.options : option);
11
12
  return /* @__PURE__ */ jsxs(Core, {
12
- onValueChange: onChange,
13
+ items,
14
+ onValueChange: (value) => {
15
+ if (value !== null) onChange?.(value);
16
+ },
13
17
  ...props,
14
18
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
15
19
  className: cn("w-full max-w-48", className),
@@ -1 +1 @@
1
- {"version":3,"file":"select.mjs","names":["select"],"sources":["../../../src/components/atoms/select.tsx"],"sourcesContent":["import React from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { select } from '../../core';\n\nconst {\n Select: Core,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} = select;\n\ninterface Option {\n label: React.ReactNode;\n value: string;\n}\n\ninterface OptionGroup {\n label: React.ReactNode;\n options: Option[];\n}\n\nconst isGroup = (option: Option | OptionGroup): option is OptionGroup => {\n return 'options' in option && Array.isArray(option.options);\n};\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'onValueChange'\n> {\n placeholder?: string;\n className?: string;\n options?: (Option | OptionGroup)[];\n onChange?: (value: string) => void;\n}\n\nconst Select = ({\n className,\n placeholder,\n options,\n onChange,\n ...props\n}: Props) => {\n return (\n <Core onValueChange={onChange} {...props}>\n <SelectTrigger className={cn('w-full max-w-48', className)}>\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {options?.map((option, index) =>\n isGroup(option) ? (\n <SelectGroup key={index}>\n <SelectLabel>{option.label}</SelectLabel>\n {option.options.map(item => (\n <SelectItem key={item.value} value={item.value}>\n {item.label}\n </SelectItem>\n ))}\n </SelectGroup>\n ) : (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ),\n )}\n </SelectContent>\n </Core>\n );\n};\n\nexport default Select;\n"],"mappings":";;;;;AAMA,MAAM,EACJ,QAAQ,MACR,eACA,aACA,YACA,aACA,eACA,gBACEA;AAYJ,MAAM,WAAW,WAAwD;CACvE,OAAO,aAAa,UAAU,MAAM,QAAQ,OAAO,OAAO;AAC5D;AAYA,MAAM,UAAU,EACd,WACA,aACA,SACA,UACA,GAAG,YACQ;CACX,OACE,qBAAC,MAAD;EAAM,eAAe;EAAU,GAAI;EAAnC,UAAA,CACE,oBAAC,eAAD;GAAe,WAAW,GAAG,mBAAmB,SAAS;GACvD,UAAA,oBAAC,aAAD,EAA0B,YAAc,CAAA;EAC3B,CAAA,GACf,oBAAC,eAAD,EAAA,UACG,SAAS,KAAK,QAAQ,UACrB,QAAQ,MAAM,IACZ,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,aAAD,EAAA,UAAc,OAAO,MAAmB,CAAA,GACvC,OAAO,QAAQ,KAAI,SAClB,oBAAC,YAAD;GAA6B,OAAO,KAAK;GACtC,UAAA,KAAK;EACI,GAFK,KAAK,KAEV,CACb,CACU,EAAA,GAPK,KAOL,IAEb,oBAAC,YAAD;GAA+B,OAAO,OAAO;GAC1C,UAAA,OAAO;EACE,GAFK,OAAO,KAEZ,CAEhB,EACa,CAAA,CACX;;AAEV"}
1
+ {"version":3,"file":"select.mjs","names":["select"],"sources":["../../../src/components/atoms/select.tsx"],"sourcesContent":["import React from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { select } from '../../core';\n\nconst {\n Select: Core,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} = select;\n\ninterface Option {\n label: React.ReactNode;\n value: string;\n}\n\ninterface OptionGroup {\n label: React.ReactNode;\n options: Option[];\n}\n\nconst isGroup = (option: Option | OptionGroup): option is OptionGroup => {\n return 'options' in option && Array.isArray(option.options);\n};\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'onValueChange'\n> {\n placeholder?: string;\n className?: string;\n options?: (Option | OptionGroup)[];\n onChange?: (value: string) => void;\n}\n\nconst Select = ({\n className,\n placeholder,\n options,\n onChange,\n ...props\n}: Props) => {\n const items = options?.flatMap(option =>\n isGroup(option) ? option.options : option,\n );\n\n return (\n <Core\n items={items}\n onValueChange={value => {\n if (value !== null) {\n onChange?.(value);\n }\n }}\n {...props}\n >\n <SelectTrigger className={cn('w-full max-w-48', className)}>\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {options?.map((option, index) =>\n isGroup(option) ? (\n <SelectGroup key={index}>\n <SelectLabel>{option.label}</SelectLabel>\n {option.options.map(item => (\n <SelectItem key={item.value} value={item.value}>\n {item.label}\n </SelectItem>\n ))}\n </SelectGroup>\n ) : (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ),\n )}\n </SelectContent>\n </Core>\n );\n};\n\nexport default Select;\n"],"mappings":";;;;;AAMA,MAAM,EACJ,QAAQ,MACR,eACA,aACA,YACA,aACA,eACA,gBACEA;AAYJ,MAAM,WAAW,WAAwD;CACvE,OAAO,aAAa,UAAU,MAAM,QAAQ,OAAO,OAAO;AAC5D;AAYA,MAAM,UAAU,EACd,WACA,aACA,SACA,UACA,GAAG,YACQ;CACX,MAAM,QAAQ,SAAS,SAAQ,WAC7B,QAAQ,MAAM,IAAI,OAAO,UAAU,MACrC;CAEA,OACE,qBAAC,MAAD;EACS;EACP,gBAAe,UAAS;GACtB,IAAI,UAAU,MACZ,WAAW,KAAK;EAEpB;EACA,GAAI;EAPN,UAAA,CASE,oBAAC,eAAD;GAAe,WAAW,GAAG,mBAAmB,SAAS;GACvD,UAAA,oBAAC,aAAD,EAA0B,YAAc,CAAA;EAC3B,CAAA,GACf,oBAAC,eAAD,EAAA,UACG,SAAS,KAAK,QAAQ,UACrB,QAAQ,MAAM,IACZ,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,aAAD,EAAA,UAAc,OAAO,MAAmB,CAAA,GACvC,OAAO,QAAQ,KAAI,SAClB,oBAAC,YAAD;GAA6B,OAAO,KAAK;GACtC,UAAA,KAAK;EACI,GAFK,KAAK,KAEV,CACb,CACU,EAAA,GAPK,KAOL,IAEb,oBAAC,YAAD;GAA+B,OAAO,OAAO;GAC1C,UAAA,OAAO;EACE,GAFK,OAAO,KAEZ,CAEhB,EACa,CAAA,CACX;;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"slider.mjs","names":["slider"],"sources":["../../../../src/components/atoms/slider/slider.tsx"],"sourcesContent":["'use client';\n\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { slider } from '../../../core';\n\nconst { Slider: Core } = slider;\n\n/** A single thumb (`number`) or a two-thumb range (`[min, max]`). */\nexport type SliderValue = number | number[];\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'span'>,\n 'onChange' | 'defaultValue' | 'dir'\n> {\n value?: SliderValue;\n defaultValue?: SliderValue;\n min?: number;\n max?: number;\n step?: number;\n disabled?: boolean;\n orientation?: 'horizontal' | 'vertical';\n onChange?: (value: SliderValue) => void;\n}\n\nconst toArray = (value: SliderValue | undefined): number[] | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n return Array.isArray(value) ? value : [value];\n};\n\nconst Slider = ({\n value: _value,\n defaultValue,\n min = 0,\n max = 100,\n step = 1,\n disabled,\n orientation = 'horizontal',\n onChange: _onChange = () => {},\n className,\n ...props\n}: Props) => {\n // A `number[]` value/defaultValue means the consumer wants a range; a bare\n // `number` means a single thumb. Radix works in `number[]` throughout, so we\n // normalise on the way in and hand the original shape back through `onChange`.\n const isRange = Array.isArray(_value ?? defaultValue);\n\n const [value, onChange] = useControllableState<number[]>({\n value: toArray(_value),\n defaultValue: toArray(defaultValue) ?? [min],\n onChange: next => {\n _onChange(isRange ? next : (next[0] ?? min));\n },\n });\n\n return (\n <Core\n value={value}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n orientation={orientation}\n className={cn(className)}\n onValueChange={onChange}\n {...props}\n />\n );\n};\n\nexport default Slider;\n"],"mappings":";;;;;;AAQA,MAAM,EAAE,QAAQ,SAASA;AAmBzB,MAAM,WAAW,UAAyD;CACxE,IAAI,UAAU,KAAA,GACZ;CAGF,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,MAAM,UAAU,EACd,OAAO,QACP,cACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,UACA,cAAc,cACd,UAAU,kBAAkB,CAAC,GAC7B,WACA,GAAG,YACQ;CAIX,MAAM,UAAU,MAAM,QAAQ,UAAU,YAAY;CAEpD,MAAM,CAAC,OAAO,YAAY,qBAA+B;EACvD,OAAO,QAAQ,MAAM;EACrB,cAAc,QAAQ,YAAY,KAAK,CAAC,GAAG;EAC3C,WAAU,SAAQ;GAChB,UAAU,UAAU,OAAQ,KAAK,MAAM,GAAI;EAC7C;CACF,CAAC;CAED,OACE,oBAAC,MAAD;EACS;EACF;EACA;EACC;EACI;EACG;EACb,WAAW,GAAG,SAAS;EACvB,eAAe;EACf,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"slider.mjs","names":["slider"],"sources":["../../../../src/components/atoms/slider/slider.tsx"],"sourcesContent":["'use client';\n\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { slider } from '../../../core';\n\nconst { Slider: Core } = slider;\n\n/** A single thumb (`number`) or a two-thumb range (`[min, max]`). */\nexport type SliderValue = number | number[];\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'span'>,\n 'onChange' | 'defaultValue' | 'dir'\n> {\n value?: SliderValue;\n defaultValue?: SliderValue;\n min?: number;\n max?: number;\n step?: number;\n disabled?: boolean;\n orientation?: 'horizontal' | 'vertical';\n onChange?: (value: SliderValue) => void;\n}\n\nconst toArray = (value: SliderValue | undefined): number[] | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n return Array.isArray(value) ? value : [value];\n};\n\nconst Slider = ({\n value: _value,\n defaultValue,\n min = 0,\n max = 100,\n step = 1,\n disabled,\n orientation = 'horizontal',\n onChange: _onChange = () => {},\n className,\n ...props\n}: Props) => {\n // A `number[]` value/defaultValue means the consumer wants a range; a bare\n // `number` means a single thumb. Normalize internally and hand the original\n // shape back through `onChange`.\n const isRange = Array.isArray(_value ?? defaultValue);\n\n const [value, onChange] = useControllableState<number[]>({\n value: toArray(_value),\n defaultValue: toArray(defaultValue) ?? [min],\n onChange: next => {\n _onChange(isRange ? next : (next[0] ?? min));\n },\n });\n\n return (\n <Core\n value={value}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n orientation={orientation}\n className={cn(className)}\n onValueChange={onChange}\n {...props}\n />\n );\n};\n\nexport default Slider;\n"],"mappings":";;;;;;AAQA,MAAM,EAAE,QAAQ,SAASA;AAmBzB,MAAM,WAAW,UAAyD;CACxE,IAAI,UAAU,KAAA,GACZ;CAGF,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,MAAM,UAAU,EACd,OAAO,QACP,cACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,UACA,cAAc,cACd,UAAU,kBAAkB,CAAC,GAC7B,WACA,GAAG,YACQ;CAIX,MAAM,UAAU,MAAM,QAAQ,UAAU,YAAY;CAEpD,MAAM,CAAC,OAAO,YAAY,qBAA+B;EACvD,OAAO,QAAQ,MAAM;EACrB,cAAc,QAAQ,YAAY,KAAK,CAAC,GAAG;EAC3C,WAAU,SAAQ;GAChB,UAAU,UAAU,OAAQ,KAAK,MAAM,GAAI;EAC7C;CACF,CAAC;CAED,OACE,oBAAC,MAAD;EACS;EACF;EACA;EACC;EACI;EACG;EACb,WAAW,GAAG,SAAS;EACvB,eAAe;EACf,GAAI;CACL,CAAA;AAEL"}
@@ -1,6 +1,6 @@
1
1
  import { ComponentSize } from "../../providers/config/types.mjs";
2
2
  //#region src/components/atoms/switch.d.ts
3
- interface Props extends Omit<React.ComponentPropsWithoutRef<'button'>, 'onChange'> {
3
+ interface Props extends Omit<React.ComponentPropsWithoutRef<'span'>, 'onChange'> {
4
4
  classNames?: {
5
5
  track?: string;
6
6
  handle?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"switch.d.mts","names":[],"sources":["../../../src/components/atoms/switch.tsx"],"mappings":";;UA+CiB,cAAc,KAC7B,MAAM;EAGN;IACE;IACA;;;;;;;;;EASF,OAAO;EACP;EACA;EACA;EACA,YAAY;EACZ,kBAAkB,MAAM;EACxB,oBAAoB,MAAM;;cAGtB,WAAU,WAAA,YAAA,MAAA,gBAAA,SAAA,UAAA,UAAA,WAAA,iBAAA,sBAAA,SAUb,0BAAK,IAAA"}
1
+ {"version":3,"file":"switch.d.mts","names":[],"sources":["../../../src/components/atoms/switch.tsx"],"mappings":";;UAiDiB,cAAc,KAC7B,MAAM;EAGN;IACE;IACA;;;;;;;;;EASF,OAAO;EACP;EACA;EACA;EACA,YAAY;EACZ,kBAAkB,MAAM;EACxB,oBAAoB,MAAM;;cAGtB,WAAU,WAAA,YAAA,MAAA,gBAAA,SAAA,UAAA,UAAA,WAAA,iBAAA,sBAAA,SAUb,0BAAK,IAAA"}
@@ -11,7 +11,7 @@ const sizeConfig = {
11
11
  core: "sm",
12
12
  track: "h-6! w-10!",
13
13
  handle: "size-5!",
14
- handleChecked: "data-[state=unchecked]:left-0.5 data-[state=checked]:left-[calc(100%-22px)]",
14
+ handleChecked: "data-unchecked:left-0.5 data-checked:left-[calc(100%-22px)]",
15
15
  fontSize: "text-[10px]",
16
16
  marginChecked: "mr-6 ml-1.5",
17
17
  marginUnchecked: "mr-1.5 ml-6"
@@ -20,7 +20,7 @@ const sizeConfig = {
20
20
  core: "default",
21
21
  track: "h-8! w-12!",
22
22
  handle: "size-6!",
23
- handleChecked: "data-[state=unchecked]:left-0.5 data-[state=checked]:left-[calc(100%-26px)]",
23
+ handleChecked: "data-unchecked:left-0.5 data-checked:left-[calc(100%-26px)]",
24
24
  fontSize: "text-xs",
25
25
  marginChecked: "mr-7 ml-2",
26
26
  marginUnchecked: "mr-2 ml-7"
@@ -29,7 +29,7 @@ const sizeConfig = {
29
29
  core: "default",
30
30
  track: "h-10! w-16!",
31
31
  handle: "size-8!",
32
- handleChecked: "data-[state=unchecked]:left-0.5 data-[state=checked]:left-[calc(100%-34px)]",
32
+ handleChecked: "data-unchecked:left-0.5 data-checked:left-[calc(100%-34px)]",
33
33
  fontSize: "text-sm",
34
34
  marginChecked: "mr-9 ml-2.5",
35
35
  marginUnchecked: "mr-2.5 ml-9"
@@ -1 +1 @@
1
- {"version":3,"file":"switch.mjs","names":["switchComponent"],"sources":["../../../src/components/atoms/switch.tsx"],"sourcesContent":["'use client';\n\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { type ComponentSize, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { switchComponent } from '../../core';\n\nconst { Switch: Core } = switchComponent;\n\n// Keyed by the shared `ComponentSize` vocabulary (#350). The `calc` offset on\n// each `handleChecked` is `handle width + 2px` (the `left-0.5` inset), so the\n// handle lands flush at both ends — it must be recomputed per row, not copied.\nconst sizeConfig = {\n small: {\n core: 'sm' as const,\n track: 'h-6! w-10!',\n handle: 'size-5!',\n handleChecked:\n 'data-[state=unchecked]:left-0.5 data-[state=checked]:left-[calc(100%-22px)]',\n fontSize: 'text-[10px]',\n marginChecked: 'mr-6 ml-1.5',\n marginUnchecked: 'mr-1.5 ml-6',\n },\n middle: {\n core: 'default' as const,\n track: 'h-8! w-12!',\n handle: 'size-6!',\n handleChecked:\n 'data-[state=unchecked]:left-0.5 data-[state=checked]:left-[calc(100%-26px)]',\n fontSize: 'text-xs',\n marginChecked: 'mr-7 ml-2',\n marginUnchecked: 'mr-2 ml-7',\n },\n large: {\n core: 'default' as const,\n track: 'h-10! w-16!',\n handle: 'size-8!',\n handleChecked:\n 'data-[state=unchecked]:left-0.5 data-[state=checked]:left-[calc(100%-34px)]',\n fontSize: 'text-sm',\n marginChecked: 'mr-9 ml-2.5',\n marginUnchecked: 'mr-2.5 ml-9',\n },\n} satisfies Record<ComponentSize, unknown>;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'button'>,\n 'onChange'\n> {\n classNames?: {\n track?: string;\n handle?: string;\n };\n /**\n * Density on the shared `ComponentSize` scale (`small` | `middle` | `large`),\n * falling back to the nearest `Config`'s `componentSize`, then `middle`.\n *\n * `medium` is accepted as a deprecated alias of `middle` — kept so existing\n * `size=\"medium\"` calls keep working; removed in the next major.\n */\n size?: ComponentSize | 'medium';\n defaultChecked?: boolean;\n checked?: boolean;\n disabled?: boolean;\n onChange?: (checked: boolean) => void;\n checkedChildren?: React.ReactNode;\n unCheckedChildren?: React.ReactNode;\n}\n\nconst Switch = ({\n className,\n classNames,\n size,\n defaultChecked,\n checked: _checked,\n onChange: _onChange = () => {},\n checkedChildren,\n unCheckedChildren,\n ...props\n}: Props) => {\n const [checked, onChange] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const { componentSize } = useConfig();\n // `medium` is the deprecated spelling of `middle`; an explicit `size` wins,\n // then the Config default, then `middle`.\n const resolvedSize =\n (size === 'medium' ? 'middle' : size) ?? componentSize ?? 'middle';\n\n const hasChildren = !!(checkedChildren || unCheckedChildren);\n const config = sizeConfig[resolvedSize];\n\n return (\n <Core\n checked={checked}\n size={config.core}\n className={cn(\n 'relative',\n config.track,\n hasChildren && 'w-auto! overflow-hidden',\n className,\n classNames?.track,\n //\n )}\n handleClassName={cn(\n config.handle,\n '!absolute top-1/2 !-translate-y-1/2 !translate-x-0',\n 'transition-[left] duration-200 will-change-[left]',\n config.handleChecked,\n classNames?.handle,\n //\n )}\n onCheckedChange={checked => {\n onChange(checked);\n }}\n {...props}\n >\n {hasChildren && (\n <span\n className={cn(\n `grid leading-none transition-[margin] duration-200\n will-change-[margin]`,\n config.fontSize,\n checked\n ? [config.marginChecked, 'text-primary-foreground']\n : [config.marginUnchecked, 'text-foreground'],\n //\n )}\n >\n <span\n className={cn(\n 'col-start-1 row-start-1 transition-opacity duration-200',\n checked ? 'opacity-100' : 'opacity-0',\n )}\n >\n {checkedChildren}\n </span>\n <span\n className={cn(\n 'col-start-1 row-start-1 transition-opacity duration-200',\n checked ? 'opacity-0' : 'opacity-100',\n )}\n >\n {unCheckedChildren}\n </span>\n </span>\n )}\n </Core>\n );\n};\n\nexport default Switch;\n"],"mappings":";;;;;;;AASA,MAAM,EAAE,QAAQ,SAASA;AAKzB,MAAM,aAAa;CACjB,OAAO;EACL,MAAM;EACN,OAAO;EACP,QAAQ;EACR,eACE;EACF,UAAU;EACV,eAAe;EACf,iBAAiB;CACnB;CACA,QAAQ;EACN,MAAM;EACN,OAAO;EACP,QAAQ;EACR,eACE;EACF,UAAU;EACV,eAAe;EACf,iBAAiB;CACnB;CACA,OAAO;EACL,MAAM;EACN,OAAO;EACP,QAAQ;EACR,eACE;EACF,UAAU;EACV,eAAe;EACf,iBAAiB;CACnB;AACF;AA0BA,MAAM,UAAU,EACd,WACA,YACA,MACA,gBACA,SAAS,UACT,UAAU,kBAAkB,CAAC,GAC7B,iBACA,mBACA,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,YAAY,qBAA8B;EACxD,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;CACZ,CAAC;CAED,MAAM,EAAE,kBAAkB,UAAU;CAGpC,MAAM,gBACH,SAAS,WAAW,WAAW,SAAS,iBAAiB;CAE5D,MAAM,cAAc,CAAC,EAAE,mBAAmB;CAC1C,MAAM,SAAS,WAAW;CAE1B,OACE,oBAAC,MAAD;EACW;EACT,MAAM,OAAO;EACb,WAAW,GACT,YACA,OAAO,OACP,eAAe,2BACf,WACA,YAAY,KAEd;EACA,iBAAiB,GACf,OAAO,QACP,sDACA,qDACA,OAAO,eACP,YAAY,MAEd;EACA,kBAAiB,YAAW;GAC1B,SAAS,OAAO;EAClB;EACA,GAAI;EAEH,UAAA,eACC,qBAAC,QAAD;GACE,WAAW,GACT;mCAEA,OAAO,UACP,UACI,CAAC,OAAO,eAAe,yBAAyB,IAChD,CAAC,OAAO,iBAAiB,iBAAiB,CAEhD;GATF,UAAA,CAWE,oBAAC,QAAD;IACE,WAAW,GACT,2DACA,UAAU,gBAAgB,WAC5B;IAEC,UAAA;GACG,CAAA,GACN,oBAAC,QAAD;IACE,WAAW,GACT,2DACA,UAAU,cAAc,aAC1B;IAEC,UAAA;GACG,CAAA,CACF;;CAEJ,CAAA;AAEV"}
1
+ {"version":3,"file":"switch.mjs","names":["switchComponent"],"sources":["../../../src/components/atoms/switch.tsx"],"sourcesContent":["'use client';\n\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { type ComponentSize, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { switchComponent } from '../../core';\n\nconst { Switch: Core } = switchComponent;\n\n// Keyed by the shared `ComponentSize` vocabulary (#350). The `calc` offset on\n// each `handleChecked` is `handle width + 2px` (the `left-0.5` inset), so the\n// handle lands flush at both ends — it must be recomputed per row, not copied.\nconst sizeConfig = {\n small: {\n core: 'sm' as const,\n track: 'h-6! w-10!',\n handle: 'size-5!',\n handleChecked:\n 'data-unchecked:left-0.5 data-checked:left-[calc(100%-22px)]',\n fontSize: 'text-[10px]',\n marginChecked: 'mr-6 ml-1.5',\n marginUnchecked: 'mr-1.5 ml-6',\n },\n middle: {\n core: 'default' as const,\n track: 'h-8! w-12!',\n handle: 'size-6!',\n handleChecked:\n 'data-unchecked:left-0.5 data-checked:left-[calc(100%-26px)]',\n fontSize: 'text-xs',\n marginChecked: 'mr-7 ml-2',\n marginUnchecked: 'mr-2 ml-7',\n },\n large: {\n core: 'default' as const,\n track: 'h-10! w-16!',\n handle: 'size-8!',\n handleChecked:\n 'data-unchecked:left-0.5 data-checked:left-[calc(100%-34px)]',\n fontSize: 'text-sm',\n marginChecked: 'mr-9 ml-2.5',\n marginUnchecked: 'mr-2.5 ml-9',\n },\n} satisfies Record<ComponentSize, unknown>;\n\n// Base UI's Switch renders a `<span>` (plus a hidden `<input>`), not the\n// `<button>` Radix used — so the forwarded host props are span-based now.\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'span'>,\n 'onChange'\n> {\n classNames?: {\n track?: string;\n handle?: string;\n };\n /**\n * Density on the shared `ComponentSize` scale (`small` | `middle` | `large`),\n * falling back to the nearest `Config`'s `componentSize`, then `middle`.\n *\n * `medium` is accepted as a deprecated alias of `middle` — kept so existing\n * `size=\"medium\"` calls keep working; removed in the next major.\n */\n size?: ComponentSize | 'medium';\n defaultChecked?: boolean;\n checked?: boolean;\n disabled?: boolean;\n onChange?: (checked: boolean) => void;\n checkedChildren?: React.ReactNode;\n unCheckedChildren?: React.ReactNode;\n}\n\nconst Switch = ({\n className,\n classNames,\n size,\n defaultChecked,\n checked: _checked,\n onChange: _onChange = () => {},\n checkedChildren,\n unCheckedChildren,\n ...props\n}: Props) => {\n const [checked, onChange] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const { componentSize } = useConfig();\n // `medium` is the deprecated spelling of `middle`; an explicit `size` wins,\n // then the Config default, then `middle`.\n const resolvedSize =\n (size === 'medium' ? 'middle' : size) ?? componentSize ?? 'middle';\n\n const hasChildren = !!(checkedChildren || unCheckedChildren);\n const config = sizeConfig[resolvedSize];\n\n return (\n <Core\n checked={checked}\n size={config.core}\n className={cn(\n 'relative',\n config.track,\n hasChildren && 'w-auto! overflow-hidden',\n className,\n classNames?.track,\n //\n )}\n handleClassName={cn(\n config.handle,\n '!absolute top-1/2 !-translate-y-1/2 !translate-x-0',\n 'transition-[left] duration-200 will-change-[left]',\n config.handleChecked,\n classNames?.handle,\n //\n )}\n onCheckedChange={checked => {\n onChange(checked);\n }}\n {...props}\n >\n {hasChildren && (\n <span\n className={cn(\n `grid leading-none transition-[margin] duration-200\n will-change-[margin]`,\n config.fontSize,\n checked\n ? [config.marginChecked, 'text-primary-foreground']\n : [config.marginUnchecked, 'text-foreground'],\n //\n )}\n >\n <span\n className={cn(\n 'col-start-1 row-start-1 transition-opacity duration-200',\n checked ? 'opacity-100' : 'opacity-0',\n )}\n >\n {checkedChildren}\n </span>\n <span\n className={cn(\n 'col-start-1 row-start-1 transition-opacity duration-200',\n checked ? 'opacity-0' : 'opacity-100',\n )}\n >\n {unCheckedChildren}\n </span>\n </span>\n )}\n </Core>\n );\n};\n\nexport default Switch;\n"],"mappings":";;;;;;;AASA,MAAM,EAAE,QAAQ,SAASA;AAKzB,MAAM,aAAa;CACjB,OAAO;EACL,MAAM;EACN,OAAO;EACP,QAAQ;EACR,eACE;EACF,UAAU;EACV,eAAe;EACf,iBAAiB;CACnB;CACA,QAAQ;EACN,MAAM;EACN,OAAO;EACP,QAAQ;EACR,eACE;EACF,UAAU;EACV,eAAe;EACf,iBAAiB;CACnB;CACA,OAAO;EACL,MAAM;EACN,OAAO;EACP,QAAQ;EACR,eACE;EACF,UAAU;EACV,eAAe;EACf,iBAAiB;CACnB;AACF;AA4BA,MAAM,UAAU,EACd,WACA,YACA,MACA,gBACA,SAAS,UACT,UAAU,kBAAkB,CAAC,GAC7B,iBACA,mBACA,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,YAAY,qBAA8B;EACxD,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;CACZ,CAAC;CAED,MAAM,EAAE,kBAAkB,UAAU;CAGpC,MAAM,gBACH,SAAS,WAAW,WAAW,SAAS,iBAAiB;CAE5D,MAAM,cAAc,CAAC,EAAE,mBAAmB;CAC1C,MAAM,SAAS,WAAW;CAE1B,OACE,oBAAC,MAAD;EACW;EACT,MAAM,OAAO;EACb,WAAW,GACT,YACA,OAAO,OACP,eAAe,2BACf,WACA,YAAY,KAEd;EACA,iBAAiB,GACf,OAAO,QACP,sDACA,qDACA,OAAO,eACP,YAAY,MAEd;EACA,kBAAiB,YAAW;GAC1B,SAAS,OAAO;EAClB;EACA,GAAI;EAEH,UAAA,eACC,qBAAC,QAAD;GACE,WAAW,GACT;mCAEA,OAAO,UACP,UACI,CAAC,OAAO,eAAe,yBAAyB,IAChD,CAAC,OAAO,iBAAiB,iBAAiB,CAEhD;GATF,UAAA,CAWE,oBAAC,QAAD;IACE,WAAW,GACT,2DACA,UAAU,gBAAgB,WAC5B;IAEC,UAAA;GACG,CAAA,GACN,oBAAC,QAAD;IACE,WAAW,GACT,2DACA,UAAU,cAAc,aAC1B;IAEC,UAAA;GACG,CAAA,CACF;;CAEJ,CAAA;AAEV"}
@@ -6,19 +6,12 @@ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/components/molecules/collapse.tsx
7
7
  const { Accordion, AccordionItem, AccordionTrigger, AccordionContent } = accordion_exports;
8
8
  const Collapse = ({ expandIcon, accordion = false, items = [], className, classNames, defaultActiveKey, activeKey: _activeKey, onChange: _onChange, ...props }) => {
9
- const controlled = _activeKey !== void 0;
10
- const accordionProps = accordion ? {
11
- type: "single",
12
- onValueChange: (value) => {
13
- _onChange?.(value ? [value] : []);
14
- },
15
- ...controlled ? { value: `${_activeKey?.[0] ?? ""}` } : { defaultValue: `${defaultActiveKey?.[0] ?? ""}` }
16
- } : {
17
- type: "multiple",
9
+ const accordionProps = {
10
+ multiple: !accordion,
18
11
  onValueChange: (values) => {
19
12
  _onChange?.(values);
20
13
  },
21
- ...controlled ? { value: _activeKey?.map((key) => `${key}`) } : { defaultValue: defaultActiveKey?.map((key) => `${key}`) }
14
+ ..._activeKey !== void 0 ? { value: (_activeKey ?? []).map((key) => `${key}`) } : { defaultValue: (defaultActiveKey ?? []).map((key) => `${key}`) }
22
15
  };
23
16
  return /* @__PURE__ */ jsx(Accordion, {
24
17
  ...props,
@@ -1 +1 @@
1
- {"version":3,"file":"collapse.mjs","names":["accordion"],"sources":["../../../src/components/molecules/collapse.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { accordion } from '../../core';\n\nconst { Accordion, AccordionItem, AccordionTrigger, AccordionContent } =\n accordion;\n\ninterface Item {\n key: React.Key;\n label: React.ReactNode;\n disabled?: boolean;\n children: React.ReactNode;\n}\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'onChange' | 'defaultValue' | 'value' | 'dir'\n> {\n items?: Item[];\n accordion?: boolean;\n expandIcon?: React.ReactNode;\n classNames?: {\n item?: string;\n header?: string;\n body?: string;\n };\n defaultActiveKey?: string[] | number[];\n activeKey?: string[] | number[];\n onChange?: (keys: string[]) => void;\n}\n\nconst Collapse = ({\n expandIcon,\n accordion = false,\n items = [],\n className,\n classNames,\n defaultActiveKey,\n activeKey: _activeKey,\n onChange: _onChange,\n ...props\n}: Props) => {\n const controlled = _activeKey !== undefined;\n\n const accordionProps = accordion\n ? {\n type: 'single' as const,\n onValueChange: (value: string) => {\n _onChange?.(value ? [value] : []);\n },\n ...(controlled\n ? { value: `${_activeKey?.[0] ?? ''}` }\n : { defaultValue: `${defaultActiveKey?.[0] ?? ''}` }),\n }\n : {\n type: 'multiple' as const,\n onValueChange: (values: string[]) => {\n _onChange?.(values);\n },\n ...(controlled\n ? { value: _activeKey?.map(key => `${key}`) }\n : { defaultValue: defaultActiveKey?.map(key => `${key}`) }),\n };\n\n return (\n <Accordion {...props} className={className} {...accordionProps}>\n {items.map(({ key, label, children, disabled }) => (\n <AccordionItem\n key={key}\n value={String(key)}\n className={cn(\n 'border-none',\n classNames?.item,\n //\n )}\n disabled={disabled}\n >\n <AccordionTrigger\n className={cn(\n 'hover:no-underline',\n classNames?.header,\n disabled && 'cursor-no-drop opacity-50',\n //\n )}\n expandIcon={expandIcon}\n disabled={disabled}\n >\n {label}\n </AccordionTrigger>\n <AccordionContent\n className={cn(\n classNames?.body,\n //\n )}\n >\n {children}\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordion>\n );\n};\n\nexport default Collapse;\n"],"mappings":";;;;;;AAQA,MAAM,EAAE,WAAW,eAAe,kBAAkB,qBAClDA;AA0BF,MAAM,YAAY,EAChB,YACA,YAAY,OACZ,QAAQ,CAAC,GACT,WACA,YACA,kBACA,WAAW,YACX,UAAU,WACV,GAAG,YACQ;CACX,MAAM,aAAa,eAAe,KAAA;CAElC,MAAM,iBAAiB,YACnB;EACE,MAAM;EACN,gBAAgB,UAAkB;GAChC,YAAY,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;EAClC;EACA,GAAI,aACA,EAAE,OAAO,GAAG,aAAa,MAAM,KAAK,IACpC,EAAE,cAAc,GAAG,mBAAmB,MAAM,KAAK;CACvD,IACA;EACE,MAAM;EACN,gBAAgB,WAAqB;GACnC,YAAY,MAAM;EACpB;EACA,GAAI,aACA,EAAE,OAAO,YAAY,KAAI,QAAO,GAAG,KAAK,EAAE,IAC1C,EAAE,cAAc,kBAAkB,KAAI,QAAO,GAAG,KAAK,EAAE;CAC7D;CAEJ,OACE,oBAAC,WAAD;EAAW,GAAI;EAAkB;EAAW,GAAI;EAC7C,UAAA,MAAM,KAAK,EAAE,KAAK,OAAO,UAAU,eAClC,qBAAC,eAAD;GAEE,OAAO,OAAO,GAAG;GACjB,WAAW,GACT,eACA,YAAY,IAEd;GACU;GARZ,UAAA,CAUE,oBAAC,kBAAD;IACE,WAAW,GACT,sBACA,YAAY,QACZ,YAAY,2BAEd;IACY;IACF;IAET,UAAA;GACe,CAAA,GAClB,oBAAC,kBAAD;IACE,WAAW,GACT,YAAY,IAEd;IAEC;GACe,CAAA,CACL;EA7BR,GAAA,GA6BQ,CAChB;CACQ,CAAA;AAEf"}
1
+ {"version":3,"file":"collapse.mjs","names":["accordion"],"sources":["../../../src/components/molecules/collapse.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { accordion } from '../../core';\n\nconst { Accordion, AccordionItem, AccordionTrigger, AccordionContent } =\n accordion;\n\ninterface Item {\n key: React.Key;\n label: React.ReactNode;\n disabled?: boolean;\n children: React.ReactNode;\n}\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'onChange' | 'defaultValue' | 'value' | 'dir'\n> {\n items?: Item[];\n accordion?: boolean;\n expandIcon?: React.ReactNode;\n classNames?: {\n item?: string;\n header?: string;\n body?: string;\n };\n defaultActiveKey?: string[] | number[];\n activeKey?: string[] | number[];\n onChange?: (keys: string[]) => void;\n}\n\nconst Collapse = ({\n expandIcon,\n accordion = false,\n items = [],\n className,\n classNames,\n defaultActiveKey,\n activeKey: _activeKey,\n onChange: _onChange,\n ...props\n}: Props) => {\n const controlled = _activeKey !== undefined;\n\n // Base UI's accordion has no `type` and always models the open set as an\n // array; `multiple` (default false) is the only single-vs-multiple switch.\n // `accordion` here means \"one panel open at a time\", so `multiple = !accordion`.\n const accordionProps = {\n multiple: !accordion,\n onValueChange: (values: string[]) => {\n _onChange?.(values);\n },\n ...(controlled\n ? { value: (_activeKey ?? []).map(key => `${key}`) }\n : { defaultValue: (defaultActiveKey ?? []).map(key => `${key}`) }),\n };\n\n return (\n <Accordion {...props} className={className} {...accordionProps}>\n {items.map(({ key, label, children, disabled }) => (\n <AccordionItem\n key={key}\n value={String(key)}\n className={cn(\n 'border-none',\n classNames?.item,\n //\n )}\n disabled={disabled}\n >\n <AccordionTrigger\n className={cn(\n 'hover:no-underline',\n classNames?.header,\n disabled && 'cursor-no-drop opacity-50',\n //\n )}\n expandIcon={expandIcon}\n disabled={disabled}\n >\n {label}\n </AccordionTrigger>\n <AccordionContent\n className={cn(\n classNames?.body,\n //\n )}\n >\n {children}\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordion>\n );\n};\n\nexport default Collapse;\n"],"mappings":";;;;;;AAQA,MAAM,EAAE,WAAW,eAAe,kBAAkB,qBAClDA;AA0BF,MAAM,YAAY,EAChB,YACA,YAAY,OACZ,QAAQ,CAAC,GACT,WACA,YACA,kBACA,WAAW,YACX,UAAU,WACV,GAAG,YACQ;CAMX,MAAM,iBAAiB;EACrB,UAAU,CAAC;EACX,gBAAgB,WAAqB;GACnC,YAAY,MAAM;EACpB;EACA,GAViB,eAAe,KAAA,IAW5B,EAAE,QAAQ,cAAc,CAAC,EAAA,CAAG,KAAI,QAAO,GAAG,KAAK,EAAE,IACjD,EAAE,eAAe,oBAAoB,CAAC,EAAA,CAAG,KAAI,QAAO,GAAG,KAAK,EAAE;CACpE;CAEA,OACE,oBAAC,WAAD;EAAW,GAAI;EAAkB;EAAW,GAAI;EAC7C,UAAA,MAAM,KAAK,EAAE,KAAK,OAAO,UAAU,eAClC,qBAAC,eAAD;GAEE,OAAO,OAAO,GAAG;GACjB,WAAW,GACT,eACA,YAAY,IAEd;GACU;GARZ,UAAA,CAUE,oBAAC,kBAAD;IACE,WAAW,GACT,sBACA,YAAY,QACZ,YAAY,2BAEd;IACY;IACF;IAET,UAAA;GACe,CAAA,GAClB,oBAAC,kBAAD;IACE,WAAW,GACT,YAAY,IAEd;IAEC;GACe,CAAA,CACL;EA7BR,GAAA,GA6BQ,CAChB;CACQ,CAAA;AAEf"}
@@ -11,7 +11,6 @@ interface Props {
11
11
  size?: 'small' | 'medium' | 'large' | 'full' | string;
12
12
  maskClosable?: boolean;
13
13
  handlebar?: boolean;
14
- draggable?: boolean;
15
14
  rounded?: boolean;
16
15
  mask?: boolean;
17
16
  className?: string;
@@ -30,7 +29,7 @@ interface Props {
30
29
  container?: HTMLElement;
31
30
  onClose: () => void;
32
31
  }
33
- declare const Drawer: ({ open, title, extra, footer, closable, closeIcon, direction, size, maskClosable, handlebar, draggable, rounded, mask, className, classNames, style, children, container, onClose, ...props }: Props) => import("react").JSX.Element;
32
+ declare const Drawer: ({ open, title, extra, footer, closable, closeIcon, direction, size, maskClosable, handlebar, rounded, mask, className, classNames, style, children, container, onClose, ...props }: Props) => import("react").JSX.Element;
34
33
  //#endregion
35
34
  export { Props, Drawer as default };
36
35
  //# sourceMappingURL=drawer.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";UA2CiB;EACf;EACA,WAAW,MAAM;EACjB,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,SAAS,MAAM;EACf;EACA,YAAY,MAAM;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ,MAAM;EACd;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEF,YAAY;EACZ;;cA8BI,WAAU,MAAA,OAAA,OAAA,QAAA,UAAA,WAAA,WAAA,MAAA,cAAA,WAAA,WAAA,SAAA,MAAA,WAAA,YAAA,OAAA,UAAA,WAAA,YAAA,SAqBb,0BAAK,IAAA"}
1
+ {"version":3,"file":"drawer.d.mts","names":[],"sources":["../../../src/components/organisms/drawer.tsx"],"mappings":";UA2CiB;EACf;EACA,WAAW,MAAM;EACjB,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,SAAS,MAAM;EACf;EACA,YAAY,MAAM;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ,MAAM;EACd;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEF,YAAY;EACZ;;cA8BI,WAAU,MAAA,OAAA,OAAA,QAAA,UAAA,WAAA,WAAA,MAAA,cAAA,WAAA,SAAA,MAAA,WAAA,YAAA,OAAA,UAAA,WAAA,YAAA,SAoBb,0BAAK,IAAA"}