@omnifyjp/ui 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ML2VNJ7R.js → chunk-37CQS347.js} +3 -3
- package/dist/{chunk-ML2VNJ7R.js.map → chunk-37CQS347.js.map} +1 -1
- package/dist/{chunk-2OPOSDEH.js → chunk-CTNIYDQI.js} +3 -3
- package/dist/{chunk-2OPOSDEH.js.map → chunk-CTNIYDQI.js.map} +1 -1
- package/dist/{chunk-Q5KDFNRD.js → chunk-CTZOQ5BS.js} +4 -4
- package/dist/chunk-CTZOQ5BS.js.map +1 -0
- package/dist/{chunk-7HHL5OFD.js → chunk-JNLYTMN5.js} +3 -3
- package/dist/chunk-JNLYTMN5.js.map +1 -0
- package/dist/{chunk-M22SIS5Z.js → chunk-JTVWK3BC.js} +3 -3
- package/dist/{chunk-M22SIS5Z.js.map → chunk-JTVWK3BC.js.map} +1 -1
- package/dist/{chunk-BBFOFRWT.js → chunk-QHHPWBZM.js} +5 -46
- package/dist/chunk-QHHPWBZM.js.map +1 -0
- package/dist/chunk-RWMRHEWT.js +8 -0
- package/dist/chunk-RWMRHEWT.js.map +1 -0
- package/dist/chunk-SWQDP3VC.js +47 -0
- package/dist/chunk-SWQDP3VC.js.map +1 -0
- package/dist/{chunk-DB42CM3T.js → chunk-TSRLQI2O.js} +4 -4
- package/dist/chunk-TSRLQI2O.js.map +1 -0
- package/dist/{chunk-YU55YBID.js → chunk-XJSGU5XZ.js} +2 -2
- package/dist/chunk-XJSGU5XZ.js.map +1 -0
- package/dist/components/domain/calendar/calendar-event-chip.js +2 -1
- package/dist/components/domain/calendar/calendar-event-chip.js.map +1 -1
- package/dist/components/domain/calendar/calendar-event-sheet.js +2 -1
- package/dist/components/domain/calendar/calendar-event-sheet.js.map +1 -1
- package/dist/components/domain/calendar/calendar-mini.js +2 -1
- package/dist/components/domain/calendar/calendar-mini.js.map +1 -1
- package/dist/components/domain/calendar/calendar-toolbar.js +2 -1
- package/dist/components/domain/calendar/calendar-toolbar.js.map +1 -1
- package/dist/components/inputs/color-picker.js +5 -4
- package/dist/components/inputs/date-picker.js +2 -1
- package/dist/components/inputs/date-picker.js.map +1 -1
- package/dist/components/inputs/input.d.ts +1 -2
- package/dist/components/inputs/input.js +4 -3
- package/dist/components/inputs/password-input.d.ts +1 -2
- package/dist/components/inputs/password-input.js +5 -4
- package/dist/components/inputs/slug-input.js +5 -4
- package/dist/components/inputs/textarea.d.ts +1 -2
- package/dist/components/inputs/textarea.js +4 -3
- package/dist/components/inputs/time-picker.js +4 -3
- package/dist/components/inputs/time-picker.js.map +1 -1
- package/dist/components/inputs/translatable-field.d.ts +1 -1
- package/dist/components/inputs/translatable-field.js +1 -1
- package/dist/components/navigation/locale-switcher.js +3 -2
- package/dist/index.d.ts +45 -1
- package/dist/index.js +10 -8
- package/dist/providers/ui-provider.d.ts +2 -63
- package/dist/providers/ui-provider.js +2 -1
- package/dist/ui-context-D0zD0xa5.d.ts +25 -0
- package/package.json +2 -2
- package/dist/chunk-7HHL5OFD.js.map +0 -1
- package/dist/chunk-BBFOFRWT.js.map +0 -1
- package/dist/chunk-DB42CM3T.js.map +0 -1
- package/dist/chunk-Q5KDFNRD.js.map +0 -1
- package/dist/chunk-YU55YBID.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inputVariants } from './chunk-
|
|
1
|
+
import { inputVariants } from './chunk-TSRLQI2O.js';
|
|
2
2
|
import { cn } from './chunk-DGPY4WP3.js';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { EyeOff, Eye } from 'lucide-react';
|
|
@@ -35,5 +35,5 @@ var PasswordInput = React.forwardRef(
|
|
|
35
35
|
PasswordInput.displayName = "PasswordInput";
|
|
36
36
|
|
|
37
37
|
export { PasswordInput };
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
39
|
-
//# sourceMappingURL=chunk-
|
|
38
|
+
//# sourceMappingURL=chunk-37CQS347.js.map
|
|
39
|
+
//# sourceMappingURL=chunk-37CQS347.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/inputs/password-input.tsx"],"names":[],"mappings":";;;;;;AAiCA,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA;AAAA,EAC1B,CAAC,EAAE,SAAA,EAAW,MAAM,GAAG,KAAA,IAAS,GAAA,KAAQ;AACtC,IAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAU,eAAS,KAAK,CAAA;AAElD,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,UAAU,MAAA,GAAS,UAAA;AAAA,UACzB,GAAA;AAAA,UACA,WAAA,EAAU,OAAA;AAAA,UACV,SAAA,EAAW,EAAA,CAAG,aAAA,CAAc,EAAE,IAAA,EAAM,SAAA,EAAW,EAAA,CAAG,+EAAA,EAAiF,SAAS,CAAA,EAAG,CAAC,CAAA;AAAA,UAC/I,GAAG;AAAA;AAAA,OACN;AAAA,sBACA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,QAAA,EAAU,EAAA;AAAA,UACV,SAAA,EAAU,mIAAA;AAAA,UACV,SAAS,MAAM,UAAA,CAAW,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA;AAAA,UACnC,YAAA,EAAY,UAAU,eAAA,GAAkB,eAAA;AAAA,UAEvC,QAAA,EAAA,OAAA,uBACE,MAAA,EAAA,EAAO,SAAA,EAAU,WAAU,CAAA,mBAE5B,GAAA,CAAC,GAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA;AAE7B,KAAA,EACF,CAAA;AAAA,EAEJ;AACF;AACA,aAAA,CAAc,WAAA,GAAc,eAAA","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/components/inputs/password-input.tsx"],"names":[],"mappings":";;;;;;AAiCA,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA;AAAA,EAC1B,CAAC,EAAE,SAAA,EAAW,MAAM,GAAG,KAAA,IAAS,GAAA,KAAQ;AACtC,IAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAU,eAAS,KAAK,CAAA;AAElD,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,UAAU,MAAA,GAAS,UAAA;AAAA,UACzB,GAAA;AAAA,UACA,WAAA,EAAU,OAAA;AAAA,UACV,SAAA,EAAW,EAAA,CAAG,aAAA,CAAc,EAAE,IAAA,EAAM,SAAA,EAAW,EAAA,CAAG,+EAAA,EAAiF,SAAS,CAAA,EAAG,CAAC,CAAA;AAAA,UAC/I,GAAG;AAAA;AAAA,OACN;AAAA,sBACA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,QAAA,EAAU,EAAA;AAAA,UACV,SAAA,EAAU,mIAAA;AAAA,UACV,SAAS,MAAM,UAAA,CAAW,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA;AAAA,UACnC,YAAA,EAAY,UAAU,eAAA,GAAkB,eAAA;AAAA,UAEvC,QAAA,EAAA,OAAA,uBACE,MAAA,EAAA,EAAO,SAAA,EAAU,WAAU,CAAA,mBAE5B,GAAA,CAAC,GAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EAAU;AAAA;AAAA;AAE7B,KAAA,EACF,CAAA;AAAA,EAEJ;AACF;AACA,aAAA,CAAc,WAAA,GAAc,eAAA","file":"chunk-37CQS347.js","sourcesContent":["import * as React from \"react\";\nimport { type VariantProps } from \"class-variance-authority\";\nimport { Eye, EyeOff } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\nimport { inputVariants } from \"./input\";\n\ninterface PasswordInputProps\n extends Omit<React.ComponentProps<\"input\">, \"type\" | \"size\">,\n VariantProps<typeof inputVariants> {}\n\n/**\n * Password input with a built-in show/hide toggle button.\n *\n * Extends native `<input>` (minus `type` which is managed internally).\n * Shares the same size variants as `Input`.\n *\n * @example\n * ```tsx\n * // Default size\n * <PasswordInput placeholder=\"Enter password\" />\n *\n * // Sizes: xs (24px) | sm (28px) | default (32px) | lg (36px) | xl (44px)\n * <PasswordInput size=\"xl\" placeholder=\"Password\" />\n *\n * // Controlled\n * <PasswordInput\n * value={password}\n * onChange={(e) => setPassword(e.target.value)}\n * placeholder=\"Password\"\n * />\n * ```\n */\nconst PasswordInput = React.forwardRef<HTMLInputElement, PasswordInputProps>(\n ({ className, size, ...props }, ref) => {\n const [visible, setVisible] = React.useState(false);\n\n return (\n <div className=\"relative\">\n <input\n type={visible ? \"text\" : \"password\"}\n ref={ref}\n data-slot=\"input\"\n className={cn(inputVariants({ size, className: cn(\"pr-10 [&::-ms-reveal]:hidden [&::-webkit-credentials-auto-fill-button]:hidden\", className) }))}\n {...props}\n />\n <button\n type=\"button\"\n tabIndex={-1}\n className=\"absolute right-0 top-0 flex h-full w-10 items-center justify-center text-muted-foreground hover:text-foreground transition-colors\"\n onClick={() => setVisible((v) => !v)}\n aria-label={visible ? \"Hide password\" : \"Show password\"}\n >\n {visible ? (\n <EyeOff className=\"h-4 w-4\" />\n ) : (\n <Eye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n );\n },\n);\nPasswordInput.displayName = \"PasswordInput\";\n\nexport { PasswordInput };\nexport type { PasswordInputProps };\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Input } from './chunk-
|
|
1
|
+
import { Input } from './chunk-TSRLQI2O.js';
|
|
2
2
|
import { Popover, PopoverTrigger, PopoverContent } from './chunk-7NMNLY7F.js';
|
|
3
3
|
import { Button } from './chunk-BOV3Q2JH.js';
|
|
4
4
|
import { cn } from './chunk-DGPY4WP3.js';
|
|
@@ -139,5 +139,5 @@ function ColorPicker({
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
export { ColorPicker };
|
|
142
|
-
//# sourceMappingURL=chunk-
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
142
|
+
//# sourceMappingURL=chunk-CTNIYDQI.js.map
|
|
143
|
+
//# sourceMappingURL=chunk-CTNIYDQI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/inputs/color-picker.tsx"],"names":[],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/components/inputs/color-picker.tsx"],"names":[],"mappings":"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","file":"chunk-CTNIYDQI.js","sourcesContent":["import * as React from \"react\";\nimport { Check } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"./button\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../overlay/popover\";\nimport { Input } from \"./input\";\n\nconst PRESET_COLORS = [\n \"#EF4444\", // Red\n \"#F97316\", // Orange\n \"#F59E0B\", // Amber\n \"#EAB308\", // Yellow\n \"#84CC16\", // Lime\n \"#22C55E\", // Green\n \"#10B981\", // Emerald\n \"#14B8A6\", // Teal\n \"#06B6D4\", // Cyan\n \"#0EA5E9\", // Sky\n \"#3B82F6\", // Blue\n \"#6366F1\", // Indigo\n \"#8B5CF6\", // Purple\n \"#A855F7\", // Violet\n \"#D946EF\", // Fuchsia\n \"#EC4899\", // Pink\n \"#F43F5E\", // Rose\n \"#64748B\", // Slate\n \"#6B7280\", // Gray\n \"#000000\", // Black\n];\n\ninterface ColorPickerProps {\n /** Currently selected color as a hex string (e.g., `\"#3B82F6\"`). */\n value?: string;\n /** Callback fired when a color is selected. Receives a hex string. */\n onChange?: (color: string) => void;\n /** Additional CSS class for the trigger button. */\n className?: string;\n /** Whether the color picker is disabled. */\n disabled?: boolean;\n /** Whether to show the preset color grid. Defaults to `true`. */\n showPresets?: boolean;\n /** Whether to show the custom hex input with native color picker. Defaults to `true`. */\n showInput?: boolean;\n}\n\n/**\n * Color picker with a popover containing preset color swatches and an optional custom hex input.\n * The trigger button shows the currently selected color swatch and its hex value.\n *\n * @example\n * ```tsx\n * const [color, setColor] = useState(\"#3B82F6\");\n *\n * <ColorPicker\n * value={color}\n * onChange={setColor}\n * showPresets\n * showInput\n * />\n * ```\n */\nexport function ColorPicker({\n value = \"#3B82F6\",\n onChange,\n className,\n disabled,\n showPresets = true,\n showInput = true,\n}: ColorPickerProps) {\n const [customColor, setCustomColor] = React.useState(value);\n\n const handleColorChange = (color: string) => {\n setCustomColor(color);\n onChange?.(color);\n };\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n disabled={disabled}\n className={cn(\n \"w-full justify-start gap-2\",\n className\n )}\n >\n <div\n className=\"h-4 w-4 rounded border border-border\"\n style={{ backgroundColor: value }}\n />\n <span className=\"flex-1 text-left\">{value}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-3\" align=\"start\">\n <div className=\"space-y-3\">\n {showPresets && (\n <div>\n <div className=\"text-xs font-medium mb-2 text-foreground\">\n Màu mặc định\n </div>\n <div className=\"grid grid-cols-10 gap-1.5\">\n {PRESET_COLORS.map((color) => (\n <button\n key={color}\n type=\"button\"\n className={cn(\n \"h-6 w-6 rounded border-2 transition-all hover:scale-110\",\n value === color\n ? \"border-foreground ring-2 ring-foreground ring-offset-1\"\n : \"border-border\"\n )}\n style={{ backgroundColor: color }}\n onClick={() => handleColorChange(color)}\n >\n {value === color && (\n <Check className=\"w-3 h-3 text-white mx-auto drop-shadow\" />\n )}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {showInput && (\n <div>\n <div className=\"text-xs font-medium mb-2 text-foreground\">\n Màu tùy chỉnh\n </div>\n <div className=\"flex gap-2\">\n <div className=\"relative flex-1\">\n <Input\n value={customColor}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setCustomColor(e.target.value)}\n onBlur={() => {\n // Validate hex color\n if (/^#[0-9A-F]{6}$/i.test(customColor)) {\n handleColorChange(customColor);\n } else {\n setCustomColor(value);\n }\n }}\n placeholder=\"#000000\"\n className=\"pr-10\"\n />\n <input\n type=\"color\"\n value={customColor}\n onChange={(e) => {\n setCustomColor(e.target.value);\n handleColorChange(e.target.value);\n }}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-6 w-6 rounded border border-border cursor-pointer\"\n />\n </div>\n </div>\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TranslatableField } from './chunk-
|
|
2
|
-
import { useUILocales, resolveTranslatableConfig } from './chunk-
|
|
1
|
+
import { TranslatableField } from './chunk-XJSGU5XZ.js';
|
|
2
|
+
import { useUILocales, resolveTranslatableConfig } from './chunk-SWQDP3VC.js';
|
|
3
3
|
import { cn } from './chunk-DGPY4WP3.js';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { jsx } from 'react/jsx-runtime';
|
|
@@ -66,5 +66,5 @@ var Textarea = React.forwardRef(
|
|
|
66
66
|
Textarea.displayName = "Textarea";
|
|
67
67
|
|
|
68
68
|
export { Textarea };
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
70
|
-
//# sourceMappingURL=chunk-
|
|
69
|
+
//# sourceMappingURL=chunk-CTZOQ5BS.js.map
|
|
70
|
+
//# sourceMappingURL=chunk-CTZOQ5BS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/inputs/textarea.tsx"],"names":["textareaRest","value","onChange"],"mappings":";;;;;;AAsDA,IAAM,aAAA,GACJ,4cAAA;AAyBF,IAAM,QAAA,GAAiB,KAAA,CAAA,UAAA;AAAA,EACrB,CAAC,OAAO,GAAA,KAAQ;AACd,IAAA,MAAM,EAAE,SAAA,EAAW,YAAA,EAAc,GAAG,MAAK,GAAI,KAAA;AAE7C,IAAA,MAAM,kBAAkB,YAAA,EAAa;AAGrC,IAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,MAAA,MAAM,MAAA,GAAS,yBAAA,CAA0B,YAAA,EAAc,eAAe,CAAA;AAGtE,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,MAAM,EAAE,KAAA,EAAO,EAAA,EAAI,UAAU,GAAA,EAAK,GAAGA,eAAa,GAAI,IAAA;AACtD,QAAA,uBACE,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,GAAA;AAAA,YACA,WAAA,EAAU,UAAA;AAAA,YACV,SAAA,EAAW,EAAA,CAAG,aAAA,EAAe,SAAS,CAAA;AAAA,YACrC,GAAIA;AAAA;AAAA,SACP;AAAA,MAEJ;AAEA,MAAA,MAAM,EAAE,KAAA,EAAAC,MAAAA,GAAQ,EAAC,EAAG,UAAAC,SAAAA,EAAU,MAAA,EAAQ,GAAGF,aAAAA,EAAa,GAAI,IAAA;AAE1D,MAAA,uBACE,GAAA;AAAA,QAAC,iBAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,KAAA,EAAOC,MAAAA;AAAA,UACP,QAAA,EAAUC,cAAa,MAAM;AAAA,UAAC,CAAA,CAAA;AAAA,UAC9B,MAAA;AAAA,UAEC,QAAA,EAAA,CAAC,EAAE,KAAA,EAAO,WAAA,EAAa,UAAU,YAAA,EAAc,mBAAA,EAAqB,UAAS,qBAC5E,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,GAAA;AAAA,cACA,WAAA,EAAU,UAAA;AAAA,cACV,mBAAA,EAAiB,IAAA;AAAA,cACjB,SAAA,EAAW,EAAA,CAAG,aAAA,EAAe,SAAS,CAAA;AAAA,cACtC,KAAA,EAAO,WAAA;AAAA,cACP,WAAA,EAAa,uBAAwBF,aAAAA,CAAmE,WAAA;AAAA,cACxG,UAAU,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,cAC3C,GAAIA,aAAAA;AAAA,cACL,cAAA,EAAc,QAAA,IAAaA,aAAAA,CAAmE,cAAc,CAAA,IAAK;AAAA;AAAA;AACnH;AAAA,OAEJ;AAAA,IAEJ;AAGA,IAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAU,GAAG,cAAa,GAAI,IAAA;AAC7C,IAAA,uBACE,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,UAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,aAAA,EAAe,SAAS,CAAA;AAAA,QACtC,KAAA;AAAA,QACA,QAAA;AAAA,QACC,GAAI;AAAA;AAAA,KACP;AAAA,EAEJ;AACF;AACA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"chunk-CTZOQ5BS.js","sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\nimport { TranslatableField } from './translatable-field';\nimport { useUILocales, resolveTranslatableConfig } from '../../providers/ui-hooks';\nimport type { TranslatableConfig, TranslatableValue } from '../../providers/ui-context';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype NativeTextareaProps = Omit<React.ComponentProps<'textarea'>, 'value' | 'onChange'>;\n\ninterface StandardTextareaProps extends NativeTextareaProps {\n /** Translatable mode disabled (default). */\n translatable?: never;\n value?: string;\n onChange?: React.ChangeEventHandler<HTMLTextAreaElement>;\n}\n\ninterface TranslatableTextareaProps extends NativeTextareaProps {\n /**\n * Enable locale-switching tabs on this textarea.\n * - `true` — inherit UIProvider's locale config\n * - `object` — override locales/defaultLocale/fallbackLocale per field\n *\n * @example\n * ```tsx\n * // Uses UIProvider config\n * <Textarea translatable value={val} onChange={setVal} />\n *\n * // Custom per-field config\n * <Textarea\n * translatable={{ locales: { en: 'English', vi: 'Tiếng Việt' }, fallbackLocale: 'en' }}\n * value={val}\n * onChange={setVal}\n * />\n * ```\n */\n translatable: TranslatableConfig;\n value?: TranslatableValue;\n onChange?: (value: TranslatableValue) => void;\n /**\n * Per-locale validation errors. Truthy string = that locale is invalid.\n * The active locale's error is forwarded as `aria-invalid` on the textarea;\n * all locale tabs with errors show a red dot indicator.\n *\n * @example `{ en: 'Required', vi: 'Too long (120/100)' }`\n */\n errors?: Partial<Record<string, string>>;\n}\n\nexport type TextareaProps = StandardTextareaProps | TranslatableTextareaProps;\n\n// ─── Base class ───────────────────────────────────────────────────────────────\n\nconst textareaClass =\n \"resize-none border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-input-background px-3 py-2 text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\";\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * Multi-line text input with auto-sizing via `field-sizing-content`.\n * Supports translatable mode via the `translatable` prop.\n *\n * @example\n * ```tsx\n * // Standard\n * <Textarea placeholder=\"Enter a description...\" />\n * <Textarea value={content} onChange={(e) => setContent(e.target.value)} />\n *\n * // Translatable — uses UIProvider's locale config\n * <Textarea translatable value={val} onChange={setVal} />\n *\n * // Translatable — custom config\n * <Textarea\n * translatable={{ locales: { en: 'English', vi: 'Tiếng Việt' }, fallbackLocale: 'en' }}\n * value={val}\n * onChange={setVal}\n * />\n * ```\n */\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n (props, ref) => {\n const { className, translatable, ...rest } = props as TranslatableTextareaProps & { className?: string };\n\n const providerLocales = useUILocales();\n\n // ── Translatable mode ──────────────────────────────────────────────────\n if (translatable !== undefined) {\n const config = resolveTranslatableConfig(translatable, providerLocales);\n\n // Fallback: if no locale config available, render standard textarea\n if (!config) {\n const { value: _v, onChange: _oc, ...textareaRest } = rest as TranslatableTextareaProps;\n return (\n <textarea\n ref={ref}\n data-slot=\"textarea\"\n className={cn(textareaClass, className)}\n {...(textareaRest as NativeTextareaProps)}\n />\n );\n }\n\n const { value = {}, onChange, errors, ...textareaRest } = rest as TranslatableTextareaProps;\n\n return (\n <TranslatableField\n config={config}\n value={value as TranslatableValue}\n onChange={onChange ?? (() => {})}\n errors={errors}\n >\n {({ value: localeValue, onChange: localeChange, fallbackPlaceholder, hasError }) => (\n <textarea\n ref={ref}\n data-slot=\"textarea\"\n data-translatable\n className={cn(textareaClass, className)}\n value={localeValue}\n placeholder={fallbackPlaceholder ?? (textareaRest as React.TextareaHTMLAttributes<HTMLTextAreaElement>).placeholder}\n onChange={(e) => localeChange(e.target.value)}\n {...(textareaRest as React.TextareaHTMLAttributes<HTMLTextAreaElement>)}\n aria-invalid={hasError || (textareaRest as React.TextareaHTMLAttributes<HTMLTextAreaElement>)['aria-invalid'] || undefined}\n />\n )}\n </TranslatableField>\n );\n }\n\n // ── Standard mode ──────────────────────────────────────────────────────\n const { value, onChange, ...textareaRest } = rest as StandardTextareaProps;\n return (\n <textarea\n ref={ref}\n data-slot=\"textarea\"\n className={cn(textareaClass, className)}\n value={value}\n onChange={onChange}\n {...(textareaRest as NativeTextareaProps)}\n />\n );\n },\n);\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem } from './chunk-DXZZURPN.js';
|
|
2
|
-
import { useLocale } from './chunk-
|
|
2
|
+
import { useLocale } from './chunk-SWQDP3VC.js';
|
|
3
3
|
import { Button } from './chunk-BOV3Q2JH.js';
|
|
4
4
|
import { cn } from './chunk-DGPY4WP3.js';
|
|
5
5
|
import { GlobeIcon } from 'lucide-react';
|
|
@@ -67,5 +67,5 @@ function LocaleSwitcher({
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export { LocaleSwitcher };
|
|
70
|
-
//# sourceMappingURL=chunk-
|
|
71
|
-
//# sourceMappingURL=chunk-
|
|
70
|
+
//# sourceMappingURL=chunk-JNLYTMN5.js.map
|
|
71
|
+
//# sourceMappingURL=chunk-JNLYTMN5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/navigation/locale-switcher.tsx"],"names":[],"mappings":"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","file":"chunk-JNLYTMN5.js","sourcesContent":["import { GlobeIcon } from 'lucide-react';\n\nimport { cn } from '../../lib/utils';\nimport { useLocale } from '../../providers/ui-hooks';\nimport type { LocaleCode } from '../../providers/ui-context';\nimport { Button } from '../inputs/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from './dropdown-menu';\n\n// ─── Flag helpers ────────────────────────────────────────────────────────────\n\n/** Common locale code → flag emoji map. */\nconst LOCALE_TO_FLAG: Record<string, string> = {\n en: '🇺🇸',\n vi: '🇻🇳',\n ja: '🇯🇵',\n ko: '🇰🇷',\n zh: '🇨🇳',\n fr: '🇫🇷',\n de: '🇩🇪',\n es: '🇪🇸',\n pt: '🇧🇷',\n it: '🇮🇹',\n ru: '🇷🇺',\n ar: '🇸🇦',\n th: '🇹🇭',\n id: '🇮🇩',\n ms: '🇲🇾',\n};\n\n/**\n * Derive flag emoji from a locale code.\n * 1. Check the built-in map using the base language (before `-`).\n * 2. If a region subtag exists (e.g. `en-US`), convert to regional indicator symbols.\n * 3. Fall back to globe emoji.\n */\nfunction deriveFlag(code: LocaleCode, customFlags?: Record<string, string>): string {\n if (customFlags?.[code]) return customFlags[code];\n\n const base = code.split('-')[0].toLowerCase();\n if (LOCALE_TO_FLAG[base]) return LOCALE_TO_FLAG[base];\n\n // Try region subtag → flag emoji (e.g. \"US\" → 🇺🇸)\n const parts = code.split('-');\n if (parts.length > 1) {\n const region = parts[parts.length - 1].toUpperCase();\n if (region.length === 2) {\n return String.fromCodePoint(\n ...Array.from(region).map((c) => 0x1f1e6 + c.charCodeAt(0) - 65),\n );\n }\n }\n\n return '🌐';\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport interface LocaleSwitcherProps {\n /** Show flag emoji. Default: false */\n showFlag?: boolean;\n /** Show locale label (e.g. \"English\"). Default: true */\n showLabel?: boolean;\n /** Show locale code (e.g. \"EN\"). Default: false */\n showCode?: boolean;\n /** Dropdown alignment. Default: \"end\" */\n align?: 'start' | 'center' | 'end';\n /** Custom flag map. Auto-derived from locale code if not provided. */\n flags?: Record<string, string>;\n /** Button variant. Default: \"ghost\" */\n variant?: 'ghost' | 'outline' | 'default';\n /** Button size. Default: inferred (icon when no label/code, default otherwise) */\n size?: 'default' | 'sm' | 'icon';\n /** Additional class names for the trigger button. */\n className?: string;\n}\n\n/**\n * Dropdown locale switcher that reads from UIProvider.\n *\n * Requires `<UIProvider locales={...}>` to be an ancestor.\n *\n * @example\n * ```tsx\n * <LocaleSwitcher />\n * <LocaleSwitcher showFlag showLabel={false} />\n * <LocaleSwitcher showCode variant=\"outline\" />\n * ```\n */\nexport function LocaleSwitcher({\n showFlag = false,\n showLabel = true,\n showCode = false,\n align = 'end',\n flags,\n variant = 'ghost',\n size,\n className,\n}: LocaleSwitcherProps) {\n const { currentLocale, setLocale, locales } = useLocale();\n\n const entries = Object.entries(locales);\n if (entries.length === 0) return null;\n\n const currentLabel = locales[currentLocale] ?? currentLocale;\n const hasText = showLabel || showCode;\n const resolvedSize = size ?? (hasText ? 'default' : 'icon');\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant={variant} size={resolvedSize} className={cn('gap-2', className)}>\n {showFlag ? (\n <span className=\"text-base leading-none\">{deriveFlag(currentLocale, flags)}</span>\n ) : (\n <GlobeIcon className=\"size-4\" />\n )}\n {showLabel && <span>{currentLabel}</span>}\n {showCode && !showLabel && (\n <span>{currentLocale.split('-')[0].toUpperCase()}</span>\n )}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align={align}>\n <DropdownMenuRadioGroup value={currentLocale} onValueChange={setLocale}>\n {entries.map(([code, label]) => (\n <DropdownMenuRadioItem key={code} value={code}>\n {showFlag && (\n <span className=\"mr-2 text-base leading-none\">\n {deriveFlag(code, flags)}\n </span>\n )}\n {label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Input } from './chunk-
|
|
1
|
+
import { Input } from './chunk-TSRLQI2O.js';
|
|
2
2
|
import { Label } from './chunk-EYJ7TJIX.js';
|
|
3
3
|
import { useEffect } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -40,5 +40,5 @@ function SlugInput({
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export { SlugInput, generateSlug };
|
|
43
|
-
//# sourceMappingURL=chunk-
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
43
|
+
//# sourceMappingURL=chunk-JTVWK3BC.js.map
|
|
44
|
+
//# sourceMappingURL=chunk-JTVWK3BC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/inputs/slug-input.tsx"],"names":[],"mappings":";;;;;AA2BA,IAAM,aAAA,GAAiC;AAAA,EACrC,IAAA,EAAM,MAAA;AAAA,EACN,aAAA,EAAe,2BAAA;AAAA,EACf,WAAA,EAAa;AACf,CAAA;AAMO,SAAS,aAAa,IAAA,EAAsB;AACjD,EAAA,OAAO,IAAA,CACJ,aAAY,CACZ,OAAA,CAAQ,wBAAwB,GAAG,CAAA,CACnC,QAAQ,gBAAA,EAAkB,GAAG,EAC7B,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA,CACvB,OAAA,CAAQ,wBAAwB,GAAG,CAAA,CACnC,QAAQ,gBAAA,EAAkB,GAAG,EAC7B,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA,CACvB,OAAA,CAAQ,MAAM,GAAG,CAAA,CACjB,QAAQ,eAAA,EAAiB,EAAE,EAC3B,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,OAAA,CAAQ,OAAO,GAAG,CAAA,CAClB,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACzB;AAqBO,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA,EACA,IAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,EAAQ;AACV,CAAA,EAAmB;AACjB,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,aAAA,EAAe,GAAG,cAAA,EAAe;AAErD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,YAAY,KAAA,EAAO;AACtB,MAAA,YAAA,CAAa,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,EAAO,QAAA,EAAU,YAAY,CAAC,CAAA;AAElC,EAAA,4BACG,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAO,iBAAO,IAAA,EAAK,CAAA;AAAA,oBACpB,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,IAAA;AAAA,QACP,UAAU,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,QAC5C,aAAa,MAAA,CAAO,WAAA;AAAA,QACpB,SAAA,EAAU;AAAA;AAAA,KACZ;AAAA,oBACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAA,EAAsC,iBAAO,aAAA,EAAc;AAAA,GAAA,EAC1E,CAAA;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/components/inputs/slug-input.tsx"],"names":[],"mappings":";;;;;AA2BA,IAAM,aAAA,GAAiC;AAAA,EACrC,IAAA,EAAM,MAAA;AAAA,EACN,aAAA,EAAe,2BAAA;AAAA,EACf,WAAA,EAAa;AACf,CAAA;AAMO,SAAS,aAAa,IAAA,EAAsB;AACjD,EAAA,OAAO,IAAA,CACJ,aAAY,CACZ,OAAA,CAAQ,wBAAwB,GAAG,CAAA,CACnC,QAAQ,gBAAA,EAAkB,GAAG,EAC7B,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA,CACvB,OAAA,CAAQ,wBAAwB,GAAG,CAAA,CACnC,QAAQ,gBAAA,EAAkB,GAAG,EAC7B,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA,CACvB,OAAA,CAAQ,MAAM,GAAG,CAAA,CACjB,QAAQ,eAAA,EAAiB,EAAE,EAC3B,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,OAAA,CAAQ,OAAO,GAAG,CAAA,CAClB,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACzB;AAqBO,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA,EACA,IAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,EAAQ;AACV,CAAA,EAAmB;AACjB,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,aAAA,EAAe,GAAG,cAAA,EAAe;AAErD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,YAAY,KAAA,EAAO;AACtB,MAAA,YAAA,CAAa,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,EAAO,QAAA,EAAU,YAAY,CAAC,CAAA;AAElC,EAAA,4BACG,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAO,iBAAO,IAAA,EAAK,CAAA;AAAA,oBACpB,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,IAAA;AAAA,QACP,UAAU,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,QAC5C,aAAa,MAAA,CAAO,WAAA;AAAA,QACpB,SAAA,EAAU;AAAA;AAAA,KACZ;AAAA,oBACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAA,EAAsC,iBAAO,aAAA,EAAc;AAAA,GAAA,EAC1E,CAAA;AAEJ","file":"chunk-JTVWK3BC.js","sourcesContent":["import { useEffect } from 'react';\nimport { Input } from './input';\nimport { Label } from './label';\n\n/** Customizable labels for the SlugInput component. */\nexport interface SlugInputLabels {\n /** Label text above the slug input field. */\n slug: string;\n /** Helper text below the slug input. */\n autoGenerated: string;\n /** Placeholder shown inside the slug input. */\n placeholder: string;\n}\n\nexport interface SlugInputProps {\n /** Source title string from which the slug is auto-generated. */\n title: string;\n /** Current slug value. */\n slug: string;\n /** Callback fired when the slug changes (auto-generated or manually edited). */\n onSlugChange: (slug: string) => void;\n /** Whether auto-generation from title is disabled and slug is manually editable only. */\n disabled?: boolean;\n /** Override default label strings for localization. */\n labels?: Partial<SlugInputLabels>;\n}\n\nconst defaultLabels: SlugInputLabels = {\n slug: 'Slug',\n autoGenerated: 'Auto-generated from title',\n placeholder: 'enter-slug-here',\n};\n\n/**\n * Generates a URL-friendly slug from a text string.\n * Handles Vietnamese diacritics and other special characters.\n */\nexport function generateSlug(text: string): string {\n return text\n .toLowerCase()\n .replace(/[àáạảãâầấậẩẫăằắặẳẵ]/g, 'a')\n .replace(/[èéẹẻẽêềếệểễ]/g, 'e')\n .replace(/[ìíịỉĩ]/g, 'i')\n .replace(/[òóọỏõôồốộổỗơờớợởỡ]/g, 'o')\n .replace(/[ùúụủũưừứựửữ]/g, 'u')\n .replace(/[ỳýỵỷỹ]/g, 'y')\n .replace(/đ/g, 'd')\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\n/**\n * URL slug input that auto-generates a slug from a title string.\n * Handles Vietnamese diacritics and special characters via `generateSlug`.\n * The slug updates automatically when the title changes (unless `disabled` is true).\n *\n * @example\n * ```tsx\n * const [title, setTitle] = useState(\"My Blog Post\");\n * const [slug, setSlug] = useState(\"\");\n *\n * <Input value={title} onChange={(e) => setTitle(e.target.value)} />\n * <SlugInput\n * title={title}\n * slug={slug}\n * onSlugChange={setSlug}\n * />\n * // slug will auto-populate as \"my-blog-post\"\n * ```\n */\nexport function SlugInput({\n title,\n slug,\n onSlugChange,\n disabled = false,\n labels: labelOverrides,\n}: SlugInputProps) {\n const labels = { ...defaultLabels, ...labelOverrides };\n\n useEffect(() => {\n if (!disabled && title) {\n onSlugChange(generateSlug(title));\n }\n }, [title, disabled, onSlugChange]);\n\n return (\n <div>\n <Label>{labels.slug}</Label>\n <Input\n value={slug}\n onChange={(e) => onSlugChange(e.target.value)}\n placeholder={labels.placeholder}\n className=\"h-element-sm mt-1 font-mono text-sm\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">{labels.autoGenerated}</p>\n </div>\n );\n}\n"]}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UIContext } from './chunk-RWMRHEWT.js';
|
|
2
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
2
3
|
import { jsx } from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
|
-
// src/providers/ui-provider.tsx
|
|
5
|
-
var UIContext = createContext(void 0);
|
|
6
5
|
function loadSavedTheme() {
|
|
7
6
|
if (typeof window === "undefined") return "system";
|
|
8
7
|
const saved = localStorage.getItem("omnify_theme");
|
|
@@ -80,47 +79,7 @@ function UIProvider({
|
|
|
80
79
|
}, [timezoneProp]);
|
|
81
80
|
return /* @__PURE__ */ jsx(UIContext.Provider, { value: { theme, setTheme, locale, currentLocale, setLocale, dateFnsLocale, timezone, setTimezone }, children });
|
|
82
81
|
}
|
|
83
|
-
function useTheme() {
|
|
84
|
-
const ctx = useContext(UIContext);
|
|
85
|
-
if (!ctx) throw new Error("useTheme must be used within UIProvider");
|
|
86
|
-
return { theme: ctx.theme, setTheme: ctx.setTheme };
|
|
87
|
-
}
|
|
88
|
-
function useUILocales() {
|
|
89
|
-
return useContext(UIContext)?.locale;
|
|
90
|
-
}
|
|
91
|
-
function useLocale() {
|
|
92
|
-
const ctx = useContext(UIContext);
|
|
93
|
-
if (!ctx) throw new Error("useLocale must be used within UIProvider");
|
|
94
|
-
const config = ctx.locale ?? { locales: {}, defaultLocale: "", fallbackLocale: "" };
|
|
95
|
-
return {
|
|
96
|
-
currentLocale: ctx.currentLocale,
|
|
97
|
-
setLocale: ctx.setLocale,
|
|
98
|
-
locales: config.locales,
|
|
99
|
-
defaultLocale: config.defaultLocale,
|
|
100
|
-
fallbackLocale: config.fallbackLocale
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
function useTimezone() {
|
|
104
|
-
const ctx = useContext(UIContext);
|
|
105
|
-
if (!ctx) throw new Error("useTimezone must be used within UIProvider");
|
|
106
|
-
return { timezone: ctx.timezone, setTimezone: ctx.setTimezone };
|
|
107
|
-
}
|
|
108
|
-
function useDateFnsLocale() {
|
|
109
|
-
return useContext(UIContext)?.dateFnsLocale;
|
|
110
|
-
}
|
|
111
|
-
function resolveTranslatableConfig(translatable, providerLocales) {
|
|
112
|
-
if (translatable === true) {
|
|
113
|
-
return providerLocales;
|
|
114
|
-
}
|
|
115
|
-
const base = providerLocales ?? { locales: {}, defaultLocale: "", fallbackLocale: "" };
|
|
116
|
-
const merged = {
|
|
117
|
-
locales: translatable.locales ?? base.locales,
|
|
118
|
-
defaultLocale: translatable.defaultLocale ?? base.defaultLocale,
|
|
119
|
-
fallbackLocale: translatable.fallbackLocale ?? base.fallbackLocale
|
|
120
|
-
};
|
|
121
|
-
return Object.keys(merged.locales).length > 0 ? merged : void 0;
|
|
122
|
-
}
|
|
123
82
|
|
|
124
|
-
export { UIProvider
|
|
125
|
-
//# sourceMappingURL=chunk-
|
|
126
|
-
//# sourceMappingURL=chunk-
|
|
83
|
+
export { UIProvider };
|
|
84
|
+
//# sourceMappingURL=chunk-QHHPWBZM.js.map
|
|
85
|
+
//# sourceMappingURL=chunk-QHHPWBZM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/ui-provider.tsx"],"names":[],"mappings":"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","file":"chunk-QHHPWBZM.js","sourcesContent":["import { useState, useEffect, useCallback, type ReactNode } from 'react';\nimport { UIContext } from './ui-context';\nimport type { Theme, LocaleMap, LocaleCode, UILocaleConfig } from './ui-context';\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction loadSavedTheme(): Theme {\n if (typeof window === 'undefined') return 'system';\n const saved = localStorage.getItem('omnify_theme');\n if (saved === 'light' || saved === 'dark' || saved === 'system') return saved;\n return 'system';\n}\n\nfunction applyTheme(theme: Theme) {\n const root = document.documentElement;\n if (theme === 'system') {\n root.classList.toggle('dark', window.matchMedia('(prefers-color-scheme: dark)').matches);\n } else {\n root.classList.toggle('dark', theme === 'dark');\n }\n}\n\n// ─── UIProvider ───────────────────────────────────────────────────────────────\n\nexport interface UIProviderProps {\n children: ReactNode;\n /**\n * Initial theme. Defaults to user's saved localStorage value or `'system'`.\n */\n defaultTheme?: Theme;\n /**\n * Available locales for translatable fields.\n * @example { en: 'English', vi: 'Tiếng Việt', ja: '日本語' }\n */\n locales?: LocaleMap;\n /**\n * Locale shown first in translatable fields.\n * Defaults to the first key in `locales`.\n */\n defaultLocale?: LocaleCode;\n /**\n * Locale used when a field has no value for the active locale.\n * Defaults to `defaultLocale`.\n */\n fallbackLocale?: LocaleCode;\n /**\n * date-fns `Locale` object used by date components (DatePicker, CalendarMini, etc.).\n * Typed as `object` to avoid importing date-fns as a direct dependency.\n *\n * @example\n * ```tsx\n * import { ja } from 'date-fns/locale';\n * <UIProvider dateFnsLocale={ja}>{children}</UIProvider>\n * ```\n */\n dateFnsLocale?: object;\n /**\n * Callback fired when the active locale changes via `setLocale`.\n * Use this to sync with i18n libraries, localStorage, etc.\n */\n onLocaleChange?: (locale: LocaleCode) => void;\n /**\n * IANA timezone string (e.g. `'Asia/Tokyo'`).\n * Defaults to the browser's local timezone.\n */\n timezone?: string;\n /**\n * Callback fired when the timezone changes via `setTimezone`.\n * Use this to sync with backend, localStorage, etc.\n */\n onTimezoneChange?: (timezone: string) => void;\n}\n\n/**\n * Root provider for @omnifyjp/ui — handles dark mode and translatable field config.\n *\n * @example\n * ```tsx\n * <UIProvider\n * locales={{ en: 'English', vi: 'Tiếng Việt', ja: '日本語' }}\n * defaultLocale=\"en\"\n * fallbackLocale=\"en\"\n * >\n * {children}\n * </UIProvider>\n * ```\n */\nexport function UIProvider({\n children,\n defaultTheme,\n locales,\n defaultLocale,\n fallbackLocale,\n dateFnsLocale,\n onLocaleChange,\n timezone: timezoneProp,\n onTimezoneChange,\n}: UIProviderProps) {\n const [theme, setThemeState] = useState<Theme>(() => defaultTheme ?? loadSavedTheme());\n\n const setTheme = useCallback((t: Theme) => setThemeState(t), []);\n\n useEffect(() => {\n localStorage.setItem('omnify_theme', theme);\n applyTheme(theme);\n }, [theme]);\n\n useEffect(() => {\n if (theme !== 'system') return;\n const mq = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = () => applyTheme('system');\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n }, [theme]);\n\n const firstLocale = locales ? Object.keys(locales)[0] : undefined;\n const resolvedDefaultLocale = defaultLocale ?? firstLocale ?? '';\n const locale: UILocaleConfig | undefined =\n locales && firstLocale\n ? {\n locales,\n defaultLocale: resolvedDefaultLocale,\n fallbackLocale: fallbackLocale ?? resolvedDefaultLocale,\n }\n : undefined;\n\n const [currentLocale, setCurrentLocale] = useState<LocaleCode>(\n () => resolvedDefaultLocale,\n );\n\n const setLocale = useCallback(\n (loc: LocaleCode) => {\n setCurrentLocale(loc);\n onLocaleChange?.(loc);\n },\n [onLocaleChange],\n );\n\n // Auto-set <html lang> for accessibility/SEO\n useEffect(() => {\n if (currentLocale) {\n document.documentElement.lang = currentLocale;\n }\n }, [currentLocale]);\n\n // ── Timezone ──\n const [timezone, setTimezoneState] = useState<string>(\n () => timezoneProp ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n );\n\n const setTimezone = useCallback(\n (tz: string) => {\n setTimezoneState(tz);\n onTimezoneChange?.(tz);\n },\n [onTimezoneChange],\n );\n\n // Sync when prop changes externally (e.g. Inertia page props update)\n useEffect(() => {\n if (timezoneProp !== undefined) {\n setTimezoneState(timezoneProp);\n }\n }, [timezoneProp]);\n\n return (\n <UIContext.Provider value={{ theme, setTheme, locale, currentLocale, setLocale, dateFnsLocale, timezone, setTimezone }}>\n {children}\n </UIContext.Provider>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/ui-context.ts"],"names":[],"mappings":";;;AAgDO,IAAM,SAAA,GAAY,cAA0C,MAAS","file":"chunk-RWMRHEWT.js","sourcesContent":["import { createContext } from 'react';\n\n// ─── Theme ────────────────────────────────────────────────────────────────────\n\nexport type Theme = 'light' | 'dark' | 'system';\n\n// ─── Locale ───────────────────────────────────────────────────────────────────\n\nexport type LocaleCode = string;\n\n/**\n * Map of locale code → display label.\n * @example { en: 'English', vi: 'Tiếng Việt', ja: '日本語' }\n */\nexport type LocaleMap = Record<LocaleCode, string>;\n\n/** Value shape for translatable fields: locale code → string content. */\nexport type TranslatableValue = Record<LocaleCode, string>;\n\n/** Locale configuration used by UIProvider and translatable fields. */\nexport interface UILocaleConfig {\n /** Available locales. e.g. `{ en: 'English', vi: 'Tiếng Việt' }` */\n locales: LocaleMap;\n /** Locale shown by default when a translatable field is first rendered. */\n defaultLocale: LocaleCode;\n /** Locale to fall back to when the active locale has no value. */\n fallbackLocale: LocaleCode;\n}\n\n/**\n * `true` — inherit UIProvider's locale config.\n * `object` — override per-field (merged with provider config).\n */\nexport type TranslatableConfig = true | Partial<UILocaleConfig>;\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport interface UIContextValue {\n theme: Theme;\n setTheme: (theme: Theme) => void;\n locale: UILocaleConfig | undefined;\n currentLocale: LocaleCode;\n setLocale: (locale: LocaleCode) => void;\n dateFnsLocale: object | undefined;\n timezone: string;\n setTimezone: (tz: string) => void;\n}\n\nexport const UIContext = createContext<UIContextValue | undefined>(undefined);\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { UIContext } from './chunk-RWMRHEWT.js';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
|
|
4
|
+
function useTheme() {
|
|
5
|
+
const ctx = useContext(UIContext);
|
|
6
|
+
if (!ctx) throw new Error("useTheme must be used within UIProvider");
|
|
7
|
+
return { theme: ctx.theme, setTheme: ctx.setTheme };
|
|
8
|
+
}
|
|
9
|
+
function useUILocales() {
|
|
10
|
+
return useContext(UIContext)?.locale;
|
|
11
|
+
}
|
|
12
|
+
function useLocale() {
|
|
13
|
+
const ctx = useContext(UIContext);
|
|
14
|
+
if (!ctx) throw new Error("useLocale must be used within UIProvider");
|
|
15
|
+
const config = ctx.locale ?? { locales: {}, defaultLocale: "", fallbackLocale: "" };
|
|
16
|
+
return {
|
|
17
|
+
currentLocale: ctx.currentLocale,
|
|
18
|
+
setLocale: ctx.setLocale,
|
|
19
|
+
locales: config.locales,
|
|
20
|
+
defaultLocale: config.defaultLocale,
|
|
21
|
+
fallbackLocale: config.fallbackLocale
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function useTimezone() {
|
|
25
|
+
const ctx = useContext(UIContext);
|
|
26
|
+
if (!ctx) throw new Error("useTimezone must be used within UIProvider");
|
|
27
|
+
return { timezone: ctx.timezone, setTimezone: ctx.setTimezone };
|
|
28
|
+
}
|
|
29
|
+
function useDateFnsLocale() {
|
|
30
|
+
return useContext(UIContext)?.dateFnsLocale;
|
|
31
|
+
}
|
|
32
|
+
function resolveTranslatableConfig(translatable, providerLocales) {
|
|
33
|
+
if (translatable === true) {
|
|
34
|
+
return providerLocales;
|
|
35
|
+
}
|
|
36
|
+
const base = providerLocales ?? { locales: {}, defaultLocale: "", fallbackLocale: "" };
|
|
37
|
+
const merged = {
|
|
38
|
+
locales: translatable.locales ?? base.locales,
|
|
39
|
+
defaultLocale: translatable.defaultLocale ?? base.defaultLocale,
|
|
40
|
+
fallbackLocale: translatable.fallbackLocale ?? base.fallbackLocale
|
|
41
|
+
};
|
|
42
|
+
return Object.keys(merged.locales).length > 0 ? merged : void 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { resolveTranslatableConfig, useDateFnsLocale, useLocale, useTheme, useTimezone, useUILocales };
|
|
46
|
+
//# sourceMappingURL=chunk-SWQDP3VC.js.map
|
|
47
|
+
//# sourceMappingURL=chunk-SWQDP3VC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/ui-hooks.ts"],"names":[],"mappings":";;;AAOO,SAAS,QAAA,GAA2D;AACzE,EAAA,MAAM,GAAA,GAAM,WAAW,SAAS,CAAA;AAChC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,yCAAyC,CAAA;AACnE,EAAA,OAAO,EAAE,KAAA,EAAO,GAAA,CAAI,KAAA,EAAO,QAAA,EAAU,IAAI,QAAA,EAAS;AACpD;AAMO,SAAS,YAAA,GAA2C;AACzD,EAAA,OAAO,UAAA,CAAW,SAAS,CAAA,EAAG,MAAA;AAChC;AAMO,SAAS,SAAA,GAMd;AACA,EAAA,MAAM,GAAA,GAAM,WAAW,SAAS,CAAA;AAChC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,0CAA0C,CAAA;AACpE,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,MAAA,IAAU,EAAE,OAAA,EAAS,EAAC,EAAG,aAAA,EAAe,EAAA,EAAI,cAAA,EAAgB,EAAA,EAAG;AAClF,EAAA,OAAO;AAAA,IACL,eAAe,GAAA,CAAI,aAAA;AAAA,IACnB,WAAW,GAAA,CAAI,SAAA;AAAA,IACf,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,eAAe,MAAA,CAAO,aAAA;AAAA,IACtB,gBAAgB,MAAA,CAAO;AAAA,GACzB;AACF;AAMO,SAAS,WAAA,GAGd;AACA,EAAA,MAAM,GAAA,GAAM,WAAW,SAAS,CAAA;AAChC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,4CAA4C,CAAA;AACtE,EAAA,OAAO,EAAE,QAAA,EAAU,GAAA,CAAI,QAAA,EAAU,WAAA,EAAa,IAAI,WAAA,EAAY;AAChE;AAMO,SAAS,gBAAA,GAAuC;AACrD,EAAA,OAAO,UAAA,CAAW,SAAS,CAAA,EAAG,aAAA;AAChC;AAMO,SAAS,yBAAA,CACd,cACA,eAAA,EAC4B;AAC5B,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,OAAO,eAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAO,mBAAmB,EAAE,OAAA,EAAS,EAAC,EAAG,aAAA,EAAe,EAAA,EAAI,cAAA,EAAgB,EAAA,EAAG;AACrF,EAAA,MAAM,MAAA,GAAyB;AAAA,IAC7B,OAAA,EAAS,YAAA,CAAa,OAAA,IAAW,IAAA,CAAK,OAAA;AAAA,IACtC,aAAA,EAAe,YAAA,CAAa,aAAA,IAAiB,IAAA,CAAK,aAAA;AAAA,IAClD,cAAA,EAAgB,YAAA,CAAa,cAAA,IAAkB,IAAA,CAAK;AAAA,GACtD;AACA,EAAA,OAAO,OAAO,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,GAAS,IAAI,MAAA,GAAS,MAAA;AAC3D","file":"chunk-SWQDP3VC.js","sourcesContent":["import { useContext } from 'react';\nimport { UIContext } from './ui-context';\nimport type { UILocaleConfig, LocaleCode, LocaleMap, Theme, TranslatableConfig } from './ui-context';\n\n// ─── Hooks ────────────────────────────────────────────────────────────────────\n\n/** Access theme and setTheme. Must be inside UIProvider. */\nexport function useTheme(): { theme: Theme; setTheme: (t: Theme) => void } {\n const ctx = useContext(UIContext);\n if (!ctx) throw new Error('useTheme must be used within UIProvider');\n return { theme: ctx.theme, setTheme: ctx.setTheme };\n}\n\n/**\n * Returns the locale config from UIProvider.\n * Returns `undefined` when no `locales` prop was passed to UIProvider.\n */\nexport function useUILocales(): UILocaleConfig | undefined {\n return useContext(UIContext)?.locale;\n}\n\n/**\n * Returns the active locale state and locale config from UIProvider.\n * Must be used inside UIProvider.\n */\nexport function useLocale(): {\n currentLocale: LocaleCode;\n setLocale: (locale: LocaleCode) => void;\n locales: LocaleMap;\n defaultLocale: LocaleCode;\n fallbackLocale: LocaleCode;\n} {\n const ctx = useContext(UIContext);\n if (!ctx) throw new Error('useLocale must be used within UIProvider');\n const config = ctx.locale ?? { locales: {}, defaultLocale: '', fallbackLocale: '' };\n return {\n currentLocale: ctx.currentLocale,\n setLocale: ctx.setLocale,\n locales: config.locales,\n defaultLocale: config.defaultLocale,\n fallbackLocale: config.fallbackLocale,\n };\n}\n\n/**\n * Returns the active timezone and setter from UIProvider.\n * Must be used inside UIProvider.\n */\nexport function useTimezone(): {\n timezone: string;\n setTimezone: (tz: string) => void;\n} {\n const ctx = useContext(UIContext);\n if (!ctx) throw new Error('useTimezone must be used within UIProvider');\n return { timezone: ctx.timezone, setTimezone: ctx.setTimezone };\n}\n\n/**\n * Returns the date-fns `Locale` object from UIProvider.\n * Returns `undefined` when no `dateFnsLocale` prop was passed.\n */\nexport function useDateFnsLocale(): object | undefined {\n return useContext(UIContext)?.dateFnsLocale;\n}\n\n/**\n * Resolves the effective UILocaleConfig for a translatable field.\n * Merges inline `TranslatableConfig` with the provider's locale config.\n */\nexport function resolveTranslatableConfig(\n translatable: TranslatableConfig,\n providerLocales: UILocaleConfig | undefined,\n): UILocaleConfig | undefined {\n if (translatable === true) {\n return providerLocales;\n }\n const base = providerLocales ?? { locales: {}, defaultLocale: '', fallbackLocale: '' };\n const merged: UILocaleConfig = {\n locales: translatable.locales ?? base.locales,\n defaultLocale: translatable.defaultLocale ?? base.defaultLocale,\n fallbackLocale: translatable.fallbackLocale ?? base.fallbackLocale,\n };\n return Object.keys(merged.locales).length > 0 ? merged : undefined;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TranslatableField } from './chunk-
|
|
2
|
-
import { useUILocales, resolveTranslatableConfig } from './chunk-
|
|
1
|
+
import { TranslatableField } from './chunk-XJSGU5XZ.js';
|
|
2
|
+
import { useUILocales, resolveTranslatableConfig } from './chunk-SWQDP3VC.js';
|
|
3
3
|
import { cn } from './chunk-DGPY4WP3.js';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { cva } from 'class-variance-authority';
|
|
@@ -86,5 +86,5 @@ var Input = React.forwardRef(
|
|
|
86
86
|
Input.displayName = "Input";
|
|
87
87
|
|
|
88
88
|
export { Input, inputVariants };
|
|
89
|
-
//# sourceMappingURL=chunk-
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
89
|
+
//# sourceMappingURL=chunk-TSRLQI2O.js.map
|
|
90
|
+
//# sourceMappingURL=chunk-TSRLQI2O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/inputs/input.tsx"],"names":["inputRest","value","onChange"],"mappings":"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","file":"chunk-TSRLQI2O.js","sourcesContent":["import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../../lib/utils\";\nimport { TranslatableField } from './translatable-field';\nimport { useUILocales, resolveTranslatableConfig } from '../../providers/ui-hooks';\nimport type { TranslatableConfig, TranslatableValue } from '../../providers/ui-context';\n\n// ─── Variants ─────────────────────────────────────────────────────────────────\n\nconst inputVariants = cva(\n \"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex w-full min-w-0 rounded-md border bg-input-background transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n size: {\n xs: \"h-element-xs px-2 text-xs\",\n sm: \"h-element-sm px-2.5 text-sm\",\n default: \"h-element px-3 py-1 text-base md:text-sm\",\n lg: \"h-element-lg px-4 text-sm\",\n xl: \"h-element-xl px-4 text-base\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n },\n);\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype InputSize = VariantProps<typeof inputVariants>['size'];\ntype NativeInputProps = Omit<React.ComponentProps<'input'>, 'value' | 'onChange' | 'size'>;\n\ninterface StandardInputProps extends NativeInputProps {\n size?: InputSize;\n /** Translatable mode disabled (default). */\n translatable?: never;\n value?: string;\n onChange?: React.ChangeEventHandler<HTMLInputElement>;\n}\n\ninterface TranslatableInputProps extends NativeInputProps {\n size?: InputSize;\n /**\n * Enable locale-switching tabs on this input.\n * - `true` — inherit UIProvider's locale config\n * - `object` — override locales/defaultLocale/fallbackLocale per field\n *\n * @example\n * ```tsx\n * // Uses UIProvider config\n * <Input translatable value={val} onChange={setVal} />\n *\n * // Custom per-field config\n * <Input\n * translatable={{ locales: { en: 'English', vi: 'Tiếng Việt' }, fallbackLocale: 'en' }}\n * value={val}\n * onChange={setVal}\n * />\n * ```\n */\n translatable: TranslatableConfig;\n value?: TranslatableValue;\n onChange?: (value: TranslatableValue) => void;\n /**\n * Per-locale validation errors. Truthy string = that locale is invalid.\n * The active locale's error is forwarded as `aria-invalid` on the input;\n * all locale tabs with errors show a red dot indicator.\n *\n * @example `{ en: 'Required', vi: 'Too long (120/100)' }`\n */\n errors?: Partial<Record<string, string>>;\n}\n\nexport type InputProps = StandardInputProps | TranslatableInputProps;\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * Text input component with multiple size variants.\n * Supports translatable mode via the `translatable` prop.\n *\n * @example\n * ```tsx\n * // Standard\n * <Input placeholder=\"Enter text...\" />\n * <Input size=\"sm\" value={val} onChange={(e) => setVal(e.target.value)} />\n *\n * // Translatable — uses UIProvider's locale config\n * <Input translatable value={val} onChange={setVal} />\n *\n * // Translatable — custom config\n * <Input\n * translatable={{ locales: { en: 'English', vi: 'Tiếng Việt' }, fallbackLocale: 'en' }}\n * value={val}\n * onChange={setVal}\n * />\n * ```\n */\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n (props, ref) => {\n const { className, type, size, translatable, ...rest } = props as TranslatableInputProps & { type?: string; className?: string };\n\n const providerLocales = useUILocales();\n\n // ── Translatable mode ──────────────────────────────────────────────────\n if (translatable !== undefined) {\n const config = resolveTranslatableConfig(translatable, providerLocales);\n\n // Fallback: if no locale config available, render standard input\n if (!config) {\n const { value: _v, onChange: _oc, ...inputRest } = rest as TranslatableInputProps;\n return (\n <input\n type={type}\n ref={ref}\n data-slot=\"input\"\n className={cn(inputVariants({ size, className }))}\n {...(inputRest as NativeInputProps)}\n />\n );\n }\n\n const { value = {}, onChange, errors, ...inputRest } = rest as TranslatableInputProps;\n\n return (\n <TranslatableField\n config={config}\n value={value as TranslatableValue}\n onChange={onChange ?? (() => {})}\n errors={errors}\n >\n {({ value: localeValue, onChange: localeChange, fallbackPlaceholder, hasError }) => (\n <input\n type={type}\n ref={ref}\n data-slot=\"input\"\n data-translatable\n className={cn(inputVariants({ size, className }))}\n value={localeValue}\n placeholder={fallbackPlaceholder ?? (inputRest as React.InputHTMLAttributes<HTMLInputElement>).placeholder}\n onChange={(e) => localeChange(e.target.value)}\n {...(inputRest as React.InputHTMLAttributes<HTMLInputElement>)}\n aria-invalid={hasError || (inputRest as React.InputHTMLAttributes<HTMLInputElement>)['aria-invalid'] || undefined}\n />\n )}\n </TranslatableField>\n );\n }\n\n // ── Standard mode ──────────────────────────────────────────────────────\n const { value, onChange, ...inputRest } = rest as StandardInputProps;\n return (\n <input\n type={type}\n ref={ref}\n data-slot=\"input\"\n className={cn(inputVariants({ size, className }))}\n value={value}\n onChange={onChange}\n {...(inputRest as NativeInputProps)}\n />\n );\n },\n);\nInput.displayName = \"Input\";\n\nexport { Input, inputVariants };\n"]}
|
|
@@ -140,5 +140,5 @@ function TranslatableField({
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
export { TranslatableField };
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
144
|
-
//# sourceMappingURL=chunk-
|
|
143
|
+
//# sourceMappingURL=chunk-XJSGU5XZ.js.map
|
|
144
|
+
//# sourceMappingURL=chunk-XJSGU5XZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/inputs/translatable-field.tsx"],"names":[],"mappings":"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","file":"chunk-XJSGU5XZ.js","sourcesContent":["import { useState, useRef, useEffect, ReactNode } from 'react';\nimport { CornerDownLeft, ChevronDown } from 'lucide-react';\nimport { cn } from '../../lib/utils';\nimport type { UILocaleConfig, LocaleCode, TranslatableValue } from '../../providers/ui-context';\n\nexport type { TranslatableValue };\n\n// ─── Config ───────────────────────────────────────────────────────────────────\n\n/** Max locale tabs shown inline; overflow goes into a dropdown. */\nconst MAX_INLINE_TABS = 3;\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface TranslatableRenderProps {\n /** Active locale code, e.g. `'en'` */\n locale: LocaleCode;\n /** String value for the active locale */\n value: string;\n /** Call with the new string to update the active locale's value */\n onChange: (value: string) => void;\n /** Fallback value shown as placeholder when the active locale is empty */\n fallbackPlaceholder: string | undefined;\n /** True when the active locale has a truthy entry in `errors` */\n hasError: boolean;\n}\n\ninterface TranslatableFieldProps {\n config: UILocaleConfig;\n value: TranslatableValue;\n onChange: (value: TranslatableValue) => void;\n /** Render the actual input. Receives locale-scoped value/onChange. */\n children: (props: TranslatableRenderProps) => ReactNode;\n className?: string;\n /**\n * Per-locale validation errors. A truthy string for a locale code marks that\n * locale as invalid: its tab dot turns red and `hasError` is `true` in the\n * render props when that locale is active.\n *\n * @example `{ en: '', vi: 'Too long' }` — only VI has an error\n */\n errors?: Partial<Record<string, string>>;\n}\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * Wraps any text input with a locale switcher tab bar.\n * Used internally by `Input` and `Textarea` when `translatable` prop is set.\n *\n * When more than 3 locales are configured, overflow locales are collapsed into\n * a dropdown button to prevent the tab bar from overflowing.\n *\n * @example\n * ```tsx\n * <TranslatableField config={localeConfig} value={val} onChange={setVal} errors={{ vi: 'Too long' }}>\n * {({ value, onChange, fallbackPlaceholder, hasError }) => (\n * <input aria-invalid={hasError || undefined} value={value} onChange={(e) => onChange(e.target.value)} />\n * )}\n * </TranslatableField>\n * ```\n */\nexport function TranslatableField({\n config,\n value,\n onChange,\n children,\n className,\n errors,\n}: TranslatableFieldProps) {\n const [activeLocale, setActiveLocale] = useState<LocaleCode>(config.defaultLocale);\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Close dropdown on outside click\n useEffect(() => {\n if (!dropdownOpen) return;\n const handler = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setDropdownOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [dropdownOpen]);\n\n const isFallback = activeLocale !== config.fallbackLocale;\n const fallbackPlaceholder = isFallback ? (value[config.fallbackLocale] ?? undefined) : undefined;\n const hasError = !!(errors?.[activeLocale]);\n\n const handleChange = (v: string) => {\n onChange({ ...value, [activeLocale]: v });\n };\n\n // ── Build visible + overflow locale lists ──────────────────────────────────\n const localeEntries = Object.entries(config.locales) as [LocaleCode, string][];\n let visibleEntries: [LocaleCode, string][];\n let overflowEntries: [LocaleCode, string][];\n\n if (localeEntries.length <= MAX_INLINE_TABS) {\n visibleEntries = localeEntries;\n overflowEntries = [];\n } else {\n // Always keep active locale visible; fill remaining slots from the front\n const nonActive = localeEntries.filter(([code]) => code !== activeLocale);\n const visibleNonActive = nonActive.slice(0, MAX_INLINE_TABS - 1);\n const visibleCodes = new Set([...visibleNonActive.map(([c]) => c), activeLocale]);\n // Preserve original order\n visibleEntries = localeEntries.filter(([code]) => visibleCodes.has(code));\n overflowEntries = localeEntries.filter(([code]) => !visibleCodes.has(code));\n }\n\n const activeInOverflow = overflowEntries.some(([code]) => code === activeLocale);\n const overflowHasValue = overflowEntries.some(([code]) => !!(value[code] ?? ''));\n const overflowHasError = overflowEntries.some(([code]) => !!(errors?.[code]));\n\n return (\n <div className={cn('flex flex-col gap-1', className)}>\n {/* Locale tab bar */}\n <div className=\"flex items-center gap-0.5\">\n\n {/* Inline locale tabs */}\n {visibleEntries.map(([code, label]) => {\n const isActive = code === activeLocale;\n const hasValue = !!(value[code] ?? '');\n const hasLocaleError = !!(errors?.[code]);\n\n return (\n <button\n key={code}\n type=\"button\"\n title={label}\n onClick={() => setActiveLocale(code)}\n className={cn(\n 'relative px-2 py-0.5 rounded text-xs font-medium transition-colors select-none',\n isActive\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n )}\n >\n {code.toUpperCase()}\n {/* dot — locale has a value or an error, but is not active */}\n {(hasValue || hasLocaleError) && !isActive && (\n <span className={cn(\n 'absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full',\n hasLocaleError ? 'bg-destructive' : 'bg-primary',\n )} />\n )}\n </button>\n );\n })}\n\n {/* Overflow dropdown */}\n {overflowEntries.length > 0 && (\n <div ref={dropdownRef} className=\"relative\">\n <button\n type=\"button\"\n title=\"More languages\"\n onClick={() => setDropdownOpen((o) => !o)}\n className={cn(\n 'relative flex items-center gap-0.5 px-1.5 py-0.5 rounded text-xs font-medium transition-colors select-none',\n activeInOverflow\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n )}\n >\n {activeInOverflow\n ? activeLocale.toUpperCase()\n : `+${overflowEntries.length}`}\n <ChevronDown className={cn('w-3 h-3 transition-transform', dropdownOpen && 'rotate-180')} />\n {/* dot when overflow has values/errors but active is not in overflow */}\n {(overflowHasValue || overflowHasError) && !activeInOverflow && (\n <span className={cn(\n 'absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full',\n overflowHasError ? 'bg-destructive' : 'bg-primary',\n )} />\n )}\n </button>\n\n {dropdownOpen && (\n <div className=\"absolute top-full left-0 mt-1 z-10 min-w-[140px] rounded-md border border-border bg-popover shadow-md py-1\">\n {overflowEntries.map(([code, label]) => {\n const isActive = code === activeLocale;\n const hasValue = !!(value[code] ?? '');\n const hasLocaleError = !!(errors?.[code]);\n return (\n <button\n key={code}\n type=\"button\"\n onClick={() => { setActiveLocale(code); setDropdownOpen(false); }}\n className={cn(\n 'w-full flex items-center gap-2 px-3 py-1.5 text-sm transition-colors',\n isActive\n ? 'bg-primary/10 text-primary font-medium'\n : 'hover:bg-accent text-foreground',\n )}\n >\n <span className=\"text-xs font-semibold w-6 shrink-0\">{code.toUpperCase()}</span>\n <span className=\"text-xs text-muted-foreground flex-1 text-left\">{label}</span>\n {(hasValue || hasLocaleError) && (\n <span className={cn(\n 'w-1.5 h-1.5 rounded-full shrink-0',\n hasLocaleError ? 'bg-destructive' : 'bg-primary',\n )} />\n )}\n </button>\n );\n })}\n </div>\n )}\n </div>\n )}\n\n {/* Fallback hint when active locale is empty */}\n {fallbackPlaceholder && !value[activeLocale] && (\n <span data-testid=\"fallback-hint\" className=\"ml-1 flex items-center gap-0.5 text-xs text-muted-foreground\">\n <CornerDownLeft className=\"w-3 h-3\" />\n {config.fallbackLocale.toUpperCase()}\n </span>\n )}\n </div>\n\n {children({\n locale: activeLocale,\n value: value[activeLocale] ?? '',\n onChange: handleChange,\n fallbackPlaceholder,\n hasError,\n })}\n </div>\n );\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { toZonedTime } from '../../../chunk-PMNLM6VF.js';
|
|
2
|
-
import { useDateFnsLocale, useTimezone } from '../../../chunk-
|
|
2
|
+
import { useDateFnsLocale, useTimezone } from '../../../chunk-SWQDP3VC.js';
|
|
3
|
+
import '../../../chunk-RWMRHEWT.js';
|
|
3
4
|
import { cn } from '../../../chunk-DGPY4WP3.js';
|
|
4
5
|
import { format } from 'date-fns';
|
|
5
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/domain/calendar/calendar-event-chip.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/domain/calendar/calendar-event-chip.tsx"],"names":[],"mappings":";;;;;;;AA4CO,SAAS,kBAAkB,EAAE,KAAA,EAAO,OAAA,GAAU,KAAA,EAAO,SAAQ,EAA2B;AAC7F,EAAA,MAAM,gBAAgB,gBAAA,EAAiB;AACvC,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,WAAA,EAAY;AAEjC,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,MAAM,OAAA,GAAU,KAAK,CAAA;AAAA,MAC9B,SAAA,EAAW,EAAA;AAAA,QACT,wHAAA;AAAA,QACA,UAAU,eAAA,GAAkB;AAAA,OAC9B;AAAA,MACA,KAAA,EAAO;AAAA,QACL,eAAA,EAAiB,CAAA,EAAG,KAAA,CAAM,KAAK,CAAA,EAAA,CAAA;AAAA,QAC/B,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,UAAA,EAAY,CAAA,UAAA,EAAa,KAAA,CAAM,KAAK,CAAA;AAAA,OACtC;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,CAAC,KAAA,CAAM,UAAU,CAAC,OAAA,wBAChB,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAmB,QAAA,EAAA,MAAA,CAAO,WAAA,CAAY,MAAM,KAAA,EAAO,QAAQ,GAAG,OAAA,EAAS,aAAA,GAAgB,EAAE,MAAA,EAAQ,aAAA,EAAc,GAAI,MAAS,CAAA,EAAE,CAAA;AAAA,QAE/I,KAAA,CAAM;AAAA;AAAA;AAAA,GACT;AAEJ","file":"calendar-event-chip.js","sourcesContent":["import { format } from 'date-fns';\nimport type { Locale } from 'date-fns';\nimport { cn } from '../../../lib/utils';\nimport { toZonedTime } from '../../../lib/timezone';\nimport { useDateFnsLocale, useTimezone } from '../../../providers/ui-hooks';\n\n/** Event data shape required by CalendarEventChip. */\nexport interface CalendarEventChipEvent {\n /** Unique event identifier. */\n id: string;\n /** Display title of the event. */\n title: string;\n /** Event start date/time. */\n start: Date;\n /** Event end date/time. */\n end: Date;\n /** Whether this is an all-day event. When true, time is not displayed. */\n allDay?: boolean;\n /** CSS color string used for the chip background, text, and left border. */\n color: string;\n}\n\nexport interface CalendarEventChipProps {\n /** The event to display. */\n event: CalendarEventChipEvent;\n /** Use compact layout with tighter line-height. Defaults to `false`. */\n compact?: boolean;\n /** Callback when the chip is clicked. */\n onClick?: (event: CalendarEventChipEvent) => void;\n}\n\n/**\n * Small colored chip representing a calendar event. Shows the event title\n * with a colored left border and tinted background. Optionally displays\n * the start time for non-all-day events.\n *\n * @example\n * ```tsx\n * <CalendarEventChip\n * event={{ id: \"1\", title: \"Standup\", start: new Date(), end: new Date(), color: \"#3b82f6\" }}\n * onClick={(e) => openDetail(e.id)}\n * />\n * ```\n */\nexport function CalendarEventChip({ event, compact = false, onClick }: CalendarEventChipProps) {\n const contextLocale = useDateFnsLocale() as Locale | undefined;\n const { timezone } = useTimezone();\n\n return (\n <button\n type=\"button\"\n onClick={() => onClick?.(event)}\n className={cn(\n 'w-full text-left rounded px-1.5 py-0.5 text-xs font-medium truncate transition-opacity hover:opacity-80 cursor-pointer',\n compact ? 'leading-tight' : 'leading-normal'\n )}\n style={{\n backgroundColor: `${event.color}20`,\n color: event.color,\n borderLeft: `2px solid ${event.color}`,\n }}\n >\n {!event.allDay && !compact && (\n <span className=\"opacity-75 mr-1\">{format(toZonedTime(event.start, timezone), 'HH:mm', contextLocale ? { locale: contextLocale } : undefined)}</span>\n )}\n {event.title}\n </button>\n );\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '../../../chunk-VOLR236J.js';
|
|
2
2
|
import { toZonedTime } from '../../../chunk-PMNLM6VF.js';
|
|
3
|
-
import { useDateFnsLocale, useTimezone } from '../../../chunk-
|
|
3
|
+
import { useDateFnsLocale, useTimezone } from '../../../chunk-SWQDP3VC.js';
|
|
4
|
+
import '../../../chunk-RWMRHEWT.js';
|
|
4
5
|
import { Separator } from '../../../chunk-KCUSO3CK.js';
|
|
5
6
|
import { CalendarCategoryBadge } from '../../../chunk-IXEPDTUE.js';
|
|
6
7
|
import '../../../chunk-5SAUUOCN.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/domain/calendar/calendar-event-sheet.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/domain/calendar/calendar-event-sheet.tsx"],"names":[],"mappings":"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","file":"calendar-event-sheet.js","sourcesContent":["import { format } from 'date-fns';\nimport type { Locale } from 'date-fns';\nimport { Clock, MapPin, Users, Trash2 } from 'lucide-react';\nimport { toZonedTime } from '../../../lib/timezone';\nimport { useDateFnsLocale, useTimezone } from '../../../providers/ui-hooks';\nimport { Sheet, SheetContent, SheetHeader, SheetTitle } from '../../overlay/sheet';\nimport { Button } from '../../inputs/button';\nimport { Separator } from '../../display/separator';\nimport { CalendarCategoryBadge } from './calendar-category-badge';\n\n/** Extended event data shape for the detail sheet, including description, location, and attendees. */\nexport interface CalendarEventSheetEvent {\n /** Unique event identifier. */\n id: string;\n /** Display title of the event. */\n title: string;\n /** Optional long description or notes for the event. */\n description?: string;\n /** Event start date/time. */\n start: Date;\n /** Event end date/time. */\n end: Date;\n /** Whether this is an all-day event. */\n allDay?: boolean;\n /** CSS color string for the event. */\n color: string;\n /** Category key (e.g. \"meeting\", \"deadline\") used by CalendarCategoryBadge. */\n category: string;\n /** Optional location string. */\n location?: string;\n /** Optional list of attendee email addresses. */\n attendees?: string[];\n}\n\n/** Localizable labels for the event detail sheet. All have English defaults. */\nexport interface CalendarEventSheetLabels {\n /** Text displayed for all-day events instead of a time range. */\n allDay?: string;\n /** Heading text for the attendees section. */\n attendees?: string;\n /** Label for the delete button. */\n delete?: string;\n}\n\nconst defaultLabels: Required<CalendarEventSheetLabels> = {\n allDay: 'All Day',\n attendees: 'Attendees',\n delete: 'Delete',\n};\n\nexport interface CalendarEventSheetProps {\n /** The event to display, or `null` to render nothing. */\n event: CalendarEventSheetEvent | null;\n /** Whether the sheet is open. */\n open: boolean;\n /** Callback to toggle the sheet open state. */\n onOpenChange: (open: boolean) => void;\n /** Optional callback when the delete button is clicked. Receives the event id. */\n onDelete?: (id: string) => void;\n /** Override display label for the category badge. */\n categoryLabel?: string;\n /** Custom className styles per category key for the CalendarCategoryBadge. */\n categoryStyles?: Record<string, string>;\n /** Localizable UI labels with English defaults. */\n labels?: CalendarEventSheetLabels;\n /** date-fns Locale object for formatting dates. Falls back to UIProvider's `dateFnsLocale`. */\n locale?: Locale;\n}\n\n/**\n * Side sheet that displays full event details including title, category badge,\n * description, date/time, location, attendees, and a delete action.\n * Built on top of the Sheet component.\n *\n * @example\n * ```tsx\n * <CalendarEventSheet\n * event={selectedEvent}\n * open={sheetOpen}\n * onOpenChange={setSheetOpen}\n * onDelete={(id) => removeEvent(id)}\n * />\n * ```\n */\nexport function CalendarEventSheet({\n event,\n open,\n onOpenChange,\n onDelete,\n categoryLabel,\n categoryStyles,\n labels: labelsProp,\n locale: localeProp,\n}: CalendarEventSheetProps) {\n const labels = { ...defaultLabels, ...labelsProp };\n const contextLocale = useDateFnsLocale() as Locale | undefined;\n const locale = localeProp ?? contextLocale;\n const { timezone } = useTimezone();\n\n if (!event) return null;\n\n const localeOpt = locale ? { locale } : undefined;\n const timeDisplay = event.allDay\n ? labels.allDay\n : `${format(toZonedTime(event.start, timezone), 'HH:mm', localeOpt)} - ${format(toZonedTime(event.end, timezone), 'HH:mm', localeOpt)}`;\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent className=\"sm:max-w-md\">\n <SheetHeader>\n <SheetTitle>{event.title}</SheetTitle>\n </SheetHeader>\n <div className=\"mt-4 space-y-4\">\n <CalendarCategoryBadge\n category={event.category}\n label={categoryLabel}\n styles={categoryStyles}\n />\n\n {event.description && (\n <p className=\"text-sm text-muted-foreground\">{event.description}</p>\n )}\n\n <Separator />\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3 text-sm\">\n <Clock className=\"w-4 h-4 text-muted-foreground flex-shrink-0\" />\n <div>\n <p className=\"font-medium\">{format(toZonedTime(event.start, timezone), 'EEEE, MMMM d, yyyy', localeOpt)}</p>\n <p className=\"text-muted-foreground\">{timeDisplay}</p>\n </div>\n </div>\n\n {event.location && (\n <div className=\"flex items-center gap-3 text-sm\">\n <MapPin className=\"w-4 h-4 text-muted-foreground flex-shrink-0\" />\n <span>{event.location}</span>\n </div>\n )}\n\n {event.attendees && event.attendees.length > 0 && (\n <div className=\"flex items-start gap-3 text-sm\">\n <Users className=\"w-4 h-4 text-muted-foreground flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium mb-1\">{labels.attendees}</p>\n <div className=\"space-y-1\">\n {event.attendees.map(email => (\n <p key={email} className=\"text-muted-foreground\">{email}</p>\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n\n <Separator />\n\n <div className=\"flex justify-end\">\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => {\n onDelete?.(event.id);\n onOpenChange(false);\n }}\n >\n <Trash2 className=\"w-4 h-4\" />\n {labels.delete}\n </Button>\n </div>\n </div>\n </SheetContent>\n </Sheet>\n );\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { nowInTimezone, toZonedTime } from '../../../chunk-PMNLM6VF.js';
|
|
2
|
-
import { useDateFnsLocale, useTimezone } from '../../../chunk-
|
|
2
|
+
import { useDateFnsLocale, useTimezone } from '../../../chunk-SWQDP3VC.js';
|
|
3
|
+
import '../../../chunk-RWMRHEWT.js';
|
|
3
4
|
import { Checkbox } from '../../../chunk-W477ZR6B.js';
|
|
4
5
|
import { Separator } from '../../../chunk-KCUSO3CK.js';
|
|
5
6
|
import { cn } from '../../../chunk-DGPY4WP3.js';
|