@karakuri-ui/react 0.3.4 → 0.3.6
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/components/ui/accordion.mjs +1 -1
- package/dist/components/ui/alert.mjs +1 -1
- package/dist/components/ui/avatar.mjs +1 -1
- package/dist/components/ui/badge.mjs +1 -1
- package/dist/components/ui/breadcrumb.mjs +1 -1
- package/dist/components/ui/button-group.mjs +1 -1
- package/dist/components/ui/button.mjs +2 -2
- package/dist/components/ui/card.mjs +1 -1
- package/dist/components/ui/chart.mjs +1 -1
- package/dist/components/ui/checkbox.js +3 -1
- package/dist/components/ui/checkbox.js.map +1 -1
- package/dist/components/ui/checkbox.mjs +5 -3
- package/dist/components/ui/checkbox.mjs.map +1 -1
- package/dist/components/ui/divider.mjs +1 -1
- package/dist/components/ui/drawer.mjs +1 -1
- package/dist/components/ui/dropdown.mjs +1 -1
- package/dist/components/ui/field.d.mts +11 -1
- package/dist/components/ui/field.d.ts +11 -1
- package/dist/components/ui/field.js +37 -4
- package/dist/components/ui/field.js.map +1 -1
- package/dist/components/ui/field.mjs +36 -4
- package/dist/components/ui/field.mjs.map +1 -1
- package/dist/components/ui/icon-button.mjs +2 -2
- package/dist/components/ui/index.d.mts +1 -1
- package/dist/components/ui/index.d.ts +1 -1
- package/dist/components/ui/index.mjs +35 -35
- package/dist/components/ui/input.js +1 -0
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/input.mjs +3 -2
- package/dist/components/ui/input.mjs.map +1 -1
- package/dist/components/ui/metric-card.mjs +1 -1
- package/dist/components/ui/modal.mjs +1 -1
- package/dist/components/ui/navigation-menu.js +30 -9
- package/dist/components/ui/navigation-menu.js.map +1 -1
- package/dist/components/ui/navigation-menu.mjs +31 -10
- package/dist/components/ui/navigation-menu.mjs.map +1 -1
- package/dist/components/ui/pagination.js +2 -2
- package/dist/components/ui/pagination.js.map +1 -1
- package/dist/components/ui/pagination.mjs +4 -4
- package/dist/components/ui/pagination.mjs.map +1 -1
- package/dist/components/ui/popover.mjs +1 -1
- package/dist/components/ui/progress.mjs +1 -1
- package/dist/components/ui/radio-group.js +3 -0
- package/dist/components/ui/radio-group.js.map +1 -1
- package/dist/components/ui/radio-group.mjs +5 -2
- package/dist/components/ui/radio-group.mjs.map +1 -1
- package/dist/components/ui/segmented.mjs +1 -1
- package/dist/components/ui/select.d.mts +1 -1
- package/dist/components/ui/select.d.ts +1 -1
- package/dist/components/ui/select.js +10 -2
- package/dist/components/ui/select.js.map +1 -1
- package/dist/components/ui/select.mjs +11 -3
- package/dist/components/ui/select.mjs.map +1 -1
- package/dist/components/ui/skeleton.mjs +1 -1
- package/dist/components/ui/slider.js +7 -1
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/slider.mjs +8 -2
- package/dist/components/ui/slider.mjs.map +1 -1
- package/dist/components/ui/spinner.mjs +1 -1
- package/dist/components/ui/switch.js +3 -1
- package/dist/components/ui/switch.js.map +1 -1
- package/dist/components/ui/switch.mjs +5 -3
- package/dist/components/ui/switch.mjs.map +1 -1
- package/dist/components/ui/table.mjs +1 -1
- package/dist/components/ui/tabs.mjs +1 -1
- package/dist/components/ui/textarea.js +1 -0
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/components/ui/textarea.mjs +3 -2
- package/dist/components/ui/textarea.mjs.map +1 -1
- package/dist/components/ui/toast.mjs +1 -1
- package/dist/components/ui/toggle-group.mjs +1 -1
- package/dist/components/ui/toggle.mjs +1 -1
- package/dist/components/ui/tooltip.mjs +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/radio-group.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\n// Color maps for checked state\nconst radioColorMap = {\n default: {\n border: 'data-[state=checked]:border-foreground',\n dot: 'bg-foreground',\n },\n primary: {\n border: 'data-[state=checked]:border-primary',\n dot: 'bg-primary',\n },\n} as const\n\nexport type RadioColor = keyof typeof radioColorMap\n\n// Context to pass size, weight, color from RadioGroup to RadioGroupItem\ntype RadioGroupContextValue = {\n size: 'sm' | 'default' | 'lg'\n weight: 'thin' | 'bold'\n color: RadioColor\n disabled?: boolean\n}\nconst RadioGroupContext = React.createContext<RadioGroupContextValue>({ size: 'default', weight: 'bold', color: 'default' })\n\n// RadioGroup container\nconst radioGroupVariants = cva('grid gap-3', {\n variants: {\n orientation: {\n vertical: 'grid-cols-1',\n horizontal: 'grid-flow-col auto-cols-max gap-4',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n size?: 'sm' | 'default' | 'lg'\n weight?: 'thin' | 'bold'\n /** Checked state color */\n color?: RadioColor\n}\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n RadioGroupProps\n>(({ className, orientation, size = 'default', weight = 'bold', color = 'default', disabled, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedDisabled = disabled ?? fieldContext?.disabled\n\n return (\n <RadioGroupContext.Provider value={{ size, weight, color, disabled: resolvedDisabled }}>\n <RadioGroupPrimitive.Root\n ref={ref}\n className={cn(radioGroupVariants({ orientation }), className)}\n orientation={orientation || undefined}\n disabled={resolvedDisabled}\n {...props}\n />\n </RadioGroupContext.Provider>\n )\n})\nRadioGroup.displayName = 'RadioGroup'\n\n// RadioGroupItem circle variants\nconst radioItemVariants = cva(\n [\n 'relative shrink-0 rounded-full border-border-form hover:border-border-form-strong transition-all duration-micro ease-out',\n 'focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n // Transparent hit area expansion via ::after\n \"after:absolute after:content-['']\",\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'w-3.5 h-3.5 after:-inset-[5px]', // 14px circle → 24px click\n default: 'w-4 h-4 after:-inset-2', // 16px circle → 32px click\n lg: 'w-5 h-5 after:-inset-2', // 20px circle → 36px click\n },\n weight: {\n thin: 'border', // 1px\n bold: 'border-2', // 2px\n },\n },\n defaultVariants: {\n size: 'default',\n weight: 'bold',\n },\n }\n)\n\n// Dot sizes per radio size\nconst dotSizes = {\n sm: 'w-1.5 h-1.5', // 6px\n default: 'w-2 h-2', // 8px\n lg: 'w-2.5 h-2.5', // 10px\n}\n\n// Label font sizes\nconst labelSizes = {\n sm: 'text-xs', // 12px\n default: 'text-md', // 14px\n lg: 'text-base', // 16px\n}\n\n// Gap between radio and label\nconst gapSizes = {\n sm: 'gap-1.5',\n default: 'gap-2',\n lg: 'gap-2.5',\n}\n\nexport interface RadioGroupItemProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n label?: string\n}\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, label, disabled, ...props }, ref) => {\n const { size, weight, color, disabled: groupDisabled } = React.useContext(RadioGroupContext)\n const resolvedDisabled = disabled ?? groupDisabled\n const itemId = React.useId()\n\n const radio = (\n <RadioGroupPrimitive.Item\n ref={ref}\n id={label ? itemId : undefined}\n disabled={resolvedDisabled}\n className={cn(\n radioItemVariants({ size, weight }),\n radioColorMap[color].border,\n className\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center animate-radio-enter\">\n <div className={cn('rounded-full', radioColorMap[color].dot, dotSizes[size])} />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n\n if (!label) return radio\n\n return (\n <div className={cn('group flex items-center', gapSizes[size])}>\n <div className=\"flex items-center\">\n {radio}\n </div>\n <label\n htmlFor={itemId}\n className={cn(\n labelSizes[size],\n 'text-text-muted cursor-pointer select-none transition-colors duration-micro',\n 'group-hover:text-foreground',\n resolvedDisabled && 'opacity-50 cursor-not-allowed'\n )}\n >\n {label}\n </label>\n </div>\n )\n})\nRadioGroupItem.displayName = 'RadioGroupItem'\n\nexport { RadioGroup, RadioGroupItem, radioGroupVariants, radioItemVariants }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/radio-group.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Color maps for checked state\nconst radioColorMap = {\n default: {\n border: 'data-[state=checked]:border-foreground',\n dot: 'bg-foreground',\n },\n primary: {\n border: 'data-[state=checked]:border-primary',\n dot: 'bg-primary',\n },\n} as const\n\nexport type RadioColor = keyof typeof radioColorMap\n\n// Context to pass size, weight, color from RadioGroup to RadioGroupItem\ntype RadioGroupContextValue = {\n size: 'sm' | 'default' | 'lg'\n weight: 'thin' | 'bold'\n color: RadioColor\n disabled?: boolean\n}\nconst RadioGroupContext = React.createContext<RadioGroupContextValue>({ size: 'default', weight: 'bold', color: 'default' })\n\n// RadioGroup container\nconst radioGroupVariants = cva('grid gap-3', {\n variants: {\n orientation: {\n vertical: 'grid-cols-1',\n horizontal: 'grid-flow-col auto-cols-max gap-4',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n size?: 'sm' | 'default' | 'lg'\n weight?: 'thin' | 'bold'\n /** Checked state color */\n color?: RadioColor\n}\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n RadioGroupProps\n>(({ className, orientation, size = 'default', weight = 'bold', color = 'default', disabled, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedDisabled = disabled ?? fieldContext?.disabled\n // Inside a Field the FieldLabel names the radio group (items keep their own labels)\n useFieldControl('labelled', Boolean(fieldContext))\n const labelledBy = fieldContext?.hasLabel && !props['aria-label'] ? fieldContext.labelId : undefined\n\n return (\n <RadioGroupContext.Provider value={{ size, weight, color, disabled: resolvedDisabled }}>\n <RadioGroupPrimitive.Root\n ref={ref}\n className={cn(radioGroupVariants({ orientation }), className)}\n orientation={orientation || undefined}\n disabled={resolvedDisabled}\n aria-labelledby={labelledBy}\n {...props}\n />\n </RadioGroupContext.Provider>\n )\n})\nRadioGroup.displayName = 'RadioGroup'\n\n// RadioGroupItem circle variants\nconst radioItemVariants = cva(\n [\n 'relative shrink-0 rounded-full border-border-form hover:border-border-form-strong transition-all duration-micro ease-out',\n 'focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n // Transparent hit area expansion via ::after\n \"after:absolute after:content-['']\",\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'w-3.5 h-3.5 after:-inset-[5px]', // 14px circle → 24px click\n default: 'w-4 h-4 after:-inset-2', // 16px circle → 32px click\n lg: 'w-5 h-5 after:-inset-2', // 20px circle → 36px click\n },\n weight: {\n thin: 'border', // 1px\n bold: 'border-2', // 2px\n },\n },\n defaultVariants: {\n size: 'default',\n weight: 'bold',\n },\n }\n)\n\n// Dot sizes per radio size\nconst dotSizes = {\n sm: 'w-1.5 h-1.5', // 6px\n default: 'w-2 h-2', // 8px\n lg: 'w-2.5 h-2.5', // 10px\n}\n\n// Label font sizes\nconst labelSizes = {\n sm: 'text-xs', // 12px\n default: 'text-md', // 14px\n lg: 'text-base', // 16px\n}\n\n// Gap between radio and label\nconst gapSizes = {\n sm: 'gap-1.5',\n default: 'gap-2',\n lg: 'gap-2.5',\n}\n\nexport interface RadioGroupItemProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n label?: string\n}\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, label, disabled, ...props }, ref) => {\n const { size, weight, color, disabled: groupDisabled } = React.useContext(RadioGroupContext)\n const resolvedDisabled = disabled ?? groupDisabled\n const itemId = React.useId()\n\n const radio = (\n <RadioGroupPrimitive.Item\n ref={ref}\n id={label ? itemId : undefined}\n disabled={resolvedDisabled}\n className={cn(\n radioItemVariants({ size, weight }),\n radioColorMap[color].border,\n className\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center animate-radio-enter\">\n <div className={cn('rounded-full', radioColorMap[color].dot, dotSizes[size])} />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n\n if (!label) return radio\n\n return (\n <div className={cn('group flex items-center', gapSizes[size])}>\n <div className=\"flex items-center\">\n {radio}\n </div>\n <label\n htmlFor={itemId}\n className={cn(\n labelSizes[size],\n 'text-text-muted cursor-pointer select-none transition-colors duration-micro',\n 'group-hover:text-foreground',\n resolvedDisabled && 'opacity-50 cursor-not-allowed'\n )}\n >\n {label}\n </label>\n </div>\n )\n})\nRadioGroupItem.displayName = 'RadioGroupItem'\n\nexport { RadioGroup, RadioGroupItem, radioGroupVariants, radioItemVariants }\n"],"mappings":"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","names":[]}
|
|
@@ -3,8 +3,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
5
5
|
import { cva } from "class-variance-authority";
|
|
6
|
-
import { cn } from "../../lib/utils";
|
|
7
|
-
import { useFieldContext } from "./field";
|
|
6
|
+
import { cn } from "../../lib/utils.mjs";
|
|
7
|
+
import { useFieldContext, useFieldControl } from "./field.mjs";
|
|
8
8
|
const radioColorMap = {
|
|
9
9
|
default: {
|
|
10
10
|
border: "data-[state=checked]:border-foreground",
|
|
@@ -30,6 +30,8 @@ const radioGroupVariants = cva("grid gap-3", {
|
|
|
30
30
|
const RadioGroup = React.forwardRef(({ className, orientation, size = "default", weight = "bold", color = "default", disabled, ...props }, ref) => {
|
|
31
31
|
const fieldContext = useFieldContext();
|
|
32
32
|
const resolvedDisabled = disabled ?? fieldContext?.disabled;
|
|
33
|
+
useFieldControl("labelled", Boolean(fieldContext));
|
|
34
|
+
const labelledBy = fieldContext?.hasLabel && !props["aria-label"] ? fieldContext.labelId : void 0;
|
|
33
35
|
return /* @__PURE__ */ jsx(RadioGroupContext.Provider, { value: { size, weight, color, disabled: resolvedDisabled }, children: /* @__PURE__ */ jsx(
|
|
34
36
|
RadioGroupPrimitive.Root,
|
|
35
37
|
{
|
|
@@ -37,6 +39,7 @@ const RadioGroup = React.forwardRef(({ className, orientation, size = "default",
|
|
|
37
39
|
className: cn(radioGroupVariants({ orientation }), className),
|
|
38
40
|
orientation: orientation || void 0,
|
|
39
41
|
disabled: resolvedDisabled,
|
|
42
|
+
"aria-labelledby": labelledBy,
|
|
40
43
|
...props
|
|
41
44
|
}
|
|
42
45
|
) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/radio-group.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\n// Color maps for checked state\nconst radioColorMap = {\n default: {\n border: 'data-[state=checked]:border-foreground',\n dot: 'bg-foreground',\n },\n primary: {\n border: 'data-[state=checked]:border-primary',\n dot: 'bg-primary',\n },\n} as const\n\nexport type RadioColor = keyof typeof radioColorMap\n\n// Context to pass size, weight, color from RadioGroup to RadioGroupItem\ntype RadioGroupContextValue = {\n size: 'sm' | 'default' | 'lg'\n weight: 'thin' | 'bold'\n color: RadioColor\n disabled?: boolean\n}\nconst RadioGroupContext = React.createContext<RadioGroupContextValue>({ size: 'default', weight: 'bold', color: 'default' })\n\n// RadioGroup container\nconst radioGroupVariants = cva('grid gap-3', {\n variants: {\n orientation: {\n vertical: 'grid-cols-1',\n horizontal: 'grid-flow-col auto-cols-max gap-4',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n size?: 'sm' | 'default' | 'lg'\n weight?: 'thin' | 'bold'\n /** Checked state color */\n color?: RadioColor\n}\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n RadioGroupProps\n>(({ className, orientation, size = 'default', weight = 'bold', color = 'default', disabled, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedDisabled = disabled ?? fieldContext?.disabled\n\n return (\n <RadioGroupContext.Provider value={{ size, weight, color, disabled: resolvedDisabled }}>\n <RadioGroupPrimitive.Root\n ref={ref}\n className={cn(radioGroupVariants({ orientation }), className)}\n orientation={orientation || undefined}\n disabled={resolvedDisabled}\n {...props}\n />\n </RadioGroupContext.Provider>\n )\n})\nRadioGroup.displayName = 'RadioGroup'\n\n// RadioGroupItem circle variants\nconst radioItemVariants = cva(\n [\n 'relative shrink-0 rounded-full border-border-form hover:border-border-form-strong transition-all duration-micro ease-out',\n 'focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n // Transparent hit area expansion via ::after\n \"after:absolute after:content-['']\",\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'w-3.5 h-3.5 after:-inset-[5px]', // 14px circle → 24px click\n default: 'w-4 h-4 after:-inset-2', // 16px circle → 32px click\n lg: 'w-5 h-5 after:-inset-2', // 20px circle → 36px click\n },\n weight: {\n thin: 'border', // 1px\n bold: 'border-2', // 2px\n },\n },\n defaultVariants: {\n size: 'default',\n weight: 'bold',\n },\n }\n)\n\n// Dot sizes per radio size\nconst dotSizes = {\n sm: 'w-1.5 h-1.5', // 6px\n default: 'w-2 h-2', // 8px\n lg: 'w-2.5 h-2.5', // 10px\n}\n\n// Label font sizes\nconst labelSizes = {\n sm: 'text-xs', // 12px\n default: 'text-md', // 14px\n lg: 'text-base', // 16px\n}\n\n// Gap between radio and label\nconst gapSizes = {\n sm: 'gap-1.5',\n default: 'gap-2',\n lg: 'gap-2.5',\n}\n\nexport interface RadioGroupItemProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n label?: string\n}\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, label, disabled, ...props }, ref) => {\n const { size, weight, color, disabled: groupDisabled } = React.useContext(RadioGroupContext)\n const resolvedDisabled = disabled ?? groupDisabled\n const itemId = React.useId()\n\n const radio = (\n <RadioGroupPrimitive.Item\n ref={ref}\n id={label ? itemId : undefined}\n disabled={resolvedDisabled}\n className={cn(\n radioItemVariants({ size, weight }),\n radioColorMap[color].border,\n className\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center animate-radio-enter\">\n <div className={cn('rounded-full', radioColorMap[color].dot, dotSizes[size])} />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n\n if (!label) return radio\n\n return (\n <div className={cn('group flex items-center', gapSizes[size])}>\n <div className=\"flex items-center\">\n {radio}\n </div>\n <label\n htmlFor={itemId}\n className={cn(\n labelSizes[size],\n 'text-text-muted cursor-pointer select-none transition-colors duration-micro',\n 'group-hover:text-foreground',\n resolvedDisabled && 'opacity-50 cursor-not-allowed'\n )}\n >\n {label}\n </label>\n </div>\n )\n})\nRadioGroupItem.displayName = 'RadioGroupItem'\n\nexport { RadioGroup, RadioGroupItem, radioGroupVariants, radioItemVariants }\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/radio-group.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Color maps for checked state\nconst radioColorMap = {\n default: {\n border: 'data-[state=checked]:border-foreground',\n dot: 'bg-foreground',\n },\n primary: {\n border: 'data-[state=checked]:border-primary',\n dot: 'bg-primary',\n },\n} as const\n\nexport type RadioColor = keyof typeof radioColorMap\n\n// Context to pass size, weight, color from RadioGroup to RadioGroupItem\ntype RadioGroupContextValue = {\n size: 'sm' | 'default' | 'lg'\n weight: 'thin' | 'bold'\n color: RadioColor\n disabled?: boolean\n}\nconst RadioGroupContext = React.createContext<RadioGroupContextValue>({ size: 'default', weight: 'bold', color: 'default' })\n\n// RadioGroup container\nconst radioGroupVariants = cva('grid gap-3', {\n variants: {\n orientation: {\n vertical: 'grid-cols-1',\n horizontal: 'grid-flow-col auto-cols-max gap-4',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n size?: 'sm' | 'default' | 'lg'\n weight?: 'thin' | 'bold'\n /** Checked state color */\n color?: RadioColor\n}\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n RadioGroupProps\n>(({ className, orientation, size = 'default', weight = 'bold', color = 'default', disabled, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedDisabled = disabled ?? fieldContext?.disabled\n // Inside a Field the FieldLabel names the radio group (items keep their own labels)\n useFieldControl('labelled', Boolean(fieldContext))\n const labelledBy = fieldContext?.hasLabel && !props['aria-label'] ? fieldContext.labelId : undefined\n\n return (\n <RadioGroupContext.Provider value={{ size, weight, color, disabled: resolvedDisabled }}>\n <RadioGroupPrimitive.Root\n ref={ref}\n className={cn(radioGroupVariants({ orientation }), className)}\n orientation={orientation || undefined}\n disabled={resolvedDisabled}\n aria-labelledby={labelledBy}\n {...props}\n />\n </RadioGroupContext.Provider>\n )\n})\nRadioGroup.displayName = 'RadioGroup'\n\n// RadioGroupItem circle variants\nconst radioItemVariants = cva(\n [\n 'relative shrink-0 rounded-full border-border-form hover:border-border-form-strong transition-all duration-micro ease-out',\n 'focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n // Transparent hit area expansion via ::after\n \"after:absolute after:content-['']\",\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'w-3.5 h-3.5 after:-inset-[5px]', // 14px circle → 24px click\n default: 'w-4 h-4 after:-inset-2', // 16px circle → 32px click\n lg: 'w-5 h-5 after:-inset-2', // 20px circle → 36px click\n },\n weight: {\n thin: 'border', // 1px\n bold: 'border-2', // 2px\n },\n },\n defaultVariants: {\n size: 'default',\n weight: 'bold',\n },\n }\n)\n\n// Dot sizes per radio size\nconst dotSizes = {\n sm: 'w-1.5 h-1.5', // 6px\n default: 'w-2 h-2', // 8px\n lg: 'w-2.5 h-2.5', // 10px\n}\n\n// Label font sizes\nconst labelSizes = {\n sm: 'text-xs', // 12px\n default: 'text-md', // 14px\n lg: 'text-base', // 16px\n}\n\n// Gap between radio and label\nconst gapSizes = {\n sm: 'gap-1.5',\n default: 'gap-2',\n lg: 'gap-2.5',\n}\n\nexport interface RadioGroupItemProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n label?: string\n}\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, label, disabled, ...props }, ref) => {\n const { size, weight, color, disabled: groupDisabled } = React.useContext(RadioGroupContext)\n const resolvedDisabled = disabled ?? groupDisabled\n const itemId = React.useId()\n\n const radio = (\n <RadioGroupPrimitive.Item\n ref={ref}\n id={label ? itemId : undefined}\n disabled={resolvedDisabled}\n className={cn(\n radioItemVariants({ size, weight }),\n radioColorMap[color].border,\n className\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center animate-radio-enter\">\n <div className={cn('rounded-full', radioColorMap[color].dot, dotSizes[size])} />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n\n if (!label) return radio\n\n return (\n <div className={cn('group flex items-center', gapSizes[size])}>\n <div className=\"flex items-center\">\n {radio}\n </div>\n <label\n htmlFor={itemId}\n className={cn(\n labelSizes[size],\n 'text-text-muted cursor-pointer select-none transition-colors duration-micro',\n 'group-hover:text-foreground',\n resolvedDisabled && 'opacity-50 cursor-not-allowed'\n )}\n >\n {label}\n </label>\n </div>\n )\n})\nRadioGroupItem.displayName = 'RadioGroupItem'\n\nexport { RadioGroup, RadioGroupItem, radioGroupVariants, radioItemVariants }\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
5
5
|
import { cva } from "class-variance-authority";
|
|
6
|
-
import { cn } from "../../lib/utils";
|
|
6
|
+
import { cn } from "../../lib/utils.mjs";
|
|
7
7
|
const SegmentedContext = React.createContext({});
|
|
8
8
|
const useSegmentedContext = () => React.useContext(SegmentedContext);
|
|
9
9
|
const segmentedVariants = cva(
|
|
@@ -3,7 +3,7 @@ import * as SelectPrimitive from '@radix-ui/react-select';
|
|
|
3
3
|
|
|
4
4
|
type SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
|
|
5
5
|
type SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl';
|
|
6
|
-
declare const Select: ({ size, radius, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
|
|
6
|
+
declare const Select: ({ size, radius, disabled, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
|
|
7
7
|
size?: SelectSize;
|
|
8
8
|
radius?: SelectRadius;
|
|
9
9
|
}) => React.JSX.Element;
|
|
@@ -3,7 +3,7 @@ import * as SelectPrimitive from '@radix-ui/react-select';
|
|
|
3
3
|
|
|
4
4
|
type SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
|
|
5
5
|
type SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl';
|
|
6
|
-
declare const Select: ({ size, radius, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
|
|
6
|
+
declare const Select: ({ size, radius, disabled, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
|
|
7
7
|
size?: SelectSize;
|
|
8
8
|
radius?: SelectRadius;
|
|
9
9
|
}) => React.JSX.Element;
|
|
@@ -43,6 +43,7 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
43
43
|
var React = __toESM(require("react"));
|
|
44
44
|
var SelectPrimitive = __toESM(require("@radix-ui/react-select"));
|
|
45
45
|
var import_utils = require("../../lib/utils");
|
|
46
|
+
var import_field = require("./field");
|
|
46
47
|
const triggerRadiusMap = {
|
|
47
48
|
none: "rounded-none",
|
|
48
49
|
sm: "rounded-sm",
|
|
@@ -147,16 +148,23 @@ const SelectStyleContext = React.createContext({ contentRadius: "xl", itemSize:
|
|
|
147
148
|
const Select = ({
|
|
148
149
|
size = "default",
|
|
149
150
|
radius = "default",
|
|
151
|
+
disabled,
|
|
150
152
|
...props
|
|
151
|
-
}) =>
|
|
153
|
+
}) => {
|
|
154
|
+
const fieldContext = (0, import_field.useFieldContext)();
|
|
155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContext.Provider, { value: { size, radius }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectPrimitive.Root, { disabled: disabled ?? fieldContext?.disabled, ...props }) });
|
|
156
|
+
};
|
|
152
157
|
const SelectValue = SelectPrimitive.Value;
|
|
153
158
|
const SelectGroup = SelectPrimitive.Group;
|
|
154
|
-
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
159
|
+
const SelectTrigger = React.forwardRef(({ className, children, id, ...props }, ref) => {
|
|
155
160
|
const { size, radius } = React.useContext(SelectContext);
|
|
161
|
+
const fieldContext = (0, import_field.useFieldContext)();
|
|
162
|
+
(0, import_field.useFieldControl)("single", Boolean(fieldContext) && !id);
|
|
156
163
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
157
164
|
SelectPrimitive.Trigger,
|
|
158
165
|
{
|
|
159
166
|
ref,
|
|
167
|
+
id: id ?? fieldContext?.id,
|
|
160
168
|
className: (0, import_utils.cn)(
|
|
161
169
|
"flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted",
|
|
162
170
|
"border border-border-form",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { cn } from '../../lib/utils'\n\n// Radius (matches Input — set at Root, propagates to Trigger and Content)\ntype SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n\nconst triggerRadiusMap: Record<SelectRadius, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n}\n\n// Auto-mapping: root radius → content radius (3 levels)\ntype SelectContentRadius = 'md' | 'lg' | 'xl'\n\nconst contentRadiusFromRoot: Record<SelectRadius, SelectContentRadius> = {\n none: 'md',\n sm: 'md',\n base: 'md',\n default: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': 'xl',\n '3xl': 'xl',\n full: 'xl',\n}\n\nconst contentRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded-md', // 6px\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n}\n\nconst itemRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded', // 4px — perceptual balance (67%)\n lg: 'rounded-md', // 6px — perceptual balance (75%)\n xl: 'rounded-lg', // 8px — perceptual balance (67%)\n}\n\n// Size variants (matches Input component)\ntype SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl'\n\n// Trigger sizes (identical to Input)\nconst triggerSizeMap: Record<SelectSize, string> = {\n xs: 'h-9 px-3 text-sm', // 36px\n sm: 'h-10 px-3 text-md', // 40px\n default: 'h-11 px-4 text-base', // 44px\n lg: 'h-12 px-4 text-base', // 48px\n xl: 'h-14 px-4 text-base', // 56px\n}\n\n// Trigger icon sizes (matches Input icon pattern)\nconst triggerIconSizeMap: Record<SelectSize, string> = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Auto-mapping: trigger size → content item size (3 levels)\ntype SelectItemSize = 'sm' | 'md' | 'lg'\n\nconst itemSizeFromTrigger: Record<SelectSize, SelectItemSize> = {\n xs: 'sm',\n sm: 'sm',\n default: 'md',\n lg: 'md',\n xl: 'lg',\n}\n\n// Item sizes (font matches Trigger for seamless selection, padding controls density)\nconst itemSizeMap: Record<SelectItemSize, string> = {\n sm: 'pl-2 pr-6 py-1.5 text-sm',\n md: 'pl-3 pr-8 py-1.5 text-base',\n lg: 'pl-3 pr-10 py-2.5 text-base',\n}\n\n// Item indicator (check mark) — right-aligned\nconst indicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-2 h-3 w-3',\n md: 'right-2 h-3.5 w-3.5',\n lg: 'right-3 h-4 w-4',\n}\n\n// Label sizes\nconst labelSizeMap: Record<SelectItemSize, string> = {\n sm: 'px-2 py-1.5 text-xs',\n md: 'px-2 py-1.5 text-xs',\n lg: 'px-3 py-2.5 text-xs',\n}\n\n// Flush mode — items span full width, no inner radius\nconst flushItemPaddingMap: Record<SelectItemSize, string> = {\n sm: 'pl-3 pr-7',\n md: 'pl-4 pr-9',\n lg: 'pl-4 pr-11',\n}\n\nconst flushIndicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-3 h-3 w-3',\n md: 'right-3 h-3.5 w-3.5',\n lg: 'right-4 h-4 w-4',\n}\n\nconst flushLabelPaddingMap: Record<SelectItemSize, string> = {\n sm: 'px-3',\n md: 'px-3',\n lg: 'px-4',\n}\n\n// Root context — set at Root, consumed by Trigger and Content\nconst SelectContext = React.createContext<{\n size: SelectSize\n radius: SelectRadius\n}>({ size: 'default', radius: 'default' })\n\n// Style context — set at Content, consumed by Item/Label\nconst SelectStyleContext = React.createContext<{\n contentRadius: SelectContentRadius\n itemSize: SelectItemSize\n flush: boolean\n}>({ contentRadius: 'xl', itemSize: 'md', flush: false })\n\n// Root — state management + size/radius context\nconst Select = ({\n size = 'default',\n radius = 'default',\n ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {\n size?: SelectSize\n radius?: SelectRadius\n}) => (\n <SelectContext.Provider value={{ size, radius }}>\n <SelectPrimitive.Root {...props} />\n </SelectContext.Provider>\n)\n\n// Value — displays selected value or placeholder\nconst SelectValue = SelectPrimitive.Value\n\n// Group — groups related items\nconst SelectGroup = SelectPrimitive.Group\n\n// Trigger — the element that opens the select (reads size + radius from context)\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n 'flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted',\n 'border border-border-form',\n triggerRadiusMap[radius],\n 'transition-colors duration-micro outline-transparent',\n 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)] focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'data-[placeholder]:text-foreground/30',\n triggerSizeMap[size],\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <svg\n className={cn('ml-2 shrink-0 text-text-muted', triggerIconSizeMap[size])}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\n// ScrollUpButton — scroll indicator at top\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 15l7-7 7 7\" />\n </svg>\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\n// ScrollDownButton — scroll indicator at bottom\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName\n\n// Content — the floating panel (reads size + radius from context, auto-maps both)\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n flush?: boolean\n }\n>(({ className, children, position = 'popper', sideOffset = 1, flush = false, onCloseAutoFocus, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n const itemSize = itemSizeFromTrigger[size]\n const contentRadius = contentRadiusFromRoot[radius]\n return (\n <SelectPrimitive.Portal>\n <SelectStyleContext.Provider value={{ contentRadius, itemSize, flush }}>\n <SelectPrimitive.Content\n ref={ref}\n onCloseAutoFocus={(e) => {\n e.preventDefault()\n onCloseAutoFocus?.(e)\n }}\n className={cn(\n 'relative z-popover min-w-[var(--radix-select-trigger-width)] overflow-hidden border border-border bg-background text-foreground shadow-lg',\n flush ? 'py-1' : 'p-1',\n contentRadiusMap[contentRadius],\n position === 'popper' &&\n 'max-h-[var(--radix-select-content-available-height)]',\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n position === 'popper' &&\n 'h-[var(--radix-select-content-available-height)] w-full'\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectStyleContext.Provider>\n </SelectPrimitive.Portal>\n )\n})\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\n// Item — a single selectable item (with right-aligned check indicator)\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => {\n const { contentRadius, itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center outline-none',\n itemSizeMap[itemSize],\n !flush && itemRadiusMap[contentRadius],\n flush && flushItemPaddingMap[itemSize],\n 'transition-colors duration-fast',\n 'focus:bg-background-muted',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n {...props}\n >\n <SelectPrimitive.ItemText className=\"truncate\">{children}</SelectPrimitive.ItemText>\n <span className={cn('absolute flex items-center justify-center', flush ? flushIndicatorSizeMap[itemSize] : indicatorSizeMap[itemSize])}>\n <SelectPrimitive.ItemIndicator>\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </SelectPrimitive.ItemIndicator>\n </span>\n </SelectPrimitive.Item>\n )\n})\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\n// Label — non-interactive group heading\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => {\n const { itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\n 'font-semibold text-text-muted',\n labelSizeMap[itemSize],\n flush && flushLabelPaddingMap[itemSize],\n className\n )}\n {...props}\n />\n )\n})\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\n// Separator — visual divider between groups\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => {\n const { flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('h-px bg-border my-1', !flush && '-mx-1', className)}\n {...props}\n />\n )\n})\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport type { SelectRadius, SelectSize }\n\nexport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n SelectGroup,\n SelectLabel,\n SelectSeparator,\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Radius (matches Input — set at Root, propagates to Trigger and Content)\ntype SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n\nconst triggerRadiusMap: Record<SelectRadius, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n}\n\n// Auto-mapping: root radius → content radius (3 levels)\ntype SelectContentRadius = 'md' | 'lg' | 'xl'\n\nconst contentRadiusFromRoot: Record<SelectRadius, SelectContentRadius> = {\n none: 'md',\n sm: 'md',\n base: 'md',\n default: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': 'xl',\n '3xl': 'xl',\n full: 'xl',\n}\n\nconst contentRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded-md', // 6px\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n}\n\nconst itemRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded', // 4px — perceptual balance (67%)\n lg: 'rounded-md', // 6px — perceptual balance (75%)\n xl: 'rounded-lg', // 8px — perceptual balance (67%)\n}\n\n// Size variants (matches Input component)\ntype SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl'\n\n// Trigger sizes (identical to Input)\nconst triggerSizeMap: Record<SelectSize, string> = {\n xs: 'h-9 px-3 text-sm', // 36px\n sm: 'h-10 px-3 text-md', // 40px\n default: 'h-11 px-4 text-base', // 44px\n lg: 'h-12 px-4 text-base', // 48px\n xl: 'h-14 px-4 text-base', // 56px\n}\n\n// Trigger icon sizes (matches Input icon pattern)\nconst triggerIconSizeMap: Record<SelectSize, string> = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Auto-mapping: trigger size → content item size (3 levels)\ntype SelectItemSize = 'sm' | 'md' | 'lg'\n\nconst itemSizeFromTrigger: Record<SelectSize, SelectItemSize> = {\n xs: 'sm',\n sm: 'sm',\n default: 'md',\n lg: 'md',\n xl: 'lg',\n}\n\n// Item sizes (font matches Trigger for seamless selection, padding controls density)\nconst itemSizeMap: Record<SelectItemSize, string> = {\n sm: 'pl-2 pr-6 py-1.5 text-sm',\n md: 'pl-3 pr-8 py-1.5 text-base',\n lg: 'pl-3 pr-10 py-2.5 text-base',\n}\n\n// Item indicator (check mark) — right-aligned\nconst indicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-2 h-3 w-3',\n md: 'right-2 h-3.5 w-3.5',\n lg: 'right-3 h-4 w-4',\n}\n\n// Label sizes\nconst labelSizeMap: Record<SelectItemSize, string> = {\n sm: 'px-2 py-1.5 text-xs',\n md: 'px-2 py-1.5 text-xs',\n lg: 'px-3 py-2.5 text-xs',\n}\n\n// Flush mode — items span full width, no inner radius\nconst flushItemPaddingMap: Record<SelectItemSize, string> = {\n sm: 'pl-3 pr-7',\n md: 'pl-4 pr-9',\n lg: 'pl-4 pr-11',\n}\n\nconst flushIndicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-3 h-3 w-3',\n md: 'right-3 h-3.5 w-3.5',\n lg: 'right-4 h-4 w-4',\n}\n\nconst flushLabelPaddingMap: Record<SelectItemSize, string> = {\n sm: 'px-3',\n md: 'px-3',\n lg: 'px-4',\n}\n\n// Root context — set at Root, consumed by Trigger and Content\nconst SelectContext = React.createContext<{\n size: SelectSize\n radius: SelectRadius\n}>({ size: 'default', radius: 'default' })\n\n// Style context — set at Content, consumed by Item/Label\nconst SelectStyleContext = React.createContext<{\n contentRadius: SelectContentRadius\n itemSize: SelectItemSize\n flush: boolean\n}>({ contentRadius: 'xl', itemSize: 'md', flush: false })\n\n// Root — state management + size/radius context. Inside a Field it inherits the\n// Field's disabled state, like Input and Textarea.\nconst Select = ({\n size = 'default',\n radius = 'default',\n disabled,\n ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {\n size?: SelectSize\n radius?: SelectRadius\n}) => {\n const fieldContext = useFieldContext()\n return (\n <SelectContext.Provider value={{ size, radius }}>\n <SelectPrimitive.Root disabled={disabled ?? fieldContext?.disabled} {...props} />\n </SelectContext.Provider>\n )\n}\n\n// Value — displays selected value or placeholder\nconst SelectValue = SelectPrimitive.Value\n\n// Group — groups related items\nconst SelectGroup = SelectPrimitive.Group\n\n// Trigger — the element that opens the select (reads size + radius from context)\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, id, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n // Inside a Field the trigger takes the Field id, so FieldLabel names it\n const fieldContext = useFieldContext()\n useFieldControl('single', Boolean(fieldContext) && !id)\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n id={id ?? fieldContext?.id}\n className={cn(\n 'flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted',\n 'border border-border-form',\n triggerRadiusMap[radius],\n 'transition-colors duration-micro outline-transparent',\n 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)] focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'data-[placeholder]:text-foreground/30',\n triggerSizeMap[size],\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <svg\n className={cn('ml-2 shrink-0 text-text-muted', triggerIconSizeMap[size])}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\n// ScrollUpButton — scroll indicator at top\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 15l7-7 7 7\" />\n </svg>\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\n// ScrollDownButton — scroll indicator at bottom\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName\n\n// Content — the floating panel (reads size + radius from context, auto-maps both)\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n flush?: boolean\n }\n>(({ className, children, position = 'popper', sideOffset = 1, flush = false, onCloseAutoFocus, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n const itemSize = itemSizeFromTrigger[size]\n const contentRadius = contentRadiusFromRoot[radius]\n return (\n <SelectPrimitive.Portal>\n <SelectStyleContext.Provider value={{ contentRadius, itemSize, flush }}>\n <SelectPrimitive.Content\n ref={ref}\n onCloseAutoFocus={(e) => {\n e.preventDefault()\n onCloseAutoFocus?.(e)\n }}\n className={cn(\n 'relative z-popover min-w-[var(--radix-select-trigger-width)] overflow-hidden border border-border bg-background text-foreground shadow-lg',\n flush ? 'py-1' : 'p-1',\n contentRadiusMap[contentRadius],\n position === 'popper' &&\n 'max-h-[var(--radix-select-content-available-height)]',\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n position === 'popper' &&\n 'h-[var(--radix-select-content-available-height)] w-full'\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectStyleContext.Provider>\n </SelectPrimitive.Portal>\n )\n})\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\n// Item — a single selectable item (with right-aligned check indicator)\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => {\n const { contentRadius, itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center outline-none',\n itemSizeMap[itemSize],\n !flush && itemRadiusMap[contentRadius],\n flush && flushItemPaddingMap[itemSize],\n 'transition-colors duration-fast',\n 'focus:bg-background-muted',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n {...props}\n >\n <SelectPrimitive.ItemText className=\"truncate\">{children}</SelectPrimitive.ItemText>\n <span className={cn('absolute flex items-center justify-center', flush ? flushIndicatorSizeMap[itemSize] : indicatorSizeMap[itemSize])}>\n <SelectPrimitive.ItemIndicator>\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </SelectPrimitive.ItemIndicator>\n </span>\n </SelectPrimitive.Item>\n )\n})\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\n// Label — non-interactive group heading\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => {\n const { itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\n 'font-semibold text-text-muted',\n labelSizeMap[itemSize],\n flush && flushLabelPaddingMap[itemSize],\n className\n )}\n {...props}\n />\n )\n})\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\n// Separator — visual divider between groups\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => {\n const { flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('h-px bg-border my-1', !flush && '-mx-1', className)}\n {...props}\n />\n )\n})\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport type { SelectRadius, SelectSize }\n\nexport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n SelectGroup,\n SelectLabel,\n SelectSeparator,\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
5
|
+
import { cn } from "../../lib/utils.mjs";
|
|
6
|
+
import { useFieldContext, useFieldControl } from "./field.mjs";
|
|
6
7
|
const triggerRadiusMap = {
|
|
7
8
|
none: "rounded-none",
|
|
8
9
|
sm: "rounded-sm",
|
|
@@ -107,16 +108,23 @@ const SelectStyleContext = React.createContext({ contentRadius: "xl", itemSize:
|
|
|
107
108
|
const Select = ({
|
|
108
109
|
size = "default",
|
|
109
110
|
radius = "default",
|
|
111
|
+
disabled,
|
|
110
112
|
...props
|
|
111
|
-
}) =>
|
|
113
|
+
}) => {
|
|
114
|
+
const fieldContext = useFieldContext();
|
|
115
|
+
return /* @__PURE__ */ jsx(SelectContext.Provider, { value: { size, radius }, children: /* @__PURE__ */ jsx(SelectPrimitive.Root, { disabled: disabled ?? fieldContext?.disabled, ...props }) });
|
|
116
|
+
};
|
|
112
117
|
const SelectValue = SelectPrimitive.Value;
|
|
113
118
|
const SelectGroup = SelectPrimitive.Group;
|
|
114
|
-
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
119
|
+
const SelectTrigger = React.forwardRef(({ className, children, id, ...props }, ref) => {
|
|
115
120
|
const { size, radius } = React.useContext(SelectContext);
|
|
121
|
+
const fieldContext = useFieldContext();
|
|
122
|
+
useFieldControl("single", Boolean(fieldContext) && !id);
|
|
116
123
|
return /* @__PURE__ */ jsxs(
|
|
117
124
|
SelectPrimitive.Trigger,
|
|
118
125
|
{
|
|
119
126
|
ref,
|
|
127
|
+
id: id ?? fieldContext?.id,
|
|
120
128
|
className: cn(
|
|
121
129
|
"flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted",
|
|
122
130
|
"border border-border-form",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { cn } from '../../lib/utils'\n\n// Radius (matches Input — set at Root, propagates to Trigger and Content)\ntype SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n\nconst triggerRadiusMap: Record<SelectRadius, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n}\n\n// Auto-mapping: root radius → content radius (3 levels)\ntype SelectContentRadius = 'md' | 'lg' | 'xl'\n\nconst contentRadiusFromRoot: Record<SelectRadius, SelectContentRadius> = {\n none: 'md',\n sm: 'md',\n base: 'md',\n default: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': 'xl',\n '3xl': 'xl',\n full: 'xl',\n}\n\nconst contentRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded-md', // 6px\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n}\n\nconst itemRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded', // 4px — perceptual balance (67%)\n lg: 'rounded-md', // 6px — perceptual balance (75%)\n xl: 'rounded-lg', // 8px — perceptual balance (67%)\n}\n\n// Size variants (matches Input component)\ntype SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl'\n\n// Trigger sizes (identical to Input)\nconst triggerSizeMap: Record<SelectSize, string> = {\n xs: 'h-9 px-3 text-sm', // 36px\n sm: 'h-10 px-3 text-md', // 40px\n default: 'h-11 px-4 text-base', // 44px\n lg: 'h-12 px-4 text-base', // 48px\n xl: 'h-14 px-4 text-base', // 56px\n}\n\n// Trigger icon sizes (matches Input icon pattern)\nconst triggerIconSizeMap: Record<SelectSize, string> = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Auto-mapping: trigger size → content item size (3 levels)\ntype SelectItemSize = 'sm' | 'md' | 'lg'\n\nconst itemSizeFromTrigger: Record<SelectSize, SelectItemSize> = {\n xs: 'sm',\n sm: 'sm',\n default: 'md',\n lg: 'md',\n xl: 'lg',\n}\n\n// Item sizes (font matches Trigger for seamless selection, padding controls density)\nconst itemSizeMap: Record<SelectItemSize, string> = {\n sm: 'pl-2 pr-6 py-1.5 text-sm',\n md: 'pl-3 pr-8 py-1.5 text-base',\n lg: 'pl-3 pr-10 py-2.5 text-base',\n}\n\n// Item indicator (check mark) — right-aligned\nconst indicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-2 h-3 w-3',\n md: 'right-2 h-3.5 w-3.5',\n lg: 'right-3 h-4 w-4',\n}\n\n// Label sizes\nconst labelSizeMap: Record<SelectItemSize, string> = {\n sm: 'px-2 py-1.5 text-xs',\n md: 'px-2 py-1.5 text-xs',\n lg: 'px-3 py-2.5 text-xs',\n}\n\n// Flush mode — items span full width, no inner radius\nconst flushItemPaddingMap: Record<SelectItemSize, string> = {\n sm: 'pl-3 pr-7',\n md: 'pl-4 pr-9',\n lg: 'pl-4 pr-11',\n}\n\nconst flushIndicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-3 h-3 w-3',\n md: 'right-3 h-3.5 w-3.5',\n lg: 'right-4 h-4 w-4',\n}\n\nconst flushLabelPaddingMap: Record<SelectItemSize, string> = {\n sm: 'px-3',\n md: 'px-3',\n lg: 'px-4',\n}\n\n// Root context — set at Root, consumed by Trigger and Content\nconst SelectContext = React.createContext<{\n size: SelectSize\n radius: SelectRadius\n}>({ size: 'default', radius: 'default' })\n\n// Style context — set at Content, consumed by Item/Label\nconst SelectStyleContext = React.createContext<{\n contentRadius: SelectContentRadius\n itemSize: SelectItemSize\n flush: boolean\n}>({ contentRadius: 'xl', itemSize: 'md', flush: false })\n\n// Root — state management + size/radius context\nconst Select = ({\n size = 'default',\n radius = 'default',\n ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {\n size?: SelectSize\n radius?: SelectRadius\n}) => (\n <SelectContext.Provider value={{ size, radius }}>\n <SelectPrimitive.Root {...props} />\n </SelectContext.Provider>\n)\n\n// Value — displays selected value or placeholder\nconst SelectValue = SelectPrimitive.Value\n\n// Group — groups related items\nconst SelectGroup = SelectPrimitive.Group\n\n// Trigger — the element that opens the select (reads size + radius from context)\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n 'flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted',\n 'border border-border-form',\n triggerRadiusMap[radius],\n 'transition-colors duration-micro outline-transparent',\n 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)] focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'data-[placeholder]:text-foreground/30',\n triggerSizeMap[size],\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <svg\n className={cn('ml-2 shrink-0 text-text-muted', triggerIconSizeMap[size])}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\n// ScrollUpButton — scroll indicator at top\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 15l7-7 7 7\" />\n </svg>\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\n// ScrollDownButton — scroll indicator at bottom\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName\n\n// Content — the floating panel (reads size + radius from context, auto-maps both)\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n flush?: boolean\n }\n>(({ className, children, position = 'popper', sideOffset = 1, flush = false, onCloseAutoFocus, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n const itemSize = itemSizeFromTrigger[size]\n const contentRadius = contentRadiusFromRoot[radius]\n return (\n <SelectPrimitive.Portal>\n <SelectStyleContext.Provider value={{ contentRadius, itemSize, flush }}>\n <SelectPrimitive.Content\n ref={ref}\n onCloseAutoFocus={(e) => {\n e.preventDefault()\n onCloseAutoFocus?.(e)\n }}\n className={cn(\n 'relative z-popover min-w-[var(--radix-select-trigger-width)] overflow-hidden border border-border bg-background text-foreground shadow-lg',\n flush ? 'py-1' : 'p-1',\n contentRadiusMap[contentRadius],\n position === 'popper' &&\n 'max-h-[var(--radix-select-content-available-height)]',\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n position === 'popper' &&\n 'h-[var(--radix-select-content-available-height)] w-full'\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectStyleContext.Provider>\n </SelectPrimitive.Portal>\n )\n})\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\n// Item — a single selectable item (with right-aligned check indicator)\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => {\n const { contentRadius, itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center outline-none',\n itemSizeMap[itemSize],\n !flush && itemRadiusMap[contentRadius],\n flush && flushItemPaddingMap[itemSize],\n 'transition-colors duration-fast',\n 'focus:bg-background-muted',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n {...props}\n >\n <SelectPrimitive.ItemText className=\"truncate\">{children}</SelectPrimitive.ItemText>\n <span className={cn('absolute flex items-center justify-center', flush ? flushIndicatorSizeMap[itemSize] : indicatorSizeMap[itemSize])}>\n <SelectPrimitive.ItemIndicator>\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </SelectPrimitive.ItemIndicator>\n </span>\n </SelectPrimitive.Item>\n )\n})\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\n// Label — non-interactive group heading\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => {\n const { itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\n 'font-semibold text-text-muted',\n labelSizeMap[itemSize],\n flush && flushLabelPaddingMap[itemSize],\n className\n )}\n {...props}\n />\n )\n})\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\n// Separator — visual divider between groups\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => {\n const { flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('h-px bg-border my-1', !flush && '-mx-1', className)}\n {...props}\n />\n )\n})\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport type { SelectRadius, SelectSize }\n\nexport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n SelectGroup,\n SelectLabel,\n SelectSeparator,\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Radius (matches Input — set at Root, propagates to Trigger and Content)\ntype SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n\nconst triggerRadiusMap: Record<SelectRadius, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n}\n\n// Auto-mapping: root radius → content radius (3 levels)\ntype SelectContentRadius = 'md' | 'lg' | 'xl'\n\nconst contentRadiusFromRoot: Record<SelectRadius, SelectContentRadius> = {\n none: 'md',\n sm: 'md',\n base: 'md',\n default: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': 'xl',\n '3xl': 'xl',\n full: 'xl',\n}\n\nconst contentRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded-md', // 6px\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n}\n\nconst itemRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded', // 4px — perceptual balance (67%)\n lg: 'rounded-md', // 6px — perceptual balance (75%)\n xl: 'rounded-lg', // 8px — perceptual balance (67%)\n}\n\n// Size variants (matches Input component)\ntype SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl'\n\n// Trigger sizes (identical to Input)\nconst triggerSizeMap: Record<SelectSize, string> = {\n xs: 'h-9 px-3 text-sm', // 36px\n sm: 'h-10 px-3 text-md', // 40px\n default: 'h-11 px-4 text-base', // 44px\n lg: 'h-12 px-4 text-base', // 48px\n xl: 'h-14 px-4 text-base', // 56px\n}\n\n// Trigger icon sizes (matches Input icon pattern)\nconst triggerIconSizeMap: Record<SelectSize, string> = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Auto-mapping: trigger size → content item size (3 levels)\ntype SelectItemSize = 'sm' | 'md' | 'lg'\n\nconst itemSizeFromTrigger: Record<SelectSize, SelectItemSize> = {\n xs: 'sm',\n sm: 'sm',\n default: 'md',\n lg: 'md',\n xl: 'lg',\n}\n\n// Item sizes (font matches Trigger for seamless selection, padding controls density)\nconst itemSizeMap: Record<SelectItemSize, string> = {\n sm: 'pl-2 pr-6 py-1.5 text-sm',\n md: 'pl-3 pr-8 py-1.5 text-base',\n lg: 'pl-3 pr-10 py-2.5 text-base',\n}\n\n// Item indicator (check mark) — right-aligned\nconst indicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-2 h-3 w-3',\n md: 'right-2 h-3.5 w-3.5',\n lg: 'right-3 h-4 w-4',\n}\n\n// Label sizes\nconst labelSizeMap: Record<SelectItemSize, string> = {\n sm: 'px-2 py-1.5 text-xs',\n md: 'px-2 py-1.5 text-xs',\n lg: 'px-3 py-2.5 text-xs',\n}\n\n// Flush mode — items span full width, no inner radius\nconst flushItemPaddingMap: Record<SelectItemSize, string> = {\n sm: 'pl-3 pr-7',\n md: 'pl-4 pr-9',\n lg: 'pl-4 pr-11',\n}\n\nconst flushIndicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-3 h-3 w-3',\n md: 'right-3 h-3.5 w-3.5',\n lg: 'right-4 h-4 w-4',\n}\n\nconst flushLabelPaddingMap: Record<SelectItemSize, string> = {\n sm: 'px-3',\n md: 'px-3',\n lg: 'px-4',\n}\n\n// Root context — set at Root, consumed by Trigger and Content\nconst SelectContext = React.createContext<{\n size: SelectSize\n radius: SelectRadius\n}>({ size: 'default', radius: 'default' })\n\n// Style context — set at Content, consumed by Item/Label\nconst SelectStyleContext = React.createContext<{\n contentRadius: SelectContentRadius\n itemSize: SelectItemSize\n flush: boolean\n}>({ contentRadius: 'xl', itemSize: 'md', flush: false })\n\n// Root — state management + size/radius context. Inside a Field it inherits the\n// Field's disabled state, like Input and Textarea.\nconst Select = ({\n size = 'default',\n radius = 'default',\n disabled,\n ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {\n size?: SelectSize\n radius?: SelectRadius\n}) => {\n const fieldContext = useFieldContext()\n return (\n <SelectContext.Provider value={{ size, radius }}>\n <SelectPrimitive.Root disabled={disabled ?? fieldContext?.disabled} {...props} />\n </SelectContext.Provider>\n )\n}\n\n// Value — displays selected value or placeholder\nconst SelectValue = SelectPrimitive.Value\n\n// Group — groups related items\nconst SelectGroup = SelectPrimitive.Group\n\n// Trigger — the element that opens the select (reads size + radius from context)\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, id, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n // Inside a Field the trigger takes the Field id, so FieldLabel names it\n const fieldContext = useFieldContext()\n useFieldControl('single', Boolean(fieldContext) && !id)\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n id={id ?? fieldContext?.id}\n className={cn(\n 'flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted',\n 'border border-border-form',\n triggerRadiusMap[radius],\n 'transition-colors duration-micro outline-transparent',\n 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)] focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'data-[placeholder]:text-foreground/30',\n triggerSizeMap[size],\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <svg\n className={cn('ml-2 shrink-0 text-text-muted', triggerIconSizeMap[size])}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\n// ScrollUpButton — scroll indicator at top\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 15l7-7 7 7\" />\n </svg>\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\n// ScrollDownButton — scroll indicator at bottom\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName\n\n// Content — the floating panel (reads size + radius from context, auto-maps both)\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n flush?: boolean\n }\n>(({ className, children, position = 'popper', sideOffset = 1, flush = false, onCloseAutoFocus, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectContext)\n const itemSize = itemSizeFromTrigger[size]\n const contentRadius = contentRadiusFromRoot[radius]\n return (\n <SelectPrimitive.Portal>\n <SelectStyleContext.Provider value={{ contentRadius, itemSize, flush }}>\n <SelectPrimitive.Content\n ref={ref}\n onCloseAutoFocus={(e) => {\n e.preventDefault()\n onCloseAutoFocus?.(e)\n }}\n className={cn(\n 'relative z-popover min-w-[var(--radix-select-trigger-width)] overflow-hidden border border-border bg-background text-foreground shadow-lg',\n flush ? 'py-1' : 'p-1',\n contentRadiusMap[contentRadius],\n position === 'popper' &&\n 'max-h-[var(--radix-select-content-available-height)]',\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n position === 'popper' &&\n 'h-[var(--radix-select-content-available-height)] w-full'\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectStyleContext.Provider>\n </SelectPrimitive.Portal>\n )\n})\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\n// Item — a single selectable item (with right-aligned check indicator)\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => {\n const { contentRadius, itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center outline-none',\n itemSizeMap[itemSize],\n !flush && itemRadiusMap[contentRadius],\n flush && flushItemPaddingMap[itemSize],\n 'transition-colors duration-fast',\n 'focus:bg-background-muted',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n {...props}\n >\n <SelectPrimitive.ItemText className=\"truncate\">{children}</SelectPrimitive.ItemText>\n <span className={cn('absolute flex items-center justify-center', flush ? flushIndicatorSizeMap[itemSize] : indicatorSizeMap[itemSize])}>\n <SelectPrimitive.ItemIndicator>\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </SelectPrimitive.ItemIndicator>\n </span>\n </SelectPrimitive.Item>\n )\n})\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\n// Label — non-interactive group heading\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => {\n const { itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\n 'font-semibold text-text-muted',\n labelSizeMap[itemSize],\n flush && flushLabelPaddingMap[itemSize],\n className\n )}\n {...props}\n />\n )\n})\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\n// Separator — visual divider between groups\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => {\n const { flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('h-px bg-border my-1', !flush && '-mx-1', className)}\n {...props}\n />\n )\n})\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport type { SelectRadius, SelectSize }\n\nexport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n SelectGroup,\n SelectLabel,\n SelectSeparator,\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
5
|
+
import { cn } from "../../lib/utils.mjs";
|
|
6
6
|
const PULSE_DURATION_MS = 2e3;
|
|
7
7
|
const WAVE_DURATION_MS = 1800;
|
|
8
8
|
const WAVE_GRADIENT = [
|
|
@@ -38,6 +38,7 @@ var React = __toESM(require("react"));
|
|
|
38
38
|
var SliderPrimitive = __toESM(require("@radix-ui/react-slider"));
|
|
39
39
|
var import_class_variance_authority = require("class-variance-authority");
|
|
40
40
|
var import_utils = require("../../lib/utils");
|
|
41
|
+
var import_field = require("./field");
|
|
41
42
|
const sliderVariants = (0, import_class_variance_authority.cva)(
|
|
42
43
|
"relative flex touch-none select-none",
|
|
43
44
|
{
|
|
@@ -82,8 +83,11 @@ const sliderColorMap = {
|
|
|
82
83
|
thumbActive: "active:shadow-[0_0_0_6px_color-mix(in_srgb,var(--color-primary)_16%,transparent)]"
|
|
83
84
|
}
|
|
84
85
|
};
|
|
85
|
-
const Slider = React.forwardRef(({ className, size, color = "default", value, defaultValue, onValueChange, showTooltip = "never", formatLabel, startContent, endContent, orientation, ...props }, ref) => {
|
|
86
|
+
const Slider = React.forwardRef(({ className, size, color = "default", value, defaultValue, onValueChange, showTooltip = "never", formatLabel, startContent, endContent, orientation, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }, ref) => {
|
|
86
87
|
const resolvedSize = size || "default";
|
|
88
|
+
const fieldContext = (0, import_field.useFieldContext)();
|
|
89
|
+
(0, import_field.useFieldControl)("labelled", Boolean(fieldContext));
|
|
90
|
+
const thumbLabelledBy = ariaLabelledBy ?? (!ariaLabel && fieldContext?.hasLabel ? fieldContext.labelId : void 0);
|
|
87
91
|
const thumbCount = value?.length ?? defaultValue?.length ?? 1;
|
|
88
92
|
const hasTooltip = showTooltip !== "never";
|
|
89
93
|
const hasWrapper = !!(startContent || endContent);
|
|
@@ -135,6 +139,8 @@ const Slider = React.forwardRef(({ className, size, color = "default", value, de
|
|
|
135
139
|
Array.from({ length: thumbCount }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
136
140
|
SliderPrimitive.Thumb,
|
|
137
141
|
{
|
|
142
|
+
"aria-label": ariaLabel,
|
|
143
|
+
"aria-labelledby": thumbLabelledBy,
|
|
138
144
|
className: (0, import_utils.cn)(
|
|
139
145
|
"group/thumb block rounded-full border-2 shadow-sm",
|
|
140
146
|
sliderColorMap[color].thumb,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/slider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SliderPrimitive from '@radix-ui/react-slider'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// Slider root variants\nconst sliderVariants = cva(\n 'relative flex touch-none select-none',\n {\n variants: {\n size: {\n sm: '',\n default: '',\n lg: '',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\n// Track sizes per orientation\nconst trackSizes = {\n sm: 'h-1 data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-1',\n default: 'h-1.5 data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-1.5',\n lg: 'h-2 data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-2',\n}\n\n// Thumb sizes\nconst thumbSizes = {\n sm: 'w-[var(--component-slider-thumb-sm)] h-[var(--component-slider-thumb-sm)]',\n default: 'w-[var(--component-slider-thumb-default)] h-[var(--component-slider-thumb-default)]',\n lg: 'w-[var(--component-slider-thumb-lg)] h-[var(--component-slider-thumb-lg)]',\n}\n\n// Content font sizes (for startContent / endContent)\nconst contentSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n}\n\n// Color maps for range and thumb\nconst sliderColorMap = {\n default: {\n range: 'bg-foreground',\n thumb: 'bg-background border-foreground',\n thumbHover: 'hover:shadow-[0_0_0_4px_color-mix(in_srgb,var(--color-text)_16%,transparent)] hover:border-foreground',\n thumbActive: 'active:shadow-[0_0_0_6px_color-mix(in_srgb,var(--color-text)_16%,transparent)]',\n },\n primary: {\n range: 'bg-primary',\n thumb: 'bg-primary-foreground border-primary',\n thumbHover: 'hover:shadow-primary-glow hover:border-primary-hover',\n thumbActive: 'active:shadow-[0_0_0_6px_color-mix(in_srgb,var(--color-primary)_16%,transparent)]',\n },\n} as const\n\nexport type SliderColor = keyof typeof sliderColorMap\n\nexport interface SliderProps\n extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n VariantProps<typeof sliderVariants> {\n /** Track and thumb color */\n color?: SliderColor\n /** Tooltip display mode: auto (hover/drag), always, never */\n showTooltip?: 'auto' | 'always' | 'never'\n /** Custom formatter for tooltip value */\n formatLabel?: (value: number) => string\n /** Content to display before the slider (icon, label, etc.) */\n startContent?: React.ReactNode\n /** Content to display after the slider */\n endContent?: React.ReactNode\n}\n\nconst Slider = React.forwardRef<\n React.ElementRef<typeof SliderPrimitive.Root>,\n SliderProps\n>(({ className, size, color = 'default', value, defaultValue, onValueChange, showTooltip = 'never', formatLabel, startContent, endContent, orientation, ...props }, ref) => {\n const resolvedSize = size || 'default'\n const thumbCount = value?.length ?? defaultValue?.length ?? 1\n const hasTooltip = showTooltip !== 'never'\n const hasWrapper = !!(startContent || endContent)\n const isVertical = orientation === 'vertical'\n\n // Track value internally for tooltip display\n const [internalValue, setInternalValue] = React.useState(\n () => value ?? defaultValue ?? Array(thumbCount).fill(props.min ?? 0)\n )\n const displayValues = value ?? internalValue\n\n const handleValueChange = React.useCallback((newValue: number[]) => {\n setInternalValue(newValue)\n onValueChange?.(newValue)\n }, [onValueChange])\n\n const sliderRoot = (\n <SliderPrimitive.Root\n ref={ref}\n className={cn(\n sliderVariants({ size }),\n isVertical\n ? 'h-full w-auto flex-col items-center'\n : 'w-full items-center',\n hasWrapper && (isVertical ? 'flex-1 min-h-0' : 'flex-1 min-w-0'),\n !hasWrapper && className\n )}\n value={value}\n defaultValue={defaultValue}\n onValueChange={hasTooltip ? handleValueChange : onValueChange}\n orientation={orientation}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(\n 'relative grow overflow-hidden rounded-full bg-border',\n isVertical ? 'h-full' : 'w-full',\n trackSizes[resolvedSize]\n )}\n >\n <SliderPrimitive.Range\n className={cn(\n 'absolute rounded-full', sliderColorMap[color].range,\n isVertical\n ? 'w-full transition-[top,bottom] duration-fast ease-out'\n : 'h-full transition-[left,right] duration-fast ease-out'\n )}\n />\n </SliderPrimitive.Track>\n {Array.from({ length: thumbCount }).map((_, i) => (\n <SliderPrimitive.Thumb\n key={i}\n className={cn(\n 'group/thumb block rounded-full border-2 shadow-sm', sliderColorMap[color].thumb,\n isVertical\n ? 'transition-[top,box-shadow,border-color] duration-fast ease-out'\n : 'transition-[left,box-shadow,border-color] duration-fast ease-out',\n sliderColorMap[color].thumbHover,\n sliderColorMap[color].thumbActive,\n 'focus-visible:focus-ring',\n 'disabled:pointer-events-none disabled:opacity-50',\n thumbSizes[resolvedSize]\n )}\n >\n {hasTooltip && (\n <div\n className={cn(\n 'absolute pointer-events-none',\n 'transition-all duration-fast ease-out',\n isVertical\n ? 'right-full top-1/2 -translate-y-1/2 mr-2 origin-right'\n : 'bottom-full left-1/2 -translate-x-1/2 mb-2 origin-bottom',\n showTooltip === 'always'\n ? 'opacity-100 scale-100'\n : [\n 'opacity-0 scale-95',\n 'group-hover/thumb:opacity-100 group-hover/thumb:scale-100',\n 'group-active/thumb:opacity-100 group-active/thumb:scale-100',\n 'group-focus-visible/thumb:opacity-100 group-focus-visible/thumb:scale-100',\n ]\n )}\n >\n <div className=\"relative bg-foreground text-background text-xs font-semibold font-mono tabular-nums px-2.5 py-1 rounded-md shadow-lg whitespace-nowrap\">\n {formatLabel ? formatLabel(displayValues[i]) : displayValues[i]}\n {/* Arrow */}\n {isVertical ? (\n <div className=\"absolute left-full top-1/2 -translate-y-1/2 border-4 border-transparent border-l-foreground\" />\n ) : (\n <div className=\"absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-foreground\" />\n )}\n </div>\n </div>\n )}\n </SliderPrimitive.Thumb>\n ))}\n </SliderPrimitive.Root>\n )\n\n if (!hasWrapper) return sliderRoot\n\n return (\n <div className={cn(\n isVertical ? 'inline-flex flex-col items-center gap-2 h-full' : 'flex items-center gap-3',\n className\n )}>\n {startContent && (\n <span className={cn('shrink-0 text-text-muted select-none', contentSizes[resolvedSize], props.disabled && 'opacity-50')}>\n {startContent}\n </span>\n )}\n {sliderRoot}\n {endContent && (\n <span className={cn('shrink-0 text-text-muted select-none', contentSizes[resolvedSize], props.disabled && 'opacity-50')}>\n {endContent}\n </span>\n )}\n </div>\n )\n})\nSlider.displayName = 'Slider'\n\nexport { Slider, sliderVariants }\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/slider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SliderPrimitive from '@radix-ui/react-slider'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Slider root variants\nconst sliderVariants = cva(\n 'relative flex touch-none select-none',\n {\n variants: {\n size: {\n sm: '',\n default: '',\n lg: '',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\n// Track sizes per orientation\nconst trackSizes = {\n sm: 'h-1 data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-1',\n default: 'h-1.5 data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-1.5',\n lg: 'h-2 data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-2',\n}\n\n// Thumb sizes\nconst thumbSizes = {\n sm: 'w-[var(--component-slider-thumb-sm)] h-[var(--component-slider-thumb-sm)]',\n default: 'w-[var(--component-slider-thumb-default)] h-[var(--component-slider-thumb-default)]',\n lg: 'w-[var(--component-slider-thumb-lg)] h-[var(--component-slider-thumb-lg)]',\n}\n\n// Content font sizes (for startContent / endContent)\nconst contentSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n}\n\n// Color maps for range and thumb\nconst sliderColorMap = {\n default: {\n range: 'bg-foreground',\n thumb: 'bg-background border-foreground',\n thumbHover: 'hover:shadow-[0_0_0_4px_color-mix(in_srgb,var(--color-text)_16%,transparent)] hover:border-foreground',\n thumbActive: 'active:shadow-[0_0_0_6px_color-mix(in_srgb,var(--color-text)_16%,transparent)]',\n },\n primary: {\n range: 'bg-primary',\n thumb: 'bg-primary-foreground border-primary',\n thumbHover: 'hover:shadow-primary-glow hover:border-primary-hover',\n thumbActive: 'active:shadow-[0_0_0_6px_color-mix(in_srgb,var(--color-primary)_16%,transparent)]',\n },\n} as const\n\nexport type SliderColor = keyof typeof sliderColorMap\n\nexport interface SliderProps\n extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n VariantProps<typeof sliderVariants> {\n /** Track and thumb color */\n color?: SliderColor\n /** Tooltip display mode: auto (hover/drag), always, never */\n showTooltip?: 'auto' | 'always' | 'never'\n /** Custom formatter for tooltip value */\n formatLabel?: (value: number) => string\n /** Content to display before the slider (icon, label, etc.) */\n startContent?: React.ReactNode\n /** Content to display after the slider */\n endContent?: React.ReactNode\n}\n\nconst Slider = React.forwardRef<\n React.ElementRef<typeof SliderPrimitive.Root>,\n SliderProps\n>(({ className, size, color = 'default', value, defaultValue, onValueChange, showTooltip = 'never', formatLabel, startContent, endContent, orientation, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }, ref) => {\n const resolvedSize = size || 'default'\n // The thumbs carry role=\"slider\", so the accessible name goes on them, not on the\n // Root. Inside a Field the FieldLabel names the slider unless a name is given.\n const fieldContext = useFieldContext()\n useFieldControl('labelled', Boolean(fieldContext))\n const thumbLabelledBy = ariaLabelledBy ?? (!ariaLabel && fieldContext?.hasLabel ? fieldContext.labelId : undefined)\n const thumbCount = value?.length ?? defaultValue?.length ?? 1\n const hasTooltip = showTooltip !== 'never'\n const hasWrapper = !!(startContent || endContent)\n const isVertical = orientation === 'vertical'\n\n // Track value internally for tooltip display\n const [internalValue, setInternalValue] = React.useState(\n () => value ?? defaultValue ?? Array(thumbCount).fill(props.min ?? 0)\n )\n const displayValues = value ?? internalValue\n\n const handleValueChange = React.useCallback((newValue: number[]) => {\n setInternalValue(newValue)\n onValueChange?.(newValue)\n }, [onValueChange])\n\n const sliderRoot = (\n <SliderPrimitive.Root\n ref={ref}\n className={cn(\n sliderVariants({ size }),\n isVertical\n ? 'h-full w-auto flex-col items-center'\n : 'w-full items-center',\n hasWrapper && (isVertical ? 'flex-1 min-h-0' : 'flex-1 min-w-0'),\n !hasWrapper && className\n )}\n value={value}\n defaultValue={defaultValue}\n onValueChange={hasTooltip ? handleValueChange : onValueChange}\n orientation={orientation}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(\n 'relative grow overflow-hidden rounded-full bg-border',\n isVertical ? 'h-full' : 'w-full',\n trackSizes[resolvedSize]\n )}\n >\n <SliderPrimitive.Range\n className={cn(\n 'absolute rounded-full', sliderColorMap[color].range,\n isVertical\n ? 'w-full transition-[top,bottom] duration-fast ease-out'\n : 'h-full transition-[left,right] duration-fast ease-out'\n )}\n />\n </SliderPrimitive.Track>\n {Array.from({ length: thumbCount }).map((_, i) => (\n <SliderPrimitive.Thumb\n key={i}\n aria-label={ariaLabel}\n aria-labelledby={thumbLabelledBy}\n className={cn(\n 'group/thumb block rounded-full border-2 shadow-sm', sliderColorMap[color].thumb,\n isVertical\n ? 'transition-[top,box-shadow,border-color] duration-fast ease-out'\n : 'transition-[left,box-shadow,border-color] duration-fast ease-out',\n sliderColorMap[color].thumbHover,\n sliderColorMap[color].thumbActive,\n 'focus-visible:focus-ring',\n 'disabled:pointer-events-none disabled:opacity-50',\n thumbSizes[resolvedSize]\n )}\n >\n {hasTooltip && (\n <div\n className={cn(\n 'absolute pointer-events-none',\n 'transition-all duration-fast ease-out',\n isVertical\n ? 'right-full top-1/2 -translate-y-1/2 mr-2 origin-right'\n : 'bottom-full left-1/2 -translate-x-1/2 mb-2 origin-bottom',\n showTooltip === 'always'\n ? 'opacity-100 scale-100'\n : [\n 'opacity-0 scale-95',\n 'group-hover/thumb:opacity-100 group-hover/thumb:scale-100',\n 'group-active/thumb:opacity-100 group-active/thumb:scale-100',\n 'group-focus-visible/thumb:opacity-100 group-focus-visible/thumb:scale-100',\n ]\n )}\n >\n <div className=\"relative bg-foreground text-background text-xs font-semibold font-mono tabular-nums px-2.5 py-1 rounded-md shadow-lg whitespace-nowrap\">\n {formatLabel ? formatLabel(displayValues[i]) : displayValues[i]}\n {/* Arrow */}\n {isVertical ? (\n <div className=\"absolute left-full top-1/2 -translate-y-1/2 border-4 border-transparent border-l-foreground\" />\n ) : (\n <div className=\"absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-foreground\" />\n )}\n </div>\n </div>\n )}\n </SliderPrimitive.Thumb>\n ))}\n </SliderPrimitive.Root>\n )\n\n if (!hasWrapper) return sliderRoot\n\n return (\n <div className={cn(\n isVertical ? 'inline-flex flex-col items-center gap-2 h-full' : 'flex items-center gap-3',\n className\n )}>\n {startContent && (\n <span className={cn('shrink-0 text-text-muted select-none', contentSizes[resolvedSize], props.disabled && 'opacity-50')}>\n {startContent}\n </span>\n )}\n {sliderRoot}\n {endContent && (\n <span className={cn('shrink-0 text-text-muted select-none', contentSizes[resolvedSize], props.disabled && 'opacity-50')}>\n {endContent}\n </span>\n )}\n </div>\n )\n})\nSlider.displayName = 'Slider'\n\nexport { Slider, sliderVariants }\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
5
5
|
import { cva } from "class-variance-authority";
|
|
6
|
-
import { cn } from "../../lib/utils";
|
|
6
|
+
import { cn } from "../../lib/utils.mjs";
|
|
7
|
+
import { useFieldContext, useFieldControl } from "./field.mjs";
|
|
7
8
|
const sliderVariants = cva(
|
|
8
9
|
"relative flex touch-none select-none",
|
|
9
10
|
{
|
|
@@ -48,8 +49,11 @@ const sliderColorMap = {
|
|
|
48
49
|
thumbActive: "active:shadow-[0_0_0_6px_color-mix(in_srgb,var(--color-primary)_16%,transparent)]"
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
|
-
const Slider = React.forwardRef(({ className, size, color = "default", value, defaultValue, onValueChange, showTooltip = "never", formatLabel, startContent, endContent, orientation, ...props }, ref) => {
|
|
52
|
+
const Slider = React.forwardRef(({ className, size, color = "default", value, defaultValue, onValueChange, showTooltip = "never", formatLabel, startContent, endContent, orientation, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }, ref) => {
|
|
52
53
|
const resolvedSize = size || "default";
|
|
54
|
+
const fieldContext = useFieldContext();
|
|
55
|
+
useFieldControl("labelled", Boolean(fieldContext));
|
|
56
|
+
const thumbLabelledBy = ariaLabelledBy ?? (!ariaLabel && fieldContext?.hasLabel ? fieldContext.labelId : void 0);
|
|
53
57
|
const thumbCount = value?.length ?? defaultValue?.length ?? 1;
|
|
54
58
|
const hasTooltip = showTooltip !== "never";
|
|
55
59
|
const hasWrapper = !!(startContent || endContent);
|
|
@@ -101,6 +105,8 @@ const Slider = React.forwardRef(({ className, size, color = "default", value, de
|
|
|
101
105
|
Array.from({ length: thumbCount }).map((_, i) => /* @__PURE__ */ jsx(
|
|
102
106
|
SliderPrimitive.Thumb,
|
|
103
107
|
{
|
|
108
|
+
"aria-label": ariaLabel,
|
|
109
|
+
"aria-labelledby": thumbLabelledBy,
|
|
104
110
|
className: cn(
|
|
105
111
|
"group/thumb block rounded-full border-2 shadow-sm",
|
|
106
112
|
sliderColorMap[color].thumb,
|