@fabio.caffarello/react-design-system 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/granular/index.js +438 -431
- package/dist/granular/index.js.map +1 -1
- package/dist/granular/ui/primitives/DataBadge/DataBadge.js +137 -0
- package/dist/granular/ui/primitives/DataBadge/DataBadge.js.map +1 -0
- package/dist/granular/ui/primitives/Input/Input.js +121 -317
- package/dist/granular/ui/primitives/Input/Input.js.map +1 -1
- package/dist/granular/ui/primitives/Input/InputBase.js +223 -0
- package/dist/granular/ui/primitives/Input/InputBase.js.map +1 -0
- package/dist/granular/ui/tokens/chart.js +73 -0
- package/dist/granular/ui/tokens/chart.js.map +1 -0
- package/dist/index.cjs +72 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3508 -3336
- package/dist/index.js.map +1 -1
- package/dist/react-design-system.css +1 -1
- package/dist/server/index.cjs +20 -20
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +1070 -773
- package/dist/server/index.js.map +1 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/primitives/DataBadge/DataBadge.d.ts +56 -0
- package/dist/ui/primitives/DataBadge/index.d.ts +2 -0
- package/dist/ui/primitives/Input/Input.d.ts +13 -15
- package/dist/ui/primitives/Input/InputBase.d.ts +52 -0
- package/dist/ui/primitives/Input/index.d.ts +2 -0
- package/dist/ui/primitives/index.d.ts +2 -0
- package/dist/ui/server.d.ts +4 -0
- package/dist/ui/tokens/TokenVisualizations.d.ts +17 -0
- package/dist/ui/tokens/chart.d.ts +79 -0
- package/dist/ui/tokens/index.d.ts +3 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sources":["../../../../../src/ui/primitives/Input/Input.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef, useState, memo, useId, useMemo, useCallback } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport {\n getTypographyClasses,\n getTypographySize,\n} from \"../../tokens/typography\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { cn, cva } from \"../../utils\";\nimport { X, Eye, EyeOff } from \"lucide-react\";\nimport Button from \"../Button/Button\";\n\n/**\n * Helper Text Component\n * Memoized component for helper/error text\n */\nconst HelperText = memo(function HelperText({\n error,\n success,\n helperText,\n errorId,\n helperId,\n}: {\n error: boolean;\n success: boolean;\n helperText?: string;\n errorId?: string;\n helperId?: string;\n}) {\n const helperClasses = useMemo(\n () =>\n cn(\n getSpacingClass(\"xs\", \"mt\"),\n getTypographyClasses(\"caption\"),\n error && \"text-fg-error\",\n success && \"text-fg-success\",\n !error && !success && \"text-fg-secondary\",\n ),\n [error, success],\n );\n\n const text = useMemo(\n () => helperText || (error ? \"Error\" : success ? \"Success\" : \"\"),\n [helperText, error, success],\n );\n\n return (\n <div\n id={errorId || helperId}\n className={helperClasses}\n role={error || success ? \"alert\" : undefined}\n >\n {text}\n </div>\n );\n});\n\nexport type InputSize = \"sm\" | \"md\" | \"lg\";\nexport type InputVariant = \"default\" | \"outlined\" | \"filled\";\nexport type InputState = \"default\" | \"error\" | \"success\";\n\nexport interface InputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n> {\n label?: ReactNode;\n error?: boolean;\n success?: boolean;\n helperText?: string;\n size?: InputSize;\n variant?: InputVariant;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n showClearButton?: boolean;\n onClear?: () => void;\n}\n\n/**\n * Input Component\n *\n * A styled text input component with label, error/success states, icons, and clear button.\n * Uses Composite Pattern when combined with Label and ErrorMessage.\n *\n * @example\n * ```tsx\n * <Input\n * id=\"email\"\n * label=\"Email\"\n * type=\"email\"\n * placeholder=\"Enter your email\"\n * error={hasError}\n * helperText={errorMessage}\n * leftIcon={<MailIcon />}\n * />\n * ```\n */\nconst Input = memo(\n forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n id,\n label,\n error = false,\n success = false,\n helperText,\n size = \"md\",\n variant = \"outlined\",\n leftIcon,\n rightIcon,\n showClearButton = false,\n onClear,\n className = \"\",\n disabled = false,\n type = \"text\",\n value,\n onChange,\n ...props\n },\n ref,\n ) {\n // Stable fallback id when the consumer doesn't provide one. useId\n // is SSR-safe and stable across renders, replacing the deprecated\n // Math.random().substr() pattern.\n const reactId = useId();\n const inputId = id || `input-${reactId}`;\n\n // Memoize error and helper IDs\n const errorId = useMemo(\n () => (error ? `${inputId}-error` : undefined),\n [error, inputId],\n );\n\n const helperId = useMemo(\n () => (helperText ? `${inputId}-helper` : undefined),\n [helperText, inputId],\n );\n\n // Password toggle state\n const [showPassword, setShowPassword] = useState(false);\n\n // Memoize password-related values\n const isPassword = useMemo(() => type === \"password\", [type]);\n const inputType = useMemo(\n () => (isPassword && showPassword ? \"text\" : type),\n [isPassword, showPassword, type],\n );\n\n // Memoize state\n const state = useMemo<InputState>(\n () => (error ? \"error\" : success ? \"success\" : \"default\"),\n [error, success],\n );\n\n // Memoize clear button visibility\n const hasValue = useMemo(\n () => value !== undefined && value !== null && value !== \"\",\n [value],\n );\n\n const shouldShowClear = useMemo(\n () => showClearButton && hasValue && !disabled,\n [showClearButton, hasValue, disabled],\n );\n\n // Memoize focus ring colors\n const primaryFocusRing = useMemo(() => \"focus:border-line-focus\", []);\n\n const errorFocusRing = useMemo(() => \"focus:border-error\", []);\n\n const successFocusRing = useMemo(() => \"focus:border-success\", []);\n\n const getFocusRingColor = useMemo(\n () => primaryFocusRing.replace(\"focus:border-\", \"focus:ring-\"),\n [primaryFocusRing],\n );\n\n const getStateFocusRingColor = useCallback(\n (stateType: \"error\" | \"success\"): string => {\n return stateType === \"error\"\n ? errorFocusRing.replace(\"focus:border-\", \"focus:ring-\")\n : successFocusRing.replace(\"focus:border-\", \"focus:ring-\");\n },\n [errorFocusRing, successFocusRing],\n );\n\n // Input variants using CVA — memoize so the function reference is\n // stable across renders. inputClasses below depends on this; without\n // memoization a fresh cva() each render would invalidate that memo\n // on every render (defeating its purpose).\n const inputVariants = useMemo(\n () =>\n cva(\n // Base classes\n cn(\n \"w-full\",\n getRadiusClass(\"md\"),\n \"transition-colors\",\n \"focus:outline-none\",\n \"focus:ring-2\",\n \"focus:ring-offset-2\",\n \"disabled:opacity-50\",\n \"disabled:cursor-not-allowed\",\n ),\n {\n variants: {\n variant: {\n default: cn(\n \"border-0\",\n \"border-b-2\",\n \"border-line-default\",\n \"focus:border-line-focus\",\n ),\n outlined: cn(\n \"border\",\n \"border-line-default\",\n \"focus:border-line-focus\",\n ),\n filled: cn(\n \"bg-surface-muted\",\n \"border-0\",\n \"focus:bg-surface-base\",\n \"focus:ring-2\",\n getFocusRingColor,\n ),\n },\n size: {\n sm: cn(\n \"h-8\",\n getTypographySize(\"bodySmall\"),\n getSpacingClass(\"md\", \"px\"),\n ),\n md: cn(\n \"h-10\",\n getTypographySize(\"body\"),\n getSpacingClass(\"base\", \"px\"),\n ),\n lg: cn(\n \"h-12\",\n getTypographySize(\"bodyLarge\"),\n getSpacingClass(\"lg\", \"px\"),\n ),\n },\n state: {\n default: \"\",\n error: cn(\n \"border-error\",\n \"focus:border-error\",\n getStateFocusRingColor(\"error\"),\n ),\n success: cn(\n \"border-success\",\n \"focus:border-success\",\n getStateFocusRingColor(\"success\"),\n ),\n },\n },\n defaultVariants: {\n variant: \"outlined\",\n size: \"md\",\n state: \"default\",\n },\n },\n ),\n [getFocusRingColor, getStateFocusRingColor],\n );\n\n // Memoize input classes\n const inputClasses = useMemo(\n () =>\n cn(\n inputVariants({ variant, size, state }),\n // Icon padding - specific values for icon positioning.\n // `pl-9` / `pr-9` aren't on the spacing scale (no semantic\n // key for 36px); they stay raw until a future PR either\n // extends the scale or refactors the icon-padding contract.\n leftIcon &&\n (size === \"sm\"\n ? \"pl-9\"\n : size === \"lg\"\n ? getSpacingClass(\"3xl\", \"pl\")\n : getSpacingClass(\"2xl\", \"pl\")),\n (rightIcon || shouldShowClear || isPassword) &&\n (size === \"sm\"\n ? \"pr-9\"\n : size === \"lg\"\n ? getSpacingClass(\"3xl\", \"pr\")\n : getSpacingClass(\"2xl\", \"pr\")),\n className,\n ),\n [\n inputVariants,\n variant,\n size,\n state,\n leftIcon,\n rightIcon,\n shouldShowClear,\n isPassword,\n className,\n ],\n );\n\n // Memoize label classes\n const labelClasses = useMemo(\n () =>\n cn(\n \"block\",\n getTypographyClasses(\"label\"),\n getSpacingClass(\"xs\", \"mb\"),\n disabled && \"opacity-50\",\n ),\n [disabled],\n );\n\n // Memoize icon size and position\n const iconSize = useMemo(\n () => (size === \"sm\" ? \"h-4 w-4\" : size === \"lg\" ? \"h-5 w-5\" : \"h-4 w-4\"),\n [size],\n );\n\n const iconPosition = useMemo(\n () => (size === \"sm\" ? \"top-2\" : size === \"lg\" ? \"top-3.5\" : \"top-2.5\"),\n [size],\n );\n\n // Memoize clear handler\n const handleClear = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onClear) {\n onClear();\n } else if (onChange) {\n // Create synthetic event to clear input\n const inputElement = e.currentTarget\n .closest(\".relative\")\n ?.querySelector(\"input\") as HTMLInputElement;\n if (inputElement) {\n const syntheticEvent = {\n target: inputElement,\n currentTarget: inputElement,\n bubbles: true,\n cancelable: true,\n defaultPrevented: false,\n eventPhase: 2,\n isTrusted: false,\n nativeEvent: new Event(\"change\"),\n preventDefault: () => {},\n stopPropagation: () => {},\n persist: () => {},\n timeStamp: Date.now(),\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n Object.defineProperty(syntheticEvent.target, \"value\", {\n value: \"\",\n writable: true,\n });\n Object.defineProperty(syntheticEvent.currentTarget, \"value\", {\n value: \"\",\n writable: true,\n });\n onChange(syntheticEvent);\n }\n }\n },\n [onClear, onChange],\n );\n\n // Memoize password toggle handler\n const handleTogglePassword = useCallback(() => {\n setShowPassword((prev) => !prev);\n }, []);\n\n return (\n <div className=\"w-full\">\n {label && (\n <label htmlFor={inputId} className={labelClasses}>\n {label}\n </label>\n )}\n <div className=\"relative\">\n {leftIcon && (\n <div\n className={`absolute left-3 ${iconPosition} text-fg-secondary opacity-60 pointer-events-none`}\n >\n <div className={iconSize}>{leftIcon}</div>\n </div>\n )}\n <input\n id={inputId}\n ref={ref}\n type={inputType}\n className={inputClasses}\n disabled={disabled}\n value={value}\n onChange={onChange}\n aria-invalid={error}\n aria-required={props.required}\n aria-describedby={errorId || helperId}\n suppressHydrationWarning\n {...props}\n />\n <div\n className={`absolute right-3 top-0 bottom-0 flex items-center ${getSpacingClass(\"xs\", \"gap\")}`}\n >\n {shouldShowClear && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleClear}\n className={`h-auto ${getSpacingClass(\"xs\", \"p\")}`}\n aria-label=\"Clear input\"\n >\n <X className={iconSize} />\n </Button>\n )}\n {isPassword && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleTogglePassword}\n className={`h-auto ${getSpacingClass(\"xs\", \"p\")}`}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n >\n {showPassword ? (\n <EyeOff className={iconSize} />\n ) : (\n <Eye className={iconSize} />\n )}\n </Button>\n )}\n {rightIcon && !shouldShowClear && !isPassword && (\n <div\n className={`text-fg-secondary opacity-60 pointer-events-none ${iconSize}`}\n >\n {rightIcon}\n </div>\n )}\n </div>\n </div>\n {(error || success || helperText) && (\n <HelperText\n error={error}\n success={success}\n helperText={helperText}\n errorId={errorId}\n helperId={helperId}\n />\n )}\n </div>\n );\n }),\n);\n\nInput.displayName = \"Input\";\n\nexport default Input;\n"],"names":["HelperText","memo","error","success","helperText","errorId","helperId","helperClasses","useMemo","cn","getSpacingClass","getTypographyClasses","text","jsx","Input","forwardRef","_a","ref","_b","id","label","size","variant","leftIcon","rightIcon","showClearButton","onClear","className","disabled","type","value","onChange","props","__objRest","reactId","useId","inputId","showPassword","setShowPassword","useState","isPassword","inputType","state","hasValue","shouldShowClear","primaryFocusRing","errorFocusRing","successFocusRing","getFocusRingColor","getStateFocusRingColor","useCallback","stateType","inputVariants","cva","getRadiusClass","getTypographySize","inputClasses","labelClasses","iconSize","iconPosition","handleClear","e","inputElement","syntheticEvent","handleTogglePassword","prev","jsxs","__spreadValues","Button","X","EyeOff","Eye"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Input.js","sources":["../../../../../src/ui/primitives/Input/Input.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef, useState, memo, useId } from \"react\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { X, Eye, EyeOff } from \"lucide-react\";\nimport Button from \"../Button/Button\";\nimport InputBase from \"./InputBase\";\nimport type { InputBaseProps } from \"./InputBase\";\n\n// The presentational variant types live on InputBase now (the shared,\n// server-safe core). Re-exported here so existing deep imports and the\n// folder index keep resolving them from \"./Input\".\nexport type { InputSize, InputVariant, InputState } from \"./InputBase\";\n\nexport interface InputProps extends Omit<InputBaseProps, \"rightSlot\"> {\n showClearButton?: boolean;\n onClear?: () => void;\n}\n\n/**\n * Input Component\n *\n * The interactive text input: everything `InputBase` renders, plus the\n * client-only affordances that require React state — the password\n * visibility toggle (`type=\"password\"`), the clear button\n * (`showClearButton`), and the `useId` auto-id fallback. It **composes**\n * `InputBase` (issue #224): the presentational shell lives once in\n * `InputBase`, and `Input` layers the stateful affixes on top, passing\n * the resolved `id`, the toggled `type`, and its buttons via `rightSlot`.\n *\n * Need a server-renderable / native-form input with no client state?\n * Import `InputBase` from `@fabio.caffarello/react-design-system/server`.\n *\n * @example\n * ```tsx\n * <Input\n * id=\"email\"\n * label=\"Email\"\n * type=\"email\"\n * placeholder=\"Enter your email\"\n * error={hasError}\n * helperText={errorMessage}\n * leftIcon={<MailIcon />}\n * />\n * ```\n */\nconst Input = memo(\n forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n id,\n label,\n error = false,\n success = false,\n helperText,\n size = \"md\",\n variant = \"outlined\",\n leftIcon,\n rightIcon,\n showClearButton = false,\n onClear,\n className = \"\",\n disabled = false,\n type = \"text\",\n value,\n onChange,\n ...props\n },\n ref,\n ) {\n // Stable fallback id when the consumer doesn't provide one. This is\n // the client hook that keeps Input on the main entry; InputBase (no\n // useId) is the server-safe half and receives the resolved id below.\n const reactId = useId();\n const inputId = id || `input-${reactId}`;\n\n // Password toggle state.\n const [showPassword, setShowPassword] = useState(false);\n const isPassword = type === \"password\";\n const inputType = isPassword && showPassword ? \"text\" : type;\n\n const hasValue = value !== undefined && value !== null && value !== \"\";\n const shouldShowClear = showClearButton && hasValue && !disabled;\n\n const iconSize =\n size === \"sm\" ? \"h-4 w-4\" : size === \"lg\" ? \"h-5 w-5\" : \"h-4 w-4\";\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onClear) {\n onClear();\n } else if (onChange) {\n // Create a synthetic event to clear the input when the consumer\n // is controlled but didn't pass onClear.\n const inputElement = e.currentTarget\n .closest(\".relative\")\n ?.querySelector(\"input\") as HTMLInputElement;\n if (inputElement) {\n const syntheticEvent = {\n target: inputElement,\n currentTarget: inputElement,\n bubbles: true,\n cancelable: true,\n defaultPrevented: false,\n eventPhase: 2,\n isTrusted: false,\n nativeEvent: new Event(\"change\"),\n preventDefault: () => {},\n stopPropagation: () => {},\n persist: () => {},\n timeStamp: Date.now(),\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n Object.defineProperty(syntheticEvent.target, \"value\", {\n value: \"\",\n writable: true,\n });\n Object.defineProperty(syntheticEvent.currentTarget, \"value\", {\n value: \"\",\n writable: true,\n });\n onChange(syntheticEvent);\n }\n }\n };\n\n const handleTogglePassword = () => setShowPassword((prev) => !prev);\n\n // Trailing-affix slot: the interactive clear + password-toggle\n // buttons (the reason Input stays client), falling back to the\n // decorative rightIcon when neither is active. Same content and DOM\n // order the pre-composition Input rendered, now projected into\n // InputBase's right-affix container.\n const hasRightAffix = shouldShowClear || isPassword || Boolean(rightIcon);\n const rightSlot = hasRightAffix ? (\n <>\n {shouldShowClear && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleClear}\n className={`h-auto ${getSpacingClass(\"xs\", \"p\")}`}\n aria-label=\"Clear input\"\n >\n <X className={iconSize} />\n </Button>\n )}\n {isPassword && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleTogglePassword}\n className={`h-auto ${getSpacingClass(\"xs\", \"p\")}`}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n >\n {showPassword ? (\n <EyeOff className={iconSize} />\n ) : (\n <Eye className={iconSize} />\n )}\n </Button>\n )}\n {rightIcon && !shouldShowClear && !isPassword && (\n <div\n className={`text-fg-secondary opacity-60 pointer-events-none ${iconSize}`}\n >\n {rightIcon}\n </div>\n )}\n </>\n ) : undefined;\n\n return (\n <InputBase\n ref={ref}\n id={inputId}\n label={label}\n error={error}\n success={success}\n helperText={helperText}\n size={size}\n variant={variant}\n leftIcon={leftIcon}\n rightSlot={rightSlot}\n className={className}\n disabled={disabled}\n type={inputType}\n value={value}\n onChange={onChange}\n {...props}\n />\n );\n }),\n);\n\nInput.displayName = \"Input\";\n\nexport default Input;\n"],"names":["Input","memo","forwardRef","_a","ref","_b","id","label","error","success","helperText","size","variant","leftIcon","rightIcon","showClearButton","onClear","className","disabled","type","value","onChange","props","__objRest","reactId","useId","inputId","showPassword","setShowPassword","useState","isPassword","inputType","hasValue","shouldShowClear","iconSize","handleClear","e","inputElement","syntheticEvent","handleTogglePassword","prev","rightSlot","jsxs","Fragment","jsx","Button","getSpacingClass","X","EyeOff","Eye","InputBase","__spreadValues"],"mappings":"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"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var D = Object.defineProperty;
|
|
3
|
+
var u = Object.getOwnPropertySymbols;
|
|
4
|
+
var w = Object.prototype.hasOwnProperty, C = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var N = (s, e, o) => e in s ? D(s, e, { enumerable: !0, configurable: !0, writable: !0, value: o }) : s[e] = o, B = (s, e) => {
|
|
6
|
+
for (var o in e || (e = {}))
|
|
7
|
+
w.call(e, o) && N(s, o, e[o]);
|
|
8
|
+
if (u)
|
|
9
|
+
for (var o of u(e))
|
|
10
|
+
C.call(e, o) && N(s, o, e[o]);
|
|
11
|
+
return s;
|
|
12
|
+
};
|
|
13
|
+
var $ = (s, e) => {
|
|
14
|
+
var o = {};
|
|
15
|
+
for (var t in s)
|
|
16
|
+
w.call(s, t) && e.indexOf(t) < 0 && (o[t] = s[t]);
|
|
17
|
+
if (s != null && u)
|
|
18
|
+
for (var t of u(s))
|
|
19
|
+
e.indexOf(t) < 0 && C.call(s, t) && (o[t] = s[t]);
|
|
20
|
+
return o;
|
|
21
|
+
};
|
|
22
|
+
import { jsxs as I, jsx as l } from "react/jsx-runtime";
|
|
23
|
+
import { forwardRef as F } from "react";
|
|
24
|
+
import { getTypographyClasses as E, getTypographySize as m } from "../../tokens/typography.js";
|
|
25
|
+
import { getRadiusClass as L } from "../../tokens/radius.js";
|
|
26
|
+
import { getSpacingClass as n } from "../../tokens/spacing.js";
|
|
27
|
+
import { cn as a } from "../../utils/cn.js";
|
|
28
|
+
import { cva as O } from "../../utils/cva.js";
|
|
29
|
+
const W = O(
|
|
30
|
+
a(
|
|
31
|
+
"w-full",
|
|
32
|
+
L("md"),
|
|
33
|
+
"transition-colors",
|
|
34
|
+
"focus:outline-none",
|
|
35
|
+
"focus:ring-2",
|
|
36
|
+
"focus:ring-offset-2",
|
|
37
|
+
"disabled:opacity-50",
|
|
38
|
+
"disabled:cursor-not-allowed"
|
|
39
|
+
),
|
|
40
|
+
{
|
|
41
|
+
variants: {
|
|
42
|
+
variant: {
|
|
43
|
+
default: a(
|
|
44
|
+
"border-0",
|
|
45
|
+
"border-b-2",
|
|
46
|
+
"border-line-default",
|
|
47
|
+
"focus:border-line-focus"
|
|
48
|
+
),
|
|
49
|
+
outlined: a(
|
|
50
|
+
"border",
|
|
51
|
+
"border-line-default",
|
|
52
|
+
"focus:border-line-focus"
|
|
53
|
+
),
|
|
54
|
+
filled: a(
|
|
55
|
+
"bg-surface-muted",
|
|
56
|
+
"border-0",
|
|
57
|
+
"focus:bg-surface-base",
|
|
58
|
+
"focus:ring-2",
|
|
59
|
+
"focus:ring-line-focus"
|
|
60
|
+
)
|
|
61
|
+
},
|
|
62
|
+
size: {
|
|
63
|
+
sm: a(
|
|
64
|
+
"h-8",
|
|
65
|
+
m("bodySmall"),
|
|
66
|
+
n("md", "px")
|
|
67
|
+
),
|
|
68
|
+
md: a(
|
|
69
|
+
"h-10",
|
|
70
|
+
m("body"),
|
|
71
|
+
n("base", "px")
|
|
72
|
+
),
|
|
73
|
+
lg: a(
|
|
74
|
+
"h-12",
|
|
75
|
+
m("bodyLarge"),
|
|
76
|
+
n("lg", "px")
|
|
77
|
+
)
|
|
78
|
+
},
|
|
79
|
+
state: {
|
|
80
|
+
default: "",
|
|
81
|
+
error: a("border-error", "focus:border-error", "focus:ring-error"),
|
|
82
|
+
success: a(
|
|
83
|
+
"border-success",
|
|
84
|
+
"focus:border-success",
|
|
85
|
+
"focus:ring-success"
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
defaultVariants: {
|
|
90
|
+
variant: "outlined",
|
|
91
|
+
size: "md",
|
|
92
|
+
state: "default"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
function _({
|
|
97
|
+
error: s,
|
|
98
|
+
success: e,
|
|
99
|
+
helperText: o,
|
|
100
|
+
errorId: t,
|
|
101
|
+
helperId: i
|
|
102
|
+
}) {
|
|
103
|
+
const c = a(
|
|
104
|
+
n("xs", "mt"),
|
|
105
|
+
E("caption"),
|
|
106
|
+
s && "text-fg-error",
|
|
107
|
+
e && "text-fg-success",
|
|
108
|
+
!s && !e && "text-fg-secondary"
|
|
109
|
+
);
|
|
110
|
+
return /* @__PURE__ */ l(
|
|
111
|
+
"div",
|
|
112
|
+
{
|
|
113
|
+
id: t || i,
|
|
114
|
+
className: c,
|
|
115
|
+
role: s || e ? "alert" : void 0,
|
|
116
|
+
children: o || (s ? "Error" : e ? "Success" : "")
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
const A = F(
|
|
121
|
+
function(G, q) {
|
|
122
|
+
var v = G, {
|
|
123
|
+
id: e,
|
|
124
|
+
label: o,
|
|
125
|
+
error: t = !1,
|
|
126
|
+
success: i = !1,
|
|
127
|
+
helperText: c,
|
|
128
|
+
size: r = "md",
|
|
129
|
+
variant: V = "outlined",
|
|
130
|
+
leftIcon: f,
|
|
131
|
+
rightIcon: p,
|
|
132
|
+
rightSlot: d,
|
|
133
|
+
className: j = "",
|
|
134
|
+
disabled: b = !1,
|
|
135
|
+
type: k = "text"
|
|
136
|
+
} = v, g = $(v, [
|
|
137
|
+
"id",
|
|
138
|
+
"label",
|
|
139
|
+
"error",
|
|
140
|
+
"success",
|
|
141
|
+
"helperText",
|
|
142
|
+
"size",
|
|
143
|
+
"variant",
|
|
144
|
+
"leftIcon",
|
|
145
|
+
"rightIcon",
|
|
146
|
+
"rightSlot",
|
|
147
|
+
"className",
|
|
148
|
+
"disabled",
|
|
149
|
+
"type"
|
|
150
|
+
]);
|
|
151
|
+
typeof process != "undefined" && process.env.NODE_ENV !== "production" && o && !e && console.warn(
|
|
152
|
+
"[InputBase] `label` was provided without an `id`. The <label> cannot bind to the input (InputBase does not auto-generate an id — that needs a client hook). Pass an `id`, or use the interactive `Input` which auto-generates one."
|
|
153
|
+
);
|
|
154
|
+
const H = t ? "error" : i ? "success" : "default", x = t && e ? `${e}-error` : void 0, h = c && e ? `${e}-helper` : void 0, y = r === "sm" ? "h-4 w-4" : r === "lg" ? "h-5 w-5" : "h-4 w-4", P = r === "sm" ? "top-2" : r === "lg" ? "top-3.5" : "top-2.5", R = a(
|
|
155
|
+
W({ variant: V, size: r, state: H }),
|
|
156
|
+
// Icon padding — `pl-9` / `pr-9` aren't on the spacing scale (no
|
|
157
|
+
// semantic key for 36px) so they stay raw at the `sm` size; md/lg use
|
|
158
|
+
// the getter. Mirrors the original Input contract.
|
|
159
|
+
f && (r === "sm" ? "pl-9" : r === "lg" ? n("3xl", "pl") : n("2xl", "pl")),
|
|
160
|
+
(p || d) && (r === "sm" ? "pr-9" : r === "lg" ? n("3xl", "pr") : n("2xl", "pr")),
|
|
161
|
+
j
|
|
162
|
+
), T = a(
|
|
163
|
+
"block",
|
|
164
|
+
E("label"),
|
|
165
|
+
n("xs", "mb"),
|
|
166
|
+
b && "opacity-50"
|
|
167
|
+
);
|
|
168
|
+
return /* @__PURE__ */ I("div", { className: "w-full", children: [
|
|
169
|
+
o && /* @__PURE__ */ l("label", { htmlFor: e, className: T, children: o }),
|
|
170
|
+
/* @__PURE__ */ I("div", { className: "relative", children: [
|
|
171
|
+
f && /* @__PURE__ */ l(
|
|
172
|
+
"div",
|
|
173
|
+
{
|
|
174
|
+
className: `absolute left-3 ${P} text-fg-secondary opacity-60 pointer-events-none`,
|
|
175
|
+
children: /* @__PURE__ */ l("div", { className: y, children: f })
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ l(
|
|
179
|
+
"input",
|
|
180
|
+
B({
|
|
181
|
+
id: e,
|
|
182
|
+
ref: q,
|
|
183
|
+
type: k,
|
|
184
|
+
className: R,
|
|
185
|
+
disabled: b,
|
|
186
|
+
"aria-invalid": t,
|
|
187
|
+
"aria-required": g.required,
|
|
188
|
+
"aria-describedby": x || h,
|
|
189
|
+
suppressHydrationWarning: !0
|
|
190
|
+
}, g)
|
|
191
|
+
),
|
|
192
|
+
(p || d) && /* @__PURE__ */ l(
|
|
193
|
+
"div",
|
|
194
|
+
{
|
|
195
|
+
className: `absolute right-3 top-0 bottom-0 flex items-center ${n("xs", "gap")}`,
|
|
196
|
+
children: d != null ? d : /* @__PURE__ */ l(
|
|
197
|
+
"div",
|
|
198
|
+
{
|
|
199
|
+
className: `text-fg-secondary opacity-60 pointer-events-none ${y}`,
|
|
200
|
+
children: p
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
] }),
|
|
206
|
+
(t || i || c) && /* @__PURE__ */ l(
|
|
207
|
+
_,
|
|
208
|
+
{
|
|
209
|
+
error: t,
|
|
210
|
+
success: i,
|
|
211
|
+
helperText: c,
|
|
212
|
+
errorId: x,
|
|
213
|
+
helperId: h
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] });
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
A.displayName = "InputBase";
|
|
220
|
+
export {
|
|
221
|
+
A as default
|
|
222
|
+
};
|
|
223
|
+
//# sourceMappingURL=InputBase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputBase.js","sources":["../../../../../src/ui/primitives/Input/InputBase.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport {\n getTypographyClasses,\n getTypographySize,\n} from \"../../tokens/typography\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { cn, cva } from \"../../utils\";\n\n// Ambient declaration so the dev-only warn below typechecks without\n// pulling @types/node into the app tsconfig. At runtime the consumer's\n// bundler replaces `process.env.NODE_ENV` with a literal; the\n// `typeof process` guard keeps the branch safe in browser/edge runtimes.\ndeclare const process: { env: { NODE_ENV?: string } };\n\nexport type InputSize = \"sm\" | \"md\" | \"lg\";\nexport type InputVariant = \"default\" | \"outlined\" | \"filled\";\nexport type InputState = \"default\" | \"error\" | \"success\";\n\n/**\n * Input variant tokens (issue #224). They used to live inside `Input`\n * wrapped in `useMemo`; moving them here, to the server-safe `InputBase`,\n * removes that decorative memo and makes `InputBase` the single source of\n * the input's visual surface — the interactive `Input` inherits it by\n * composing `InputBase` rather than re-declaring the cva. The focus-ring\n * colours are inlined directly (the old code derived them via\n * `.replace(\"focus:border-\", \"focus:ring-\")`, which produced exactly\n * these classes).\n */\nconst inputVariants = cva(\n cn(\n \"w-full\",\n getRadiusClass(\"md\"),\n \"transition-colors\",\n \"focus:outline-none\",\n \"focus:ring-2\",\n \"focus:ring-offset-2\",\n \"disabled:opacity-50\",\n \"disabled:cursor-not-allowed\",\n ),\n {\n variants: {\n variant: {\n default: cn(\n \"border-0\",\n \"border-b-2\",\n \"border-line-default\",\n \"focus:border-line-focus\",\n ),\n outlined: cn(\n \"border\",\n \"border-line-default\",\n \"focus:border-line-focus\",\n ),\n filled: cn(\n \"bg-surface-muted\",\n \"border-0\",\n \"focus:bg-surface-base\",\n \"focus:ring-2\",\n \"focus:ring-line-focus\",\n ),\n },\n size: {\n sm: cn(\n \"h-8\",\n getTypographySize(\"bodySmall\"),\n getSpacingClass(\"md\", \"px\"),\n ),\n md: cn(\n \"h-10\",\n getTypographySize(\"body\"),\n getSpacingClass(\"base\", \"px\"),\n ),\n lg: cn(\n \"h-12\",\n getTypographySize(\"bodyLarge\"),\n getSpacingClass(\"lg\", \"px\"),\n ),\n },\n state: {\n default: \"\",\n error: cn(\"border-error\", \"focus:border-error\", \"focus:ring-error\"),\n success: cn(\n \"border-success\",\n \"focus:border-success\",\n \"focus:ring-success\",\n ),\n },\n },\n defaultVariants: {\n variant: \"outlined\",\n size: \"md\",\n state: \"default\",\n },\n },\n);\n\n/**\n * Helper / error text. De-memoized (issue #224) — the original wrapped\n * its class string and text in `useMemo`, a decorative memo that blocked\n * server-safety. Inlined here; the work is nanoseconds.\n */\nfunction HelperText({\n error,\n success,\n helperText,\n errorId,\n helperId,\n}: {\n error: boolean;\n success: boolean;\n helperText?: string;\n errorId?: string;\n helperId?: string;\n}) {\n const helperClasses = cn(\n getSpacingClass(\"xs\", \"mt\"),\n getTypographyClasses(\"caption\"),\n error && \"text-fg-error\",\n success && \"text-fg-success\",\n !error && !success && \"text-fg-secondary\",\n );\n const text = helperText || (error ? \"Error\" : success ? \"Success\" : \"\");\n\n return (\n <div\n id={errorId || helperId}\n className={helperClasses}\n role={error || success ? \"alert\" : undefined}\n >\n {text}\n </div>\n );\n}\n\nexport interface InputBaseProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n> {\n label?: ReactNode;\n error?: boolean;\n success?: boolean;\n helperText?: string;\n size?: InputSize;\n variant?: InputVariant;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n /**\n * Raw trailing-affix slot rendered inside the input's right edge with\n * full interactivity (no `pointer-events-none`). The interactive\n * `Input` injects its password-toggle / clear buttons here; consumers\n * can use it for a static suffix (a unit, a badge). When omitted,\n * `rightIcon` renders instead with the muted decorative treatment.\n */\n rightSlot?: ReactNode;\n}\n\n/**\n * InputBase\n *\n * The **presentational core** of the text input — label, the `<input>`\n * itself, decorative left/right icons, the trailing-affix slot, and the\n * helper/error line. It holds **no React client state** (no `useState`,\n * `useId`, `useCallback`), so it is server-safe and ships from the\n * `./server` entry (issue #224).\n *\n * The interactive `Input` (default export of this folder) composes\n * `InputBase`, owning the password-toggle state, the clear button, and\n * the `useId` auto-id fallback — it passes the resolved `id`, the\n * toggled `type`, and its affix buttons (`rightSlot`) down. Use\n * `InputBase` directly for server-rendered / native-form inputs where\n * none of that interactivity is needed (`<form method=\"GET\">` filters,\n * RSC pages).\n *\n * Accessible name: pass `id` when you pass `label` so the `<label\n * htmlFor>` binds — `InputBase` does NOT auto-generate an id (that needs\n * `useId`, which would make it client). A dev-only warning fires when a\n * `label` is given without an `id`.\n *\n * @example\n * ```tsx\n * // Server component / native form — zero client state.\n * <InputBase id=\"q\" name=\"q\" placeholder=\"Buscar…\" />\n * ```\n */\nconst InputBase = forwardRef<HTMLInputElement, InputBaseProps>(\n function InputBase(\n {\n id,\n label,\n error = false,\n success = false,\n helperText,\n size = \"md\",\n variant = \"outlined\",\n leftIcon,\n rightIcon,\n rightSlot,\n className = \"\",\n disabled = false,\n type = \"text\",\n ...props\n },\n ref,\n ) {\n if (\n typeof process !== \"undefined\" &&\n process.env.NODE_ENV !== \"production\" &&\n label &&\n !id\n ) {\n console.warn(\n \"[InputBase] `label` was provided without an `id`. The <label> cannot bind to the input (InputBase does not auto-generate an id — that needs a client hook). Pass an `id`, or use the interactive `Input` which auto-generates one.\",\n );\n }\n\n const state: InputState = error ? \"error\" : success ? \"success\" : \"default\";\n\n const errorId = error && id ? `${id}-error` : undefined;\n const helperId = helperText && id ? `${id}-helper` : undefined;\n\n const iconSize =\n size === \"sm\" ? \"h-4 w-4\" : size === \"lg\" ? \"h-5 w-5\" : \"h-4 w-4\";\n const iconPosition =\n size === \"sm\" ? \"top-2\" : size === \"lg\" ? \"top-3.5\" : \"top-2.5\";\n\n const inputClasses = cn(\n inputVariants({ variant, size, state }),\n // Icon padding — `pl-9` / `pr-9` aren't on the spacing scale (no\n // semantic key for 36px) so they stay raw at the `sm` size; md/lg use\n // the getter. Mirrors the original Input contract.\n leftIcon &&\n (size === \"sm\"\n ? \"pl-9\"\n : size === \"lg\"\n ? getSpacingClass(\"3xl\", \"pl\")\n : getSpacingClass(\"2xl\", \"pl\")),\n (rightIcon || rightSlot) &&\n (size === \"sm\"\n ? \"pr-9\"\n : size === \"lg\"\n ? getSpacingClass(\"3xl\", \"pr\")\n : getSpacingClass(\"2xl\", \"pr\")),\n className,\n );\n\n const labelClasses = cn(\n \"block\",\n getTypographyClasses(\"label\"),\n getSpacingClass(\"xs\", \"mb\"),\n disabled && \"opacity-50\",\n );\n\n return (\n <div className=\"w-full\">\n {label && (\n <label htmlFor={id} className={labelClasses}>\n {label}\n </label>\n )}\n <div className=\"relative\">\n {leftIcon && (\n <div\n className={`absolute left-3 ${iconPosition} text-fg-secondary opacity-60 pointer-events-none`}\n >\n <div className={iconSize}>{leftIcon}</div>\n </div>\n )}\n <input\n id={id}\n ref={ref}\n type={type}\n className={inputClasses}\n disabled={disabled}\n aria-invalid={error}\n aria-required={props.required}\n aria-describedby={errorId || helperId}\n suppressHydrationWarning\n {...props}\n />\n {(rightIcon || rightSlot) && (\n <div\n className={`absolute right-3 top-0 bottom-0 flex items-center ${getSpacingClass(\"xs\", \"gap\")}`}\n >\n {rightSlot ?? (\n <div\n className={`text-fg-secondary opacity-60 pointer-events-none ${iconSize}`}\n >\n {rightIcon}\n </div>\n )}\n </div>\n )}\n </div>\n {(error || success || helperText) && (\n <HelperText\n error={error}\n success={success}\n helperText={helperText}\n errorId={errorId}\n helperId={helperId}\n />\n )}\n </div>\n );\n },\n);\n\nInputBase.displayName = \"InputBase\";\n\nexport default InputBase;\n"],"names":["inputVariants","cva","cn","getRadiusClass","getTypographySize","getSpacingClass","HelperText","error","success","helperText","errorId","helperId","helperClasses","getTypographyClasses","jsx","InputBase","forwardRef","_a","ref","_b","id","label","size","variant","leftIcon","rightIcon","rightSlot","className","disabled","type","props","__objRest","state","iconSize","iconPosition","inputClasses","labelClasses","jsxs","__spreadValues"],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const c = 8, n = [
|
|
3
|
+
{
|
|
4
|
+
index: 1,
|
|
5
|
+
name: "Orange",
|
|
6
|
+
var: "var(--color-chart-1)",
|
|
7
|
+
bg: "bg-chart-1",
|
|
8
|
+
text: "text-chart-1"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
index: 2,
|
|
12
|
+
name: "Sky blue",
|
|
13
|
+
var: "var(--color-chart-2)",
|
|
14
|
+
bg: "bg-chart-2",
|
|
15
|
+
text: "text-chart-2"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
index: 3,
|
|
19
|
+
name: "Bluish green",
|
|
20
|
+
var: "var(--color-chart-3)",
|
|
21
|
+
bg: "bg-chart-3",
|
|
22
|
+
text: "text-chart-3"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
index: 4,
|
|
26
|
+
name: "Vermillion",
|
|
27
|
+
var: "var(--color-chart-4)",
|
|
28
|
+
bg: "bg-chart-4",
|
|
29
|
+
text: "text-chart-4"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
index: 5,
|
|
33
|
+
name: "Blue",
|
|
34
|
+
var: "var(--color-chart-5)",
|
|
35
|
+
bg: "bg-chart-5",
|
|
36
|
+
text: "text-chart-5"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
index: 6,
|
|
40
|
+
name: "Reddish purple",
|
|
41
|
+
var: "var(--color-chart-6)",
|
|
42
|
+
bg: "bg-chart-6",
|
|
43
|
+
text: "text-chart-6"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
index: 7,
|
|
47
|
+
name: "Yellow",
|
|
48
|
+
var: "var(--color-chart-7)",
|
|
49
|
+
bg: "bg-chart-7",
|
|
50
|
+
text: "text-chart-7"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
index: 8,
|
|
54
|
+
name: "Gray",
|
|
55
|
+
var: "var(--color-chart-8)",
|
|
56
|
+
bg: "bg-chart-8",
|
|
57
|
+
text: "text-chart-8"
|
|
58
|
+
}
|
|
59
|
+
];
|
|
60
|
+
function o(t) {
|
|
61
|
+
return `var(--color-chart-${(Math.trunc(t) % 8 + 8) % 8 + 1})`;
|
|
62
|
+
}
|
|
63
|
+
function h(t, r = "bg") {
|
|
64
|
+
const e = (Math.trunc(t) % 8 + 8) % 8;
|
|
65
|
+
return `${r}-chart-${e + 1}`;
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
c as CHART_PALETTE_SIZE,
|
|
69
|
+
n as CHART_PALETTE_TOKENS,
|
|
70
|
+
o as getChartColor,
|
|
71
|
+
h as getChartColorClass
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=chart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart.js","sources":["../../../../src/ui/tokens/chart.ts"],"sourcesContent":["/**\n * Data-Visualization Categorical Palette (Okabe-Ito)\n *\n * Eight colorblind-safe categorical colors for chart series (parties, vote\n * types, ranges, …). This is a SEPARATE axis from the semantic feedback\n * colors: `success`/`warning`/`error`/`info` encode *state*, never\n * *category* — using `error` for \"series 3\" is semantically wrong and\n * destroys meaning. A categorical palette answers \"which series is this\",\n * and it must stay distinguishable under color-vision deficiency.\n *\n * The values are the canonical Okabe & Ito (2008) palette — the reference\n * categorical palette engineered to be distinguishable in deuteranopia,\n * protanopia, and tritanopia — with `black` swapped for a neutral gray so\n * the 8th series survives on a dark canvas. Light values are the canonical\n * tones; the dark theme lifts each toward higher luminance (hue preserved)\n * so every series clears the WCAG 1.4.11 graphical-object 3:1 contrast over\n * `surface-canvas` (slate-950). The CSS source of truth is\n * `src/styles/semantic/colors.css` (light) and `src/styles/themes/dark.css`\n * (dark, both blocks).\n *\n * On-WHITE caveat: orange/sky-blue/yellow/gray are below 3:1 against a white\n * canvas — an intrinsic property of Okabe-Ito's light hues. Fine for FILLS\n * (bars, areas, large marks); for thin strokes (lines, 1px borders) add a\n * stroke/outline or use a darker series first. Colorblind-safety (the point\n * of the palette) is preserved regardless.\n */\n\n/** Number of distinct colors in the categorical palette. */\nexport const CHART_PALETTE_SIZE = 8 as const;\n\n/** 1-based position within the categorical palette. */\nexport type ChartColorIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;\n\nexport interface ChartColorToken {\n /** 1-based palette position (matches the `--color-chart-N` token). */\n index: ChartColorIndex;\n /** Okabe-Ito hue name — use for legends / documentation. */\n name: string;\n /** Theme-aware CSS reference, e.g. `\"var(--color-chart-1)\"`. */\n var: string;\n /** Tailwind background class, e.g. `\"bg-chart-1\"`. */\n bg: string;\n /** Tailwind text class, e.g. `\"text-chart-1\"`. */\n text: string;\n}\n\n/**\n * Palette metadata in canonical order. The actual color values live in CSS\n * (theme-aware); these tokens carry the references and human-readable names.\n */\nexport const CHART_PALETTE_TOKENS: readonly ChartColorToken[] = [\n {\n index: 1,\n name: \"Orange\",\n var: \"var(--color-chart-1)\",\n bg: \"bg-chart-1\",\n text: \"text-chart-1\",\n },\n {\n index: 2,\n name: \"Sky blue\",\n var: \"var(--color-chart-2)\",\n bg: \"bg-chart-2\",\n text: \"text-chart-2\",\n },\n {\n index: 3,\n name: \"Bluish green\",\n var: \"var(--color-chart-3)\",\n bg: \"bg-chart-3\",\n text: \"text-chart-3\",\n },\n {\n index: 4,\n name: \"Vermillion\",\n var: \"var(--color-chart-4)\",\n bg: \"bg-chart-4\",\n text: \"text-chart-4\",\n },\n {\n index: 5,\n name: \"Blue\",\n var: \"var(--color-chart-5)\",\n bg: \"bg-chart-5\",\n text: \"text-chart-5\",\n },\n {\n index: 6,\n name: \"Reddish purple\",\n var: \"var(--color-chart-6)\",\n bg: \"bg-chart-6\",\n text: \"text-chart-6\",\n },\n {\n index: 7,\n name: \"Yellow\",\n var: \"var(--color-chart-7)\",\n bg: \"bg-chart-7\",\n text: \"text-chart-7\",\n },\n {\n index: 8,\n name: \"Gray\",\n var: \"var(--color-chart-8)\",\n bg: \"bg-chart-8\",\n text: \"text-chart-8\",\n },\n] as const;\n\n/**\n * Resolve a chart series index to a theme-aware color reference.\n *\n * `seriesIndex` is **0-based** (built for `data.map((d, i) => …)`) and wraps\n * modulo {@link CHART_PALETTE_SIZE}, so a 10-series chart cycles back to the\n * first color rather than running out. Negative indices wrap correctly too.\n * The returned `var(--color-chart-N)` resolves per active theme (light/dark),\n * so charts re-tint automatically — pass it straight to a recharts\n * `fill`/`stroke` or an inline `style`.\n *\n * @example\n * ```tsx\n * import { getChartColor } from \"@fabio.caffarello/react-design-system\";\n *\n * {series.map((s, i) => (\n * <Bar key={s.id} dataKey={s.id} fill={getChartColor(i)} />\n * ))}\n * ```\n *\n * @param seriesIndex - 0-based series position.\n * @returns A `var(--color-chart-N)` reference (theme-aware).\n */\nexport function getChartColor(seriesIndex: number): string {\n const n = Math.trunc(seriesIndex);\n const wrapped =\n ((n % CHART_PALETTE_SIZE) + CHART_PALETTE_SIZE) % CHART_PALETTE_SIZE;\n return `var(--color-chart-${wrapped + 1})`;\n}\n\n/**\n * Tailwind class variant of {@link getChartColor} for DOM elements (legend\n * dots, swatches) where a class is more convenient than an inline style.\n *\n * @param seriesIndex - 0-based series position (wraps modulo the palette).\n * @param property - `\"bg\"` (default) or `\"text\"`.\n * @returns A `bg-chart-N` / `text-chart-N` class string.\n */\nexport function getChartColorClass(\n seriesIndex: number,\n property: \"bg\" | \"text\" = \"bg\",\n): string {\n const n = Math.trunc(seriesIndex);\n const wrapped =\n ((n % CHART_PALETTE_SIZE) + CHART_PALETTE_SIZE) % CHART_PALETTE_SIZE;\n return `${property}-chart-${wrapped + 1}`;\n}\n"],"names":["CHART_PALETTE_SIZE","CHART_PALETTE_TOKENS","getChartColor","seriesIndex","getChartColorClass","property","wrapped"],"mappings":";AA4BO,MAAMA,IAAqB,GAsBrBC,IAAmD;AAAA,EAC9D;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAEV;AAwBO,SAASC,EAAcC,GAA6B;AAIzD,SAAO,sBAHG,KAAK,MAAMA,CAAW,IAExB,IAAsB,KAAsB,IACd,CAAC;AACzC;AAUO,SAASC,EACdD,GACAE,IAA0B,MAClB;AAER,QAAMC,KADI,KAAK,MAAMH,CAAW,IAExB,IAAsB,KAAsB;AACpD,SAAO,GAAGE,CAAQ,UAAUC,IAAU,CAAC;AACzC;"}
|