@epilot/spark-ui 0.26.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordion.cjs.map +1 -1
- package/dist/components/accordion.d.cts +1 -1
- package/dist/components/accordion.d.ts +1 -1
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/alert-dialog.cjs +1 -1
- package/dist/components/alert-dialog.cjs.map +1 -1
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/attachment.d.cts +1 -1
- package/dist/components/attachment.d.ts +1 -1
- package/dist/components/banner.d.cts +1 -1
- package/dist/components/banner.d.ts +1 -1
- package/dist/components/bubble.d.cts +1 -1
- package/dist/components/bubble.d.ts +1 -1
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/callout.cjs +1 -1
- package/dist/components/callout.cjs.map +1 -1
- package/dist/components/callout.d.cts +1 -1
- package/dist/components/callout.d.ts +1 -1
- package/dist/components/callout.js +1 -1
- package/dist/components/callout.js.map +1 -1
- package/dist/components/dialog.cjs +1 -1
- package/dist/components/dialog.cjs.map +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/drawer.cjs +1 -1
- package/dist/components/drawer.cjs.map +1 -1
- package/dist/components/drawer.js +1 -1
- package/dist/components/drawer.js.map +1 -1
- package/dist/components/empty-state.cjs +3 -13
- package/dist/components/empty-state.cjs.map +1 -1
- package/dist/components/empty-state.d.cts +3 -3
- package/dist/components/empty-state.d.ts +3 -3
- package/dist/components/empty-state.js +3 -13
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/energy-breakdown.cjs +1 -1
- package/dist/components/energy-breakdown.cjs.map +1 -1
- package/dist/components/energy-breakdown.js +1 -1
- package/dist/components/energy-breakdown.js.map +1 -1
- package/dist/components/entity-card.cjs +1 -1
- package/dist/components/entity-card.cjs.map +1 -1
- package/dist/components/entity-card.js +1 -1
- package/dist/components/entity-card.js.map +1 -1
- package/dist/components/field.cjs +3 -3
- package/dist/components/field.cjs.map +1 -1
- package/dist/components/field.js +3 -3
- package/dist/components/field.js.map +1 -1
- package/dist/components/marker.d.cts +1 -1
- package/dist/components/marker.d.ts +1 -1
- package/dist/components/message-scroller.cjs +1 -1
- package/dist/components/message-scroller.cjs.map +1 -1
- package/dist/components/message-scroller.js +1 -1
- package/dist/components/message-scroller.js.map +1 -1
- package/dist/components/schedule-list.cjs +1 -1
- package/dist/components/schedule-list.cjs.map +1 -1
- package/dist/components/schedule-list.js +1 -1
- package/dist/components/schedule-list.js.map +1 -1
- package/dist/components/stat-card.cjs +1 -1
- package/dist/components/stat-card.cjs.map +1 -1
- package/dist/components/stat-card.js +1 -1
- package/dist/components/stat-card.js.map +1 -1
- package/dist/components/toast.cjs +1 -1
- package/dist/components/toast.cjs.map +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 { 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 errorId: string\n hasError: boolean\n setHasError: (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 errorId = field?.hasError ? field.errorId : undefined\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n // error before hint: the actionable message should be announced first\n const ariaDescribedBy =\n [errorId, descriptionId, options?.ariaDescribedBy]\n .filter(Boolean)\n .join(' ') || undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const ariaInvalid = field?.hasError || undefined\n return { field, id, ariaDescribedBy, ariaInvalid, 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 input's box —\n // rounded-md tracks Input/Select/etc.'s own control radius, not the container one.\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-md 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 'data-invalid'?: boolean | 'true' | 'false'\n}\n\nfunction Field({\n className,\n children,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n readOnly = false,\n 'data-invalid': dataInvalid,\n ...props\n}: FieldProps) {\n const id = useId()\n const [descriptionCount, setDescriptionCount] = React.useState(0)\n const [errorCount, setErrorCount] = React.useState(0)\n // counts, not flags: one slot unmounting must not clear what siblings still need\n const setHasDescription = React.useCallback(\n (has: boolean) => setDescriptionCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const setHasError = React.useCallback(\n (has: boolean) => setErrorCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const hasDescription = descriptionCount > 0\n const hasError = errorCount > 0\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 errorId: `${fieldId}-error`,\n hasError,\n setHasError,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [\n fieldId,\n labelId,\n hasDescription,\n setHasDescription,\n hasError,\n setHasError,\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 data-invalid={dataInvalid ?? (hasError || undefined)}\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 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 id,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const field = useFieldContext()\n const setHasError = field?.setHasError\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) =>\n error?.message && <li key={error.message}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n const hasContent = Boolean(content)\n // a custom id means no element carries field.errorId, so don't advertise it\n const hasCustomId = id != null\n\n // must run before the empty-content early return to keep hook order stable\n React.useEffect(() => {\n if (!setHasError || !hasContent || hasCustomId) return\n setHasError(true)\n return () => setHasError(false)\n }, [setHasError, hasContent, hasCustomId])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n id={id ?? field?.errorId}\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
|
+
{"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 errorId: string\n hasError: boolean\n setHasError: (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 errorId = field?.hasError ? field.errorId : undefined\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n // error before hint: the actionable message should be announced first\n const ariaDescribedBy =\n [errorId, descriptionId, options?.ariaDescribedBy]\n .filter(Boolean)\n .join(' ') || undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const ariaInvalid = field?.hasError || undefined\n return { field, id, ariaDescribedBy, ariaInvalid, 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 input's box —\n // rounded-md tracks Input/Select/etc.'s own control radius, not the container one.\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-md 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 'data-invalid'?: boolean | 'true' | 'false'\n}\n\nfunction Field({\n className,\n children,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n readOnly = false,\n 'data-invalid': dataInvalid,\n ...props\n}: FieldProps) {\n const id = useId()\n const [descriptionCount, setDescriptionCount] = React.useState(0)\n const [errorCount, setErrorCount] = React.useState(0)\n // counts, not flags: one slot unmounting must not clear what siblings still need\n const setHasDescription = React.useCallback(\n (has: boolean) => setDescriptionCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const setHasError = React.useCallback(\n (has: boolean) => setErrorCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const hasDescription = descriptionCount > 0\n const hasError = errorCount > 0\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 errorId: `${fieldId}-error`,\n hasError,\n setHasError,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [\n fieldId,\n labelId,\n hasDescription,\n setHasDescription,\n hasError,\n setHasError,\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 data-invalid={dataInvalid ?? (hasError || undefined)}\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-1 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldLabelClassName =\n 'text-sm leading-5 font-normal text-gray 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('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 id,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const field = useFieldContext()\n const setHasError = field?.setHasError\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) =>\n error?.message && <li key={error.message}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n const hasContent = Boolean(content)\n // a custom id means no element carries field.errorId, so don't advertise it\n const hasCustomId = id != null\n\n // must run before the empty-content early return to keep hook order stable\n React.useEffect(() => {\n if (!setHasError || !hasContent || hasCustomId) return\n setHasError(true)\n return () => setHasError(false)\n }, [setHasError, hasContent, hasCustomId])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n id={id ?? field?.errorId}\n className={cn('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":";;;;;;;;;;;AA8BA,MAAM,eAAeA,QAAM,cAAwC,IAAI;AAEvE,SAAgB,kBAAkB;CAChC,OAAOA,QAAM,WAAW,YAAY;AACtC;AAOA,SAAgB,gBAAgB,SAI7B;CACD,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,QAAQ,SAAS;CACvB,MAAM,KAAK,SAAS,MAAM,OAAO;CAIjC,MAAM,kBACJ;EAJc,OAAO,WAAW,MAAM,UAAU,KAAA;EAC5B,OAAO,iBAAiB,MAAM,gBAAgB,KAAA;EAGzC,SAAS;CAAe,EAC9C,OAAO,OAAO,EACd,KAAK,GAAG,KAAK,KAAA;CAClB,MAAM,aACJ,SAAS,WAAW,OAAO,cAAc,MAAM,cAAc;CAC/D,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAE5D,OAAO;EAAE;EAAO;EAAI;EAAiB,aADjB,OAAO,YAAY,KAAA;EACW;EAAY;CAAW;AAC3E;AAEA,SAAS,SAAS,EAAE,WAAW,GAAG,SAA2C;CAC3E,OACE,oBAAC,YAAD;EACE,aAAU;EACV,WAAW,GACT,uDACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EACnB,WACA,UAAU,UACV,GAAG,SACiE;CACpE,OACE,oBAAC,UAAD;EACE,aAAU;EACV,gBAAc;EACd,WAAW,GACT,6FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,gFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,gBAAgB,IACpB,mFACA;CACE,UAAU;EACR,eAAe;GAIb,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;AAUA,SAAS,MAAM,EACb,WACA,UACA,eAAe,mBACf,YAAY,gBACZ,YAAY,gBACZ,WAAW,OACX,gBAAgB,aAChB,GAAG,SACU;CACb,MAAM,KAAK,MAAM;CACjB,MAAM,CAAC,kBAAkB,uBAAuBA,QAAM,SAAS,CAAC;CAChE,MAAM,CAAC,YAAY,iBAAiBA,QAAM,SAAS,CAAC;CAEpD,MAAM,oBAAoBA,QAAM,aAC7B,QAAiB,qBAAqB,MAAM,KAAK,MAAM,IAAI,GAAG,GAC/D,CAAC,CACH;CACA,MAAM,cAAcA,QAAM,aACvB,QAAiB,eAAe,MAAM,KAAK,MAAM,IAAI,GAAG,GACzD,CAAC,CACH;CACA,MAAM,iBAAiB,mBAAmB;CAC1C,MAAM,WAAW,aAAa;CAG9B,MAAM,QAAQ,SAAS;CACvB,MAAM,gBAAgB,qBAAqB,MAAM,iBAAiB;CAClE,MAAM,aAAa,kBAAkB,MAAM,cAAc;CACzD,MAAM,aAAa,kBAAkB,MAAM,cAAc;CACzD,MAAM,UAAU,SAAS;CACzB,MAAM,UAAU,GAAG,QAAQ;CAC3B,MAAM,QAAQA,QAAM,eACX;EACL,IAAI;EACJ;EACA,eAAe,GAAG,QAAQ;EAC1B;EACA;EACA,SAAS,GAAG,QAAQ;EACpB;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,OACE,oBAAC,aAAa,UAAd;EAA8B;YAC5B,oBAAC,OAAD;GACE,MAAK;GACL,aAAU;GACV,uBAAqB;GACrB,oBAAkB;GAClB,oBAAkB;GAClB,gBAAc,gBAAgB,YAAY,KAAA;GAC1C,mBAAiB,WAAW,UAAU,KAAA;GACtC,WAAW,GACT,cAAc;IAAE;IAAe;IAAY;GAAW,CAAC,GACvD,SACF;GACA,GAAI;GAEH;EACE,CAAA;CACgB,CAAA;AAE3B;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,mDACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,sBACJ;AAEF,SAAS,WAAW,EAClB,WACA,SACA,QACA,UACA,GAAG,SACoD;CACvD,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,aAAa,GAGjB,qBAEA,UAAU,WACV,SACF;CAEA,IAAI,OAAO,UACT,OACE,oBAAC,OAAD;EAAK,aAAU;EAAc,IAAI,MAAM;EAAS,WAAW;EACxD;CACE,CAAA;CAIT,OACE,oBAAC,SAAD;EACE,aAAU;EACV,WAAW;EACX,SAAS,WAAW,OAAO;EAC3B,GAAI;EAEH;CACI,CAAA;AAEX;AAEA,SAAS,WAAW,EAClB,WACA,IACA,OACA,UACA,UACA,GAAG,SACoD;CACvD,OACE,oBAAC,OAAD;EACE,aAAU;EACN;EAEJ,OACE,UACC,YAAY,OAAO,aAAa,WAAW,WAAW,KAAA;EAEzD,WAAW,GAET,+FACA,WACI,6BACA,8DACJ,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET;AAEA,SAAS,cAAc,EACrB,WACA,gBACA,gBACA,UACA,GAAG,SAKF;CACD,OACE,qBAAC,OAAD;EACE,aAAU;EACV,eAAY;EACZ,WAAW,GAAG,gCAAgC,SAAS;EACvD,GAAI;YAJN,CAME,oBAAC,UAAD;GACE,aAAU;GACV,WAAW,GAAG,YAAY,cAAc;EACzC,CAAA,GACD,oBAAC,UAAD;GACE,aAAU;GACV,WAAW,GACT,sBACA,YAAY,uBACZ,cACF;EACD,CAAA,CACE;;AAET;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,+DACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,IACA,GAAG,SAC2B;CAC9B,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,oBAAoB,OAAO;CAEjC,QAAM,gBAAgB;EACpB,IAAI,CAAC,mBAAmB;EACxB,kBAAkB,IAAI;EACtB,aAAa,kBAAkB,KAAK;CACtC,GAAG,CAAC,iBAAiB,CAAC;CAEtB,OACE,oBAAC,OAAD;EACE,aAAU;EACV,IAAI,MAAM,OAAO;EACjB,WAAW,GAAG,0CAA0C,SAAS;EACjE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EACtB,UACA,WACA,GAAG,SAC2B;CAC9B,OACE,qBAAC,OAAD;EACE,aAAU;EACV,gBAAc,CAAC,CAAC;EAChB,WAAW,GAAG,8BAA8B,SAAS;EACrD,GAAI;YAJN,CAME,oBAAC,WAAD,EAAW,WAAU,2BAA4B,CAAA,GAChD,YACC,oBAAC,QAAD;GACE,WAAU;GACV,aAAU;GAET;EACG,CAAA,CAEL;;AAET;AAEA,SAAS,WAAW,EAClB,WACA,UACA,QACA,IACA,GAAG,SAGF;CACD,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,cAAc,OAAO;CAC3B,MAAM,UAAUA,QAAM,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,oBAAC,MAAD;GAAI,WAAU;aACX,OAAO,KACL,UACC,OAAO,WAAW,oBAAC,MAAD,EAAA,UAAyB,MAAM,QAAY,GAAlC,MAAM,OAA4B,CACjE;EACE,CAAA;CAER,GAAG,CAAC,UAAU,MAAM,CAAC;CAErB,MAAM,aAAa,QAAQ,OAAO;CAElC,MAAM,cAAc,MAAM;CAG1B,QAAM,gBAAgB;EACpB,IAAI,CAAC,eAAe,CAAC,cAAc,aAAa;EAChD,YAAY,IAAI;EAChB,aAAa,YAAY,KAAK;CAChC,GAAG;EAAC;EAAa;EAAY;CAAW,CAAC;CAEzC,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,oBAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,IAAI,MAAM,OAAO;EACjB,WAAW,GAAG,kCAAkC,SAAS;EACzD,GAAI;YAEH;CACE,CAAA;AAET"}
|
|
@@ -6,7 +6,7 @@ import { useRender } from "@base-ui/react/use-render";
|
|
|
6
6
|
|
|
7
7
|
//#region src/components/marker.d.ts
|
|
8
8
|
declare const markerVariants: (props?: ({
|
|
9
|
-
variant?: "
|
|
9
|
+
variant?: "default" | "separator" | "border" | null | undefined;
|
|
10
10
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
11
11
|
declare function Marker({
|
|
12
12
|
className,
|
|
@@ -6,7 +6,7 @@ import { useRender } from "@base-ui/react/use-render";
|
|
|
6
6
|
|
|
7
7
|
//#region src/components/marker.d.ts
|
|
8
8
|
declare const markerVariants: (props?: ({
|
|
9
|
-
variant?: "
|
|
9
|
+
variant?: "default" | "separator" | "border" | null | undefined;
|
|
10
10
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
11
11
|
declare function Marker({
|
|
12
12
|
className,
|
|
@@ -46,7 +46,7 @@ function MessageScrollerViewport({ className, ...props }) {
|
|
|
46
46
|
function MessageScrollerContent({ className, ...props }) {
|
|
47
47
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_shadcn_react_message_scroller.MessageScroller.Content, {
|
|
48
48
|
"data-slot": "message-scroller-content",
|
|
49
|
-
className: (0, cn.cn)("flex h-max min-h-full flex-col gap-8", className),
|
|
49
|
+
className: (0, cn.cn)("flex h-max min-h-full flex-col gap-[calc(var(--spark-layout-gap)*8)]", className),
|
|
50
50
|
...props
|
|
51
51
|
});
|
|
52
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-scroller.cjs","names":["React","LazyMotion","domAnimation","MessageScrollerPrimitive","useReducedMotion","MESSAGE_ANIMATIONS","Button","ArrowDownward","ArrowUpward"],"sources":["../../src/components/message-scroller.tsx"],"sourcesContent":["import { ArrowDownward, ArrowUpward } from '@epilot/spark-icons'\nimport {\n MessageScroller as MessageScrollerPrimitive,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n} from '@shadcn/react/message-scroller'\nimport { LazyMotion, domAnimation } from 'motion/react'\nimport { create } from 'motion/react-m'\nimport * as React from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { MESSAGE_ANIMATIONS } from '../lib/message-animations'\nimport { cn } from '../utils/cn'\nimport { Button, type ButtonProps } from './button'\n\nconst MessageScrollerAnimationReadyContext = React.createContext(false)\nconst MotionDiv = create('div')\n\ntype MessageScrollerItemProps = Omit<\n React.ComponentProps<typeof MessageScrollerPrimitive.Item>,\n | 'animate'\n | 'exit'\n | 'initial'\n | 'variants'\n | 'onAnimationStart'\n | 'onDrag'\n | 'onDragStart'\n | 'onDragEnd'\n | 'onDragTransitionEnd'\n>\n\nfunction MessageScrollerProvider(\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) {\n const [ready, setReady] = React.useState(false)\n\n React.useEffect(() => {\n setReady(true)\n }, [])\n\n return (\n <LazyMotion features={domAnimation} strict>\n <MessageScrollerAnimationReadyContext.Provider value={ready}>\n <MessageScrollerPrimitive.Provider {...props} />\n </MessageScrollerAnimationReadyContext.Provider>\n </LazyMotion>\n )\n}\n\nfunction MessageScroller({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n return (\n <MessageScrollerPrimitive.Root\n data-slot=\"message-scroller\"\n className={cn(\n 'group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerViewport({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n return (\n <MessageScrollerPrimitive.Viewport\n data-slot=\"message-scroller-viewport\"\n // The bottom fade follows the primitive's data-scrollable instead of a\n // scroll timeline, which counts the anchor spacer and so faded the last\n // message with nothing below it. Never hide the bar with no-scrollbar\n // here: it drops the stable gutter, so content reflows and can retrigger\n // autoscroll in a loop.\n className={cn(\n 'size-full min-h-0 min-w-0 overflow-y-auto overscroll-contain [mask-image:linear-gradient(to_bottom,#000_calc(100%_-_var(--scroll-fade-b)),transparent)] transition-[--scroll-fade-b] duration-200 contain-content [--scroll-fade-b:0px] [scrollbar-gutter:stable] [scrollbar-width:thin] focus-visible:ring-2 focus-visible:ring-spark-11 focus-visible:ring-offset-2 focus-visible:outline-hidden data-[scrollable~=end]:[--scroll-fade-b:min(12%,calc(var(--spacing)*10))] motion-reduce:transition-none',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerContent({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n return (\n <MessageScrollerPrimitive.Content\n data-slot=\"message-scroller-content\"\n className={cn('flex h-max min-h-full flex-col gap-8'
|
|
1
|
+
{"version":3,"file":"message-scroller.cjs","names":["React","LazyMotion","domAnimation","MessageScrollerPrimitive","useReducedMotion","MESSAGE_ANIMATIONS","Button","ArrowDownward","ArrowUpward"],"sources":["../../src/components/message-scroller.tsx"],"sourcesContent":["import { ArrowDownward, ArrowUpward } from '@epilot/spark-icons'\nimport {\n MessageScroller as MessageScrollerPrimitive,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n} from '@shadcn/react/message-scroller'\nimport { LazyMotion, domAnimation } from 'motion/react'\nimport { create } from 'motion/react-m'\nimport * as React from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { MESSAGE_ANIMATIONS } from '../lib/message-animations'\nimport { cn } from '../utils/cn'\nimport { Button, type ButtonProps } from './button'\n\nconst MessageScrollerAnimationReadyContext = React.createContext(false)\nconst MotionDiv = create('div')\n\ntype MessageScrollerItemProps = Omit<\n React.ComponentProps<typeof MessageScrollerPrimitive.Item>,\n | 'animate'\n | 'exit'\n | 'initial'\n | 'variants'\n | 'onAnimationStart'\n | 'onDrag'\n | 'onDragStart'\n | 'onDragEnd'\n | 'onDragTransitionEnd'\n>\n\nfunction MessageScrollerProvider(\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) {\n const [ready, setReady] = React.useState(false)\n\n React.useEffect(() => {\n setReady(true)\n }, [])\n\n return (\n <LazyMotion features={domAnimation} strict>\n <MessageScrollerAnimationReadyContext.Provider value={ready}>\n <MessageScrollerPrimitive.Provider {...props} />\n </MessageScrollerAnimationReadyContext.Provider>\n </LazyMotion>\n )\n}\n\nfunction MessageScroller({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n return (\n <MessageScrollerPrimitive.Root\n data-slot=\"message-scroller\"\n className={cn(\n 'group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerViewport({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n return (\n <MessageScrollerPrimitive.Viewport\n data-slot=\"message-scroller-viewport\"\n // The bottom fade follows the primitive's data-scrollable instead of a\n // scroll timeline, which counts the anchor spacer and so faded the last\n // message with nothing below it. Never hide the bar with no-scrollbar\n // here: it drops the stable gutter, so content reflows and can retrigger\n // autoscroll in a loop.\n className={cn(\n 'size-full min-h-0 min-w-0 overflow-y-auto overscroll-contain [mask-image:linear-gradient(to_bottom,#000_calc(100%_-_var(--scroll-fade-b)),transparent)] transition-[--scroll-fade-b] duration-200 contain-content [--scroll-fade-b:0px] [scrollbar-gutter:stable] [scrollbar-width:thin] focus-visible:ring-2 focus-visible:ring-spark-11 focus-visible:ring-offset-2 focus-visible:outline-hidden data-[scrollable~=end]:[--scroll-fade-b:min(12%,calc(var(--spacing)*10))] motion-reduce:transition-none',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerContent({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n return (\n <MessageScrollerPrimitive.Content\n data-slot=\"message-scroller-content\"\n className={cn(\n 'flex h-max min-h-full flex-col gap-[calc(var(--spark-layout-gap)*8)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerItem({\n className,\n scrollAnchor = false,\n children,\n ...props\n}: MessageScrollerItemProps) {\n const ready = React.useContext(MessageScrollerAnimationReadyContext)\n const shouldReduceMotion = useReducedMotion()\n const skipEntrance = !ready || shouldReduceMotion\n\n return (\n <MessageScrollerPrimitive.Item\n {...props}\n data-slot=\"message-scroller-item\"\n scrollAnchor={scrollAnchor}\n className={cn(\n 'min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]',\n className,\n )}\n >\n <MotionDiv\n className=\"w-full min-w-0\"\n variants={MESSAGE_ANIMATIONS['slide-up'].variants}\n initial={skipEntrance ? false : 'initial'}\n animate=\"animate\"\n exit={skipEntrance ? undefined : 'exit'}\n >\n {children}\n </MotionDiv>\n </MessageScrollerPrimitive.Item>\n )\n}\n\n// Renders a spark <Button> via `render`, so its `styleVariant`/`color`/`size`\n// recipe paints the chrome — we only add positioning + the enter/leave animation\n// keyed off the primitive's data-[active] state. Icon is a Spark icon, pointing\n// down for `end` and up for `start`.\nfunction MessageScrollerButton({\n direction = 'end',\n className,\n children,\n render,\n styleVariant = 'surface',\n color = 'neutral',\n size = 'icon-small',\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &\n Pick<ButtonProps, 'styleVariant' | 'color' | 'size'>) {\n return (\n <MessageScrollerPrimitive.Button\n data-slot=\"message-scroller-button\"\n data-direction={direction}\n direction={direction}\n className={cn(\n 'absolute inset-s-1/2 -translate-x-1/2 rounded-full transition-[translate,scale,opacity] duration-200 data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full motion-reduce:transition-none rtl:translate-x-1/2',\n className,\n )}\n render={\n render ?? (\n <Button styleVariant={styleVariant} color={color} size={size} />\n )\n }\n {...props}\n >\n {children ?? (\n <>\n {direction === 'end' ? <ArrowDownward /> : <ArrowUpward />}\n <span className=\"sr-only\">\n {direction === 'end' ? 'Scroll to end' : 'Scroll to start'}\n </span>\n </>\n )}\n </MessageScrollerPrimitive.Button>\n )\n}\n\nexport {\n MessageScroller,\n MessageScrollerButton,\n MessageScrollerContent,\n MessageScrollerItem,\n MessageScrollerProvider,\n MessageScrollerViewport,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,MAAM,uCAAuCA,MAAM,cAAc,KAAK;AACtE,MAAM,aAAA,GAAA,eAAA,QAAmB,KAAK;AAe9B,SAAS,wBACP,OACA;CACA,MAAM,CAAC,OAAO,YAAYA,MAAM,SAAS,KAAK;CAE9C,MAAM,gBAAgB;EACpB,SAAS,IAAI;CACf,GAAG,CAAC,CAAC;CAEL,OACE,iBAAA,GAAA,kBAAA,KAACC,aAAAA,YAAD;EAAY,UAAUC,aAAAA;EAAc,QAAA;YAClC,iBAAA,GAAA,kBAAA,KAAC,qCAAqC,UAAtC;GAA+C,OAAO;aACpD,iBAAA,GAAA,kBAAA,KAACC,+BAAAA,gBAAyB,UAA1B,EAAmC,GAAI,MAAQ,CAAA;EACF,CAAA;CACrC,CAAA;AAEhB;AAEA,SAAS,gBAAgB,EACvB,WACA,GAAG,SAC0D;CAC7D,OACE,iBAAA,GAAA,kBAAA,KAACA,+BAAAA,gBAAyB,MAA1B;EACE,aAAU;EACV,YAAA,GAAA,GAAA,IACE,mFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,wBAAwB,EAC/B,WACA,GAAG,SAC8D;CACjE,OACE,iBAAA,GAAA,kBAAA,KAACA,+BAAAA,gBAAyB,UAA1B;EACE,aAAU;EAMV,YAAA,GAAA,GAAA,IACE,8eACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,iBAAA,GAAA,kBAAA,KAACA,+BAAAA,gBAAyB,SAA1B;EACE,aAAU;EACV,YAAA,GAAA,GAAA,IACE,wEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,WACA,eAAe,OACf,UACA,GAAG,SACwB;CAC3B,MAAM,QAAQH,MAAM,WAAW,oCAAoC;CACnE,MAAM,qBAAqBI,iCAAAA,iBAAiB;CAC5C,MAAM,eAAe,CAAC,SAAS;CAE/B,OACE,iBAAA,GAAA,kBAAA,KAACD,+BAAAA,gBAAyB,MAA1B;EACE,GAAI;EACJ,aAAU;EACI;EACd,YAAA,GAAA,GAAA,IACE,kFACA,SACF;YAEA,iBAAA,GAAA,kBAAA,KAAC,WAAD;GACE,WAAU;GACV,UAAUE,+BAAAA,mBAAmB,YAAY;GACzC,SAAS,eAAe,QAAQ;GAChC,SAAQ;GACR,MAAM,eAAe,KAAA,IAAY;GAEhC;EACQ,CAAA;CACkB,CAAA;AAEnC;AAMA,SAAS,sBAAsB,EAC7B,YAAY,OACZ,WACA,UACA,QACA,eAAe,WACf,QAAQ,WACR,OAAO,cACP,GAAG,SAEmD;CACtD,OACE,iBAAA,GAAA,kBAAA,KAACF,+BAAAA,gBAAyB,QAA1B;EACE,aAAU;EACV,kBAAgB;EACL;EACX,YAAA,GAAA,GAAA,IACE,ypBACA,SACF;EACA,QACE,UACE,iBAAA,GAAA,kBAAA,KAACG,0BAAAA,QAAD;GAAsB;GAAqB;GAAa;EAAO,CAAA;EAGnE,GAAI;YAEH,YACC,iBAAA,GAAA,kBAAA,MAAA,kBAAA,UAAA,EAAA,UAAA,CACG,cAAc,QAAQ,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,eAAD,CAAgB,CAAA,IAAI,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,aAAD,CAAc,CAAA,GACzD,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAAM,WAAU;aACb,cAAc,QAAQ,kBAAkB;EACrC,CAAA,CACN,EAAA,CAAA;CAE2B,CAAA;AAErC"}
|
|
@@ -43,7 +43,7 @@ function MessageScrollerViewport({ className, ...props }) {
|
|
|
43
43
|
function MessageScrollerContent({ className, ...props }) {
|
|
44
44
|
return /* @__PURE__ */ jsx(MessageScroller$1.Content, {
|
|
45
45
|
"data-slot": "message-scroller-content",
|
|
46
|
-
className: cn("flex h-max min-h-full flex-col gap-8", className),
|
|
46
|
+
className: cn("flex h-max min-h-full flex-col gap-[calc(var(--spark-layout-gap)*8)]", className),
|
|
47
47
|
...props
|
|
48
48
|
});
|
|
49
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-scroller.js","names":["React","MessageScrollerPrimitive"],"sources":["../../src/components/message-scroller.tsx"],"sourcesContent":["import { ArrowDownward, ArrowUpward } from '@epilot/spark-icons'\nimport {\n MessageScroller as MessageScrollerPrimitive,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n} from '@shadcn/react/message-scroller'\nimport { LazyMotion, domAnimation } from 'motion/react'\nimport { create } from 'motion/react-m'\nimport * as React from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { MESSAGE_ANIMATIONS } from '../lib/message-animations'\nimport { cn } from '../utils/cn'\nimport { Button, type ButtonProps } from './button'\n\nconst MessageScrollerAnimationReadyContext = React.createContext(false)\nconst MotionDiv = create('div')\n\ntype MessageScrollerItemProps = Omit<\n React.ComponentProps<typeof MessageScrollerPrimitive.Item>,\n | 'animate'\n | 'exit'\n | 'initial'\n | 'variants'\n | 'onAnimationStart'\n | 'onDrag'\n | 'onDragStart'\n | 'onDragEnd'\n | 'onDragTransitionEnd'\n>\n\nfunction MessageScrollerProvider(\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) {\n const [ready, setReady] = React.useState(false)\n\n React.useEffect(() => {\n setReady(true)\n }, [])\n\n return (\n <LazyMotion features={domAnimation} strict>\n <MessageScrollerAnimationReadyContext.Provider value={ready}>\n <MessageScrollerPrimitive.Provider {...props} />\n </MessageScrollerAnimationReadyContext.Provider>\n </LazyMotion>\n )\n}\n\nfunction MessageScroller({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n return (\n <MessageScrollerPrimitive.Root\n data-slot=\"message-scroller\"\n className={cn(\n 'group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerViewport({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n return (\n <MessageScrollerPrimitive.Viewport\n data-slot=\"message-scroller-viewport\"\n // The bottom fade follows the primitive's data-scrollable instead of a\n // scroll timeline, which counts the anchor spacer and so faded the last\n // message with nothing below it. Never hide the bar with no-scrollbar\n // here: it drops the stable gutter, so content reflows and can retrigger\n // autoscroll in a loop.\n className={cn(\n 'size-full min-h-0 min-w-0 overflow-y-auto overscroll-contain [mask-image:linear-gradient(to_bottom,#000_calc(100%_-_var(--scroll-fade-b)),transparent)] transition-[--scroll-fade-b] duration-200 contain-content [--scroll-fade-b:0px] [scrollbar-gutter:stable] [scrollbar-width:thin] focus-visible:ring-2 focus-visible:ring-spark-11 focus-visible:ring-offset-2 focus-visible:outline-hidden data-[scrollable~=end]:[--scroll-fade-b:min(12%,calc(var(--spacing)*10))] motion-reduce:transition-none',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerContent({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n return (\n <MessageScrollerPrimitive.Content\n data-slot=\"message-scroller-content\"\n className={cn('flex h-max min-h-full flex-col gap-8'
|
|
1
|
+
{"version":3,"file":"message-scroller.js","names":["React","MessageScrollerPrimitive"],"sources":["../../src/components/message-scroller.tsx"],"sourcesContent":["import { ArrowDownward, ArrowUpward } from '@epilot/spark-icons'\nimport {\n MessageScroller as MessageScrollerPrimitive,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n} from '@shadcn/react/message-scroller'\nimport { LazyMotion, domAnimation } from 'motion/react'\nimport { create } from 'motion/react-m'\nimport * as React from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { MESSAGE_ANIMATIONS } from '../lib/message-animations'\nimport { cn } from '../utils/cn'\nimport { Button, type ButtonProps } from './button'\n\nconst MessageScrollerAnimationReadyContext = React.createContext(false)\nconst MotionDiv = create('div')\n\ntype MessageScrollerItemProps = Omit<\n React.ComponentProps<typeof MessageScrollerPrimitive.Item>,\n | 'animate'\n | 'exit'\n | 'initial'\n | 'variants'\n | 'onAnimationStart'\n | 'onDrag'\n | 'onDragStart'\n | 'onDragEnd'\n | 'onDragTransitionEnd'\n>\n\nfunction MessageScrollerProvider(\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) {\n const [ready, setReady] = React.useState(false)\n\n React.useEffect(() => {\n setReady(true)\n }, [])\n\n return (\n <LazyMotion features={domAnimation} strict>\n <MessageScrollerAnimationReadyContext.Provider value={ready}>\n <MessageScrollerPrimitive.Provider {...props} />\n </MessageScrollerAnimationReadyContext.Provider>\n </LazyMotion>\n )\n}\n\nfunction MessageScroller({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n return (\n <MessageScrollerPrimitive.Root\n data-slot=\"message-scroller\"\n className={cn(\n 'group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerViewport({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n return (\n <MessageScrollerPrimitive.Viewport\n data-slot=\"message-scroller-viewport\"\n // The bottom fade follows the primitive's data-scrollable instead of a\n // scroll timeline, which counts the anchor spacer and so faded the last\n // message with nothing below it. Never hide the bar with no-scrollbar\n // here: it drops the stable gutter, so content reflows and can retrigger\n // autoscroll in a loop.\n className={cn(\n 'size-full min-h-0 min-w-0 overflow-y-auto overscroll-contain [mask-image:linear-gradient(to_bottom,#000_calc(100%_-_var(--scroll-fade-b)),transparent)] transition-[--scroll-fade-b] duration-200 contain-content [--scroll-fade-b:0px] [scrollbar-gutter:stable] [scrollbar-width:thin] focus-visible:ring-2 focus-visible:ring-spark-11 focus-visible:ring-offset-2 focus-visible:outline-hidden data-[scrollable~=end]:[--scroll-fade-b:min(12%,calc(var(--spacing)*10))] motion-reduce:transition-none',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerContent({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n return (\n <MessageScrollerPrimitive.Content\n data-slot=\"message-scroller-content\"\n className={cn(\n 'flex h-max min-h-full flex-col gap-[calc(var(--spark-layout-gap)*8)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerItem({\n className,\n scrollAnchor = false,\n children,\n ...props\n}: MessageScrollerItemProps) {\n const ready = React.useContext(MessageScrollerAnimationReadyContext)\n const shouldReduceMotion = useReducedMotion()\n const skipEntrance = !ready || shouldReduceMotion\n\n return (\n <MessageScrollerPrimitive.Item\n {...props}\n data-slot=\"message-scroller-item\"\n scrollAnchor={scrollAnchor}\n className={cn(\n 'min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]',\n className,\n )}\n >\n <MotionDiv\n className=\"w-full min-w-0\"\n variants={MESSAGE_ANIMATIONS['slide-up'].variants}\n initial={skipEntrance ? false : 'initial'}\n animate=\"animate\"\n exit={skipEntrance ? undefined : 'exit'}\n >\n {children}\n </MotionDiv>\n </MessageScrollerPrimitive.Item>\n )\n}\n\n// Renders a spark <Button> via `render`, so its `styleVariant`/`color`/`size`\n// recipe paints the chrome — we only add positioning + the enter/leave animation\n// keyed off the primitive's data-[active] state. Icon is a Spark icon, pointing\n// down for `end` and up for `start`.\nfunction MessageScrollerButton({\n direction = 'end',\n className,\n children,\n render,\n styleVariant = 'surface',\n color = 'neutral',\n size = 'icon-small',\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &\n Pick<ButtonProps, 'styleVariant' | 'color' | 'size'>) {\n return (\n <MessageScrollerPrimitive.Button\n data-slot=\"message-scroller-button\"\n data-direction={direction}\n direction={direction}\n className={cn(\n 'absolute inset-s-1/2 -translate-x-1/2 rounded-full transition-[translate,scale,opacity] duration-200 data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full motion-reduce:transition-none rtl:translate-x-1/2',\n className,\n )}\n render={\n render ?? (\n <Button styleVariant={styleVariant} color={color} size={size} />\n )\n }\n {...props}\n >\n {children ?? (\n <>\n {direction === 'end' ? <ArrowDownward /> : <ArrowUpward />}\n <span className=\"sr-only\">\n {direction === 'end' ? 'Scroll to end' : 'Scroll to start'}\n </span>\n </>\n )}\n </MessageScrollerPrimitive.Button>\n )\n}\n\nexport {\n MessageScroller,\n MessageScrollerButton,\n MessageScrollerContent,\n MessageScrollerItem,\n MessageScrollerProvider,\n MessageScrollerViewport,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n}\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,uCAAuCA,QAAM,cAAc,KAAK;AACtE,MAAM,YAAY,OAAO,KAAK;AAe9B,SAAS,wBACP,OACA;CACA,MAAM,CAAC,OAAO,YAAYA,QAAM,SAAS,KAAK;CAE9C,QAAM,gBAAgB;EACpB,SAAS,IAAI;CACf,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,YAAD;EAAY,UAAU;EAAc,QAAA;YAClC,oBAAC,qCAAqC,UAAtC;GAA+C,OAAO;aACpD,oBAACC,kBAAyB,UAA1B,EAAmC,GAAI,MAAQ,CAAA;EACF,CAAA;CACrC,CAAA;AAEhB;AAEA,SAAS,gBAAgB,EACvB,WACA,GAAG,SAC0D;CAC7D,OACE,oBAACA,kBAAyB,MAA1B;EACE,aAAU;EACV,WAAW,GACT,mFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,wBAAwB,EAC/B,WACA,GAAG,SAC8D;CACjE,OACE,oBAACA,kBAAyB,UAA1B;EACE,aAAU;EAMV,WAAW,GACT,8eACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,oBAACA,kBAAyB,SAA1B;EACE,aAAU;EACV,WAAW,GACT,wEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,WACA,eAAe,OACf,UACA,GAAG,SACwB;CAC3B,MAAM,QAAQD,QAAM,WAAW,oCAAoC;CACnE,MAAM,qBAAqB,iBAAiB;CAC5C,MAAM,eAAe,CAAC,SAAS;CAE/B,OACE,oBAACC,kBAAyB,MAA1B;EACE,GAAI;EACJ,aAAU;EACI;EACd,WAAW,GACT,kFACA,SACF;YAEA,oBAAC,WAAD;GACE,WAAU;GACV,UAAU,mBAAmB,YAAY;GACzC,SAAS,eAAe,QAAQ;GAChC,SAAQ;GACR,MAAM,eAAe,KAAA,IAAY;GAEhC;EACQ,CAAA;CACkB,CAAA;AAEnC;AAMA,SAAS,sBAAsB,EAC7B,YAAY,OACZ,WACA,UACA,QACA,eAAe,WACf,QAAQ,WACR,OAAO,cACP,GAAG,SAEmD;CACtD,OACE,oBAACA,kBAAyB,QAA1B;EACE,aAAU;EACV,kBAAgB;EACL;EACX,WAAW,GACT,ypBACA,SACF;EACA,QACE,UACE,oBAAC,QAAD;GAAsB;GAAqB;GAAa;EAAO,CAAA;EAGnE,GAAI;YAEH,YACC,qBAAA,UAAA,EAAA,UAAA,CACG,cAAc,QAAQ,oBAAC,eAAD,CAAgB,CAAA,IAAI,oBAAC,aAAD,CAAc,CAAA,GACzD,oBAAC,QAAD;GAAM,WAAU;aACb,cAAc,QAAQ,kBAAkB;EACrC,CAAA,CACN,EAAA,CAAA;CAE2B,CAAA;AAErC"}
|
|
@@ -51,7 +51,7 @@ const ScheduleEntry = react.forwardRef(({ children, className, disabled, onClick
|
|
|
51
51
|
ScheduleEntry.displayName = "ScheduleEntry";
|
|
52
52
|
const ScheduleEntryContent = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
53
53
|
ref,
|
|
54
|
-
className: (0, cn.cn)("flex min-w-0 flex-1 flex-col gap-
|
|
54
|
+
className: (0, cn.cn)("flex min-w-0 flex-1 flex-col gap-1", className),
|
|
55
55
|
...props
|
|
56
56
|
}));
|
|
57
57
|
ScheduleEntryContent.displayName = "ScheduleEntryContent";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-list.cjs","names":["React","Add","Delete"],"sources":["../../src/components/schedule-list.tsx"],"sourcesContent":["import { Add, Delete } from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleList = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*2)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleList.displayName = 'ScheduleList'\n\nconst ScheduleListEmpty = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('px-3 py-2 text-sm text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleListEmpty.displayName = 'ScheduleListEmpty'\n\ninterface ScheduleListAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Optional icon override; defaults to a `+`. */\n icon?: React.ReactNode\n}\n\nconst ScheduleListAdd = React.forwardRef<\n HTMLButtonElement,\n ScheduleListAddProps\n>(({ children, className, icon, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n 'inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {icon ?? <Add className=\"[--spark-icon-size:14px]\" />}\n {children}\n </button>\n))\n\nScheduleListAdd.displayName = 'ScheduleListAdd'\n\ninterface ScheduleEntryProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Make the row interactive — enables hover, role=button, keyboard activation. */\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScheduleEntry = React.forwardRef<HTMLDivElement, ScheduleEntryProps>(\n ({ children, className, disabled, onClick, ...props }, ref) => {\n const interactive = onClick !== undefined && !disabled\n // role, tab stop and key handler travel together -- the row is never\n // clickable without Enter/Space, and never focusable without a role\n const interaction = interactive\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick,\n onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick()\n }\n },\n }\n : undefined\n return (\n <div\n ref={ref}\n {...interaction}\n aria-disabled={disabled || undefined}\n className={cn(\n 'flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none',\n interactive &&\n 'cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\n\nScheduleEntry.displayName = 'ScheduleEntry'\n\nconst ScheduleEntryContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col gap-
|
|
1
|
+
{"version":3,"file":"schedule-list.cjs","names":["React","Add","Delete"],"sources":["../../src/components/schedule-list.tsx"],"sourcesContent":["import { Add, Delete } from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleList = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*2)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleList.displayName = 'ScheduleList'\n\nconst ScheduleListEmpty = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('px-3 py-2 text-sm text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleListEmpty.displayName = 'ScheduleListEmpty'\n\ninterface ScheduleListAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Optional icon override; defaults to a `+`. */\n icon?: React.ReactNode\n}\n\nconst ScheduleListAdd = React.forwardRef<\n HTMLButtonElement,\n ScheduleListAddProps\n>(({ children, className, icon, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n 'inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {icon ?? <Add className=\"[--spark-icon-size:14px]\" />}\n {children}\n </button>\n))\n\nScheduleListAdd.displayName = 'ScheduleListAdd'\n\ninterface ScheduleEntryProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Make the row interactive — enables hover, role=button, keyboard activation. */\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScheduleEntry = React.forwardRef<HTMLDivElement, ScheduleEntryProps>(\n ({ children, className, disabled, onClick, ...props }, ref) => {\n const interactive = onClick !== undefined && !disabled\n // role, tab stop and key handler travel together -- the row is never\n // clickable without Enter/Space, and never focusable without a role\n const interaction = interactive\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick,\n onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick()\n }\n },\n }\n : undefined\n return (\n <div\n ref={ref}\n {...interaction}\n aria-disabled={disabled || undefined}\n className={cn(\n 'flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none',\n interactive &&\n 'cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\n\nScheduleEntry.displayName = 'ScheduleEntry'\n\nconst ScheduleEntryContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col gap-1', className)}\n {...props}\n />\n))\n\nScheduleEntryContent.displayName = 'ScheduleEntryContent'\n\nconst ScheduleEntryTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex min-w-0 items-center gap-2 truncate text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n))\n\nScheduleEntryTitle.displayName = 'ScheduleEntryTitle'\n\nconst ScheduleEntrySubtitle = React.forwardRef<\n HTMLSpanElement,\n React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n className={cn('truncate text-xs text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleEntrySubtitle.displayName = 'ScheduleEntrySubtitle'\n\n/** Right-aligned action area. Stops click propagation so inner controls\n * don't fire the parent `ScheduleEntry`'s `onClick`. */\nconst ScheduleEntryActions = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, onClick, ...props }, ref) => (\n <div\n ref={ref}\n // a layout wrapper, not a control: the handler only shields the inner\n // buttons' clicks (keyboard activation included) from the parent row\n role=\"presentation\"\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn('flex shrink-0 items-center gap-1.5', className)}\n {...props}\n />\n))\n\nScheduleEntryActions.displayName = 'ScheduleEntryActions'\n\ninterface ScheduleEntryDeleteProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nconst ScheduleEntryDelete = React.forwardRef<\n HTMLButtonElement,\n ScheduleEntryDeleteProps\n>(\n (\n {\n 'aria-label': ariaLabel = 'Delete schedule entry',\n children,\n className,\n onClick,\n type = 'button',\n ...props\n },\n ref,\n ) => (\n <button\n ref={ref}\n type={type}\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn(\n 'inline-flex size-8 shrink-0 items-center justify-center rounded-full text-gray-light transition-colors hover:bg-base-error-soft hover:text-error focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children ?? <Delete className=\"[--spark-icon-size:14px]\" />}\n </button>\n ),\n)\n\nScheduleEntryDelete.displayName = 'ScheduleEntryDelete'\n\nexport {\n ScheduleEntry,\n ScheduleEntryActions,\n ScheduleEntryContent,\n ScheduleEntryDelete,\n ScheduleEntrySubtitle,\n ScheduleEntryTitle,\n ScheduleList,\n ScheduleListAdd,\n ScheduleListEmpty,\n}\n"],"mappings":"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"}
|
|
@@ -48,7 +48,7 @@ const ScheduleEntry = React$1.forwardRef(({ children, className, disabled, onCli
|
|
|
48
48
|
ScheduleEntry.displayName = "ScheduleEntry";
|
|
49
49
|
const ScheduleEntryContent = React$1.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", {
|
|
50
50
|
ref,
|
|
51
|
-
className: cn("flex min-w-0 flex-1 flex-col gap-
|
|
51
|
+
className: cn("flex min-w-0 flex-1 flex-col gap-1", className),
|
|
52
52
|
...props
|
|
53
53
|
}));
|
|
54
54
|
ScheduleEntryContent.displayName = "ScheduleEntryContent";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-list.js","names":["React"],"sources":["../../src/components/schedule-list.tsx"],"sourcesContent":["import { Add, Delete } from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleList = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*2)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleList.displayName = 'ScheduleList'\n\nconst ScheduleListEmpty = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('px-3 py-2 text-sm text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleListEmpty.displayName = 'ScheduleListEmpty'\n\ninterface ScheduleListAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Optional icon override; defaults to a `+`. */\n icon?: React.ReactNode\n}\n\nconst ScheduleListAdd = React.forwardRef<\n HTMLButtonElement,\n ScheduleListAddProps\n>(({ children, className, icon, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n 'inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {icon ?? <Add className=\"[--spark-icon-size:14px]\" />}\n {children}\n </button>\n))\n\nScheduleListAdd.displayName = 'ScheduleListAdd'\n\ninterface ScheduleEntryProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Make the row interactive — enables hover, role=button, keyboard activation. */\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScheduleEntry = React.forwardRef<HTMLDivElement, ScheduleEntryProps>(\n ({ children, className, disabled, onClick, ...props }, ref) => {\n const interactive = onClick !== undefined && !disabled\n // role, tab stop and key handler travel together -- the row is never\n // clickable without Enter/Space, and never focusable without a role\n const interaction = interactive\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick,\n onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick()\n }\n },\n }\n : undefined\n return (\n <div\n ref={ref}\n {...interaction}\n aria-disabled={disabled || undefined}\n className={cn(\n 'flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none',\n interactive &&\n 'cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\n\nScheduleEntry.displayName = 'ScheduleEntry'\n\nconst ScheduleEntryContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col gap-
|
|
1
|
+
{"version":3,"file":"schedule-list.js","names":["React"],"sources":["../../src/components/schedule-list.tsx"],"sourcesContent":["import { Add, Delete } from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleList = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*2)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleList.displayName = 'ScheduleList'\n\nconst ScheduleListEmpty = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('px-3 py-2 text-sm text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleListEmpty.displayName = 'ScheduleListEmpty'\n\ninterface ScheduleListAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Optional icon override; defaults to a `+`. */\n icon?: React.ReactNode\n}\n\nconst ScheduleListAdd = React.forwardRef<\n HTMLButtonElement,\n ScheduleListAddProps\n>(({ children, className, icon, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n 'inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {icon ?? <Add className=\"[--spark-icon-size:14px]\" />}\n {children}\n </button>\n))\n\nScheduleListAdd.displayName = 'ScheduleListAdd'\n\ninterface ScheduleEntryProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Make the row interactive — enables hover, role=button, keyboard activation. */\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScheduleEntry = React.forwardRef<HTMLDivElement, ScheduleEntryProps>(\n ({ children, className, disabled, onClick, ...props }, ref) => {\n const interactive = onClick !== undefined && !disabled\n // role, tab stop and key handler travel together -- the row is never\n // clickable without Enter/Space, and never focusable without a role\n const interaction = interactive\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick,\n onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick()\n }\n },\n }\n : undefined\n return (\n <div\n ref={ref}\n {...interaction}\n aria-disabled={disabled || undefined}\n className={cn(\n 'flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none',\n interactive &&\n 'cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\n\nScheduleEntry.displayName = 'ScheduleEntry'\n\nconst ScheduleEntryContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col gap-1', className)}\n {...props}\n />\n))\n\nScheduleEntryContent.displayName = 'ScheduleEntryContent'\n\nconst ScheduleEntryTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex min-w-0 items-center gap-2 truncate text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n))\n\nScheduleEntryTitle.displayName = 'ScheduleEntryTitle'\n\nconst ScheduleEntrySubtitle = React.forwardRef<\n HTMLSpanElement,\n React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n className={cn('truncate text-xs text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleEntrySubtitle.displayName = 'ScheduleEntrySubtitle'\n\n/** Right-aligned action area. Stops click propagation so inner controls\n * don't fire the parent `ScheduleEntry`'s `onClick`. */\nconst ScheduleEntryActions = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, onClick, ...props }, ref) => (\n <div\n ref={ref}\n // a layout wrapper, not a control: the handler only shields the inner\n // buttons' clicks (keyboard activation included) from the parent row\n role=\"presentation\"\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn('flex shrink-0 items-center gap-1.5', className)}\n {...props}\n />\n))\n\nScheduleEntryActions.displayName = 'ScheduleEntryActions'\n\ninterface ScheduleEntryDeleteProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nconst ScheduleEntryDelete = React.forwardRef<\n HTMLButtonElement,\n ScheduleEntryDeleteProps\n>(\n (\n {\n 'aria-label': ariaLabel = 'Delete schedule entry',\n children,\n className,\n onClick,\n type = 'button',\n ...props\n },\n ref,\n ) => (\n <button\n ref={ref}\n type={type}\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn(\n 'inline-flex size-8 shrink-0 items-center justify-center rounded-full text-gray-light transition-colors hover:bg-base-error-soft hover:text-error focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children ?? <Delete className=\"[--spark-icon-size:14px]\" />}\n </button>\n ),\n)\n\nScheduleEntryDelete.displayName = 'ScheduleEntryDelete'\n\nexport {\n ScheduleEntry,\n ScheduleEntryActions,\n ScheduleEntryContent,\n ScheduleEntryDelete,\n ScheduleEntrySubtitle,\n ScheduleEntryTitle,\n ScheduleList,\n ScheduleListAdd,\n ScheduleListEmpty,\n}\n"],"mappings":";;;;;;AAIA,MAAM,eAAeA,QAAM,YAGxB,EAAE,WAAW,GAAG,SAAS,QAC1B,oBAAC,OAAD;CACO;CACL,WAAW,GACT,uDACA,SACF;CACA,GAAI;AACL,CAAA,CACF;AAED,aAAa,cAAc;AAE3B,MAAM,oBAAoBA,QAAM,YAG7B,EAAE,WAAW,GAAG,SAAS,QAC1B,oBAAC,KAAD;CACO;CACL,WAAW,GAAG,qCAAqC,SAAS;CAC5D,GAAI;AACL,CAAA,CACF;AAED,kBAAkB,cAAc;AAOhC,MAAM,kBAAkBA,QAAM,YAG3B,EAAE,UAAU,WAAW,MAAM,OAAO,UAAU,GAAG,SAAS,QAC3D,qBAAC,UAAD;CACO;CACC;CACN,WAAW,GACT,iWACA,SACF;CACA,GAAI;WAPN,CASG,QAAQ,oBAAC,KAAD,EAAK,WAAU,2BAA4B,CAAA,GACnD,QACK;EACT;AAED,gBAAgB,cAAc;AAQ9B,MAAM,gBAAgBA,QAAM,YACzB,EAAE,UAAU,WAAW,UAAU,SAAS,GAAG,SAAS,QAAQ;CAC7D,MAAM,cAAc,YAAY,KAAA,KAAa,CAAC;CAgB9C,OACE,oBAAC,OAAD;EACO;EACL,GAhBgB,cAChB;GACE,MAAM;GACN,UAAU;GACV;GACA,YAAY,UAA+C;IACzD,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;KAC9C,MAAM,eAAe;KACrB,QAAQ;IACV;GACF;EACF,IACA,KAAA;EAKA,iBAAe,YAAY,KAAA;EAC3B,WAAW,GACT,oHACA,eACE,kIACF,YAAY,iCACZ,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET,CACF;AAEA,cAAc,cAAc;AAE5B,MAAM,uBAAuBA,QAAM,YAGhC,EAAE,WAAW,GAAG,SAAS,QAC1B,oBAAC,OAAD;CACO;CACL,WAAW,GAAG,sCAAsC,SAAS;CAC7D,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;AAEnC,MAAM,qBAAqBA,QAAM,YAG9B,EAAE,WAAW,GAAG,SAAS,QAC1B,oBAAC,OAAD;CACO;CACL,WAAW,GACT,0EACA,SACF;CACA,GAAI;AACL,CAAA,CACF;AAED,mBAAmB,cAAc;AAEjC,MAAM,wBAAwBA,QAAM,YAGjC,EAAE,WAAW,GAAG,SAAS,QAC1B,oBAAC,QAAD;CACO;CACL,WAAW,GAAG,oCAAoC,SAAS;CAC3D,GAAI;AACL,CAAA,CACF;AAED,sBAAsB,cAAc;;;AAIpC,MAAM,uBAAuBA,QAAM,YAGhC,EAAE,WAAW,SAAS,GAAG,SAAS,QACnC,oBAAC,OAAD;CACO;CAGL,MAAK;CACL,UAAU,UAAU;EAClB,MAAM,gBAAgB;EACtB,UAAU,KAAK;CACjB;CACA,WAAW,GAAG,sCAAsC,SAAS;CAC7D,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;AAInC,MAAM,sBAAsBA,QAAM,YAK9B,EACE,cAAc,YAAY,yBAC1B,UACA,WACA,SACA,OAAO,UACP,GAAG,SAEL,QAEA,oBAAC,UAAD;CACO;CACC;CACN,cAAY;CACZ,UAAU,UAAU;EAClB,MAAM,gBAAgB;EACtB,UAAU,KAAK;CACjB;CACA,WAAW,GACT,kRACA,SACF;CACA,GAAI;WAEH,YAAY,oBAAC,QAAD,EAAQ,WAAU,2BAA4B,CAAA;AACrD,CAAA,CAEZ;AAEA,oBAAoB,cAAc"}
|
|
@@ -23,7 +23,7 @@ const StatCardContent = ({ className, ...rest }) => {
|
|
|
23
23
|
};
|
|
24
24
|
const StatCardValueContainer = ({ className, ...rest }) => {
|
|
25
25
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
26
|
-
className: (0, cn.cn)("flex flex-col gap-
|
|
26
|
+
className: (0, cn.cn)("flex flex-col gap-1", className),
|
|
27
27
|
...rest
|
|
28
28
|
});
|
|
29
29
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stat-card.cjs","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-
|
|
1
|
+
{"version":3,"file":"stat-card.cjs","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-1', className)} {...rest} />\n}\n\nconst StatCardValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-lg font-bold text-gray tabular-nums', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardSecondaryValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return <span className={cn('text-xs text-gray-light', className)} {...rest} />\n}\n\nconst StatCardIcon = ({ className, ...rest }: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn(\n // max() pill escape (matches Icon): a tile stays rounded-md at low Roundness but\n // becomes a circle at large/full, same as it did pre-harmonization via clamping.\n 'flex size-10 shrink-0 items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]',\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport {\n StatCardContainer,\n StatCardLabel,\n StatCardContent,\n StatCardValueContainer,\n StatCardValue,\n StatCardSecondaryValue,\n StatCardIcon,\n}\n"],"mappings":";;;;;AAEA,MAAM,qBAAqB,EACzB,WACA,GAAG,WAC8B;CACjC,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,GAAA,IAAc,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,GAAA,IAAc,uCAAuC,SAAS;EAC9D,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,mBAAmB,EACvB,WACA,GAAG,WAC8B;CACjC,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,GAAA,IAAc,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC8B;CACjC,OAAO,iBAAA,GAAA,kBAAA,KAAC,OAAD;EAAK,YAAA,GAAA,GAAA,IAAc,uBAAuB,SAAS;EAAG,GAAI;CAAO,CAAA;AAC1E;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,GAAA,IAAc,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC+B;CAClC,OAAO,iBAAA,GAAA,kBAAA,KAAC,QAAD;EAAM,YAAA,GAAA,GAAA,IAAc,2BAA2B,SAAS;EAAG,GAAI;CAAO,CAAA;AAC/E;AAEA,MAAM,gBAAgB,EAAE,WAAW,GAAG,WAAwC;CAC5E,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,GAAA,IAGE,sHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -22,7 +22,7 @@ const StatCardContent = ({ className, ...rest }) => {
|
|
|
22
22
|
};
|
|
23
23
|
const StatCardValueContainer = ({ className, ...rest }) => {
|
|
24
24
|
return /* @__PURE__ */ jsx("div", {
|
|
25
|
-
className: cn("flex flex-col gap-
|
|
25
|
+
className: cn("flex flex-col gap-1", className),
|
|
26
26
|
...rest
|
|
27
27
|
});
|
|
28
28
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stat-card.js","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-
|
|
1
|
+
{"version":3,"file":"stat-card.js","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-1', className)} {...rest} />\n}\n\nconst StatCardValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-lg font-bold text-gray tabular-nums', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardSecondaryValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return <span className={cn('text-xs text-gray-light', className)} {...rest} />\n}\n\nconst StatCardIcon = ({ className, ...rest }: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn(\n // max() pill escape (matches Icon): a tile stays rounded-md at low Roundness but\n // becomes a circle at large/full, same as it did pre-harmonization via clamping.\n 'flex size-10 shrink-0 items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]',\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport {\n StatCardContainer,\n StatCardLabel,\n StatCardContent,\n StatCardValueContainer,\n StatCardValue,\n StatCardSecondaryValue,\n StatCardIcon,\n}\n"],"mappings":";;;;AAEA,MAAM,qBAAqB,EACzB,WACA,GAAG,WAC8B;CACjC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,uCAAuC,SAAS;EAC9D,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,mBAAmB,EACvB,WACA,GAAG,WAC8B;CACjC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC8B;CACjC,OAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,uBAAuB,SAAS;EAAG,GAAI;CAAO,CAAA;AAC1E;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC+B;CAClC,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,2BAA2B,SAAS;EAAG,GAAI;CAAO,CAAA;AAC/E;AAEA,MAAM,gBAAgB,EAAE,WAAW,GAAG,WAAwC;CAC5E,OACE,oBAAC,OAAD;EACE,WAAW,GAGT,sHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -146,7 +146,7 @@ function ToastItem({ closeButton, closeLabel, richColors, toast: toastObject })
|
|
|
146
146
|
type: toastObject.type
|
|
147
147
|
}),
|
|
148
148
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_base_ui_react_toast.Toast.Content, {
|
|
149
|
-
className: "flex min-w-0 flex-1 flex-col gap-
|
|
149
|
+
className: "flex min-w-0 flex-1 flex-col gap-1",
|
|
150
150
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_toast.Toast.Title, {
|
|
151
151
|
className: "text-sm font-medium",
|
|
152
152
|
"data-slot": "toast-title"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.cjs","names":["CheckCircle","Info","Warning","Cancel","ToastPrimitive","Spinner","buttonVariants","Close","PortalTheme"],"sources":["../../src/components/toast.tsx"],"sourcesContent":["'use client'\n\nimport { Toast as ToastPrimitive } from '@base-ui/react/toast'\nimport type { BaseUIEvent } from '@base-ui/react/types'\nimport {\n Cancel,\n CheckCircle,\n Close,\n Info,\n Warning,\n type SparkIcon,\n} from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\nimport { buttonVariants } from './button'\nimport { Spinner } from './spinner'\nimport { PortalTheme } from './theme'\n\ntype ToastType = 'success' | 'info' | 'warning' | 'error' | 'loading'\n\ntype ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right'\n\n// Per-toast overrides Base UI carries through untouched as opaque `data`.\ntype ToastData = {\n closeButton?: boolean\n closeLabel?: string\n icon?: React.ReactNode\n onCloseClick?: (event: React.MouseEvent<HTMLButtonElement>) => void\n}\n\n// `label` is the button's content; everything else a `<button>` takes passes\n// straight through, so a caller can set `className`, `disabled`, `type`, and\n// the rest without a new prop for each one.\ntype ToastAction = Omit<\n React.ComponentPropsWithoutRef<'button'>,\n 'children'\n> & {\n label: React.ReactNode\n}\n\ntype ToastOptions = {\n description?: React.ReactNode\n /** Auto-dismiss time in ms. `0` keeps the toast until dismissed. */\n duration?: number\n /** Reuse an id to update a toast in place instead of stacking a new one. */\n id?: string\n closeButton?: boolean\n /** Accessible name of the close button; overrides the Toaster's `closeLabel`. */\n closeLabel?: string\n /**\n * Replaces the type icon. `null` renders no icon. The icon is decorative,\n * so the title has to carry the meaning on its own.\n */\n icon?: React.ReactNode\n /**\n * Runs when the close button is clicked. Call `event.preventDefault()` to\n * keep the toast open, for example to cancel a running download first.\n */\n onCloseClick?: (event: React.MouseEvent<HTMLButtonElement>) => void\n action?: ToastAction\n onDismiss?: () => void\n /** `high` announces urgently (assertive); the default is polite. */\n priority?: 'low' | 'high'\n}\n\ntype ToastPromiseMessages<Value> = {\n loading: string\n success: string | ((value: Value) => string)\n error: string | ((error: unknown) => string)\n}\n\nconst TOAST_ICONS: Record<\n Exclude<ToastType, 'loading'>,\n { icon: SparkIcon; className: string }\n> = {\n success: { icon: CheckCircle, className: 'text-success-light' },\n info: { icon: Info, className: 'text-info-light' },\n warning: { icon: Warning, className: 'text-warning-light' },\n error: { icon: Cancel, className: 'text-error-light' },\n}\n\n// Opaque radix steps (bg 2, border 6, text 11) so a floating toast never lets\n// page content bleed through the way the alpha `-soft` tokens would. The border\n// carries the tone too, otherwise a tinted toast keeps a grey outline.\nconst TONE_CLASSES: Record<Exclude<ToastType, 'loading'>, string> = {\n success: 'border-green-6 bg-green-2 text-green-11',\n info: 'border-blue-6 bg-blue-2 text-blue-11',\n warning: 'border-orange-6 bg-orange-2 text-orange-11',\n error: 'border-red-6 bg-red-2 text-red-11',\n}\n\n// Mobile-first: every position drops to a full-width stack at the top, which\n// is what the end-customer portal ships. `position` only takes effect from the\n// `sm` breakpoint up.\nconst POSITION_CLASSES: Record<ToastPosition, string> = {\n 'top-left': 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-4',\n 'top-center':\n 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-1/2 sm:-translate-x-1/2',\n 'top-right': 'sm:top-4 sm:right-4 sm:bottom-auto sm:left-auto',\n 'bottom-left': 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-4',\n 'bottom-center':\n 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-1/2 sm:-translate-x-1/2',\n 'bottom-right': 'sm:top-auto sm:right-4 sm:bottom-4 sm:left-auto',\n}\n\nconst manager = ToastPrimitive.createToastManager<ToastData>()\n\nlet sequence = 0\n\n// `label` names the content and `onClick` is wrapped, so neither reaches the\n// DOM button as-is; everything else does.\nfunction actionRest({\n label: _label,\n onClick: _onClick,\n ...rest\n}: ToastAction) {\n return rest\n}\n\nfunction toManagerOptions(\n id: string,\n title: React.ReactNode,\n type: ToastType | undefined,\n options: ToastOptions | undefined,\n) {\n const action = options?.action\n return {\n id,\n title,\n type,\n description: options?.description,\n timeout: options?.duration,\n priority: options?.priority,\n onClose: options?.onDismiss,\n // Base UI leaves the toast open after an action; dismissing matches what\n // callers expect from an \"Undo\" button.\n actionProps: action && {\n ...actionRest(action),\n children: action.label,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n action.onClick?.(event)\n manager.close(id)\n },\n },\n data: {\n closeButton: options?.closeButton,\n closeLabel: options?.closeLabel,\n icon: options?.icon,\n onCloseClick: options?.onCloseClick,\n },\n }\n}\n\nconst emit =\n (type?: ToastType) =>\n (message: React.ReactNode, options?: ToastOptions): string => {\n // an id up front lets the action handler close the toast it belongs to\n const id = options?.id ?? `spark-toast-${(sequence += 1)}`\n return manager.add(toManagerOptions(id, message, type, options))\n }\n\n// A string phase becomes a titled toast of that type; an object phase keeps\n// whatever the caller set and only fills in the type.\nconst phase =\n <Value,>(\n value: ToastPromiseMessages<Value>[keyof ToastPromiseMessages<Value>],\n type: ToastType,\n ) =>\n (result: Value) => {\n const resolved = typeof value === 'function' ? value(result) : value\n return { title: resolved, type }\n }\n\nconst toast = Object.assign(emit(), {\n success: emit('success'),\n info: emit('info'),\n warning: emit('warning'),\n error: emit('error'),\n loading: emit('loading'),\n /** Dismiss one toast, or every toast when called without an id. */\n dismiss: (id?: string) => manager.close(id),\n promise: <Value,>(\n promiseValue: Promise<Value>,\n messages: ToastPromiseMessages<Value>,\n ) =>\n manager.promise(promiseValue, {\n loading: { title: messages.loading, type: 'loading' as const },\n success: phase(messages.success, 'success'),\n error: phase(messages.error as never, 'error'),\n }),\n})\n\nfunction ToastIcon({\n custom,\n type,\n}: {\n custom: React.ReactNode | undefined\n type?: string\n}) {\n const icon = TOAST_ICONS[type as Exclude<ToastType, 'loading'>]\n if (custom !== undefined) {\n if (custom === null || custom === false) return null\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center [--spark-icon-size:20px]\"\n data-slot=\"toast-icon\"\n >\n {custom}\n </span>\n )\n }\n if (type !== 'loading' && !icon) return null\n\n const Glyph = icon?.icon\n\n // Fixed box matching the title's line height, so the glyph and the spinner\n // both centre on the first line whether or not a description follows.\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center\"\n data-slot=\"toast-icon\"\n >\n {type === 'loading' ? (\n // Decorative: the toast already announces the loading message, so the\n // spinner must not add a second status live region.\n <Spinner\n className=\"text-gray-11\"\n label=\"\"\n role=\"presentation\"\n size=\"sm\"\n />\n ) : Glyph ? (\n <Glyph className={cn('[--spark-icon-size:20px]', icon.className)} />\n ) : null}\n </span>\n )\n}\n\nfunction ToastItem({\n closeButton,\n closeLabel,\n richColors,\n toast: toastObject,\n}: {\n closeButton: boolean\n closeLabel: string\n richColors: boolean\n toast: ToastPrimitive.Root.ToastObject<ToastData>\n}) {\n const tone = TONE_CLASSES[toastObject.type as Exclude<ToastType, 'loading'>]\n const showClose = toastObject.data?.closeButton ?? closeButton\n const onCloseClick = toastObject.data?.onCloseClick\n\n return (\n <ToastPrimitive.Root\n data-slot=\"toast\"\n className={cn(\n // Skin only. All geometry (position, stacking, transitions, the\n // pointer bridge) lives in styles/index.css, because Tailwind's\n // `utilities` layer outranks `components` and a stray `bottom-0` here\n // would beat the stylesheet's `bottom: auto` on top-anchored stacks.\n // The border is what makes the cards behind the front one legible.\n 'flex items-start gap-2 rounded-lg border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none',\n richColors && tone,\n )}\n // the stack is top-anchored on mobile and bottom-anchored above `sm`, so\n // both vertical directions have to dismiss\n swipeDirection={['up', 'down', 'right']}\n toast={toastObject}\n >\n <ToastIcon custom={toastObject.data?.icon} type={toastObject.type} />\n <ToastPrimitive.Content className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <ToastPrimitive.Title\n className=\"text-sm font-medium\"\n data-slot=\"toast-title\"\n />\n <ToastPrimitive.Description\n className={cn(\n 'text-sm',\n richColors && tone ? 'text-inherit' : 'text-gray-11',\n )}\n data-slot=\"toast-description\"\n />\n </ToastPrimitive.Content>\n {toastObject.actionProps ? (\n <ToastPrimitive.Action\n // -my-2 keeps the 36px control from stretching a single-line row past\n // the 20px text; self-center then lands it on the title when there is\n // no description, and mid-block when there is one\n className={cn(\n buttonVariants({ size: 'small', variant: 'primary' }),\n '-my-2 shrink-0 self-center rounded-full',\n )}\n data-slot=\"toast-action\"\n />\n ) : null}\n {showClose ? (\n <ToastPrimitive.Close\n aria-label={toastObject.data?.closeLabel ?? closeLabel}\n className={cn(\n buttonVariants({ size: 'icon-small', variant: 'tertiary' }),\n // -my-1: same reason as the action, for a 28px control\n '-my-1 -mr-1 size-7 shrink-0 self-center text-gray-11',\n )}\n data-slot=\"toast-close\"\n onClick={\n onCloseClick &&\n ((event: BaseUIEvent<React.MouseEvent<HTMLButtonElement>>) => {\n onCloseClick(event)\n // Base UI's own close runs after this handler unless prevented.\n if (event.defaultPrevented) event.preventBaseUIHandler()\n })\n }\n >\n <Close aria-hidden=\"true\" className=\"[--spark-icon-size:18px]\" />\n </ToastPrimitive.Close>\n ) : null}\n </ToastPrimitive.Root>\n )\n}\n\nfunction ToastList({\n closeButton,\n closeLabel,\n richColors,\n}: {\n closeButton: boolean\n closeLabel: string\n richColors: boolean\n}) {\n const { toasts } = ToastPrimitive.useToastManager<ToastData>()\n\n return toasts.map((toastObject) => (\n <ToastItem\n closeButton={closeButton}\n closeLabel={closeLabel}\n key={toastObject.id}\n richColors={richColors}\n toast={toastObject}\n />\n ))\n}\n\ntype ToasterProps = {\n className?: string\n /** Corner or edge the toasts stack in. */\n position?: ToastPosition\n /** Close button on every toast; a per-toast `closeButton` wins. */\n closeButton?: boolean\n /** Accessible name of every close button; a per-toast `closeLabel` wins. */\n closeLabel?: string\n /** Tinted surfaces for success/info/warning/error toasts. */\n richColors?: boolean\n /** Default auto-dismiss time in ms. `0` disables auto-dismiss. */\n duration?: number\n /** Toasts visible at once before older ones are marked `data-limited`. */\n limit?: number\n /**\n * Vertical edge below the `sm` breakpoint, where the stack is always\n * full-width and `position` does not apply. Defaults to `top`, matching the\n * end-customer portal.\n */\n mobilePosition?: 'top' | 'bottom'\n}\n\nfunction Toaster({\n className,\n closeButton = true,\n closeLabel = 'Close',\n duration = 4000,\n limit,\n mobilePosition = 'top',\n position = 'bottom-right',\n richColors = true,\n}: ToasterProps) {\n return (\n <ToastPrimitive.Provider\n limit={limit}\n timeout={duration}\n toastManager={manager}\n >\n <ToastPrimitive.Portal>\n <PortalTheme>\n <ToastPrimitive.Viewport\n // block + zero height: the toasts are absolutely positioned against\n // this box's bottom edge, the way Base UI's stacked example works\n className={cn(\n 'fixed inset-x-4 z-50 block h-0 outline-none',\n mobilePosition === 'top' ? 'top-4' : 'bottom-4',\n 'sm:inset-x-auto sm:w-96 sm:max-w-[calc(100vw-2rem)]',\n POSITION_CLASSES[position],\n className,\n )}\n data-mobile-side={mobilePosition}\n data-side={position.startsWith('top') ? 'top' : 'bottom'}\n data-slot=\"toaster\"\n >\n <ToastList\n closeButton={closeButton}\n closeLabel={closeLabel}\n richColors={richColors}\n />\n </ToastPrimitive.Viewport>\n </PortalTheme>\n </ToastPrimitive.Portal>\n </ToastPrimitive.Provider>\n )\n}\n\nexport { Toaster, toast }\nexport type {\n ToastAction,\n ToasterProps,\n ToastOptions,\n ToastPosition,\n ToastPromiseMessages,\n ToastType,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toast.cjs","names":["CheckCircle","Info","Warning","Cancel","ToastPrimitive","Spinner","buttonVariants","Close","PortalTheme"],"sources":["../../src/components/toast.tsx"],"sourcesContent":["'use client'\n\nimport { Toast as ToastPrimitive } from '@base-ui/react/toast'\nimport type { BaseUIEvent } from '@base-ui/react/types'\nimport {\n Cancel,\n CheckCircle,\n Close,\n Info,\n Warning,\n type SparkIcon,\n} from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\nimport { buttonVariants } from './button'\nimport { Spinner } from './spinner'\nimport { PortalTheme } from './theme'\n\ntype ToastType = 'success' | 'info' | 'warning' | 'error' | 'loading'\n\ntype ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right'\n\n// Per-toast overrides Base UI carries through untouched as opaque `data`.\ntype ToastData = {\n closeButton?: boolean\n closeLabel?: string\n icon?: React.ReactNode\n onCloseClick?: (event: React.MouseEvent<HTMLButtonElement>) => void\n}\n\n// `label` is the button's content; everything else a `<button>` takes passes\n// straight through, so a caller can set `className`, `disabled`, `type`, and\n// the rest without a new prop for each one.\ntype ToastAction = Omit<\n React.ComponentPropsWithoutRef<'button'>,\n 'children'\n> & {\n label: React.ReactNode\n}\n\ntype ToastOptions = {\n description?: React.ReactNode\n /** Auto-dismiss time in ms. `0` keeps the toast until dismissed. */\n duration?: number\n /** Reuse an id to update a toast in place instead of stacking a new one. */\n id?: string\n closeButton?: boolean\n /** Accessible name of the close button; overrides the Toaster's `closeLabel`. */\n closeLabel?: string\n /**\n * Replaces the type icon. `null` renders no icon. The icon is decorative,\n * so the title has to carry the meaning on its own.\n */\n icon?: React.ReactNode\n /**\n * Runs when the close button is clicked. Call `event.preventDefault()` to\n * keep the toast open, for example to cancel a running download first.\n */\n onCloseClick?: (event: React.MouseEvent<HTMLButtonElement>) => void\n action?: ToastAction\n onDismiss?: () => void\n /** `high` announces urgently (assertive); the default is polite. */\n priority?: 'low' | 'high'\n}\n\ntype ToastPromiseMessages<Value> = {\n loading: string\n success: string | ((value: Value) => string)\n error: string | ((error: unknown) => string)\n}\n\nconst TOAST_ICONS: Record<\n Exclude<ToastType, 'loading'>,\n { icon: SparkIcon; className: string }\n> = {\n success: { icon: CheckCircle, className: 'text-success-light' },\n info: { icon: Info, className: 'text-info-light' },\n warning: { icon: Warning, className: 'text-warning-light' },\n error: { icon: Cancel, className: 'text-error-light' },\n}\n\n// Opaque radix steps (bg 2, border 6, text 11) so a floating toast never lets\n// page content bleed through the way the alpha `-soft` tokens would. The border\n// carries the tone too, otherwise a tinted toast keeps a grey outline.\nconst TONE_CLASSES: Record<Exclude<ToastType, 'loading'>, string> = {\n success: 'border-green-6 bg-green-2 text-green-11',\n info: 'border-blue-6 bg-blue-2 text-blue-11',\n warning: 'border-orange-6 bg-orange-2 text-orange-11',\n error: 'border-red-6 bg-red-2 text-red-11',\n}\n\n// Mobile-first: every position drops to a full-width stack at the top, which\n// is what the end-customer portal ships. `position` only takes effect from the\n// `sm` breakpoint up.\nconst POSITION_CLASSES: Record<ToastPosition, string> = {\n 'top-left': 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-4',\n 'top-center':\n 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-1/2 sm:-translate-x-1/2',\n 'top-right': 'sm:top-4 sm:right-4 sm:bottom-auto sm:left-auto',\n 'bottom-left': 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-4',\n 'bottom-center':\n 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-1/2 sm:-translate-x-1/2',\n 'bottom-right': 'sm:top-auto sm:right-4 sm:bottom-4 sm:left-auto',\n}\n\nconst manager = ToastPrimitive.createToastManager<ToastData>()\n\nlet sequence = 0\n\n// `label` names the content and `onClick` is wrapped, so neither reaches the\n// DOM button as-is; everything else does.\nfunction actionRest({\n label: _label,\n onClick: _onClick,\n ...rest\n}: ToastAction) {\n return rest\n}\n\nfunction toManagerOptions(\n id: string,\n title: React.ReactNode,\n type: ToastType | undefined,\n options: ToastOptions | undefined,\n) {\n const action = options?.action\n return {\n id,\n title,\n type,\n description: options?.description,\n timeout: options?.duration,\n priority: options?.priority,\n onClose: options?.onDismiss,\n // Base UI leaves the toast open after an action; dismissing matches what\n // callers expect from an \"Undo\" button.\n actionProps: action && {\n ...actionRest(action),\n children: action.label,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n action.onClick?.(event)\n manager.close(id)\n },\n },\n data: {\n closeButton: options?.closeButton,\n closeLabel: options?.closeLabel,\n icon: options?.icon,\n onCloseClick: options?.onCloseClick,\n },\n }\n}\n\nconst emit =\n (type?: ToastType) =>\n (message: React.ReactNode, options?: ToastOptions): string => {\n // an id up front lets the action handler close the toast it belongs to\n const id = options?.id ?? `spark-toast-${(sequence += 1)}`\n return manager.add(toManagerOptions(id, message, type, options))\n }\n\n// A string phase becomes a titled toast of that type; an object phase keeps\n// whatever the caller set and only fills in the type.\nconst phase =\n <Value,>(\n value: ToastPromiseMessages<Value>[keyof ToastPromiseMessages<Value>],\n type: ToastType,\n ) =>\n (result: Value) => {\n const resolved = typeof value === 'function' ? value(result) : value\n return { title: resolved, type }\n }\n\nconst toast = Object.assign(emit(), {\n success: emit('success'),\n info: emit('info'),\n warning: emit('warning'),\n error: emit('error'),\n loading: emit('loading'),\n /** Dismiss one toast, or every toast when called without an id. */\n dismiss: (id?: string) => manager.close(id),\n promise: <Value,>(\n promiseValue: Promise<Value>,\n messages: ToastPromiseMessages<Value>,\n ) =>\n manager.promise(promiseValue, {\n loading: { title: messages.loading, type: 'loading' as const },\n success: phase(messages.success, 'success'),\n error: phase(messages.error as never, 'error'),\n }),\n})\n\nfunction ToastIcon({\n custom,\n type,\n}: {\n custom: React.ReactNode | undefined\n type?: string\n}) {\n const icon = TOAST_ICONS[type as Exclude<ToastType, 'loading'>]\n if (custom !== undefined) {\n if (custom === null || custom === false) return null\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center [--spark-icon-size:20px]\"\n data-slot=\"toast-icon\"\n >\n {custom}\n </span>\n )\n }\n if (type !== 'loading' && !icon) return null\n\n const Glyph = icon?.icon\n\n // Fixed box matching the title's line height, so the glyph and the spinner\n // both centre on the first line whether or not a description follows.\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center\"\n data-slot=\"toast-icon\"\n >\n {type === 'loading' ? (\n // Decorative: the toast already announces the loading message, so the\n // spinner must not add a second status live region.\n <Spinner\n className=\"text-gray-11\"\n label=\"\"\n role=\"presentation\"\n size=\"sm\"\n />\n ) : Glyph ? (\n <Glyph className={cn('[--spark-icon-size:20px]', icon.className)} />\n ) : null}\n </span>\n )\n}\n\nfunction ToastItem({\n closeButton,\n closeLabel,\n richColors,\n toast: toastObject,\n}: {\n closeButton: boolean\n closeLabel: string\n richColors: boolean\n toast: ToastPrimitive.Root.ToastObject<ToastData>\n}) {\n const tone = TONE_CLASSES[toastObject.type as Exclude<ToastType, 'loading'>]\n const showClose = toastObject.data?.closeButton ?? closeButton\n const onCloseClick = toastObject.data?.onCloseClick\n\n return (\n <ToastPrimitive.Root\n data-slot=\"toast\"\n className={cn(\n // Skin only. All geometry (position, stacking, transitions, the\n // pointer bridge) lives in styles/index.css, because Tailwind's\n // `utilities` layer outranks `components` and a stray `bottom-0` here\n // would beat the stylesheet's `bottom: auto` on top-anchored stacks.\n // The border is what makes the cards behind the front one legible.\n 'flex items-start gap-2 rounded-lg border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none',\n richColors && tone,\n )}\n // the stack is top-anchored on mobile and bottom-anchored above `sm`, so\n // both vertical directions have to dismiss\n swipeDirection={['up', 'down', 'right']}\n toast={toastObject}\n >\n <ToastIcon custom={toastObject.data?.icon} type={toastObject.type} />\n <ToastPrimitive.Content className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <ToastPrimitive.Title\n className=\"text-sm font-medium\"\n data-slot=\"toast-title\"\n />\n <ToastPrimitive.Description\n className={cn(\n 'text-sm',\n richColors && tone ? 'text-inherit' : 'text-gray-11',\n )}\n data-slot=\"toast-description\"\n />\n </ToastPrimitive.Content>\n {toastObject.actionProps ? (\n <ToastPrimitive.Action\n // -my-2 keeps the 36px control from stretching a single-line row past\n // the 20px text; self-center then lands it on the title when there is\n // no description, and mid-block when there is one\n className={cn(\n buttonVariants({ size: 'small', variant: 'primary' }),\n '-my-2 shrink-0 self-center rounded-full',\n )}\n data-slot=\"toast-action\"\n />\n ) : null}\n {showClose ? (\n <ToastPrimitive.Close\n aria-label={toastObject.data?.closeLabel ?? closeLabel}\n className={cn(\n buttonVariants({ size: 'icon-small', variant: 'tertiary' }),\n // -my-1: same reason as the action, for a 28px control\n '-my-1 -mr-1 size-7 shrink-0 self-center text-gray-11',\n )}\n data-slot=\"toast-close\"\n onClick={\n onCloseClick &&\n ((event: BaseUIEvent<React.MouseEvent<HTMLButtonElement>>) => {\n onCloseClick(event)\n // Base UI's own close runs after this handler unless prevented.\n if (event.defaultPrevented) event.preventBaseUIHandler()\n })\n }\n >\n <Close aria-hidden=\"true\" className=\"[--spark-icon-size:18px]\" />\n </ToastPrimitive.Close>\n ) : null}\n </ToastPrimitive.Root>\n )\n}\n\nfunction ToastList({\n closeButton,\n closeLabel,\n richColors,\n}: {\n closeButton: boolean\n closeLabel: string\n richColors: boolean\n}) {\n const { toasts } = ToastPrimitive.useToastManager<ToastData>()\n\n return toasts.map((toastObject) => (\n <ToastItem\n closeButton={closeButton}\n closeLabel={closeLabel}\n key={toastObject.id}\n richColors={richColors}\n toast={toastObject}\n />\n ))\n}\n\ntype ToasterProps = {\n className?: string\n /** Corner or edge the toasts stack in. */\n position?: ToastPosition\n /** Close button on every toast; a per-toast `closeButton` wins. */\n closeButton?: boolean\n /** Accessible name of every close button; a per-toast `closeLabel` wins. */\n closeLabel?: string\n /** Tinted surfaces for success/info/warning/error toasts. */\n richColors?: boolean\n /** Default auto-dismiss time in ms. `0` disables auto-dismiss. */\n duration?: number\n /** Toasts visible at once before older ones are marked `data-limited`. */\n limit?: number\n /**\n * Vertical edge below the `sm` breakpoint, where the stack is always\n * full-width and `position` does not apply. Defaults to `top`, matching the\n * end-customer portal.\n */\n mobilePosition?: 'top' | 'bottom'\n}\n\nfunction Toaster({\n className,\n closeButton = true,\n closeLabel = 'Close',\n duration = 4000,\n limit,\n mobilePosition = 'top',\n position = 'bottom-right',\n richColors = true,\n}: ToasterProps) {\n return (\n <ToastPrimitive.Provider\n limit={limit}\n timeout={duration}\n toastManager={manager}\n >\n <ToastPrimitive.Portal>\n <PortalTheme>\n <ToastPrimitive.Viewport\n // block + zero height: the toasts are absolutely positioned against\n // this box's bottom edge, the way Base UI's stacked example works\n className={cn(\n 'fixed inset-x-4 z-50 block h-0 outline-none',\n mobilePosition === 'top' ? 'top-4' : 'bottom-4',\n 'sm:inset-x-auto sm:w-96 sm:max-w-[calc(100vw-2rem)]',\n POSITION_CLASSES[position],\n className,\n )}\n data-mobile-side={mobilePosition}\n data-side={position.startsWith('top') ? 'top' : 'bottom'}\n data-slot=\"toaster\"\n >\n <ToastList\n closeButton={closeButton}\n closeLabel={closeLabel}\n richColors={richColors}\n />\n </ToastPrimitive.Viewport>\n </PortalTheme>\n </ToastPrimitive.Portal>\n </ToastPrimitive.Provider>\n )\n}\n\nexport { Toaster, toast }\nexport type {\n ToastAction,\n ToasterProps,\n ToastOptions,\n ToastPosition,\n ToastPromiseMessages,\n ToastType,\n}\n"],"mappings":"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"}
|
package/dist/components/toast.js
CHANGED
|
@@ -143,7 +143,7 @@ function ToastItem({ closeButton, closeLabel, richColors, toast: toastObject })
|
|
|
143
143
|
type: toastObject.type
|
|
144
144
|
}),
|
|
145
145
|
/* @__PURE__ */ jsxs(Toast.Content, {
|
|
146
|
-
className: "flex min-w-0 flex-1 flex-col gap-
|
|
146
|
+
className: "flex min-w-0 flex-1 flex-col gap-1",
|
|
147
147
|
children: [/* @__PURE__ */ jsx(Toast.Title, {
|
|
148
148
|
className: "text-sm font-medium",
|
|
149
149
|
"data-slot": "toast-title"
|