@hex-core/components 1.8.0 → 1.9.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/sonner/sonner.tsx"],"names":["SonnerToaster"],"mappings":";;;;AAYA,SAAS,OAAA,CAAQ,EAAE,GAAG,KAAA,EAAM,EAAiB;AAC5C,EAAA,uBACC,GAAA;AAAA,IAACA,SAAA;AAAA,IAAA;AAAA,MACA,KAAA,EAAM,QAAA;AAAA,MACN,SAAA,EAAU,eAAA;AAAA,MACV,YAAA,EAAc;AAAA,QACb,UAAA,EAAY;AAAA,UACX,KAAA,EACC,uIAAA;AAAA,UACD,WAAA,EAAa,sCAAA;AAAA,UACb,YAAA,EACC,kEAAA;AAAA,UACD,YAAA,EACC;AAAA;AACF,OACD;AAAA,MACC,GAAG;AAAA;AAAA,GACL;AAEF","file":"sonner.js","sourcesContent":["\"use client\";\n\nimport { Toaster as SonnerToaster, toast } from \"sonner\";\n\ntype ToasterProps = React.ComponentProps<typeof SonnerToaster>;\n\n/**\n * The global toast container. Render once in your app root.\n * Re-export of Sonner's Toaster styled to use Hex UI theme tokens.\n * @param props - Sonner Toaster props (position, richColors, etc.)\n * @returns A styled portal container for toast notifications\n */\nfunction Toaster({ ...props }: ToasterProps) {\n\treturn (\n\t\t<SonnerToaster\n\t\t\ttheme=\"system\"\n\t\t\tclassName=\"toaster group\"\n\t\t\ttoastOptions={{\n\t\t\t\tclassNames: {\n\t\t\t\t\ttoast:\n\t\t\t\t\t\t\"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg\",\n\t\t\t\t\tdescription: \"group-[.toast]:text-muted-foreground\",\n\t\t\t\t\tactionButton:\n\t\t\t\t\t\t\"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n\t\t\t\t\tcancelButton:\n\t\t\t\t\t\t\"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport { Toaster, toast };\n"]}
1
+ {"version":3,"sources":["../src/components/sonner/sonner.tsx"],"names":["SonnerToaster"],"mappings":";;;;AAYA,SAAS,OAAA,CAAQ,EAAE,GAAG,KAAA,EAAM,EAAiB;AAC5C,EAAA,uBACC,GAAA;AAAA,IAACA,SAAA;AAAA,IAAA;AAAA,MACA,KAAA,EAAM,QAAA;AAAA,MACN,SAAA,EAAU,eAAA;AAAA,MACV,YAAA,EAAc;AAAA,QACb,UAAA,EAAY;AAAA,UACX,KAAA,EACC,uIAAA;AAAA,UACD,WAAA,EAAa,sCAAA;AAAA,UACb,YAAA,EACC,kEAAA;AAAA,UACD,YAAA,EACC;AAAA;AACF,OACD;AAAA,MACC,GAAG;AAAA;AAAA,GACL;AAEF","file":"sonner.js","sourcesContent":["\"use client\";\n\nimport { Toaster as SonnerToaster, toast } from \"sonner\";\n\ntype ToasterProps = React.ComponentProps<typeof SonnerToaster>;\n\n/**\n * The global toast container. Render once in your app root.\n * Re-export of Sonner's Toaster styled to use Hex Core theme tokens.\n * @param props - Sonner Toaster props (position, richColors, etc.)\n * @returns A styled portal container for toast notifications\n */\nfunction Toaster({ ...props }: ToasterProps) {\n\treturn (\n\t\t<SonnerToaster\n\t\t\ttheme=\"system\"\n\t\t\tclassName=\"toaster group\"\n\t\t\ttoastOptions={{\n\t\t\t\tclassNames: {\n\t\t\t\t\ttoast:\n\t\t\t\t\t\t\"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg\",\n\t\t\t\t\tdescription: \"group-[.toast]:text-muted-foreground\",\n\t\t\t\t\tactionButton:\n\t\t\t\t\t\t\"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n\t\t\t\t\tcancelButton:\n\t\t\t\t\t\t\"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport { Toaster, toast };\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/color.ts","../src/lib/utils.ts","../src/ai/terminal/terminal.tsx"],"names":[],"mappings":"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","file":"terminal.js","sourcesContent":["/**\n * Color conversion utilities for the HSL-triplet token format used across\n * `@hex-core/tokens` themes (`H S% L%`, e.g. `\"240 5.9% 10%\"` — no `hsl()`\n * wrapper, no commas).\n *\n * The triplet is the round-trip-safe serialization for Hex UI: tokens flow\n * triplet → CSS `hsl(var(--token))` → rendered color, and the ColorPicker\n * component edits triplets directly. Hex/RGB conversions are display\n * adapters, not the source of truth.\n */\n\n/** Parsed HSL components. `h` is degrees (0–360); `s` and `l` are percentages (0–100). */\nexport interface HslTriplet {\n\th: number;\n\ts: number;\n\tl: number;\n}\n\n/** Parsed RGB components. Each channel is 0–255. */\nexport interface RgbColor {\n\tr: number;\n\tg: number;\n\tb: number;\n}\n\n/**\n * Parse an HSL triplet string into numeric components.\n *\n * Note: malformed input silently coerces to `{0,0,0}` (pure black) rather than\n * returning an error signal. Callers that need to distinguish \"user typed\n * black\" from \"user typed garbage\" should validate the input format first.\n * `hexToHslTriplet` returns `null` for malformed hex; this asymmetry is\n * intentional — triplets feed CSS variables where any non-color value would\n * already break rendering.\n *\n * @param triplet - String in the form `\"<H> <S>% <L>%\"` (e.g. `\"240 5.9% 10%\"`).\n * @returns Numeric components, or `{0,0,0}` if the input is malformed.\n */\nexport function parseHslTriplet(triplet: string): HslTriplet {\n\tconst parts = triplet.trim().split(/\\s+/);\n\treturn {\n\t\th: Number.parseFloat(parts[0]) || 0,\n\t\ts: Number.parseFloat(parts[1]) || 0,\n\t\tl: Number.parseFloat(parts[2]) || 0,\n\t};\n}\n\n/**\n * Format HSL components into an HSL triplet string (the canonical token format).\n * @param hsl - Numeric components.\n * @returns Triplet in the form `\"<H> <S>% <L>%\"`.\n */\nexport function formatHslTriplet({ h, s, l }: HslTriplet): string {\n\t// Tolerant integer check: rgbToHsl can produce values like 5.0000000001 due\n\t// to float arithmetic; format those as \"5\" rather than \"5.0\".\n\tconst round = (n: number) =>\n\t\tMath.abs(n - Math.round(n)) < 1e-6 ? `${Math.round(n)}` : n.toFixed(1);\n\treturn `${Math.round(h)} ${round(s)}% ${round(l)}%`;\n}\n\n/**\n * Convert HSL components to RGB.\n * @param h - Hue (0–360).\n * @param s - Saturation (0–100).\n * @param l - Lightness (0–100).\n * @returns RGB channels (0–255, rounded).\n */\nexport function hslToRgb(h: number, s: number, l: number): RgbColor {\n\tconst sN = s / 100;\n\tconst lN = l / 100;\n\tconst k = (n: number) => (n + h / 30) % 12;\n\tconst a = sN * Math.min(lN, 1 - lN);\n\tconst f = (n: number) => lN - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));\n\treturn {\n\t\tr: Math.round(255 * f(0)),\n\t\tg: Math.round(255 * f(8)),\n\t\tb: Math.round(255 * f(4)),\n\t};\n}\n\n/**\n * Convert RGB components to HSL.\n * @param r - Red (0–255).\n * @param g - Green (0–255).\n * @param b - Blue (0–255).\n * @returns HSL components (h: 0–360, s: 0–100, l: 0–100).\n */\nexport function rgbToHsl(r: number, g: number, b: number): HslTriplet {\n\tconst rN = r / 255;\n\tconst gN = g / 255;\n\tconst bN = b / 255;\n\tconst max = Math.max(rN, gN, bN);\n\tconst min = Math.min(rN, gN, bN);\n\tlet h = 0;\n\tlet s = 0;\n\tconst l = (max + min) / 2;\n\tif (max !== min) {\n\t\tconst d = max - min;\n\t\ts = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\t\tif (max === rN) h = (gN - bN) / d + (gN < bN ? 6 : 0);\n\t\telse if (max === gN) h = (bN - rN) / d + 2;\n\t\telse h = (rN - gN) / d + 4;\n\t\th /= 6;\n\t}\n\treturn { h: h * 360, s: s * 100, l: l * 100 };\n}\n\n/**\n * Convert an HSL triplet to a 6-digit hex string.\n * @param triplet - HSL triplet (e.g. `\"240 5.9% 10%\"`).\n * @returns Lowercase hex string with leading `#` (e.g. `\"#181a1f\"`).\n */\nexport function hslTripletToHex(triplet: string): string {\n\tconst { h, s, l } = parseHslTriplet(triplet);\n\tconst { r, g, b } = hslToRgb(h, s, l);\n\tconst toHex = (n: number) => n.toString(16).padStart(2, \"0\");\n\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n}\n\n/**\n * Convert a hex string to an HSL triplet.\n * Accepts 3-digit (`#abc`) or 6-digit (`#aabbcc`) hex with optional `#`.\n * @param hex - Hex color string.\n * @returns HSL triplet, or `null` if the input is malformed.\n */\nexport function hexToHslTriplet(hex: string): string | null {\n\tconst clean = hex.trim().replace(/^#/, \"\");\n\tlet normalized: string;\n\tif (/^[0-9a-fA-F]{3}$/.test(clean)) {\n\t\tnormalized = clean\n\t\t\t.split(\"\")\n\t\t\t.map((c) => c + c)\n\t\t\t.join(\"\");\n\t} else if (/^[0-9a-fA-F]{6}$/.test(clean)) {\n\t\tnormalized = clean;\n\t} else {\n\t\treturn null;\n\t}\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn formatHslTriplet(rgbToHsl(r, g, b));\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { hslTripletToHex } from \"../../lib/color.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Headless terminal display backed by xterm.js. Renders an xterm grid\n * inside a div the consumer styles. No PTY, no shell — the consumer\n * owns the data-flow:\n *\n * - Pass `output` (string or string[]) to write to the display. Each\n * change is diffed against the prior render and only the new tail\n * is `term.write()`-ed, so feeding a streaming buffer doesn't redraw.\n * - Pass `onInput` to receive bytes the user typed. Wire it to a\n * WebSocket / IPC / fetch stream — terminal doesn't care.\n *\n * Heavy peer: requires `@xterm/xterm` (~150 KB gzip). The hex-core CLI's\n * `add` flow prompts before installing.\n *\n * @example\n * <Terminal\n * output={[\"$ ls\\r\\n\", \"package.json src/\\r\\n\", \"$ \"]}\n * onInput={(data) => ws.send(data)}\n * rows={24}\n * cols={80}\n * />\n */\nexport interface TerminalProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\" | \"onInput\"> {\n\t/**\n\t * Bytes to display. String is written verbatim; string[] is joined.\n\t * On change, only the suffix beyond the prior render is emitted, so\n\t * appending to a streaming buffer is O(delta).\n\t */\n\toutput?: string | string[];\n\t/** Receive bytes the user typed (incl. control sequences). */\n\tonInput?: (data: string) => void;\n\t/** Initial cols. xterm allows runtime resize via fit-addon (not bundled). Default 80. */\n\tcols?: number;\n\t/** Initial rows. Default 24. */\n\trows?: number;\n\t/** Theme tokens — defaults to neutral light/dark via CSS vars. */\n\ttheme?: \"dark\" | \"light\";\n\t/** Enable cursor blink. Default true. */\n\tcursorBlink?: boolean;\n\t/** Whether the user can type into the terminal. Default true. */\n\tdisableInput?: boolean;\n}\n\n// Fallback xterm themes used when the consumer hasn't loaded `@hex-core/tokens`\n// or hasn't defined the standard `--background` / `--foreground` CSS vars\n// (e.g. consumer mounted Terminal in isolation). Match the `Terminal`\n// wrapper's inline `themeBg` defaults below — both must agree or there's\n// a visible seam between the xterm canvas and the wrapper.\nconst DARK_FALLBACK = {\n\tbackground: \"#0a0a0a\",\n\tforeground: \"#e5e5e5\",\n\tcursor: \"#e5e5e5\",\n\tselectionBackground: \"#404040\",\n};\nconst LIGHT_FALLBACK = {\n\tbackground: \"#fafafa\",\n\tforeground: \"#171717\",\n\tcursor: \"#171717\",\n\tselectionBackground: \"#d4d4d4\",\n};\n\n/**\n * Read a CSS HSL-triplet variable from `:root` (or the nearest theme\n * scope) and convert it to a 6-digit hex string suitable for xterm's\n * `theme: { background: \"#...\" }` option, which accepts hex/rgb but NOT\n * CSS variables. Returns `null` if the variable is unset, so the caller\n * can fall back to a hand-tuned theme without rendering pure-black.\n *\n * @param name - CSS variable name without the leading `--` (e.g. `\"background\"`).\n * @returns A `#xxxxxx` hex color string, or `null` if the var isn't defined.\n */\nfunction readCssVarAsHex(name: string): string | null {\n\tif (typeof document === \"undefined\") return null;\n\tconst triplet = getComputedStyle(document.documentElement)\n\t\t.getPropertyValue(`--${name}`)\n\t\t.trim();\n\tif (!triplet) return null;\n\treturn hslTripletToHex(triplet);\n}\n\n/**\n * Renders an xterm.js terminal display.\n * @param props - Terminal output + input handler + display options\n * @returns A div containing the xterm grid\n */\nfunction Terminal({\n\toutput,\n\tonInput,\n\tcols = 80,\n\trows = 24,\n\ttheme = \"dark\",\n\tcursorBlink = true,\n\tdisableInput = false,\n\tclassName,\n\t...rest\n}: TerminalProps) {\n\tconst containerRef = React.useRef<HTMLDivElement | null>(null);\n\tconst termRef = React.useRef<import(\"@xterm/xterm\").Terminal | null>(null);\n\tconst writtenRef = React.useRef<string>(\"\");\n\tconst onInputRef = React.useRef(onInput);\n\tonInputRef.current = onInput;\n\t// Latest-output mirror so the dynamic-import callback can read the value\n\t// at the moment the engine actually mounts (not the value at first render\n\t// — those can differ when the parent's `output` prop is set lazily).\n\tconst outputRef = React.useRef(output);\n\toutputRef.current = output;\n\n\t// Initialize xterm once on mount. Dynamic import keeps the engine out\n\t// of consumers' bundles unless they actually mount the component.\n\tReact.useEffect(() => {\n\t\tif (!containerRef.current) return;\n\n\t\tlet disposed = false;\n\t\tlet inputDispose: { dispose: () => void } | null = null;\n\n\t\tvoid (async () => {\n\t\t\tconst xtermModule = await import(\"@xterm/xterm\");\n\t\t\tif (disposed || !containerRef.current) return;\n\n\t\t\t// xterm needs hex colors (it can't accept CSS vars), so read\n\t\t\t// the consumer's `--background` / `--foreground` triplets at\n\t\t\t// mount time and convert. A consumer who themes those tokens\n\t\t\t// gets a terminal that follows the page; a consumer mounting\n\t\t\t// Terminal in isolation falls back to the hand-tuned defaults.\n\t\t\tconst fallback = theme === \"dark\" ? DARK_FALLBACK : LIGHT_FALLBACK;\n\t\t\tconst bgHex = readCssVarAsHex(\"background\") ?? fallback.background;\n\t\t\tconst fgHex = readCssVarAsHex(\"foreground\") ?? fallback.foreground;\n\n\t\t\tconst term = new xtermModule.Terminal({\n\t\t\t\tcols,\n\t\t\t\trows,\n\t\t\t\tcursorBlink,\n\t\t\t\tdisableStdin: disableInput,\n\t\t\t\ttheme: {\n\t\t\t\t\tbackground: bgHex,\n\t\t\t\t\tforeground: fgHex,\n\t\t\t\t\tcursor: fgHex,\n\t\t\t\t\tselectionBackground: fallback.selectionBackground,\n\t\t\t\t},\n\t\t\t\tfontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n\t\t\t\tfontSize: 13,\n\t\t\t});\n\t\t\tterm.open(containerRef.current);\n\t\t\ttermRef.current = term;\n\n\t\t\t// Read the LATEST output via the ref — between mount and\n\t\t\t// import-resolve, the parent may have updated the prop. Without\n\t\t\t// this, fast prop changes get clobbered.\n\t\t\tconst latest = normalizeOutput(outputRef.current);\n\t\t\tif (latest) {\n\t\t\t\tterm.write(latest);\n\t\t\t\twrittenRef.current = latest;\n\t\t\t}\n\n\t\t\tinputDispose = term.onData((data) => {\n\t\t\t\tonInputRef.current?.(data);\n\t\t\t});\n\t\t})();\n\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tinputDispose?.dispose();\n\t\t\ttermRef.current?.dispose();\n\t\t\ttermRef.current = null;\n\t\t\twrittenRef.current = \"\";\n\t\t};\n\t\t// cols/rows/theme/cursorBlink/disableInput are mount-time options.\n\t\t// Changing them mid-session would force a full re-init that'd lose\n\t\t// scrollback — out of scope for v1.\n\t}, []);\n\n\t// Diff `output` against what's already on screen and write only the new tail.\n\tReact.useEffect(() => {\n\t\tconst term = termRef.current;\n\t\tif (!term) return;\n\t\tconst next = normalizeOutput(output);\n\t\tif (next === writtenRef.current) return;\n\t\tif (next.startsWith(writtenRef.current)) {\n\t\t\tconst delta = next.slice(writtenRef.current.length);\n\t\t\tif (delta) term.write(delta);\n\t\t} else {\n\t\t\t// Non-suffix change (e.g. consumer cleared the buffer or replaced it\n\t\t\t// with unrelated content) — reset the screen and write fresh.\n\t\t\tterm.reset();\n\t\t\tif (next) term.write(next);\n\t\t}\n\t\twrittenRef.current = next;\n\t}, [output]);\n\n\t// Inline background matches the xterm theme bg. xterm renders its grid\n\t// into a canvas (or DOM rows without their own background-color), so\n\t// a11y tools walk up the DOM looking for a background and would\n\t// otherwise hit the docs-page bg, producing a contrast false positive\n\t// against the xterm fg. The CSS var fallback is an HSL triplet — `hsl()`\n\t// rejects hex literals as a fallback, so the triplet is what makes this\n\t// work when a consumer mounts Terminal without loading `@hex-core/tokens`.\n\tconst fallbackTriplet = theme === \"dark\" ? \"0 0% 4%\" : \"0 0% 98%\";\n\tconst themeBg = `hsl(var(--background, ${fallbackTriplet}))`;\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tref={containerRef}\n\t\t\tdata-hex-terminal\n\t\t\tdata-theme={theme}\n\t\t\tstyle={{ backgroundColor: themeBg, ...(rest.style ?? {}) }}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-hidden rounded-md border p-2\",\n\t\t\t\t\"font-mono text-sm leading-tight\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nfunction normalizeOutput(value: string | string[] | undefined): string {\n\tif (value == null) return \"\";\n\treturn Array.isArray(value) ? value.join(\"\") : value;\n}\n\nexport { Terminal };\n"]}
1
+ {"version":3,"sources":["../src/lib/color.ts","../src/lib/utils.ts","../src/ai/terminal/terminal.tsx"],"names":[],"mappings":";;;;;;AAsCO,SAAS,gBAAgB,OAAA,EAA6B;AAC5D,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,IAAA,EAAK,CAAE,MAAM,KAAK,CAAA;AACxC,EAAA,OAAO;AAAA,IACN,GAAG,MAAA,CAAO,UAAA,CAAW,KAAA,CAAM,CAAC,CAAC,CAAA,IAAK,CAAA;AAAA,IAClC,GAAG,MAAA,CAAO,UAAA,CAAW,KAAA,CAAM,CAAC,CAAC,CAAA,IAAK,CAAA;AAAA,IAClC,GAAG,MAAA,CAAO,UAAA,CAAW,KAAA,CAAM,CAAC,CAAC,CAAA,IAAK;AAAA,GACnC;AACD;AAsBO,SAAS,QAAA,CAAS,CAAA,EAAW,CAAA,EAAW,CAAA,EAAqB;AACnE,EAAA,MAAM,KAAK,CAAA,GAAI,GAAA;AACf,EAAA,MAAM,KAAK,CAAA,GAAI,GAAA;AACf,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,KAAA,CAAe,CAAA,GAAI,IAAI,EAAA,IAAM,EAAA;AACxC,EAAA,MAAM,IAAI,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,IAAI,EAAE,CAAA;AAClC,EAAA,MAAM,IAAI,CAAC,CAAA,KAAc,KAAK,CAAA,GAAI,IAAA,CAAK,IAAI,EAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAE,CAAC,IAAI,CAAA,EAAG,CAAA,GAAI,EAAE,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA;AAC9E,EAAA,OAAO;AAAA,IACN,GAAG,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IACxB,GAAG,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IACxB,GAAG,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAC;AAAA,GACzB;AACD;AAkCO,SAAS,gBAAgB,OAAA,EAAyB;AACxD,EAAA,MAAM,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE,GAAI,gBAAgB,OAAO,CAAA;AAC3C,EAAA,MAAM,EAAE,GAAG,CAAA,EAAG,CAAA,KAAM,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAc,CAAA,CAAE,SAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AAC3D,EAAA,OAAO,CAAA,CAAA,EAAI,KAAA,CAAM,CAAC,CAAC,CAAA,EAAG,KAAA,CAAM,CAAC,CAAC,CAAA,EAAG,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAC1C;AC7GO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;AC4CA,IAAM,aAAA,GAAgB;AAAA,EACrB,UAAA,EAAY,SAAA;AAAA,EACZ,UAAA,EAAY,SAAA;AAAA,EAEZ,mBAAA,EAAqB;AACtB,CAAA;AACA,IAAM,cAAA,GAAiB;AAAA,EACtB,UAAA,EAAY,SAAA;AAAA,EACZ,UAAA,EAAY,SAAA;AAAA,EAEZ,mBAAA,EAAqB;AACtB,CAAA;AAYA,SAAS,gBAAgB,IAAA,EAA6B;AACrD,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,EAAa,OAAO,IAAA;AAC5C,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAiB,QAAA,CAAS,eAAe,CAAA,CACvD,iBAAiB,CAAA,EAAA,EAAK,IAAI,CAAA,CAAE,CAAA,CAC5B,IAAA,EAAK;AACP,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,OAAO,gBAAgB,OAAO,CAAA;AAC/B;AAOA,SAAS,QAAA,CAAS;AAAA,EACjB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA,GAAO,EAAA;AAAA,EACP,IAAA,GAAO,EAAA;AAAA,EACP,KAAA,GAAQ,MAAA;AAAA,EACR,WAAA,GAAc,IAAA;AAAA,EACd,YAAA,GAAe,KAAA;AAAA,EACf,SAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAkB;AACjB,EAAA,MAAM,YAAA,GAAqB,aAA8B,IAAI,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAgB,aAA+C,IAAI,CAAA;AACzE,EAAA,MAAM,UAAA,GAAmB,aAAe,EAAE,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAmB,aAAO,OAAO,CAAA;AACvC,EAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAIrB,EAAA,MAAM,SAAA,GAAkB,aAAO,MAAM,CAAA;AACrC,EAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAIpB,EAAM,gBAAU,MAAM;AACrB,IAAA,IAAI,CAAC,aAAa,OAAA,EAAS;AAE3B,IAAA,IAAI,QAAA,GAAW,KAAA;AACf,IAAA,IAAI,YAAA,GAA+C,IAAA;AAEnD,IAAA,KAAA,CAAM,YAAY;AACjB,MAAA,MAAM,WAAA,GAAc,MAAM,OAAO,cAAc,CAAA;AAC/C,MAAA,IAAI,QAAA,IAAY,CAAC,YAAA,CAAa,OAAA,EAAS;AAOvC,MAAA,MAAM,QAAA,GAAW,KAAA,KAAU,MAAA,GAAS,aAAA,GAAgB,cAAA;AACpD,MAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,YAAY,CAAA,IAAK,QAAA,CAAS,UAAA;AACxD,MAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,YAAY,CAAA,IAAK,QAAA,CAAS,UAAA;AAExD,MAAA,MAAM,IAAA,GAAO,IAAI,WAAA,CAAY,QAAA,CAAS;AAAA,QACrC,IAAA;AAAA,QACA,IAAA;AAAA,QACA,WAAA;AAAA,QACA,YAAA,EAAc,YAAA;AAAA,QACd,KAAA,EAAO;AAAA,UACN,UAAA,EAAY,KAAA;AAAA,UACZ,UAAA,EAAY,KAAA;AAAA,UACZ,MAAA,EAAQ,KAAA;AAAA,UACR,qBAAqB,QAAA,CAAS;AAAA,SAC/B;AAAA,QACA,UAAA,EAAY,gDAAA;AAAA,QACZ,QAAA,EAAU;AAAA,OACV,CAAA;AACD,MAAA,IAAA,CAAK,IAAA,CAAK,aAAa,OAAO,CAAA;AAC9B,MAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAKlB,MAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,SAAA,CAAU,OAAO,CAAA;AAChD,MAAA,IAAI,MAAA,EAAQ;AACX,QAAA,IAAA,CAAK,MAAM,MAAM,CAAA;AACjB,QAAA,UAAA,CAAW,OAAA,GAAU,MAAA;AAAA,MACtB;AAEA,MAAA,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,CAAC,IAAA,KAAS;AACpC,QAAA,UAAA,CAAW,UAAU,IAAI,CAAA;AAAA,MAC1B,CAAC,CAAA;AAAA,IACF,CAAA,GAAG;AAEH,IAAA,OAAO,MAAM;AACZ,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,YAAA,EAAc,OAAA,EAAQ;AACtB,MAAA,OAAA,CAAQ,SAAS,OAAA,EAAQ;AACzB,MAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAClB,MAAA,UAAA,CAAW,OAAA,GAAU,EAAA;AAAA,IACtB,CAAA;AAAA,EAID,CAAA,EAAG,EAAE,CAAA;AAGL,EAAM,gBAAU,MAAM;AACrB,IAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,IAAA,GAAO,gBAAgB,MAAM,CAAA;AACnC,IAAA,IAAI,IAAA,KAAS,WAAW,OAAA,EAAS;AACjC,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,UAAA,CAAW,OAAO,CAAA,EAAG;AACxC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,QAAQ,MAAM,CAAA;AAClD,MAAA,IAAI,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAAA,IAC5B,CAAA,MAAO;AAGN,MAAA,IAAA,CAAK,KAAA,EAAM;AACX,MAAA,IAAI,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAAA,IAC1B;AACA,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AAAA,EACtB,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AASX,EAAA,MAAM,eAAA,GAAkB,KAAA,KAAU,MAAA,GAAS,SAAA,GAAY,UAAA;AACvD,EAAA,MAAM,OAAA,GAAU,yBAAyB,eAAe,CAAA,EAAA,CAAA;AACxD,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,GAAA,EAAK,YAAA;AAAA,MACL,mBAAA,EAAiB,IAAA;AAAA,MACjB,YAAA,EAAY,KAAA;AAAA,MACZ,KAAA,EAAO,EAAE,eAAA,EAAiB,OAAA,EAAS,GAAI,IAAA,CAAK,KAAA,IAAS,EAAC,EAAG;AAAA,MACzD,SAAA,EAAW,EAAA;AAAA,QACV,uCAAA;AAAA,QACA,iCAAA;AAAA,QACA;AAAA;AACD;AAAA,GACD;AAEF;AAEA,SAAS,gBAAgB,KAAA,EAA8C;AACtE,EAAA,IAAI,KAAA,IAAS,MAAM,OAAO,EAAA;AAC1B,EAAA,OAAO,MAAM,OAAA,CAAQ,KAAK,IAAI,KAAA,CAAM,IAAA,CAAK,EAAE,CAAA,GAAI,KAAA;AAChD","file":"terminal.js","sourcesContent":["/**\n * Color conversion utilities for the HSL-triplet token format used across\n * `@hex-core/tokens` themes (`H S% L%`, e.g. `\"240 5.9% 10%\"` — no `hsl()`\n * wrapper, no commas).\n *\n * The triplet is the round-trip-safe serialization for Hex Core: tokens flow\n * triplet → CSS `hsl(var(--token))` → rendered color, and the ColorPicker\n * component edits triplets directly. Hex/RGB conversions are display\n * adapters, not the source of truth.\n */\n\n/** Parsed HSL components. `h` is degrees (0–360); `s` and `l` are percentages (0–100). */\nexport interface HslTriplet {\n\th: number;\n\ts: number;\n\tl: number;\n}\n\n/** Parsed RGB components. Each channel is 0–255. */\nexport interface RgbColor {\n\tr: number;\n\tg: number;\n\tb: number;\n}\n\n/**\n * Parse an HSL triplet string into numeric components.\n *\n * Note: malformed input silently coerces to `{0,0,0}` (pure black) rather than\n * returning an error signal. Callers that need to distinguish \"user typed\n * black\" from \"user typed garbage\" should validate the input format first.\n * `hexToHslTriplet` returns `null` for malformed hex; this asymmetry is\n * intentional — triplets feed CSS variables where any non-color value would\n * already break rendering.\n *\n * @param triplet - String in the form `\"<H> <S>% <L>%\"` (e.g. `\"240 5.9% 10%\"`).\n * @returns Numeric components, or `{0,0,0}` if the input is malformed.\n */\nexport function parseHslTriplet(triplet: string): HslTriplet {\n\tconst parts = triplet.trim().split(/\\s+/);\n\treturn {\n\t\th: Number.parseFloat(parts[0]) || 0,\n\t\ts: Number.parseFloat(parts[1]) || 0,\n\t\tl: Number.parseFloat(parts[2]) || 0,\n\t};\n}\n\n/**\n * Format HSL components into an HSL triplet string (the canonical token format).\n * @param hsl - Numeric components.\n * @returns Triplet in the form `\"<H> <S>% <L>%\"`.\n */\nexport function formatHslTriplet({ h, s, l }: HslTriplet): string {\n\t// Tolerant integer check: rgbToHsl can produce values like 5.0000000001 due\n\t// to float arithmetic; format those as \"5\" rather than \"5.0\".\n\tconst round = (n: number) =>\n\t\tMath.abs(n - Math.round(n)) < 1e-6 ? `${Math.round(n)}` : n.toFixed(1);\n\treturn `${Math.round(h)} ${round(s)}% ${round(l)}%`;\n}\n\n/**\n * Convert HSL components to RGB.\n * @param h - Hue (0–360).\n * @param s - Saturation (0–100).\n * @param l - Lightness (0–100).\n * @returns RGB channels (0–255, rounded).\n */\nexport function hslToRgb(h: number, s: number, l: number): RgbColor {\n\tconst sN = s / 100;\n\tconst lN = l / 100;\n\tconst k = (n: number) => (n + h / 30) % 12;\n\tconst a = sN * Math.min(lN, 1 - lN);\n\tconst f = (n: number) => lN - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));\n\treturn {\n\t\tr: Math.round(255 * f(0)),\n\t\tg: Math.round(255 * f(8)),\n\t\tb: Math.round(255 * f(4)),\n\t};\n}\n\n/**\n * Convert RGB components to HSL.\n * @param r - Red (0–255).\n * @param g - Green (0–255).\n * @param b - Blue (0–255).\n * @returns HSL components (h: 0–360, s: 0–100, l: 0–100).\n */\nexport function rgbToHsl(r: number, g: number, b: number): HslTriplet {\n\tconst rN = r / 255;\n\tconst gN = g / 255;\n\tconst bN = b / 255;\n\tconst max = Math.max(rN, gN, bN);\n\tconst min = Math.min(rN, gN, bN);\n\tlet h = 0;\n\tlet s = 0;\n\tconst l = (max + min) / 2;\n\tif (max !== min) {\n\t\tconst d = max - min;\n\t\ts = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\t\tif (max === rN) h = (gN - bN) / d + (gN < bN ? 6 : 0);\n\t\telse if (max === gN) h = (bN - rN) / d + 2;\n\t\telse h = (rN - gN) / d + 4;\n\t\th /= 6;\n\t}\n\treturn { h: h * 360, s: s * 100, l: l * 100 };\n}\n\n/**\n * Convert an HSL triplet to a 6-digit hex string.\n * @param triplet - HSL triplet (e.g. `\"240 5.9% 10%\"`).\n * @returns Lowercase hex string with leading `#` (e.g. `\"#181a1f\"`).\n */\nexport function hslTripletToHex(triplet: string): string {\n\tconst { h, s, l } = parseHslTriplet(triplet);\n\tconst { r, g, b } = hslToRgb(h, s, l);\n\tconst toHex = (n: number) => n.toString(16).padStart(2, \"0\");\n\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n}\n\n/**\n * Convert a hex string to an HSL triplet.\n * Accepts 3-digit (`#abc`) or 6-digit (`#aabbcc`) hex with optional `#`.\n * @param hex - Hex color string.\n * @returns HSL triplet, or `null` if the input is malformed.\n */\nexport function hexToHslTriplet(hex: string): string | null {\n\tconst clean = hex.trim().replace(/^#/, \"\");\n\tlet normalized: string;\n\tif (/^[0-9a-fA-F]{3}$/.test(clean)) {\n\t\tnormalized = clean\n\t\t\t.split(\"\")\n\t\t\t.map((c) => c + c)\n\t\t\t.join(\"\");\n\t} else if (/^[0-9a-fA-F]{6}$/.test(clean)) {\n\t\tnormalized = clean;\n\t} else {\n\t\treturn null;\n\t}\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn formatHslTriplet(rgbToHsl(r, g, b));\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { hslTripletToHex } from \"../../lib/color.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Headless terminal display backed by xterm.js. Renders an xterm grid\n * inside a div the consumer styles. No PTY, no shell — the consumer\n * owns the data-flow:\n *\n * - Pass `output` (string or string[]) to write to the display. Each\n * change is diffed against the prior render and only the new tail\n * is `term.write()`-ed, so feeding a streaming buffer doesn't redraw.\n * - Pass `onInput` to receive bytes the user typed. Wire it to a\n * WebSocket / IPC / fetch stream — terminal doesn't care.\n *\n * Heavy peer: requires `@xterm/xterm` (~150 KB gzip). The hex-core CLI's\n * `add` flow prompts before installing.\n *\n * @example\n * <Terminal\n * output={[\"$ ls\\r\\n\", \"package.json src/\\r\\n\", \"$ \"]}\n * onInput={(data) => ws.send(data)}\n * rows={24}\n * cols={80}\n * />\n */\nexport interface TerminalProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\" | \"onInput\"> {\n\t/**\n\t * Bytes to display. String is written verbatim; string[] is joined.\n\t * On change, only the suffix beyond the prior render is emitted, so\n\t * appending to a streaming buffer is O(delta).\n\t */\n\toutput?: string | string[];\n\t/** Receive bytes the user typed (incl. control sequences). */\n\tonInput?: (data: string) => void;\n\t/** Initial cols. xterm allows runtime resize via fit-addon (not bundled). Default 80. */\n\tcols?: number;\n\t/** Initial rows. Default 24. */\n\trows?: number;\n\t/** Theme tokens — defaults to neutral light/dark via CSS vars. */\n\ttheme?: \"dark\" | \"light\";\n\t/** Enable cursor blink. Default true. */\n\tcursorBlink?: boolean;\n\t/** Whether the user can type into the terminal. Default true. */\n\tdisableInput?: boolean;\n}\n\n// Fallback xterm themes used when the consumer hasn't loaded `@hex-core/tokens`\n// or hasn't defined the standard `--background` / `--foreground` CSS vars\n// (e.g. consumer mounted Terminal in isolation). Match the `Terminal`\n// wrapper's inline `themeBg` defaults below — both must agree or there's\n// a visible seam between the xterm canvas and the wrapper.\nconst DARK_FALLBACK = {\n\tbackground: \"#0a0a0a\",\n\tforeground: \"#e5e5e5\",\n\tcursor: \"#e5e5e5\",\n\tselectionBackground: \"#404040\",\n};\nconst LIGHT_FALLBACK = {\n\tbackground: \"#fafafa\",\n\tforeground: \"#171717\",\n\tcursor: \"#171717\",\n\tselectionBackground: \"#d4d4d4\",\n};\n\n/**\n * Read a CSS HSL-triplet variable from `:root` (or the nearest theme\n * scope) and convert it to a 6-digit hex string suitable for xterm's\n * `theme: { background: \"#...\" }` option, which accepts hex/rgb but NOT\n * CSS variables. Returns `null` if the variable is unset, so the caller\n * can fall back to a hand-tuned theme without rendering pure-black.\n *\n * @param name - CSS variable name without the leading `--` (e.g. `\"background\"`).\n * @returns A `#xxxxxx` hex color string, or `null` if the var isn't defined.\n */\nfunction readCssVarAsHex(name: string): string | null {\n\tif (typeof document === \"undefined\") return null;\n\tconst triplet = getComputedStyle(document.documentElement)\n\t\t.getPropertyValue(`--${name}`)\n\t\t.trim();\n\tif (!triplet) return null;\n\treturn hslTripletToHex(triplet);\n}\n\n/**\n * Renders an xterm.js terminal display.\n * @param props - Terminal output + input handler + display options\n * @returns A div containing the xterm grid\n */\nfunction Terminal({\n\toutput,\n\tonInput,\n\tcols = 80,\n\trows = 24,\n\ttheme = \"dark\",\n\tcursorBlink = true,\n\tdisableInput = false,\n\tclassName,\n\t...rest\n}: TerminalProps) {\n\tconst containerRef = React.useRef<HTMLDivElement | null>(null);\n\tconst termRef = React.useRef<import(\"@xterm/xterm\").Terminal | null>(null);\n\tconst writtenRef = React.useRef<string>(\"\");\n\tconst onInputRef = React.useRef(onInput);\n\tonInputRef.current = onInput;\n\t// Latest-output mirror so the dynamic-import callback can read the value\n\t// at the moment the engine actually mounts (not the value at first render\n\t// — those can differ when the parent's `output` prop is set lazily).\n\tconst outputRef = React.useRef(output);\n\toutputRef.current = output;\n\n\t// Initialize xterm once on mount. Dynamic import keeps the engine out\n\t// of consumers' bundles unless they actually mount the component.\n\tReact.useEffect(() => {\n\t\tif (!containerRef.current) return;\n\n\t\tlet disposed = false;\n\t\tlet inputDispose: { dispose: () => void } | null = null;\n\n\t\tvoid (async () => {\n\t\t\tconst xtermModule = await import(\"@xterm/xterm\");\n\t\t\tif (disposed || !containerRef.current) return;\n\n\t\t\t// xterm needs hex colors (it can't accept CSS vars), so read\n\t\t\t// the consumer's `--background` / `--foreground` triplets at\n\t\t\t// mount time and convert. A consumer who themes those tokens\n\t\t\t// gets a terminal that follows the page; a consumer mounting\n\t\t\t// Terminal in isolation falls back to the hand-tuned defaults.\n\t\t\tconst fallback = theme === \"dark\" ? DARK_FALLBACK : LIGHT_FALLBACK;\n\t\t\tconst bgHex = readCssVarAsHex(\"background\") ?? fallback.background;\n\t\t\tconst fgHex = readCssVarAsHex(\"foreground\") ?? fallback.foreground;\n\n\t\t\tconst term = new xtermModule.Terminal({\n\t\t\t\tcols,\n\t\t\t\trows,\n\t\t\t\tcursorBlink,\n\t\t\t\tdisableStdin: disableInput,\n\t\t\t\ttheme: {\n\t\t\t\t\tbackground: bgHex,\n\t\t\t\t\tforeground: fgHex,\n\t\t\t\t\tcursor: fgHex,\n\t\t\t\t\tselectionBackground: fallback.selectionBackground,\n\t\t\t\t},\n\t\t\t\tfontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n\t\t\t\tfontSize: 13,\n\t\t\t});\n\t\t\tterm.open(containerRef.current);\n\t\t\ttermRef.current = term;\n\n\t\t\t// Read the LATEST output via the ref — between mount and\n\t\t\t// import-resolve, the parent may have updated the prop. Without\n\t\t\t// this, fast prop changes get clobbered.\n\t\t\tconst latest = normalizeOutput(outputRef.current);\n\t\t\tif (latest) {\n\t\t\t\tterm.write(latest);\n\t\t\t\twrittenRef.current = latest;\n\t\t\t}\n\n\t\t\tinputDispose = term.onData((data) => {\n\t\t\t\tonInputRef.current?.(data);\n\t\t\t});\n\t\t})();\n\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tinputDispose?.dispose();\n\t\t\ttermRef.current?.dispose();\n\t\t\ttermRef.current = null;\n\t\t\twrittenRef.current = \"\";\n\t\t};\n\t\t// cols/rows/theme/cursorBlink/disableInput are mount-time options.\n\t\t// Changing them mid-session would force a full re-init that'd lose\n\t\t// scrollback — out of scope for v1.\n\t}, []);\n\n\t// Diff `output` against what's already on screen and write only the new tail.\n\tReact.useEffect(() => {\n\t\tconst term = termRef.current;\n\t\tif (!term) return;\n\t\tconst next = normalizeOutput(output);\n\t\tif (next === writtenRef.current) return;\n\t\tif (next.startsWith(writtenRef.current)) {\n\t\t\tconst delta = next.slice(writtenRef.current.length);\n\t\t\tif (delta) term.write(delta);\n\t\t} else {\n\t\t\t// Non-suffix change (e.g. consumer cleared the buffer or replaced it\n\t\t\t// with unrelated content) — reset the screen and write fresh.\n\t\t\tterm.reset();\n\t\t\tif (next) term.write(next);\n\t\t}\n\t\twrittenRef.current = next;\n\t}, [output]);\n\n\t// Inline background matches the xterm theme bg. xterm renders its grid\n\t// into a canvas (or DOM rows without their own background-color), so\n\t// a11y tools walk up the DOM looking for a background and would\n\t// otherwise hit the docs-page bg, producing a contrast false positive\n\t// against the xterm fg. The CSS var fallback is an HSL triplet — `hsl()`\n\t// rejects hex literals as a fallback, so the triplet is what makes this\n\t// work when a consumer mounts Terminal without loading `@hex-core/tokens`.\n\tconst fallbackTriplet = theme === \"dark\" ? \"0 0% 4%\" : \"0 0% 98%\";\n\tconst themeBg = `hsl(var(--background, ${fallbackTriplet}))`;\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tref={containerRef}\n\t\t\tdata-hex-terminal\n\t\t\tdata-theme={theme}\n\t\t\tstyle={{ backgroundColor: themeBg, ...(rest.style ?? {}) }}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-hidden rounded-md border p-2\",\n\t\t\t\t\"font-mono text-sm leading-tight\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nfunction normalizeOutput(value: string | string[] | undefined): string {\n\tif (value == null) return \"\";\n\treturn Array.isArray(value) ? value.join(\"\") : value;\n}\n\nexport { Terminal };\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/primitives/textarea/textarea.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACDA,IAAM,QAAA,GAAiB,KAAA,CAAA,UAAA;AAAA,EACtB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,KAAQ;AACjC,IAAA,uBACC,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACV,sIAAA;AAAA,UACA,iEAAA;AAAA,UACA,qDAAA;AAAA,UACA,mCAAA;AAAA,UACA,qGAAA;AAAA,UACA,sDAAA;AAAA,UACA,sCAAA;AAAA,UACA,iDAAA;AAAA,UACA;AAAA,SACD;AAAA,QACA,GAAA;AAAA,QACC,GAAG;AAAA;AAAA,KACL;AAAA,EAEF;AACD;AACA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"textarea.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * A styled multi-line text input with smooth focus transitions and shadow effects.\n * Extends the native HTML textarea element with Hex UI styling.\n */\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n\t({ className, ...props }, ref) => {\n\t\treturn (\n\t\t\t<textarea\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex min-h-[80px] w-full rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\"placeholder:text-muted-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\t\"focus-visible:shadow-md focus-visible:border-ring/50\",\n\t\t\t\t\t\"hover:border-ring/30 hover:shadow-md\",\n\t\t\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/primitives/textarea/textarea.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACDA,IAAM,QAAA,GAAiB,KAAA,CAAA,UAAA;AAAA,EACtB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,KAAQ;AACjC,IAAA,uBACC,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACV,sIAAA;AAAA,UACA,iEAAA;AAAA,UACA,qDAAA;AAAA,UACA,mCAAA;AAAA,UACA,qGAAA;AAAA,UACA,sDAAA;AAAA,UACA,sCAAA;AAAA,UACA,iDAAA;AAAA,UACA;AAAA,SACD;AAAA,QACA,GAAA;AAAA,QACC,GAAG;AAAA;AAAA,KACL;AAAA,EAEF;AACD;AACA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"textarea.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * A styled multi-line text input with smooth focus transitions and shadow effects.\n * Extends the native HTML textarea element with Hex Core styling.\n */\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n\t({ className, ...props }, ref) => {\n\t\treturn (\n\t\t\t<textarea\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex min-h-[80px] w-full rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\"placeholder:text-muted-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\t\"focus-visible:shadow-md focus-visible:border-ring/50\",\n\t\t\t\t\t\"hover:border-ring/30 hover:shadow-md\",\n\t\t\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hex-core/components",
3
- "version": "1.8.0",
4
- "description": "AI-native React components for Hex UI — Radix UI + Tailwind CSS with machine-readable schemas. RSC-aware per-component bundles + tree-shakable.",
3
+ "version": "1.9.0",
4
+ "description": "AI-native React components for Hex Core — Radix UI + Tailwind CSS with machine-readable schemas. RSC-aware per-component bundles + tree-shakable.",
5
5
  "keywords": [
6
6
  "react",
7
7
  "components",
@@ -10,7 +10,7 @@
10
10
  "mcp",
11
11
  "ai-native",
12
12
  "component-library",
13
- "hex-ui"
13
+ "hex-core"
14
14
  ],
15
15
  "license": "MIT",
16
16
  "author": "Oscar Corona <oabc4004@gmail.com>",
@@ -113,7 +113,7 @@
113
113
  "typescript": "^6.0.3",
114
114
  "vaul": "^1.1.2",
115
115
  "wavesurfer.js": "^7.8.0",
116
- "@hex-core/registry": "^0.3.4"
116
+ "@hex-core/registry": "^0.4.0"
117
117
  },
118
118
  "peerDependencies": {
119
119
  "@hex-core/registry": "*",