@epilot/spark-ui 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/components/avatar.d.cts +1 -1
- package/dist/components/avatar.d.ts +1 -1
- package/dist/components/badge.cjs +1 -1
- package/dist/components/badge.cjs.map +1 -1
- package/dist/components/badge.d.cts +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/badge.js +1 -1
- package/dist/components/badge.js.map +1 -1
- package/dist/components/bar-chart.cjs +4 -7
- package/dist/components/bar-chart.cjs.map +1 -1
- package/dist/components/bar-chart.js +4 -7
- package/dist/components/bar-chart.js.map +1 -1
- package/dist/components/battery-progress-row.cjs +6 -7
- package/dist/components/battery-progress-row.cjs.map +1 -1
- package/dist/components/battery-progress-row.js +6 -7
- package/dist/components/battery-progress-row.js.map +1 -1
- package/dist/components/box.cjs +42 -0
- package/dist/components/box.cjs.map +1 -0
- package/dist/components/box.d.cts +35 -0
- package/dist/components/box.d.ts +35 -0
- package/dist/components/box.js +41 -0
- package/dist/components/box.js.map +1 -0
- package/dist/components/bubble.d.cts +1 -1
- package/dist/components/button-group.d.cts +1 -1
- package/dist/components/button-group.d.ts +1 -1
- package/dist/components/button.cjs +1 -1
- package/dist/components/button.cjs.map +1 -1
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/button.js +1 -1
- package/dist/components/button.js.map +1 -1
- package/dist/components/card.cjs +10 -14
- package/dist/components/card.cjs.map +1 -1
- package/dist/components/card.d.cts +6 -3
- package/dist/components/card.d.ts +6 -3
- package/dist/components/card.js +10 -14
- package/dist/components/card.js.map +1 -1
- package/dist/components/checkbox.cjs +4 -2
- package/dist/components/checkbox.cjs.map +1 -1
- package/dist/components/checkbox.d.cts +1 -1
- package/dist/components/checkbox.d.ts +1 -1
- package/dist/components/checkbox.js +4 -2
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/empty-state.cjs +4 -7
- package/dist/components/empty-state.cjs.map +1 -1
- package/dist/components/empty-state.js +4 -7
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/field.cjs +43 -10
- package/dist/components/field.cjs.map +1 -1
- package/dist/components/field.d.cts +19 -2
- package/dist/components/field.d.ts +19 -2
- package/dist/components/field.js +43 -11
- package/dist/components/field.js.map +1 -1
- package/dist/components/icon.cjs +12 -9
- package/dist/components/icon.cjs.map +1 -1
- package/dist/components/icon.d.cts +6 -2
- package/dist/components/icon.d.ts +6 -2
- package/dist/components/icon.js +12 -9
- package/dist/components/icon.js.map +1 -1
- package/dist/components/input.d.cts +1 -1
- package/dist/components/input.d.ts +1 -1
- package/dist/components/marker.d.cts +1 -1
- package/dist/components/marker.d.ts +1 -1
- package/dist/components/metering-row.cjs +28 -11
- package/dist/components/metering-row.cjs.map +1 -1
- package/dist/components/metering-row.js +28 -11
- package/dist/components/metering-row.js.map +1 -1
- package/dist/components/pill.cjs +1 -1
- package/dist/components/pill.cjs.map +1 -1
- package/dist/components/pill.d.cts +1 -1
- package/dist/components/pill.d.ts +1 -1
- package/dist/components/pill.js +1 -1
- package/dist/components/pill.js.map +1 -1
- package/dist/components/radio.cjs +4 -2
- package/dist/components/radio.cjs.map +1 -1
- package/dist/components/radio.d.cts +3 -1
- package/dist/components/radio.d.ts +3 -1
- package/dist/components/radio.js +4 -2
- package/dist/components/radio.js.map +1 -1
- package/dist/components/segmented-control.d.cts +1 -1
- package/dist/components/segmented-control.d.ts +1 -1
- package/dist/components/select.d.cts +1 -1
- package/dist/components/select.d.ts +1 -1
- package/dist/components/switch.cjs +3 -1
- package/dist/components/switch.cjs.map +1 -1
- package/dist/components/switch.d.cts +3 -1
- package/dist/components/switch.d.ts +3 -1
- package/dist/components/switch.js +3 -1
- package/dist/components/switch.js.map +1 -1
- package/dist/components/textarea.d.cts +1 -1
- package/dist/components/textarea.d.ts +1 -1
- package/dist/components/theme.cjs +35 -9
- package/dist/components/theme.cjs.map +1 -1
- package/dist/components/theme.d.cts +12 -1
- package/dist/components/theme.d.ts +12 -1
- package/dist/components/theme.js +36 -10
- package/dist/components/theme.js.map +1 -1
- package/dist/icons/material-symbol.cjs +1 -0
- package/dist/icons/material-symbol.cjs.map +1 -1
- package/dist/icons/material-symbol.js +1 -0
- package/dist/icons/material-symbol.js.map +1 -1
- package/dist/lib/accent-theme.cjs +102 -14
- package/dist/lib/accent-theme.cjs.map +1 -1
- package/dist/lib/accent-theme.d.cts +29 -4
- package/dist/lib/accent-theme.d.ts +29 -4
- package/dist/lib/accent-theme.js +100 -15
- package/dist/lib/accent-theme.js.map +1 -1
- package/dist/lib/container-chrome.cjs +53 -0
- package/dist/lib/container-chrome.cjs.map +1 -0
- package/dist/lib/container-chrome.d.cts +15 -0
- package/dist/lib/container-chrome.d.ts +15 -0
- package/dist/lib/container-chrome.js +48 -0
- package/dist/lib/container-chrome.js.map +1 -0
- package/dist/lib/input-box-variants.d.cts +1 -1
- package/dist/lib/input-box-variants.d.ts +1 -1
- package/dist/lib/theme-types.d.cts +1 -1
- package/dist/lib/theme-types.d.ts +1 -1
- package/dist/styles/spark-default.css +34 -8
- package/dist/{theme-types-8wjgiNA_.d.ts → theme-types-1yB0d8mp.d.cts} +6 -6
- package/dist/{theme-types-8wjgiNA_.d.cts → theme-types-1yB0d8mp.d.ts} +6 -6
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
5
5
|
const require_components_separator = require("./separator.cjs");
|
|
6
|
+
const require_components_skeleton = require("./skeleton.cjs");
|
|
6
7
|
const require_components_theme = require("./theme.cjs");
|
|
7
8
|
let react = require("react");
|
|
8
9
|
react = require_chunk.__toESM(react);
|
|
@@ -118,24 +119,30 @@ const fieldVariants = (0, class_variance_authority.cva)("group/field relative fl
|
|
|
118
119
|
}
|
|
119
120
|
]
|
|
120
121
|
});
|
|
121
|
-
function Field({ className, labelPosition: labelPositionProp, inputStyle: inputStyleProp, inputColor: inputColorProp, ...props }) {
|
|
122
|
+
function Field({ className, children, labelPosition: labelPositionProp, inputStyle: inputStyleProp, inputColor: inputColorProp, readOnly = false, ...props }) {
|
|
122
123
|
const id = (0, react.useId)();
|
|
123
124
|
const [hasDescription, setHasDescription] = react.useState(false);
|
|
124
125
|
const theme = require_components_theme.useTheme();
|
|
125
126
|
const labelPosition = labelPositionProp ?? theme.labelPosition ?? "inset";
|
|
126
127
|
const inputStyle = inputStyleProp ?? theme.inputStyle ?? "soft";
|
|
127
128
|
const inputColor = inputColorProp ?? theme.inputColor ?? "brand";
|
|
129
|
+
const fieldId = `field-${id}`;
|
|
130
|
+
const labelId = `${fieldId}-label`;
|
|
128
131
|
const value = react.useMemo(() => ({
|
|
129
|
-
id:
|
|
130
|
-
|
|
132
|
+
id: fieldId,
|
|
133
|
+
labelId,
|
|
134
|
+
descriptionId: `${fieldId}-description`,
|
|
131
135
|
hasDescription,
|
|
132
136
|
setHasDescription,
|
|
137
|
+
readOnly,
|
|
133
138
|
labelPosition,
|
|
134
139
|
inputStyle,
|
|
135
140
|
inputColor
|
|
136
141
|
}), [
|
|
137
|
-
|
|
142
|
+
fieldId,
|
|
143
|
+
labelId,
|
|
138
144
|
hasDescription,
|
|
145
|
+
readOnly,
|
|
139
146
|
labelPosition,
|
|
140
147
|
inputStyle,
|
|
141
148
|
inputColor
|
|
@@ -148,12 +155,14 @@ function Field({ className, labelPosition: labelPositionProp, inputStyle: inputS
|
|
|
148
155
|
"data-label-position": labelPosition,
|
|
149
156
|
"data-input-style": inputStyle,
|
|
150
157
|
"data-input-color": inputColor,
|
|
158
|
+
"aria-labelledby": readOnly ? labelId : void 0,
|
|
151
159
|
className: (0, cnfast.cn)(fieldVariants({
|
|
152
160
|
labelPosition,
|
|
153
161
|
inputStyle,
|
|
154
162
|
inputColor
|
|
155
163
|
}), className),
|
|
156
|
-
...props
|
|
164
|
+
...props,
|
|
165
|
+
children
|
|
157
166
|
})
|
|
158
167
|
});
|
|
159
168
|
}
|
|
@@ -164,26 +173,49 @@ function FieldContent({ className, ...props }) {
|
|
|
164
173
|
...props
|
|
165
174
|
});
|
|
166
175
|
}
|
|
167
|
-
|
|
176
|
+
const fieldLabelClassName = "text-sm leading-5 font-normal text-gray-light transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none";
|
|
177
|
+
function FieldLabel({ className, htmlFor, srOnly, children, ...props }) {
|
|
168
178
|
const field = useFieldContext();
|
|
179
|
+
const classNames = (0, cnfast.cn)(fieldLabelClassName, srOnly && "sr-only", className);
|
|
180
|
+
if (field?.readOnly) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
181
|
+
"data-slot": "field-label",
|
|
182
|
+
id: field.labelId,
|
|
183
|
+
className: classNames,
|
|
184
|
+
children
|
|
185
|
+
});
|
|
169
186
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
170
187
|
"data-slot": "field-label",
|
|
171
|
-
className:
|
|
188
|
+
className: classNames,
|
|
172
189
|
htmlFor: htmlFor ?? field?.id,
|
|
173
|
-
...props
|
|
190
|
+
...props,
|
|
191
|
+
children
|
|
174
192
|
});
|
|
175
193
|
}
|
|
176
194
|
function FieldValue({ className, id, title, truncate, children, ...props }) {
|
|
177
|
-
const field = useFieldContext();
|
|
178
195
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
179
196
|
"data-slot": "field-value",
|
|
180
|
-
id
|
|
197
|
+
id,
|
|
181
198
|
title: title ?? (truncate && typeof children === "string" ? children : void 0),
|
|
182
199
|
className: (0, cnfast.cn)("min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70", truncate ? "block truncate leading-8" : "inline-flex items-center wrap-anywhere whitespace-pre-wrap", className),
|
|
183
200
|
...props,
|
|
184
201
|
children
|
|
185
202
|
});
|
|
186
203
|
}
|
|
204
|
+
function FieldSkeleton({ className, labelClassName, valueClassName, truncate, ...props }) {
|
|
205
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
206
|
+
"data-slot": "field-skeleton",
|
|
207
|
+
"aria-hidden": "true",
|
|
208
|
+
className: (0, cnfast.cn)("flex w-full flex-col gap-y-1", className),
|
|
209
|
+
...props,
|
|
210
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_skeleton.Skeleton, {
|
|
211
|
+
"data-slot": "field-skeleton-label",
|
|
212
|
+
className: (0, cnfast.cn)("h-5 w-24", labelClassName)
|
|
213
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_skeleton.Skeleton, {
|
|
214
|
+
"data-slot": "field-skeleton-value",
|
|
215
|
+
className: (0, cnfast.cn)("h-8 min-h-8 w-full", truncate && "max-w-full truncate", valueClassName)
|
|
216
|
+
})]
|
|
217
|
+
});
|
|
218
|
+
}
|
|
187
219
|
function FieldTitle({ className, ...props }) {
|
|
188
220
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
189
221
|
"data-slot": "field-title",
|
|
@@ -249,6 +281,7 @@ exports.FieldLabel = FieldLabel;
|
|
|
249
281
|
exports.FieldLegend = FieldLegend;
|
|
250
282
|
exports.FieldSeparator = FieldSeparator;
|
|
251
283
|
exports.FieldSet = FieldSet;
|
|
284
|
+
exports.FieldSkeleton = FieldSkeleton;
|
|
252
285
|
exports.FieldTitle = FieldTitle;
|
|
253
286
|
exports.FieldValue = FieldValue;
|
|
254
287
|
exports.useFieldContext = useFieldContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.cjs","names":["React","useTheme","Separator"],"sources":["../../src/components/field.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { useId } from 'react'\nimport type {\n SparkInputColor,\n SparkInputStyle,\n SparkLabelPosition,\n} from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { Separator } from './separator'\nimport { useTheme } from './theme'\n\ntype FieldContextValue = {\n id: string\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n labelPosition: SparkLabelPosition\n inputStyle: SparkInputStyle\n inputColor: SparkInputColor\n}\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nexport function useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Field→Theme→default resolution + id/aria-describedby wiring, shared by every\n// control that can sit inside a Field (Input, SelectTrigger, …) so they can't\n// drift on how a style/color/id resolves. `variant` is the control's own\n// per-instance override (already normalized — e.g. Input maps its 'none' to\n// undefined before calling this).\nexport function useFieldControl(options?: {\n id?: string\n ariaDescribedBy?: string\n variant?: SparkInputStyle\n}) {\n const field = useFieldContext()\n const theme = useTheme()\n const id = options?.id ?? field?.id\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n const ariaDescribedBy =\n [descriptionId, options?.ariaDescribedBy].filter(Boolean).join(' ') ||\n undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n return { field, id, ariaDescribedBy, inputStyle, inputColor }\n}\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLegend({\n className,\n variant = 'legend',\n ...props\n}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n 'mb-1.5 font-medium text-gray data-[variant=label]:text-sm data-[variant=legend]:text-base',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n 'group/field-group flex w-full flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n 'group/field relative flex w-full flex-col data-[invalid=true]:text-error-active',\n {\n variants: {\n labelPosition: {\n // inset puts label + input inside one shell, so the shell is the box\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-lg px-4 py-3',\n outset: 'gap-y-2',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-gray-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: 'border border-input bg-base-accent-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: 'border border-input-gray bg-base-gray-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: 'border border-input',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: 'border border-input-gray',\n },\n // ghost inset = bare label + underlined input; the input carries the line\n {\n labelPosition: 'inset',\n inputStyle: 'ghost',\n class: 'rounded-none px-0',\n },\n // shared inset states: filled shells swap bg, bordered shells swap border\n // invalid hover deepens the error tint instead of falling back to accent\n {\n labelPosition: 'inset',\n inputStyle: ['soft', 'surface'],\n class:\n 'data-[disabled=true]:bg-base-gray-soft data-[invalid=true]:bg-base-error-soft data-[invalid=true]:has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-red-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: ['surface', 'outlined'],\n class:\n 'data-[disabled=true]:border-input-disabled data-[invalid=true]:border-input-invalid',\n },\n ],\n },\n)\n\ninterface FieldProps extends React.ComponentProps<'div'> {\n labelPosition?: SparkLabelPosition\n inputStyle?: SparkInputStyle\n inputColor?: SparkInputColor\n}\n\nfunction Field({\n className,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n ...props\n}: FieldProps) {\n const id = useId()\n const [hasDescription, setHasDescription] = React.useState(false)\n // knobs are structural (they move the label / pick the box carrier), so they\n // resolve here via the <Theme> context; props override per instance\n const theme = useTheme()\n const labelPosition = labelPositionProp ?? theme.labelPosition ?? 'inset'\n const inputStyle = inputStyleProp ?? theme.inputStyle ?? 'soft'\n const inputColor = inputColorProp ?? theme.inputColor ?? 'brand'\n const value = React.useMemo<FieldContextValue>(\n () => ({\n id: `field-${id}`,\n descriptionId: `field-${id}-description`,\n hasDescription,\n setHasDescription,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [id, hasDescription, labelPosition, inputStyle, inputColor],\n )\n\n return (\n <FieldContext.Provider value={value}>\n <div\n role=\"group\"\n data-slot=\"field\"\n data-label-position={labelPosition}\n data-input-style={inputStyle}\n data-input-color={inputColor}\n className={cn(\n fieldVariants({ labelPosition, inputStyle, inputColor }),\n className,\n )}\n {...props}\n />\n </FieldContext.Provider>\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n 'flex min-w-0 flex-1 flex-col gap-0.5 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLabel({\n className,\n htmlFor,\n srOnly,\n ...props\n}: React.ComponentProps<'label'> & { srOnly?: boolean }) {\n const field = useFieldContext()\n return (\n <label\n data-slot=\"field-label\"\n className={cn(\n // labels stay full-contrast even when disabled — the control itself\n // (dimmed text, gray shell) signals the state\n 'text-sm leading-5 font-normal text-gray-light transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none',\n // visually hidden but kept in the a11y tree (still names + focuses the control)\n srOnly && 'sr-only',\n className,\n )}\n htmlFor={htmlFor ?? field?.id}\n {...props}\n />\n )\n}\n\nfunction FieldValue({\n className,\n id,\n title,\n truncate,\n children,\n ...props\n}: React.ComponentProps<'div'> & { truncate?: boolean }) {\n const field = useFieldContext()\n return (\n <div\n data-slot=\"field-value\"\n id={id ?? field?.id}\n // truncated string values keep the full text reachable on hover\n title={\n title ??\n (truncate && typeof children === 'string' ? children : undefined)\n }\n className={cn(\n // values are content, not controls — disabled dims but stays ≥4.5:1\n 'min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70',\n truncate\n ? 'block truncate leading-8'\n : 'inline-flex items-center wrap-anywhere whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-title\"\n className={cn(\n 'flex w-fit items-center gap-2 text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({\n className,\n id,\n ...props\n}: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const setHasDescription = field?.setHasDescription\n\n React.useEffect(() => {\n if (!setHasDescription) return\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return (\n <div\n data-slot=\"field-description\"\n id={id ?? field?.descriptionId}\n className={cn('mt-0.5 text-sm leading-normal text-gray-light', className)}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn('relative -my-2 h-5 text-sm', className)}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-(--spark-background) px-2 text-gray-light\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const content = React.useMemo(() => {\n if (children) return children\n if (!errors?.length) return null\n const unique = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n if (unique.length === 1) return unique[0]?.message\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {unique.map(\n (error, index) =>\n error?.message && <li key={index}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n className={cn('mt-0.5 text-sm font-normal text-error', className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldTitle,\n FieldValue,\n}\nexport type { FieldProps }\n"],"mappings":";;;;;;;;;;;;AAwBA,MAAM,eAAeA,MAAM,cAAwC,IAAI;AAEvE,SAAgB,kBAAkB;CAChC,OAAOA,MAAM,WAAW,YAAY;AACtC;AAOA,SAAgB,gBAAgB,SAI7B;CACD,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,QAAQC,yBAAAA,SAAS;CASvB,OAAO;EAAE;EAAO,IARL,SAAS,MAAM,OAAO;EAQb,iBALlB,CAFoB,OAAO,iBAAiB,MAAM,gBAAgB,KAAA,GAElD,SAAS,eAAe,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAClE,KAAA;EAImC,YAFnC,SAAS,WAAW,OAAO,cAAc,MAAM,cAAc;EAEd,YAD9B,OAAO,cAAc,MAAM,cAAc;CACA;AAC9D;AAEA,SAAS,SAAS,EAAE,WAAW,GAAG,SAA2C;CAC3E,OACE,iBAAA,GAAA,kBAAA,KAAC,YAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IACE,uDACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EACnB,WACA,UAAU,UACV,GAAG,SACiE;CACpE,OACE,iBAAA,GAAA,kBAAA,KAAC,UAAD;EACE,aAAU;EACV,gBAAc;EACd,YAAA,GAAA,OAAA,IACE,6FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IACE,gFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAA,GAAA,yBAAA,KACJ,mFACA;CACE,UAAU;EACR,eAAe;GAGb,OAAO;GACP,QAAQ;EACV;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;CACpC;CACA,kBAAkB;EAChB;GACE,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EAEA;GACE,eAAe;GACf,YAAY;GACZ,OAAO;EACT;EAGA;GACE,eAAe;GACf,YAAY,CAAC,QAAQ,SAAS;GAC9B,OACE;EACJ;EACA;GACE,eAAe;GACf,YAAY,CAAC,WAAW,UAAU;GAClC,OACE;EACJ;CACF;AACF,CACF;AAQA,SAAS,MAAM,EACb,WACA,eAAe,mBACf,YAAY,gBACZ,YAAY,gBACZ,GAAG,SACU;CACb,MAAM,MAAA,GAAA,MAAA,OAAW;CACjB,MAAM,CAAC,gBAAgB,qBAAqBD,MAAM,SAAS,KAAK;CAGhE,MAAM,QAAQC,yBAAAA,SAAS;CACvB,MAAM,gBAAgB,qBAAqB,MAAM,iBAAiB;CAClE,MAAM,aAAa,kBAAkB,MAAM,cAAc;CACzD,MAAM,aAAa,kBAAkB,MAAM,cAAc;CACzD,MAAM,QAAQD,MAAM,eACX;EACL,IAAI,SAAS;EACb,eAAe,SAAS,GAAG;EAC3B;EACA;EACA;EACA;EACA;CACF,IACA;EAAC;EAAI;EAAgB;EAAe;EAAY;CAAU,CAC5D;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAC,aAAa,UAAd;EAA8B;YAC5B,iBAAA,GAAA,kBAAA,KAAC,OAAD;GACE,MAAK;GACL,aAAU;GACV,uBAAqB;GACrB,oBAAkB;GAClB,oBAAkB;GAClB,YAAA,GAAA,OAAA,IACE,cAAc;IAAE;IAAe;IAAY;GAAW,CAAC,GACvD,SACF;GACA,GAAI;EACL,CAAA;CACoB,CAAA;AAE3B;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IACE,qDACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAClB,WACA,SACA,QACA,GAAG,SACoD;CACvD,MAAM,QAAQ,gBAAgB;CAC9B,OACE,iBAAA,GAAA,kBAAA,KAAC,SAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IAGE,iJAEA,UAAU,WACV,SACF;EACA,SAAS,WAAW,OAAO;EAC3B,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAClB,WACA,IACA,OACA,UACA,UACA,GAAG,SACoD;CACvD,MAAM,QAAQ,gBAAgB;CAC9B,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,IAAI,MAAM,OAAO;EAEjB,OACE,UACC,YAAY,OAAO,aAAa,WAAW,WAAW,KAAA;EAEzD,YAAA,GAAA,OAAA,IAEE,+FACA,WACI,6BACA,8DACJ,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IACE,+DACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,IACA,GAAG,SAC2B;CAC9B,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,oBAAoB,OAAO;CAEjC,MAAM,gBAAgB;EACpB,IAAI,CAAC,mBAAmB;EACxB,kBAAkB,IAAI;EACtB,aAAa,kBAAkB,KAAK;CACtC,GAAG,CAAC,iBAAiB,CAAC;CAEtB,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,IAAI,MAAM,OAAO;EACjB,YAAA,GAAA,OAAA,IAAc,iDAAiD,SAAS;EACxE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EACtB,UACA,WACA,GAAG,SAC2B;CAC9B,OACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EACE,aAAU;EACV,gBAAc,CAAC,CAAC;EAChB,YAAA,GAAA,OAAA,IAAc,8BAA8B,SAAS;EACrD,GAAI;YAJN,CAME,iBAAA,GAAA,kBAAA,KAACE,6BAAAA,WAAD,EAAW,WAAU,2BAA4B,CAAA,GAChD,YACC,iBAAA,GAAA,kBAAA,KAAC,QAAD;GACE,WAAU;GACV,aAAU;GAET;EACG,CAAA,CAEL;;AAET;AAEA,SAAS,WAAW,EAClB,WACA,UACA,QACA,GAAG,SAGF;CACD,MAAM,UAAUF,MAAM,cAAc;EAClC,IAAI,UAAU,OAAO;EACrB,IAAI,CAAC,QAAQ,QAAQ,OAAO;EAC5B,MAAM,SAAS,CACb,GAAG,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,OAAO,SAAS,KAAK,CAAC,CAAC,EAAE,OAAO,CACpE;EACA,IAAI,OAAO,WAAW,GAAG,OAAO,OAAO,IAAI;EAC3C,OACE,iBAAA,GAAA,kBAAA,KAAC,MAAD;GAAI,WAAU;aACX,OAAO,KACL,OAAO,UACN,OAAO,WAAW,iBAAA,GAAA,kBAAA,KAAC,MAAD,EAAA,UAAiB,MAAM,QAAY,GAA1B,KAA0B,CACzD;EACE,CAAA;CAER,GAAG,CAAC,UAAU,MAAM,CAAC;CAErB,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,YAAA,GAAA,OAAA,IAAc,yCAAyC,SAAS;EAChE,GAAI;YAEH;CACE,CAAA;AAET"}
|
|
1
|
+
{"version":3,"file":"field.cjs","names":["React","useTheme","Skeleton","Separator"],"sources":["../../src/components/field.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { useId } from 'react'\nimport type {\n SparkInputColor,\n SparkInputStyle,\n SparkLabelPosition,\n} from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { Separator } from './separator'\nimport { Skeleton } from './skeleton'\nimport { useTheme } from './theme'\n\ntype FieldContextValue = {\n id: string\n labelId: string\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n readOnly: boolean\n labelPosition: SparkLabelPosition\n inputStyle: SparkInputStyle\n inputColor: SparkInputColor\n}\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nexport function useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Field→Theme→default resolution + id/aria-describedby wiring, shared by every\n// control that can sit inside a Field (Input, SelectTrigger, …) so they can't\n// drift on how a style/color/id resolves. `variant` is the control's own\n// per-instance override (already normalized — e.g. Input maps its 'none' to\n// undefined before calling this).\nexport function useFieldControl(options?: {\n id?: string\n ariaDescribedBy?: string\n variant?: SparkInputStyle\n}) {\n const field = useFieldContext()\n const theme = useTheme()\n const id = options?.id ?? field?.id\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n const ariaDescribedBy =\n [descriptionId, options?.ariaDescribedBy].filter(Boolean).join(' ') ||\n undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n return { field, id, ariaDescribedBy, inputStyle, inputColor }\n}\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLegend({\n className,\n variant = 'legend',\n ...props\n}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n 'mb-1.5 font-medium text-gray data-[variant=label]:text-sm data-[variant=legend]:text-base',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n 'group/field-group flex w-full flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n 'group/field relative flex w-full flex-col data-[invalid=true]:text-error-active',\n {\n variants: {\n labelPosition: {\n // inset puts label + input inside one shell, so the shell is the box\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-lg px-4 py-3',\n outset: 'gap-y-2',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-gray-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: 'border border-input bg-base-accent-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: 'border border-input-gray bg-base-gray-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: 'border border-input',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: 'border border-input-gray',\n },\n // ghost inset = bare label + underlined input; the input carries the line\n {\n labelPosition: 'inset',\n inputStyle: 'ghost',\n class: 'rounded-none px-0',\n },\n // shared inset states: filled shells swap bg, bordered shells swap border\n // invalid hover deepens the error tint instead of falling back to accent\n {\n labelPosition: 'inset',\n inputStyle: ['soft', 'surface'],\n class:\n 'data-[disabled=true]:bg-base-gray-soft data-[invalid=true]:bg-base-error-soft data-[invalid=true]:has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-red-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: ['surface', 'outlined'],\n class:\n 'data-[disabled=true]:border-input-disabled data-[invalid=true]:border-input-invalid',\n },\n ],\n },\n)\n\ninterface FieldProps extends React.ComponentProps<'div'> {\n labelPosition?: SparkLabelPosition\n inputStyle?: SparkInputStyle\n inputColor?: SparkInputColor\n readOnly?: boolean\n}\n\nfunction Field({\n className,\n children,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n readOnly = false,\n ...props\n}: FieldProps) {\n const id = useId()\n const [hasDescription, setHasDescription] = React.useState(false)\n // knobs are structural (they move the label / pick the box carrier), so they\n // resolve here via the <Theme> context; props override per instance\n const theme = useTheme()\n const labelPosition = labelPositionProp ?? theme.labelPosition ?? 'inset'\n const inputStyle = inputStyleProp ?? theme.inputStyle ?? 'soft'\n const inputColor = inputColorProp ?? theme.inputColor ?? 'brand'\n const fieldId = `field-${id}`\n const labelId = `${fieldId}-label`\n const value = React.useMemo<FieldContextValue>(\n () => ({\n id: fieldId,\n labelId,\n descriptionId: `${fieldId}-description`,\n hasDescription,\n setHasDescription,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [\n fieldId,\n labelId,\n hasDescription,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n ],\n )\n\n return (\n <FieldContext.Provider value={value}>\n <div\n role=\"group\"\n data-slot=\"field\"\n data-label-position={labelPosition}\n data-input-style={inputStyle}\n data-input-color={inputColor}\n aria-labelledby={readOnly ? labelId : undefined}\n className={cn(\n fieldVariants({ labelPosition, inputStyle, inputColor }),\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </FieldContext.Provider>\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n 'flex min-w-0 flex-1 flex-col gap-0.5 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldLabelClassName =\n 'text-sm leading-5 font-normal text-gray-light transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none'\n\nfunction FieldLabel({\n className,\n htmlFor,\n srOnly,\n children,\n ...props\n}: React.ComponentProps<'label'> & { srOnly?: boolean }) {\n const field = useFieldContext()\n const classNames = cn(\n // labels stay full-contrast even when disabled — the control itself\n // (dimmed text, gray shell) signals the state\n fieldLabelClassName,\n // visually hidden but kept in the a11y tree (still names + focuses the control)\n srOnly && 'sr-only',\n className,\n )\n\n if (field?.readOnly) {\n return (\n <div data-slot=\"field-label\" id={field.labelId} className={classNames}>\n {children}\n </div>\n )\n }\n\n return (\n <label\n data-slot=\"field-label\"\n className={classNames}\n htmlFor={htmlFor ?? field?.id}\n {...props}\n >\n {children}\n </label>\n )\n}\n\nfunction FieldValue({\n className,\n id,\n title,\n truncate,\n children,\n ...props\n}: React.ComponentProps<'div'> & { truncate?: boolean }) {\n return (\n <div\n data-slot=\"field-value\"\n id={id}\n // truncated string values keep the full text reachable on hover\n title={\n title ??\n (truncate && typeof children === 'string' ? children : undefined)\n }\n className={cn(\n // values are content, not controls — disabled dims but stays ≥4.5:1\n 'min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70',\n truncate\n ? 'block truncate leading-8'\n : 'inline-flex items-center wrap-anywhere whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction FieldSkeleton({\n className,\n labelClassName,\n valueClassName,\n truncate,\n ...props\n}: React.ComponentProps<'div'> & {\n truncate?: boolean\n labelClassName?: string\n valueClassName?: string\n}) {\n return (\n <div\n data-slot=\"field-skeleton\"\n aria-hidden=\"true\"\n className={cn('flex w-full flex-col gap-y-1', className)}\n {...props}\n >\n <Skeleton\n data-slot=\"field-skeleton-label\"\n className={cn('h-5 w-24', labelClassName)}\n />\n <Skeleton\n data-slot=\"field-skeleton-value\"\n className={cn(\n 'h-8 min-h-8 w-full',\n truncate && 'max-w-full truncate',\n valueClassName,\n )}\n />\n </div>\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-title\"\n className={cn(\n 'flex w-fit items-center gap-2 text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({\n className,\n id,\n ...props\n}: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const setHasDescription = field?.setHasDescription\n\n React.useEffect(() => {\n if (!setHasDescription) return\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return (\n <div\n data-slot=\"field-description\"\n id={id ?? field?.descriptionId}\n className={cn('mt-0.5 text-sm leading-normal text-gray-light', className)}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn('relative -my-2 h-5 text-sm', className)}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-(--spark-background) px-2 text-gray-light\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const content = React.useMemo(() => {\n if (children) return children\n if (!errors?.length) return null\n const unique = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n if (unique.length === 1) return unique[0]?.message\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {unique.map(\n (error, index) =>\n error?.message && <li key={index}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n className={cn('mt-0.5 text-sm font-normal text-error', className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldSkeleton,\n FieldTitle,\n FieldValue,\n}\nexport type { FieldProps }\n"],"mappings":"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"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { a as SparkLabelPosition, i as SparkInputStyle, r as SparkInputColor } from "../theme-types-
|
|
3
|
+
import { a as SparkLabelPosition, i as SparkInputStyle, r as SparkInputColor } from "../theme-types-1yB0d8mp.cjs";
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
|
|
6
6
|
//#region src/components/field.d.ts
|
|
7
7
|
type FieldContextValue = {
|
|
8
8
|
id: string;
|
|
9
|
+
labelId: string;
|
|
9
10
|
descriptionId: string;
|
|
10
11
|
hasDescription: boolean;
|
|
11
12
|
setHasDescription: (has: boolean) => void;
|
|
13
|
+
readOnly: boolean;
|
|
12
14
|
labelPosition: SparkLabelPosition;
|
|
13
15
|
inputStyle: SparkInputStyle;
|
|
14
16
|
inputColor: SparkInputColor;
|
|
@@ -44,12 +46,15 @@ interface FieldProps extends React$1.ComponentProps<'div'> {
|
|
|
44
46
|
labelPosition?: SparkLabelPosition;
|
|
45
47
|
inputStyle?: SparkInputStyle;
|
|
46
48
|
inputColor?: SparkInputColor;
|
|
49
|
+
readOnly?: boolean;
|
|
47
50
|
}
|
|
48
51
|
declare function Field({
|
|
49
52
|
className,
|
|
53
|
+
children,
|
|
50
54
|
labelPosition: labelPositionProp,
|
|
51
55
|
inputStyle: inputStyleProp,
|
|
52
56
|
inputColor: inputColorProp,
|
|
57
|
+
readOnly,
|
|
53
58
|
...props
|
|
54
59
|
}: FieldProps): import("react/jsx-runtime").JSX.Element;
|
|
55
60
|
declare function FieldContent({
|
|
@@ -60,6 +65,7 @@ declare function FieldLabel({
|
|
|
60
65
|
className,
|
|
61
66
|
htmlFor,
|
|
62
67
|
srOnly,
|
|
68
|
+
children,
|
|
63
69
|
...props
|
|
64
70
|
}: React$1.ComponentProps<'label'> & {
|
|
65
71
|
srOnly?: boolean;
|
|
@@ -74,6 +80,17 @@ declare function FieldValue({
|
|
|
74
80
|
}: React$1.ComponentProps<'div'> & {
|
|
75
81
|
truncate?: boolean;
|
|
76
82
|
}): import("react/jsx-runtime").JSX.Element;
|
|
83
|
+
declare function FieldSkeleton({
|
|
84
|
+
className,
|
|
85
|
+
labelClassName,
|
|
86
|
+
valueClassName,
|
|
87
|
+
truncate,
|
|
88
|
+
...props
|
|
89
|
+
}: React$1.ComponentProps<'div'> & {
|
|
90
|
+
truncate?: boolean;
|
|
91
|
+
labelClassName?: string;
|
|
92
|
+
valueClassName?: string;
|
|
93
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
77
94
|
declare function FieldTitle({
|
|
78
95
|
className,
|
|
79
96
|
...props
|
|
@@ -99,5 +116,5 @@ declare function FieldError({
|
|
|
99
116
|
} | undefined>;
|
|
100
117
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
101
118
|
//#endregion
|
|
102
|
-
export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, type FieldProps, FieldSeparator, FieldSet, FieldTitle, FieldValue, useFieldContext, useFieldControl };
|
|
119
|
+
export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, type FieldProps, FieldSeparator, FieldSet, FieldSkeleton, FieldTitle, FieldValue, useFieldContext, useFieldControl };
|
|
103
120
|
//# sourceMappingURL=field.d.cts.map
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { a as SparkLabelPosition, i as SparkInputStyle, r as SparkInputColor } from "../theme-types-
|
|
3
|
+
import { a as SparkLabelPosition, i as SparkInputStyle, r as SparkInputColor } from "../theme-types-1yB0d8mp.js";
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
|
|
6
6
|
//#region src/components/field.d.ts
|
|
7
7
|
type FieldContextValue = {
|
|
8
8
|
id: string;
|
|
9
|
+
labelId: string;
|
|
9
10
|
descriptionId: string;
|
|
10
11
|
hasDescription: boolean;
|
|
11
12
|
setHasDescription: (has: boolean) => void;
|
|
13
|
+
readOnly: boolean;
|
|
12
14
|
labelPosition: SparkLabelPosition;
|
|
13
15
|
inputStyle: SparkInputStyle;
|
|
14
16
|
inputColor: SparkInputColor;
|
|
@@ -44,12 +46,15 @@ interface FieldProps extends React$1.ComponentProps<'div'> {
|
|
|
44
46
|
labelPosition?: SparkLabelPosition;
|
|
45
47
|
inputStyle?: SparkInputStyle;
|
|
46
48
|
inputColor?: SparkInputColor;
|
|
49
|
+
readOnly?: boolean;
|
|
47
50
|
}
|
|
48
51
|
declare function Field({
|
|
49
52
|
className,
|
|
53
|
+
children,
|
|
50
54
|
labelPosition: labelPositionProp,
|
|
51
55
|
inputStyle: inputStyleProp,
|
|
52
56
|
inputColor: inputColorProp,
|
|
57
|
+
readOnly,
|
|
53
58
|
...props
|
|
54
59
|
}: FieldProps): import("react/jsx-runtime").JSX.Element;
|
|
55
60
|
declare function FieldContent({
|
|
@@ -60,6 +65,7 @@ declare function FieldLabel({
|
|
|
60
65
|
className,
|
|
61
66
|
htmlFor,
|
|
62
67
|
srOnly,
|
|
68
|
+
children,
|
|
63
69
|
...props
|
|
64
70
|
}: React$1.ComponentProps<'label'> & {
|
|
65
71
|
srOnly?: boolean;
|
|
@@ -74,6 +80,17 @@ declare function FieldValue({
|
|
|
74
80
|
}: React$1.ComponentProps<'div'> & {
|
|
75
81
|
truncate?: boolean;
|
|
76
82
|
}): import("react/jsx-runtime").JSX.Element;
|
|
83
|
+
declare function FieldSkeleton({
|
|
84
|
+
className,
|
|
85
|
+
labelClassName,
|
|
86
|
+
valueClassName,
|
|
87
|
+
truncate,
|
|
88
|
+
...props
|
|
89
|
+
}: React$1.ComponentProps<'div'> & {
|
|
90
|
+
truncate?: boolean;
|
|
91
|
+
labelClassName?: string;
|
|
92
|
+
valueClassName?: string;
|
|
93
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
77
94
|
declare function FieldTitle({
|
|
78
95
|
className,
|
|
79
96
|
...props
|
|
@@ -99,5 +116,5 @@ declare function FieldError({
|
|
|
99
116
|
} | undefined>;
|
|
100
117
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
101
118
|
//#endregion
|
|
102
|
-
export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, type FieldProps, FieldSeparator, FieldSet, FieldTitle, FieldValue, useFieldContext, useFieldControl };
|
|
119
|
+
export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, type FieldProps, FieldSeparator, FieldSet, FieldSkeleton, FieldTitle, FieldValue, useFieldContext, useFieldControl };
|
|
103
120
|
//# sourceMappingURL=field.d.ts.map
|
package/dist/components/field.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import { cn } from "../utils/cn.js";
|
|
4
4
|
import { Separator } from "./separator.js";
|
|
5
|
+
import { Skeleton } from "./skeleton.js";
|
|
5
6
|
import { useTheme } from "./theme.js";
|
|
6
7
|
import * as React$1 from "react";
|
|
7
8
|
import { useId } from "react";
|
|
@@ -116,24 +117,30 @@ const fieldVariants = cva("group/field relative flex w-full flex-col data-[inval
|
|
|
116
117
|
}
|
|
117
118
|
]
|
|
118
119
|
});
|
|
119
|
-
function Field({ className, labelPosition: labelPositionProp, inputStyle: inputStyleProp, inputColor: inputColorProp, ...props }) {
|
|
120
|
+
function Field({ className, children, labelPosition: labelPositionProp, inputStyle: inputStyleProp, inputColor: inputColorProp, readOnly = false, ...props }) {
|
|
120
121
|
const id = useId();
|
|
121
122
|
const [hasDescription, setHasDescription] = React$1.useState(false);
|
|
122
123
|
const theme = useTheme();
|
|
123
124
|
const labelPosition = labelPositionProp ?? theme.labelPosition ?? "inset";
|
|
124
125
|
const inputStyle = inputStyleProp ?? theme.inputStyle ?? "soft";
|
|
125
126
|
const inputColor = inputColorProp ?? theme.inputColor ?? "brand";
|
|
127
|
+
const fieldId = `field-${id}`;
|
|
128
|
+
const labelId = `${fieldId}-label`;
|
|
126
129
|
const value = React$1.useMemo(() => ({
|
|
127
|
-
id:
|
|
128
|
-
|
|
130
|
+
id: fieldId,
|
|
131
|
+
labelId,
|
|
132
|
+
descriptionId: `${fieldId}-description`,
|
|
129
133
|
hasDescription,
|
|
130
134
|
setHasDescription,
|
|
135
|
+
readOnly,
|
|
131
136
|
labelPosition,
|
|
132
137
|
inputStyle,
|
|
133
138
|
inputColor
|
|
134
139
|
}), [
|
|
135
|
-
|
|
140
|
+
fieldId,
|
|
141
|
+
labelId,
|
|
136
142
|
hasDescription,
|
|
143
|
+
readOnly,
|
|
137
144
|
labelPosition,
|
|
138
145
|
inputStyle,
|
|
139
146
|
inputColor
|
|
@@ -146,12 +153,14 @@ function Field({ className, labelPosition: labelPositionProp, inputStyle: inputS
|
|
|
146
153
|
"data-label-position": labelPosition,
|
|
147
154
|
"data-input-style": inputStyle,
|
|
148
155
|
"data-input-color": inputColor,
|
|
156
|
+
"aria-labelledby": readOnly ? labelId : void 0,
|
|
149
157
|
className: cn(fieldVariants({
|
|
150
158
|
labelPosition,
|
|
151
159
|
inputStyle,
|
|
152
160
|
inputColor
|
|
153
161
|
}), className),
|
|
154
|
-
...props
|
|
162
|
+
...props,
|
|
163
|
+
children
|
|
155
164
|
})
|
|
156
165
|
});
|
|
157
166
|
}
|
|
@@ -162,26 +171,49 @@ function FieldContent({ className, ...props }) {
|
|
|
162
171
|
...props
|
|
163
172
|
});
|
|
164
173
|
}
|
|
165
|
-
|
|
174
|
+
const fieldLabelClassName = "text-sm leading-5 font-normal text-gray-light transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none";
|
|
175
|
+
function FieldLabel({ className, htmlFor, srOnly, children, ...props }) {
|
|
166
176
|
const field = useFieldContext();
|
|
177
|
+
const classNames = cn(fieldLabelClassName, srOnly && "sr-only", className);
|
|
178
|
+
if (field?.readOnly) return /* @__PURE__ */ jsx("div", {
|
|
179
|
+
"data-slot": "field-label",
|
|
180
|
+
id: field.labelId,
|
|
181
|
+
className: classNames,
|
|
182
|
+
children
|
|
183
|
+
});
|
|
167
184
|
return /* @__PURE__ */ jsx("label", {
|
|
168
185
|
"data-slot": "field-label",
|
|
169
|
-
className:
|
|
186
|
+
className: classNames,
|
|
170
187
|
htmlFor: htmlFor ?? field?.id,
|
|
171
|
-
...props
|
|
188
|
+
...props,
|
|
189
|
+
children
|
|
172
190
|
});
|
|
173
191
|
}
|
|
174
192
|
function FieldValue({ className, id, title, truncate, children, ...props }) {
|
|
175
|
-
const field = useFieldContext();
|
|
176
193
|
return /* @__PURE__ */ jsx("div", {
|
|
177
194
|
"data-slot": "field-value",
|
|
178
|
-
id
|
|
195
|
+
id,
|
|
179
196
|
title: title ?? (truncate && typeof children === "string" ? children : void 0),
|
|
180
197
|
className: cn("min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70", truncate ? "block truncate leading-8" : "inline-flex items-center wrap-anywhere whitespace-pre-wrap", className),
|
|
181
198
|
...props,
|
|
182
199
|
children
|
|
183
200
|
});
|
|
184
201
|
}
|
|
202
|
+
function FieldSkeleton({ className, labelClassName, valueClassName, truncate, ...props }) {
|
|
203
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
204
|
+
"data-slot": "field-skeleton",
|
|
205
|
+
"aria-hidden": "true",
|
|
206
|
+
className: cn("flex w-full flex-col gap-y-1", className),
|
|
207
|
+
...props,
|
|
208
|
+
children: [/* @__PURE__ */ jsx(Skeleton, {
|
|
209
|
+
"data-slot": "field-skeleton-label",
|
|
210
|
+
className: cn("h-5 w-24", labelClassName)
|
|
211
|
+
}), /* @__PURE__ */ jsx(Skeleton, {
|
|
212
|
+
"data-slot": "field-skeleton-value",
|
|
213
|
+
className: cn("h-8 min-h-8 w-full", truncate && "max-w-full truncate", valueClassName)
|
|
214
|
+
})]
|
|
215
|
+
});
|
|
216
|
+
}
|
|
185
217
|
function FieldTitle({ className, ...props }) {
|
|
186
218
|
return /* @__PURE__ */ jsx("div", {
|
|
187
219
|
"data-slot": "field-title",
|
|
@@ -238,6 +270,6 @@ function FieldError({ className, children, errors, ...props }) {
|
|
|
238
270
|
});
|
|
239
271
|
}
|
|
240
272
|
//#endregion
|
|
241
|
-
export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FieldValue, useFieldContext, useFieldControl };
|
|
273
|
+
export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldSkeleton, FieldTitle, FieldValue, useFieldContext, useFieldControl };
|
|
242
274
|
|
|
243
275
|
//# sourceMappingURL=field.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.js","names":["React"],"sources":["../../src/components/field.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { useId } from 'react'\nimport type {\n SparkInputColor,\n SparkInputStyle,\n SparkLabelPosition,\n} from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { Separator } from './separator'\nimport { useTheme } from './theme'\n\ntype FieldContextValue = {\n id: string\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n labelPosition: SparkLabelPosition\n inputStyle: SparkInputStyle\n inputColor: SparkInputColor\n}\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nexport function useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Field→Theme→default resolution + id/aria-describedby wiring, shared by every\n// control that can sit inside a Field (Input, SelectTrigger, …) so they can't\n// drift on how a style/color/id resolves. `variant` is the control's own\n// per-instance override (already normalized — e.g. Input maps its 'none' to\n// undefined before calling this).\nexport function useFieldControl(options?: {\n id?: string\n ariaDescribedBy?: string\n variant?: SparkInputStyle\n}) {\n const field = useFieldContext()\n const theme = useTheme()\n const id = options?.id ?? field?.id\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n const ariaDescribedBy =\n [descriptionId, options?.ariaDescribedBy].filter(Boolean).join(' ') ||\n undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n return { field, id, ariaDescribedBy, inputStyle, inputColor }\n}\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLegend({\n className,\n variant = 'legend',\n ...props\n}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n 'mb-1.5 font-medium text-gray data-[variant=label]:text-sm data-[variant=legend]:text-base',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n 'group/field-group flex w-full flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n 'group/field relative flex w-full flex-col data-[invalid=true]:text-error-active',\n {\n variants: {\n labelPosition: {\n // inset puts label + input inside one shell, so the shell is the box\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-lg px-4 py-3',\n outset: 'gap-y-2',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-gray-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: 'border border-input bg-base-accent-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: 'border border-input-gray bg-base-gray-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: 'border border-input',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: 'border border-input-gray',\n },\n // ghost inset = bare label + underlined input; the input carries the line\n {\n labelPosition: 'inset',\n inputStyle: 'ghost',\n class: 'rounded-none px-0',\n },\n // shared inset states: filled shells swap bg, bordered shells swap border\n // invalid hover deepens the error tint instead of falling back to accent\n {\n labelPosition: 'inset',\n inputStyle: ['soft', 'surface'],\n class:\n 'data-[disabled=true]:bg-base-gray-soft data-[invalid=true]:bg-base-error-soft data-[invalid=true]:has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-red-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: ['surface', 'outlined'],\n class:\n 'data-[disabled=true]:border-input-disabled data-[invalid=true]:border-input-invalid',\n },\n ],\n },\n)\n\ninterface FieldProps extends React.ComponentProps<'div'> {\n labelPosition?: SparkLabelPosition\n inputStyle?: SparkInputStyle\n inputColor?: SparkInputColor\n}\n\nfunction Field({\n className,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n ...props\n}: FieldProps) {\n const id = useId()\n const [hasDescription, setHasDescription] = React.useState(false)\n // knobs are structural (they move the label / pick the box carrier), so they\n // resolve here via the <Theme> context; props override per instance\n const theme = useTheme()\n const labelPosition = labelPositionProp ?? theme.labelPosition ?? 'inset'\n const inputStyle = inputStyleProp ?? theme.inputStyle ?? 'soft'\n const inputColor = inputColorProp ?? theme.inputColor ?? 'brand'\n const value = React.useMemo<FieldContextValue>(\n () => ({\n id: `field-${id}`,\n descriptionId: `field-${id}-description`,\n hasDescription,\n setHasDescription,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [id, hasDescription, labelPosition, inputStyle, inputColor],\n )\n\n return (\n <FieldContext.Provider value={value}>\n <div\n role=\"group\"\n data-slot=\"field\"\n data-label-position={labelPosition}\n data-input-style={inputStyle}\n data-input-color={inputColor}\n className={cn(\n fieldVariants({ labelPosition, inputStyle, inputColor }),\n className,\n )}\n {...props}\n />\n </FieldContext.Provider>\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n 'flex min-w-0 flex-1 flex-col gap-0.5 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLabel({\n className,\n htmlFor,\n srOnly,\n ...props\n}: React.ComponentProps<'label'> & { srOnly?: boolean }) {\n const field = useFieldContext()\n return (\n <label\n data-slot=\"field-label\"\n className={cn(\n // labels stay full-contrast even when disabled — the control itself\n // (dimmed text, gray shell) signals the state\n 'text-sm leading-5 font-normal text-gray-light transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none',\n // visually hidden but kept in the a11y tree (still names + focuses the control)\n srOnly && 'sr-only',\n className,\n )}\n htmlFor={htmlFor ?? field?.id}\n {...props}\n />\n )\n}\n\nfunction FieldValue({\n className,\n id,\n title,\n truncate,\n children,\n ...props\n}: React.ComponentProps<'div'> & { truncate?: boolean }) {\n const field = useFieldContext()\n return (\n <div\n data-slot=\"field-value\"\n id={id ?? field?.id}\n // truncated string values keep the full text reachable on hover\n title={\n title ??\n (truncate && typeof children === 'string' ? children : undefined)\n }\n className={cn(\n // values are content, not controls — disabled dims but stays ≥4.5:1\n 'min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70',\n truncate\n ? 'block truncate leading-8'\n : 'inline-flex items-center wrap-anywhere whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-title\"\n className={cn(\n 'flex w-fit items-center gap-2 text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({\n className,\n id,\n ...props\n}: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const setHasDescription = field?.setHasDescription\n\n React.useEffect(() => {\n if (!setHasDescription) return\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return (\n <div\n data-slot=\"field-description\"\n id={id ?? field?.descriptionId}\n className={cn('mt-0.5 text-sm leading-normal text-gray-light', className)}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn('relative -my-2 h-5 text-sm', className)}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-(--spark-background) px-2 text-gray-light\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const content = React.useMemo(() => {\n if (children) return children\n if (!errors?.length) return null\n const unique = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n if (unique.length === 1) return unique[0]?.message\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {unique.map(\n (error, index) =>\n error?.message && <li key={index}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n className={cn('mt-0.5 text-sm font-normal text-error', className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldTitle,\n FieldValue,\n}\nexport type { FieldProps }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"field.js","names":["React"],"sources":["../../src/components/field.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { useId } from 'react'\nimport type {\n SparkInputColor,\n SparkInputStyle,\n SparkLabelPosition,\n} from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { Separator } from './separator'\nimport { Skeleton } from './skeleton'\nimport { useTheme } from './theme'\n\ntype FieldContextValue = {\n id: string\n labelId: string\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n readOnly: boolean\n labelPosition: SparkLabelPosition\n inputStyle: SparkInputStyle\n inputColor: SparkInputColor\n}\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nexport function useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Field→Theme→default resolution + id/aria-describedby wiring, shared by every\n// control that can sit inside a Field (Input, SelectTrigger, …) so they can't\n// drift on how a style/color/id resolves. `variant` is the control's own\n// per-instance override (already normalized — e.g. Input maps its 'none' to\n// undefined before calling this).\nexport function useFieldControl(options?: {\n id?: string\n ariaDescribedBy?: string\n variant?: SparkInputStyle\n}) {\n const field = useFieldContext()\n const theme = useTheme()\n const id = options?.id ?? field?.id\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n const ariaDescribedBy =\n [descriptionId, options?.ariaDescribedBy].filter(Boolean).join(' ') ||\n undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n return { field, id, ariaDescribedBy, inputStyle, inputColor }\n}\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLegend({\n className,\n variant = 'legend',\n ...props\n}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n 'mb-1.5 font-medium text-gray data-[variant=label]:text-sm data-[variant=legend]:text-base',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n 'group/field-group flex w-full flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n 'group/field relative flex w-full flex-col data-[invalid=true]:text-error-active',\n {\n variants: {\n labelPosition: {\n // inset puts label + input inside one shell, so the shell is the box\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-lg px-4 py-3',\n outset: 'gap-y-2',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-gray-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: 'border border-input bg-base-accent-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: 'border border-input-gray bg-base-gray-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: 'border border-input',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: 'border border-input-gray',\n },\n // ghost inset = bare label + underlined input; the input carries the line\n {\n labelPosition: 'inset',\n inputStyle: 'ghost',\n class: 'rounded-none px-0',\n },\n // shared inset states: filled shells swap bg, bordered shells swap border\n // invalid hover deepens the error tint instead of falling back to accent\n {\n labelPosition: 'inset',\n inputStyle: ['soft', 'surface'],\n class:\n 'data-[disabled=true]:bg-base-gray-soft data-[invalid=true]:bg-base-error-soft data-[invalid=true]:has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-red-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: ['surface', 'outlined'],\n class:\n 'data-[disabled=true]:border-input-disabled data-[invalid=true]:border-input-invalid',\n },\n ],\n },\n)\n\ninterface FieldProps extends React.ComponentProps<'div'> {\n labelPosition?: SparkLabelPosition\n inputStyle?: SparkInputStyle\n inputColor?: SparkInputColor\n readOnly?: boolean\n}\n\nfunction Field({\n className,\n children,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n readOnly = false,\n ...props\n}: FieldProps) {\n const id = useId()\n const [hasDescription, setHasDescription] = React.useState(false)\n // knobs are structural (they move the label / pick the box carrier), so they\n // resolve here via the <Theme> context; props override per instance\n const theme = useTheme()\n const labelPosition = labelPositionProp ?? theme.labelPosition ?? 'inset'\n const inputStyle = inputStyleProp ?? theme.inputStyle ?? 'soft'\n const inputColor = inputColorProp ?? theme.inputColor ?? 'brand'\n const fieldId = `field-${id}`\n const labelId = `${fieldId}-label`\n const value = React.useMemo<FieldContextValue>(\n () => ({\n id: fieldId,\n labelId,\n descriptionId: `${fieldId}-description`,\n hasDescription,\n setHasDescription,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [\n fieldId,\n labelId,\n hasDescription,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n ],\n )\n\n return (\n <FieldContext.Provider value={value}>\n <div\n role=\"group\"\n data-slot=\"field\"\n data-label-position={labelPosition}\n data-input-style={inputStyle}\n data-input-color={inputColor}\n aria-labelledby={readOnly ? labelId : undefined}\n className={cn(\n fieldVariants({ labelPosition, inputStyle, inputColor }),\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </FieldContext.Provider>\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n 'flex min-w-0 flex-1 flex-col gap-0.5 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldLabelClassName =\n 'text-sm leading-5 font-normal text-gray-light transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none'\n\nfunction FieldLabel({\n className,\n htmlFor,\n srOnly,\n children,\n ...props\n}: React.ComponentProps<'label'> & { srOnly?: boolean }) {\n const field = useFieldContext()\n const classNames = cn(\n // labels stay full-contrast even when disabled — the control itself\n // (dimmed text, gray shell) signals the state\n fieldLabelClassName,\n // visually hidden but kept in the a11y tree (still names + focuses the control)\n srOnly && 'sr-only',\n className,\n )\n\n if (field?.readOnly) {\n return (\n <div data-slot=\"field-label\" id={field.labelId} className={classNames}>\n {children}\n </div>\n )\n }\n\n return (\n <label\n data-slot=\"field-label\"\n className={classNames}\n htmlFor={htmlFor ?? field?.id}\n {...props}\n >\n {children}\n </label>\n )\n}\n\nfunction FieldValue({\n className,\n id,\n title,\n truncate,\n children,\n ...props\n}: React.ComponentProps<'div'> & { truncate?: boolean }) {\n return (\n <div\n data-slot=\"field-value\"\n id={id}\n // truncated string values keep the full text reachable on hover\n title={\n title ??\n (truncate && typeof children === 'string' ? children : undefined)\n }\n className={cn(\n // values are content, not controls — disabled dims but stays ≥4.5:1\n 'min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70',\n truncate\n ? 'block truncate leading-8'\n : 'inline-flex items-center wrap-anywhere whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction FieldSkeleton({\n className,\n labelClassName,\n valueClassName,\n truncate,\n ...props\n}: React.ComponentProps<'div'> & {\n truncate?: boolean\n labelClassName?: string\n valueClassName?: string\n}) {\n return (\n <div\n data-slot=\"field-skeleton\"\n aria-hidden=\"true\"\n className={cn('flex w-full flex-col gap-y-1', className)}\n {...props}\n >\n <Skeleton\n data-slot=\"field-skeleton-label\"\n className={cn('h-5 w-24', labelClassName)}\n />\n <Skeleton\n data-slot=\"field-skeleton-value\"\n className={cn(\n 'h-8 min-h-8 w-full',\n truncate && 'max-w-full truncate',\n valueClassName,\n )}\n />\n </div>\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-title\"\n className={cn(\n 'flex w-fit items-center gap-2 text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({\n className,\n id,\n ...props\n}: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const setHasDescription = field?.setHasDescription\n\n React.useEffect(() => {\n if (!setHasDescription) return\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return (\n <div\n data-slot=\"field-description\"\n id={id ?? field?.descriptionId}\n className={cn('mt-0.5 text-sm leading-normal text-gray-light', className)}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn('relative -my-2 h-5 text-sm', className)}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-(--spark-background) px-2 text-gray-light\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const content = React.useMemo(() => {\n if (children) return children\n if (!errors?.length) return null\n const unique = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n if (unique.length === 1) return unique[0]?.message\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {unique.map(\n (error, index) =>\n error?.message && <li key={index}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n className={cn('mt-0.5 text-sm font-normal text-error', className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldSkeleton,\n FieldTitle,\n FieldValue,\n}\nexport type { FieldProps }\n"],"mappings":"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"}
|
package/dist/components/icon.cjs
CHANGED
|
@@ -2,28 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
4
4
|
const require_icons_material_symbol = require("../icons/material-symbol.cjs");
|
|
5
|
+
const require_lib_accent_colors = require("../lib/accent-colors.cjs");
|
|
5
6
|
let react = require("react");
|
|
6
7
|
react = require_chunk.__toESM(react);
|
|
7
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
9
|
let cnfast = require("cnfast");
|
|
9
10
|
//#region src/components/icon.tsx
|
|
10
11
|
const variantClasses = {
|
|
11
|
-
soft: "bg-
|
|
12
|
-
surface: "border border-[color:var(--icon-bd,var(--
|
|
13
|
-
solid: "bg-
|
|
14
|
-
ghost: "[[data-high-contrast]_&]:[--icon-ink:var(--
|
|
15
|
-
outline: "border border-[color:var(--icon-bd,var(--
|
|
12
|
+
soft: "bg-(--icon-bg,var(--spark-a3)) [[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)]",
|
|
13
|
+
surface: "border border-[color:var(--icon-bd,var(--spark-a6))] bg-(--icon-bg,var(--spark-a2)) [[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)] [[data-high-contrast]_&]:[--icon-bd:var(--spark-a11)]",
|
|
14
|
+
solid: "bg-(--icon-bg,var(--spark-12)) text-(--icon-ink,var(--spark-1))",
|
|
15
|
+
ghost: "[[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)]",
|
|
16
|
+
outline: "border border-[color:var(--icon-bd,var(--spark-a8))] [[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)] [[data-high-contrast]_&]:[--icon-bd:var(--spark-a11)]"
|
|
16
17
|
};
|
|
17
18
|
const sizeClasses = {
|
|
18
19
|
small: "size-6 [--spark-icon-size:calc(var(--spacing)*4)]",
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
medium: "size-8 [--spark-icon-size:calc(var(--spacing)*5)]",
|
|
21
|
+
large: "size-10 [--spark-icon-size:calc(var(--spacing)*6)]",
|
|
22
|
+
xl: "size-12 [--spark-icon-size:calc(var(--spacing)*7)]"
|
|
21
23
|
};
|
|
22
|
-
function Icon({ className, name, children, variant = "soft", size = "
|
|
24
|
+
function Icon({ className, name, children, variant = "soft", color = "neutral", size = "medium", ...props }) {
|
|
23
25
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
26
|
+
"data-accent-color": require_lib_accent_colors.accentByColor[color],
|
|
24
27
|
"data-slot": "icon",
|
|
25
28
|
role: "aria-label" in props ? "img" : void 0,
|
|
26
|
-
className: (0, cnfast.cn)("box-border inline-flex shrink-0 items-center justify-center", "rounded-[max(var(--spark-rounded-lg),var(--spark-rounded-full))]", "text-[color:var(--icon-ink,var(--
|
|
29
|
+
className: (0, cnfast.cn)("box-border inline-flex shrink-0 items-center justify-center", "rounded-[max(var(--spark-rounded-lg),var(--spark-rounded-full))]", "text-[color:var(--icon-ink,var(--spark-a11))]", variantClasses[variant], sizeClasses[size], className),
|
|
27
30
|
...props,
|
|
28
31
|
children: children ?? (name ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_material_symbol.MaterialSymbol, { name }) : null)
|
|
29
32
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.cjs","names":["MaterialSymbol"],"sources":["../../src/components/icon.tsx"],"sourcesContent":["import * as React from 'react'\nimport {\n MaterialSymbol,\n type MaterialSymbolIconName,\n} from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\ninterface IconProps extends React.HTMLAttributes<HTMLSpanElement> {\n name?: MaterialSymbolIconName\n /** Fill treatment.
|
|
1
|
+
{"version":3,"file":"icon.cjs","names":["accentByColor","MaterialSymbol"],"sources":["../../src/components/icon.tsx"],"sourcesContent":["import * as React from 'react'\nimport {\n MaterialSymbol,\n type MaterialSymbolIconName,\n} from '../icons/material-symbol'\nimport { accentByColor, type SparkAccentColor } from '../lib/accent-colors'\nimport { cn } from '../utils/cn'\n\ninterface IconProps extends React.HTMLAttributes<HTMLSpanElement> {\n name?: MaterialSymbolIconName\n /** Fill treatment. */\n variant?: 'soft' | 'surface' | 'solid' | 'ghost' | 'outline'\n /** Colour axis, matching Button/Pill/Avatar. Neutral (gray) by default. */\n color?: SparkAccentColor\n size?: 'small' | 'medium' | 'large' | 'xl'\n}\n\n// Every variant reads its fill/ink/border off the accent scale (--spark-*), the same\n// indirection Button/Pill/Avatar use for their `color` prop — data-accent-color re-points\n// --spark-* to gray/red/green/orange, so `color` recolours all five variants without any\n// icon-specific colour plumbing. --icon-bg/--icon-ink/--icon-bd stay the outer override\n// (a consumer className still wins via tailwind-merge over either). data-high-contrast\n// (on the icon or an ancestor) darkens the glyph a11→a12 and strengthens the\n// surface/outline border →a11; solid is already max-contrast, so HC leaves it unchanged.\n// border-box keeps the frame size constant when surface/outline add their 1px edge.\nconst variantClasses = {\n soft: 'bg-(--icon-bg,var(--spark-a3)) [[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)]',\n surface:\n 'border border-[color:var(--icon-bd,var(--spark-a6))] bg-(--icon-bg,var(--spark-a2)) [[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)] [[data-high-contrast]_&]:[--icon-bd:var(--spark-a11)]',\n solid: 'bg-(--icon-bg,var(--spark-12)) text-(--icon-ink,var(--spark-1))',\n ghost: '[[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)]',\n outline:\n 'border border-[color:var(--icon-bd,var(--spark-a8))] [[data-high-contrast]_&]:[--icon-ink:var(--spark-a12)] [[data-high-contrast]_&]:[--icon-bd:var(--spark-a11)]',\n}\n\n// Frame + glyph sizes are spacing-derived so both track the scaling/spacing knobs.\nconst sizeClasses = {\n small: 'size-6 [--spark-icon-size:calc(var(--spacing)*4)]',\n medium: 'size-8 [--spark-icon-size:calc(var(--spacing)*5)]',\n large: 'size-10 [--spark-icon-size:calc(var(--spacing)*6)]',\n xl: 'size-12 [--spark-icon-size:calc(var(--spacing)*7)]',\n}\n\nfunction Icon({\n className,\n name,\n children,\n variant = 'soft',\n color = 'neutral',\n size = 'medium',\n ...props\n}: IconProps) {\n return (\n <span\n data-accent-color={accentByColor[color]}\n data-slot=\"icon\"\n // labeled = meaningful image; otherwise decorative (the glyph is aria-hidden)\n role={'aria-label' in props ? 'img' : undefined}\n className={cn(\n 'box-border inline-flex shrink-0 items-center justify-center',\n // Button's pill idiom: radius=full → circle, other radii → rounded square\n 'rounded-[max(var(--spark-rounded-lg),var(--spark-rounded-full))]',\n 'text-[color:var(--icon-ink,var(--spark-a11))]',\n variantClasses[variant],\n sizeClasses[size],\n className,\n )}\n {...props}\n >\n {children ?? (name ? <MaterialSymbol name={name} /> : null)}\n </span>\n )\n}\n\nIcon.displayName = 'Icon'\n\nexport { Icon }\nexport type { IconProps }\n"],"mappings":";;;;;;;;;;AAyBA,MAAM,iBAAiB;CACrB,MAAM;CACN,SACE;CACF,OAAO;CACP,OAAO;CACP,SACE;AACJ;AAGA,MAAM,cAAc;CAClB,OAAO;CACP,QAAQ;CACR,OAAO;CACP,IAAI;AACN;AAEA,SAAS,KAAK,EACZ,WACA,MACA,UACA,UAAU,QACV,QAAQ,WACR,OAAO,UACP,GAAG,SACS;CACZ,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,qBAAmBA,0BAAAA,cAAc;EACjC,aAAU;EAEV,MAAM,gBAAgB,QAAQ,QAAQ,KAAA;EACtC,YAAA,GAAA,OAAA,IACE,+DAEA,oEACA,iDACA,eAAe,UACf,YAAY,OACZ,SACF;EACA,GAAI;YAEH,aAAa,OAAO,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,gBAAD,EAAsB,KAAO,CAAA,IAAI;CAClD,CAAA;AAEV;AAEA,KAAK,cAAc"}
|