@particle-academy/react-fancy 6.5.0 → 6.6.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/chunk-2X54BVXG.js +58 -0
  3. package/dist/chunk-2X54BVXG.js.map +1 -0
  4. package/dist/chunk-5WXY3Q6X.cjs +63 -0
  5. package/dist/chunk-5WXY3Q6X.cjs.map +1 -0
  6. package/dist/{chunk-YRI6OFLY.js → chunk-MI57NAKF.js} +24 -21
  7. package/dist/chunk-MI57NAKF.js.map +1 -0
  8. package/dist/{chunk-QH4YSG7C.cjs → chunk-PM5I5ZHK.cjs} +23 -20
  9. package/dist/chunk-PM5I5ZHK.cjs.map +1 -0
  10. package/dist/{chunk-PVHZO4T3.js → chunk-TFX4LL7V.js} +17 -12
  11. package/dist/chunk-TFX4LL7V.js.map +1 -0
  12. package/dist/{chunk-RE4BYTVM.cjs → chunk-THMFLRDW.cjs} +4 -4
  13. package/dist/{chunk-RE4BYTVM.cjs.map → chunk-THMFLRDW.cjs.map} +1 -1
  14. package/dist/{chunk-YYNUTUJO.js → chunk-VSTUGU7W.js} +3 -3
  15. package/dist/{chunk-YYNUTUJO.js.map → chunk-VSTUGU7W.js.map} +1 -1
  16. package/dist/{chunk-TQL3QW7F.cjs → chunk-YQZB5Z7C.cjs} +16 -11
  17. package/dist/chunk-YQZB5Z7C.cjs.map +1 -0
  18. package/dist/code-block.cjs +3 -3
  19. package/dist/code-block.js +2 -2
  20. package/dist/code-view.cjs +3 -3
  21. package/dist/code-view.js +2 -2
  22. package/dist/editor.cjs +5 -5
  23. package/dist/editor.js +3 -3
  24. package/dist/index.cjs +8 -8
  25. package/dist/index.js +4 -4
  26. package/dist/styles.css +20 -0
  27. package/dist/styles.css.map +1 -1
  28. package/docs/CodeBlock.md +11 -3
  29. package/docs/CodeView.md +7 -3
  30. package/package.json +2 -2
  31. package/dist/chunk-6BB32POL.js +0 -29
  32. package/dist/chunk-6BB32POL.js.map +0 -1
  33. package/dist/chunk-HZUKPYR3.cjs +0 -31
  34. package/dist/chunk-HZUKPYR3.cjs.map +0 -1
  35. package/dist/chunk-PVHZO4T3.js.map +0 -1
  36. package/dist/chunk-QH4YSG7C.cjs.map +0 -1
  37. package/dist/chunk-TQL3QW7F.cjs.map +0 -1
  38. package/dist/chunk-YRI6OFLY.js.map +0 -1
package/dist/styles.css CHANGED
@@ -35,6 +35,26 @@
35
35
  --color-secondary-900: var(--color-zinc-100);
36
36
  --color-secondary-950: var(--color-zinc-50);
37
37
  }
38
+ :where(.dark [data-react-fancy-code-palette], [data-theme=dark] [data-react-fancy-code-palette], .dark[data-react-fancy-code-palette], [data-theme=dark][data-react-fancy-code-palette]) {
39
+ --fc-background: var(--fc-background-d);
40
+ --fc-foreground: var(--fc-foreground-d);
41
+ --fc-gutterBackground: var(--fc-gutterBackground-d);
42
+ --fc-gutterForeground: var(--fc-gutterForeground-d);
43
+ --fc-gutterBorder: var(--fc-gutterBorder-d);
44
+ --fc-cursorColor: var(--fc-cursorColor-d);
45
+ --fc-keyword: var(--fc-keyword-d);
46
+ --fc-string: var(--fc-string-d);
47
+ --fc-comment: var(--fc-comment-d);
48
+ --fc-number: var(--fc-number-d);
49
+ --fc-operator: var(--fc-operator-d);
50
+ --fc-function: var(--fc-function-d);
51
+ --fc-type: var(--fc-type-d);
52
+ --fc-tag: var(--fc-tag-d);
53
+ --fc-attribute: var(--fc-attribute-d);
54
+ --fc-attributeValue: var(--fc-attributeValue-d);
55
+ --fc-punctuation: var(--fc-punctuation-d);
56
+ --fc-variable: var(--fc-variable-d);
57
+ }
38
58
  [data-react-fancy-input] input,
39
59
  [data-react-fancy-textarea],
40
60
  [data-react-fancy-select],
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @particle-academy/react-fancy — base styles + animations */\n\n/* ─── Brand colour scheme ────────────────────────────────────────────────────\n Three token families every Fancy package can rely on, so a component never\n has to invent a palette or hardcode a literal:\n\n brand one accent — the thing a consumer rebrands first\n primary-* the accent as a full 50→950 scale\n secondary-* the NEUTRAL scale for surfaces, borders and body text\n\n Why this exists: packages were already writing `bg-brand`, `text-primary-600`\n and `border-secondary-200` against tokens nothing defined. Tailwind generated\n no such utility, the class silently resolved to nothing, and the component\n rendered unstyled — correct markup, no colour, no error. Defining them here\n turns those classes into a contract instead of a hope.\n\n SECONDARY INVERTS WITH THE THEME. `text-secondary-900` means \"strongest\n foreground\", not \"nearly black\" — so it stays readable on a dark surface.\n That distinction is the whole point: mixing a literal background (`bg-white`)\n with a semantic foreground (`text-secondary-900`) is what produced\n white-on-white in a dark host.\n\n OVERRIDE IT. Redefine any of these in your own `@theme` (or on `:root`) and\n yours wins — nothing here is `!important`, and the utilities read the variable\n rather than baking a value in:\n\n @theme { --color-brand: var(--color-emerald-600); }\n ──────────────────────────────────────────────────────────────────────────── */\n@theme {\n /* THE HOST'S OWN COLOUR. `color=\"brand\"` on any component resolves to these.\n Three variables, not one: a generated hover assumes \"same hue, darker\",\n and a brand palette need not work that way — a navy whose hover is gold\n cannot be derived from navy. So the host states the hover instead of the\n kit guessing it.\n\n :root {\n --color-brand: #003057;\n --color-brand-contrast: #ffffff; text/icon ON the brand colour\n --color-brand-hover: #D4A017; need not be a shade of brand\n }\n\n PER MODE, SWAP THE PAIR. `--color-brand` and `--color-brand-contrast` only\n mean anything together. Repointing one alone fails QUIETLY -- the button\n still renders, it is just unreadable (a pale surface still carrying white\n text; or, on ghost/outline where brand is the LABEL, dark text on a dark\n background):\n\n .dark { --color-brand: #BFD7EA; --color-brand-contrast: #003057; }\n\n `--color-brand-hover` usually needs no per-mode value: an accent chosen to\n stand against the brand tends to stand against it in both modes.\n\n NOTE: this comment does not survive the build -- `@theme` is emitted\n without it. The consumer-facing copy is in README.md, and that is the one\n to keep correct.\n\n Defaults keep the kit's violet so nothing changes for a host that never\n sets them. Soft/outline/ghost variants derive their tints with opacity\n modifiers (`bg-brand/10`), which is what lets three variables cover four\n variants without asking for a whole scale. */\n --color-brand: var(--color-violet-600);\n --color-brand-contrast: var(--color-white);\n --color-brand-hover: var(--color-violet-700);\n\n --color-primary-50: var(--color-violet-50);\n --color-primary-100: var(--color-violet-100);\n --color-primary-200: var(--color-violet-200);\n --color-primary-300: var(--color-violet-300);\n --color-primary-400: var(--color-violet-400);\n --color-primary-500: var(--color-violet-500);\n --color-primary-600: var(--color-violet-600);\n --color-primary-700: var(--color-violet-700);\n --color-primary-800: var(--color-violet-800);\n --color-primary-900: var(--color-violet-900);\n --color-primary-950: var(--color-violet-950);\n\n /* Light-theme defaults: 50 = faintest surface, 900/950 = strongest text. */\n --color-secondary-50: var(--color-zinc-50);\n --color-secondary-100: var(--color-zinc-100);\n --color-secondary-200: var(--color-zinc-200);\n --color-secondary-300: var(--color-zinc-300);\n --color-secondary-400: var(--color-zinc-400);\n --color-secondary-500: var(--color-zinc-500);\n --color-secondary-600: var(--color-zinc-600);\n --color-secondary-700: var(--color-zinc-700);\n --color-secondary-800: var(--color-zinc-800);\n --color-secondary-900: var(--color-zinc-900);\n --color-secondary-950: var(--color-zinc-950);\n}\n\n/* ─── Full screen in the top layer — neutralise the UA popover box ───────────\n An overlay-mode FullScreen is promoted with popover=\"manual\" so ancestor\n transforms / filters cannot trap it, and the UA sheet then styles it as a\n popover: padding .25em, a solid border, Canvas / CanvasText colours,\n overflow:auto. Any author rule outranks the UA origin, so this zero-\n specificity rule in the base layer puts those back to what a plain box has,\n while every utility a consumer passes through className still wins. Inline\n styles could not do that: they would beat the consumer's own classes. The\n box geometry (inset, width, height, margin) is set inline by the hook. */\n@layer base {\n :where([data-fullscreen-layer=\"top\"]) {\n padding: 0;\n border: 0 solid;\n background-color: transparent;\n color: inherit;\n overflow: visible;\n }\n}\n\n@layer base {\n\n/* ─── Progress (circular) — named diameters ──────────────────────────────────\n These ship as real CSS rather than Tailwind classes on the element, because a\n consumer who has not @sourced this package gets no generated utilities and\n the ring would render with NO SIZE at all. They were inline styles before,\n which always worked but could not be overridden by className (issue #17).\n\n Being inside @layer base, a className utility now beats them — which is the\n whole point, and the reason #20 had to land first. */\n[data-react-fancy-progress][data-size=\"sm\"] { width: 2rem; height: 2rem; }\n[data-react-fancy-progress][data-size=\"md\"] { width: 3rem; height: 3rem; }\n[data-react-fancy-progress][data-size=\"lg\"] { width: 4rem; height: 4rem; }\n\n\n\n/* Dark: the neutral scale flips, so \"900\" still means strongest foreground and\n \"50\" still means faintest surface. Wrapped in :where() for zero specificity,\n matching the rest of this file — any consumer override beats it.\n\n EVERY dark selector in this file names `[data-theme=\"dark\"]` beside `.dark`\n (5.53.0). A consumer's `@custom-variant dark` cannot reach these: it rewrites\n `dark:` utilities, never a selector with `.dark` written into it.\n tests/data-theme.test.ts fails on any `.dark` selector without its twin. */\n:where(.dark, [data-theme=\"dark\"]) {\n --color-secondary-50: var(--color-zinc-950);\n --color-secondary-100: var(--color-zinc-900);\n --color-secondary-200: var(--color-zinc-800);\n --color-secondary-300: var(--color-zinc-700);\n --color-secondary-400: var(--color-zinc-600);\n --color-secondary-500: var(--color-zinc-500);\n --color-secondary-600: var(--color-zinc-400);\n --color-secondary-700: var(--color-zinc-300);\n --color-secondary-800: var(--color-zinc-200);\n --color-secondary-900: var(--color-zinc-100);\n --color-secondary-950: var(--color-zinc-50);\n}\n\n/* ─── Input & Field defaults ─────────────────────────────────────────────────\n Better UX out of the box: spacing between stacked fields, smooth transitions,\n and polished dark-mode defaults. All overridable via data-attribute selectors.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Field spacing is the CONTAINER's job, not the field's.\n ────────────────────────────────────────────────────────────────────────────\n This used to be:\n\n [data-react-fancy-field] + [data-react-fancy-field] { margin-top: 1rem; }\n\n An adjacent-sibling selector cannot know which way its parent lays children\n out. Stacked vertically it read as spacing; inside a `grid-cols-2` row it\n pushed the right-hand cell 16px down, and `items-start` could not fix it\n because a margin is not alignment. The only escape was wrapping every field\n in a plain <div> so each became an only-child.\n\n Space fields with the container instead — `space-y-4`, or `gap-4` on a flex\n or grid parent. A container knows its own axis; a sibling selector never\n can. See CHANGELOG 5.17.0 for the migration.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Smooth transitions on all text inputs, selects, and textareas */\n[data-react-fancy-input] input,\n[data-react-fancy-textarea],\n[data-react-fancy-select],\n[data-react-fancy-date-picker],\n[data-react-fancy-autocomplete] input,\n[data-react-fancy-pillbox],\n[data-react-fancy-otp-input] input,\n[data-react-fancy-time-picker] input,\n[data-react-fancy-color-picker] input {\n transition: border-color 0.15s ease, box-shadow 0.15s ease,\n background-color 0.15s ease;\n}\n\n/* Dark-mode input refinements — slightly darker bg for contrast against page */\n/* ─── Inherent dark-mode defaults ────────────────────────────────────────────\n Every rule below is wrapped in :where() so it carries ZERO specificity, which\n buys two properties at once:\n 1. Inherent — a sensible dark appearance ships out of the box, even when the\n consumer's Tailwind build doesn't generate react-fancy's `dark:` utility\n classes (e.g. they didn't @source the package). This is what lets the\n overlays (Dropdown, Menu, Popover, …) go dark on their own.\n 2. Override-friendly — because specificity is 0, ANY consumer override wins:\n a plain `dark:bg-…` utility, a custom class, or the component's own\n `dark:` class (when it IS generated) all take precedence — no !important,\n no need to target the data-attribute.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Every colour below reads a semantic token (`--fancy-<role>-dark`, see\n THEME_TOKENS / README \"Semantic tokens\") with today's value as the fallback,\n so a host that sets nothing sees exactly what it saw before. */\n\n/* Inputs / selects / textareas — darker bg for contrast against the page */\n:where(.dark [data-react-fancy-input] input, [data-theme=\"dark\"] [data-react-fancy-input] input),\n:where(.dark [data-react-fancy-textarea], [data-theme=\"dark\"] [data-react-fancy-textarea]),\n:where(.dark [data-react-fancy-select], [data-theme=\"dark\"] [data-react-fancy-select]),\n:where(.dark [data-react-fancy-date-picker], [data-theme=\"dark\"] [data-react-fancy-date-picker]),\n:where(.dark [data-react-fancy-autocomplete] input, [data-theme=\"dark\"] [data-react-fancy-autocomplete] input),\n:where(.dark [data-react-fancy-pillbox], [data-theme=\"dark\"] [data-react-fancy-pillbox]),\n:where(.dark [data-react-fancy-otp-input] input, [data-theme=\"dark\"] [data-react-fancy-otp-input] input),\n:where(.dark [data-react-fancy-time-picker] input, [data-theme=\"dark\"] [data-react-fancy-time-picker] input) {\n background-color: var(--fancy-input-dark, #1e1e24);\n border-color: var(--fancy-border-strong-dark, #3f3f46);\n}\n\n/* Focus ring — brighter border + subtle glow */\n:where(.dark [data-react-fancy-input] input:focus, [data-theme=\"dark\"] [data-react-fancy-input] input:focus),\n:where(.dark [data-react-fancy-textarea]:focus, [data-theme=\"dark\"] [data-react-fancy-textarea]:focus),\n:where(.dark [data-react-fancy-select]:focus, [data-theme=\"dark\"] [data-react-fancy-select]:focus),\n:where(.dark [data-react-fancy-date-picker]:focus, [data-theme=\"dark\"] [data-react-fancy-date-picker]:focus),\n:where(.dark [data-react-fancy-autocomplete] input:focus, [data-theme=\"dark\"] [data-react-fancy-autocomplete] input:focus),\n:where(.dark [data-react-fancy-otp-input] input:focus, [data-theme=\"dark\"] [data-react-fancy-otp-input] input:focus),\n:where(.dark [data-react-fancy-time-picker] input:focus, [data-theme=\"dark\"] [data-react-fancy-time-picker] input:focus) {\n border-color: var(--fancy-focus-dark, #60a5fa);\n /* = rgba(96, 165, 250, 0.15) when the token is unset */\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fancy-focus-dark, #60a5fa) 15%, transparent);\n}\n\n/* Field labels — brighter for readability */\n:where(.dark [data-react-fancy-field] > label:first-child, [data-theme=\"dark\"] [data-react-fancy-field] > label:first-child) {\n color: var(--fancy-text-dark, #f4f4f5);\n}\n\n/* Checkbox & radio */\n:where(.dark [data-react-fancy-checkbox] input, [data-theme=\"dark\"] [data-react-fancy-checkbox] input),\n:where(.dark [data-react-fancy-radio-group] input, [data-theme=\"dark\"] [data-react-fancy-radio-group] input) {\n background-color: var(--fancy-input-dark, #1e1e24);\n border-color: var(--fancy-border-strong-dark, #3f3f46);\n}\n\n/* Switch unchecked track */\n:where(.dark [data-react-fancy-switch] button[aria-checked=\"false\"], [data-theme=\"dark\"] [data-react-fancy-switch] button[aria-checked=\"false\"]) {\n background-color: var(--fancy-border-dark, #3f3f46);\n}\n\n/* Input wrapper affixes */\n:where(.dark [data-react-fancy-input-wrapper] > span:first-child, [data-theme=\"dark\"] [data-react-fancy-input-wrapper] > span:first-child),\n:where(.dark [data-react-fancy-input-wrapper] > span:last-child, [data-theme=\"dark\"] [data-react-fancy-input-wrapper] > span:last-child) {\n border-color: var(--fancy-border-strong-dark, #3f3f46);\n background-color: var(--fancy-surface-muted-dark, #27272a);\n}\n\n/* Date picker icon (calendar, clock) */\n:where(.dark [data-react-fancy-date-picker]::-webkit-calendar-picker-indicator, [data-theme=\"dark\"] [data-react-fancy-date-picker]::-webkit-calendar-picker-indicator) {\n filter: invert(0.8);\n}\n\n/* ─── Overlays — inherent dark surfaces ──────────────────────────────────────\n Dropdown / Menu / Popover / ContextMenu / MobileMenu flyout / Modal / Toast.\n Mirrors the components' own `dark:` utilities (zinc-900 surface, zinc-700\n border, zinc-300 text) so overlays render correctly in dark mode WITHOUT the\n consumer @sourcing react-fancy. When those utilities ARE generated they win\n (specificity 0 here), so there's no drift or double-styling. */\n:where(.dark [data-react-fancy-dropdown], [data-theme=\"dark\"] [data-react-fancy-dropdown]),\n:where(.dark [data-react-fancy-menu], [data-theme=\"dark\"] [data-react-fancy-menu]),\n:where(.dark [data-react-fancy-popover], [data-theme=\"dark\"] [data-react-fancy-popover]),\n:where(.dark [data-react-fancy-context-menu], [data-theme=\"dark\"] [data-react-fancy-context-menu]),\n:where(.dark [data-react-fancy-context-menu-sub-content], [data-theme=\"dark\"] [data-react-fancy-context-menu-sub-content]),\n:where(.dark [data-react-fancy-mobile-menu-flyout], [data-theme=\"dark\"] [data-react-fancy-mobile-menu-flyout]),\n:where(.dark [data-react-fancy-modal], [data-theme=\"dark\"] [data-react-fancy-modal]),\n:where(.dark [data-react-fancy-toast-item], [data-theme=\"dark\"] [data-react-fancy-toast-item]) {\n background-color: var(--fancy-surface-dark, #18181b); /* zinc-900 */\n border-color: var(--fancy-border-dark, #3f3f46); /* zinc-700 */\n color: var(--fancy-text-soft-dark, #d4d4d8); /* zinc-300 */\n}\n\n/* Overlay item hover states */\n:where(.dark [data-react-fancy-dropdown-item]:hover, [data-theme=\"dark\"] [data-react-fancy-dropdown-item]:hover),\n:where(.dark [data-react-fancy-menu-item]:hover, [data-theme=\"dark\"] [data-react-fancy-menu-item]:hover),\n:where(.dark [data-react-fancy-context-menu-item]:hover, [data-theme=\"dark\"] [data-react-fancy-context-menu-item]:hover) {\n background-color: var(--fancy-surface-muted-dark, #27272a); /* zinc-800 */\n}\n\n/* Overlay separators */\n:where(.dark [data-react-fancy-dropdown-separator], [data-theme=\"dark\"] [data-react-fancy-dropdown-separator]),\n:where(.dark [data-react-fancy-context-menu-separator], [data-theme=\"dark\"] [data-react-fancy-context-menu-separator]) {\n background-color: var(--fancy-border-dark, #3f3f46); /* zinc-700 */\n}\n\n/* ─── Media viewer — transparency checkerboard ───────────────────────────────\n Backdrop for <ImageViewer> / <MediaViewer> so transparent images read clearly.\n Light + dark variants; the dark rule is wrapped in :where() (zero specificity)\n so it ships out of the box without the consumer @sourcing react-fancy. */\n.fancy-checkerboard {\n background-color: #ffffff;\n background-image:\n linear-gradient(45deg, #e5e7eb 25%, transparent 25%),\n linear-gradient(-45deg, #e5e7eb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #e5e7eb 75%),\n linear-gradient(-45deg, transparent 75%, #e5e7eb 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n}\n\n:where(.dark, [data-theme=\"dark\"]) .fancy-checkerboard {\n background-color: #18181b; /* zinc-900 */\n background-image:\n linear-gradient(45deg, #27272a 25%, transparent 25%),\n linear-gradient(-45deg, #27272a 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #27272a 75%),\n linear-gradient(-45deg, transparent 75%, #27272a 75%);\n}\n}\n\n\n@keyframes fancy-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-left {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-right {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@layer base {\n\n\n.fancy-fade-in {\n animation: fancy-fade-in 0.2s ease-out;\n}\n\n.fancy-slide-left {\n animation: fancy-slide-left 0.3s ease-out;\n}\n\n.fancy-slide-right {\n animation: fancy-slide-right 0.3s ease-out;\n}\n}\n\n\n/* Overlay / floating animations */\n\n@keyframes fancy-scale-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes fancy-slide-up {\n from {\n opacity: 0;\n transform: translateY(16px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-fade-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n@keyframes fancy-toast-in {\n from {\n opacity: 0;\n transform: translateX(100%);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-collapse-open {\n from {\n grid-template-rows: 0fr;\n }\n to {\n grid-template-rows: 1fr;\n }\n}\n\n@keyframes fancy-collapse-close {\n from {\n grid-template-rows: 1fr;\n }\n to {\n grid-template-rows: 0fr;\n }\n}\n\n@layer base {\n\n\n.fancy-scale-in {\n animation: fancy-scale-in 0.15s ease-out;\n}\n\n.fancy-slide-up {\n animation: fancy-slide-up 0.2s ease-out;\n}\n\n.fancy-fade-out {\n animation: fancy-fade-out 0.15s ease-in forwards;\n}\n\n.fancy-toast-in {\n animation: fancy-toast-in 0.3s ease-out;\n}\n\n.fancy-collapse-open {\n animation: fancy-collapse-open 0.2s ease-out forwards;\n}\n\n.fancy-collapse-close {\n animation: fancy-collapse-close 0.15s ease-in forwards;\n}\n}\n\n\n/* Mobile flyout slide animations */\n\n@keyframes fancy-slide-in-left {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-out-left {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-100%);\n }\n}\n\n@keyframes fancy-slide-in-right {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n/* Avatar glow — a looping halo ring (box-shadow only, no reflow). Color comes\n from the --fancy-glow custom property set on the element. */\n@keyframes fancy-avatar-glow {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 55%, transparent);\n opacity: 0.9;\n }\n 70% {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.5;\n }\n 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.9;\n }\n}\n\n@layer base {\n\n\n.fancy-avatar-glow {\n position: absolute;\n inset: 0;\n border-radius: 9999px;\n pointer-events: none;\n box-shadow:\n 0 0 0 2px color-mix(in srgb, var(--fancy-glow, #a855f7) 70%, transparent),\n 0 0 10px 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 45%, transparent);\n animation: fancy-avatar-glow 1.6s ease-out infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fancy-avatar-glow {\n animation: none;\n }\n}\n}\n\n\n@keyframes fancy-slide-out-right {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n@layer base {\n\n\n.fancy-slide-in-left {\n animation: fancy-slide-in-left 0.25s ease-out;\n}\n\n.fancy-slide-out-left {\n animation: fancy-slide-out-left 0.2s ease-in forwards;\n}\n\n.fancy-slide-in-right {\n animation: fancy-slide-in-right 0.25s ease-out;\n}\n\n.fancy-slide-out-right {\n animation: fancy-slide-out-right 0.2s ease-in forwards;\n}\n}\n\n\n/* Vertical drawer edges. The horizontal pair above predates Drawer (it was\n built for MobileMenu.Flyout, which only ever opened left/right); these\n complete the set so `side=\"top\"`/`side=\"bottom\"` animate rather than pop. */\n\n@keyframes fancy-slide-in-top {\n from {\n transform: translateY(-100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-out-top {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(-100%);\n }\n}\n\n@keyframes fancy-slide-in-bottom {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-out-bottom {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n\n@layer base {\n\n\n.fancy-slide-in-top {\n animation: fancy-slide-in-top 0.25s ease-out;\n}\n\n.fancy-slide-out-top {\n animation: fancy-slide-out-top 0.2s ease-in forwards;\n}\n\n.fancy-slide-in-bottom {\n animation: fancy-slide-in-bottom 0.25s ease-out;\n}\n\n.fancy-slide-out-bottom {\n animation: fancy-slide-out-bottom 0.2s ease-in forwards;\n}\n\n/* Reduced motion collapses the travel to a ~0 duration. Since 5.51.0\n `useAnimation` also unmounts when no animation runs at all, so this is no\n longer what keeps a closed drawer from staying in the DOM — but a ~0 duration\n keeps the exit on the same path as every other close. */\n@media (prefers-reduced-motion: reduce) {\n .fancy-slide-in-left,\n .fancy-slide-out-left,\n .fancy-slide-in-right,\n .fancy-slide-out-right,\n .fancy-slide-in-top,\n .fancy-slide-out-top,\n .fancy-slide-in-bottom,\n .fancy-slide-out-bottom {\n animation-duration: 0.01ms;\n }\n}\n\n/* ─── Marquee ────────────────────────────────────────────────────────────────\n Edge-to-edge auto-scrolling strip. The track holds two identical copies of\n the content; translateX(-50%) over one loop shifts exactly one copy, so the\n wrap is seamless. Duration/gap/fade arrive as custom properties set by the\n component. No animation under prefers-reduced-motion.\n ──────────────────────────────────────────────────────────────────────────── */\n\n[data-react-fancy-marquee] {\n overflow: hidden;\n width: 100%;\n}\n\n.fancy-marquee--fade {\n -webkit-mask-image: linear-gradient(\n to right,\n transparent,\n black var(--fancy-marquee-fade, 48px),\n black calc(100% - var(--fancy-marquee-fade, 48px)),\n transparent\n );\n mask-image: linear-gradient(\n to right,\n transparent,\n black var(--fancy-marquee-fade, 48px),\n black calc(100% - var(--fancy-marquee-fade, 48px)),\n transparent\n );\n}\n\n.fancy-marquee__track {\n display: flex;\n width: max-content;\n animation: fancy-marquee var(--fancy-marquee-duration, 40s) linear infinite;\n will-change: transform;\n}\n\n[data-react-fancy-marquee][data-direction=\"right\"] .fancy-marquee__track {\n animation-direction: reverse;\n}\n\n.fancy-marquee--pause-hover:hover .fancy-marquee__track,\n[data-react-fancy-marquee][data-paused] .fancy-marquee__track {\n animation-play-state: paused;\n}\n\n.fancy-marquee__group {\n display: flex;\n flex: none;\n}\n\n.fancy-marquee__unit {\n display: flex;\n flex: none;\n align-items: center;\n gap: var(--fancy-marquee-gap, 40px);\n padding-inline-end: var(--fancy-marquee-gap, 40px);\n white-space: nowrap;\n}\n\n.fancy-marquee__item,\n.fancy-marquee__separator {\n flex: none;\n}\n}\n\n\n@keyframes fancy-marquee {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-50%);\n }\n}\n\n@layer base {\n\n\n@media (prefers-reduced-motion: reduce) {\n .fancy-marquee__track {\n animation: none;\n }\n}\n}\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @particle-academy/react-fancy — base styles + animations */\n\n/* ─── Brand colour scheme ────────────────────────────────────────────────────\n Three token families every Fancy package can rely on, so a component never\n has to invent a palette or hardcode a literal:\n\n brand one accent — the thing a consumer rebrands first\n primary-* the accent as a full 50→950 scale\n secondary-* the NEUTRAL scale for surfaces, borders and body text\n\n Why this exists: packages were already writing `bg-brand`, `text-primary-600`\n and `border-secondary-200` against tokens nothing defined. Tailwind generated\n no such utility, the class silently resolved to nothing, and the component\n rendered unstyled — correct markup, no colour, no error. Defining them here\n turns those classes into a contract instead of a hope.\n\n SECONDARY INVERTS WITH THE THEME. `text-secondary-900` means \"strongest\n foreground\", not \"nearly black\" — so it stays readable on a dark surface.\n That distinction is the whole point: mixing a literal background (`bg-white`)\n with a semantic foreground (`text-secondary-900`) is what produced\n white-on-white in a dark host.\n\n OVERRIDE IT. Redefine any of these in your own `@theme` (or on `:root`) and\n yours wins — nothing here is `!important`, and the utilities read the variable\n rather than baking a value in:\n\n @theme { --color-brand: var(--color-emerald-600); }\n ──────────────────────────────────────────────────────────────────────────── */\n@theme {\n /* THE HOST'S OWN COLOUR. `color=\"brand\"` on any component resolves to these.\n Three variables, not one: a generated hover assumes \"same hue, darker\",\n and a brand palette need not work that way — a navy whose hover is gold\n cannot be derived from navy. So the host states the hover instead of the\n kit guessing it.\n\n :root {\n --color-brand: #003057;\n --color-brand-contrast: #ffffff; text/icon ON the brand colour\n --color-brand-hover: #D4A017; need not be a shade of brand\n }\n\n PER MODE, SWAP THE PAIR. `--color-brand` and `--color-brand-contrast` only\n mean anything together. Repointing one alone fails QUIETLY -- the button\n still renders, it is just unreadable (a pale surface still carrying white\n text; or, on ghost/outline where brand is the LABEL, dark text on a dark\n background):\n\n .dark { --color-brand: #BFD7EA; --color-brand-contrast: #003057; }\n\n `--color-brand-hover` usually needs no per-mode value: an accent chosen to\n stand against the brand tends to stand against it in both modes.\n\n NOTE: this comment does not survive the build -- `@theme` is emitted\n without it. The consumer-facing copy is in README.md, and that is the one\n to keep correct.\n\n Defaults keep the kit's violet so nothing changes for a host that never\n sets them. Soft/outline/ghost variants derive their tints with opacity\n modifiers (`bg-brand/10`), which is what lets three variables cover four\n variants without asking for a whole scale. */\n --color-brand: var(--color-violet-600);\n --color-brand-contrast: var(--color-white);\n --color-brand-hover: var(--color-violet-700);\n\n --color-primary-50: var(--color-violet-50);\n --color-primary-100: var(--color-violet-100);\n --color-primary-200: var(--color-violet-200);\n --color-primary-300: var(--color-violet-300);\n --color-primary-400: var(--color-violet-400);\n --color-primary-500: var(--color-violet-500);\n --color-primary-600: var(--color-violet-600);\n --color-primary-700: var(--color-violet-700);\n --color-primary-800: var(--color-violet-800);\n --color-primary-900: var(--color-violet-900);\n --color-primary-950: var(--color-violet-950);\n\n /* Light-theme defaults: 50 = faintest surface, 900/950 = strongest text. */\n --color-secondary-50: var(--color-zinc-50);\n --color-secondary-100: var(--color-zinc-100);\n --color-secondary-200: var(--color-zinc-200);\n --color-secondary-300: var(--color-zinc-300);\n --color-secondary-400: var(--color-zinc-400);\n --color-secondary-500: var(--color-zinc-500);\n --color-secondary-600: var(--color-zinc-600);\n --color-secondary-700: var(--color-zinc-700);\n --color-secondary-800: var(--color-zinc-800);\n --color-secondary-900: var(--color-zinc-900);\n --color-secondary-950: var(--color-zinc-950);\n}\n\n/* ─── Full screen in the top layer — neutralise the UA popover box ───────────\n An overlay-mode FullScreen is promoted with popover=\"manual\" so ancestor\n transforms / filters cannot trap it, and the UA sheet then styles it as a\n popover: padding .25em, a solid border, Canvas / CanvasText colours,\n overflow:auto. Any author rule outranks the UA origin, so this zero-\n specificity rule in the base layer puts those back to what a plain box has,\n while every utility a consumer passes through className still wins. Inline\n styles could not do that: they would beat the consumer's own classes. The\n box geometry (inset, width, height, margin) is set inline by the hook. */\n@layer base {\n :where([data-fullscreen-layer=\"top\"]) {\n padding: 0;\n border: 0 solid;\n background-color: transparent;\n color: inherit;\n overflow: visible;\n }\n}\n\n@layer base {\n\n/* ─── Progress (circular) — named diameters ──────────────────────────────────\n These ship as real CSS rather than Tailwind classes on the element, because a\n consumer who has not @sourced this package gets no generated utilities and\n the ring would render with NO SIZE at all. They were inline styles before,\n which always worked but could not be overridden by className (issue #17).\n\n Being inside @layer base, a className utility now beats them — which is the\n whole point, and the reason #20 had to land first. */\n[data-react-fancy-progress][data-size=\"sm\"] { width: 2rem; height: 2rem; }\n[data-react-fancy-progress][data-size=\"md\"] { width: 3rem; height: 3rem; }\n[data-react-fancy-progress][data-size=\"lg\"] { width: 4rem; height: 4rem; }\n\n\n\n/* Dark: the neutral scale flips, so \"900\" still means strongest foreground and\n \"50\" still means faintest surface. Wrapped in :where() for zero specificity,\n matching the rest of this file — any consumer override beats it.\n\n EVERY dark selector in this file names `[data-theme=\"dark\"]` beside `.dark`\n (5.53.0). A consumer's `@custom-variant dark` cannot reach these: it rewrites\n `dark:` utilities, never a selector with `.dark` written into it.\n tests/data-theme.test.ts fails on any `.dark` selector without its twin. */\n:where(.dark, [data-theme=\"dark\"]) {\n --color-secondary-50: var(--color-zinc-950);\n --color-secondary-100: var(--color-zinc-900);\n --color-secondary-200: var(--color-zinc-800);\n --color-secondary-300: var(--color-zinc-700);\n --color-secondary-400: var(--color-zinc-600);\n --color-secondary-500: var(--color-zinc-500);\n --color-secondary-600: var(--color-zinc-400);\n --color-secondary-700: var(--color-zinc-300);\n --color-secondary-800: var(--color-zinc-200);\n --color-secondary-900: var(--color-zinc-100);\n --color-secondary-950: var(--color-zinc-50);\n}\n\n/* ─── CodeBlock / CodeView palette ───────────────────────────────────────────\n Both components declare the light AND dark syntax palette on their root\n (`--fc-<key>-l` / `--fc-<key>-d`) and paint with\n `var(--fc-<key>, var(--fc-<key>-l))`, so server-rendered HTML is right in\n either theme. Their `dark:[--fc-<key>:…]` classes switch it under the\n consumer's Tailwind `dark` variant; this rule does the same under `.dark` /\n `[data-theme=\"dark\"]` for a host whose Tailwind does not scan the package.\n Keep the key list in step with CODE_PALETTE_KEYS (a test checks). */\n:where(\n .dark [data-react-fancy-code-palette],\n [data-theme=\"dark\"] [data-react-fancy-code-palette],\n .dark[data-react-fancy-code-palette],\n [data-theme=\"dark\"][data-react-fancy-code-palette]\n) {\n --fc-background: var(--fc-background-d);\n --fc-foreground: var(--fc-foreground-d);\n --fc-gutterBackground: var(--fc-gutterBackground-d);\n --fc-gutterForeground: var(--fc-gutterForeground-d);\n --fc-gutterBorder: var(--fc-gutterBorder-d);\n --fc-cursorColor: var(--fc-cursorColor-d);\n --fc-keyword: var(--fc-keyword-d);\n --fc-string: var(--fc-string-d);\n --fc-comment: var(--fc-comment-d);\n --fc-number: var(--fc-number-d);\n --fc-operator: var(--fc-operator-d);\n --fc-function: var(--fc-function-d);\n --fc-type: var(--fc-type-d);\n --fc-tag: var(--fc-tag-d);\n --fc-attribute: var(--fc-attribute-d);\n --fc-attributeValue: var(--fc-attributeValue-d);\n --fc-punctuation: var(--fc-punctuation-d);\n --fc-variable: var(--fc-variable-d);\n}\n\n/* ─── Input & Field defaults ─────────────────────────────────────────────────\n Better UX out of the box: spacing between stacked fields, smooth transitions,\n and polished dark-mode defaults. All overridable via data-attribute selectors.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Field spacing is the CONTAINER's job, not the field's.\n ────────────────────────────────────────────────────────────────────────────\n This used to be:\n\n [data-react-fancy-field] + [data-react-fancy-field] { margin-top: 1rem; }\n\n An adjacent-sibling selector cannot know which way its parent lays children\n out. Stacked vertically it read as spacing; inside a `grid-cols-2` row it\n pushed the right-hand cell 16px down, and `items-start` could not fix it\n because a margin is not alignment. The only escape was wrapping every field\n in a plain <div> so each became an only-child.\n\n Space fields with the container instead — `space-y-4`, or `gap-4` on a flex\n or grid parent. A container knows its own axis; a sibling selector never\n can. See CHANGELOG 5.17.0 for the migration.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Smooth transitions on all text inputs, selects, and textareas */\n[data-react-fancy-input] input,\n[data-react-fancy-textarea],\n[data-react-fancy-select],\n[data-react-fancy-date-picker],\n[data-react-fancy-autocomplete] input,\n[data-react-fancy-pillbox],\n[data-react-fancy-otp-input] input,\n[data-react-fancy-time-picker] input,\n[data-react-fancy-color-picker] input {\n transition: border-color 0.15s ease, box-shadow 0.15s ease,\n background-color 0.15s ease;\n}\n\n/* Dark-mode input refinements — slightly darker bg for contrast against page */\n/* ─── Inherent dark-mode defaults ────────────────────────────────────────────\n Every rule below is wrapped in :where() so it carries ZERO specificity, which\n buys two properties at once:\n 1. Inherent — a sensible dark appearance ships out of the box, even when the\n consumer's Tailwind build doesn't generate react-fancy's `dark:` utility\n classes (e.g. they didn't @source the package). This is what lets the\n overlays (Dropdown, Menu, Popover, …) go dark on their own.\n 2. Override-friendly — because specificity is 0, ANY consumer override wins:\n a plain `dark:bg-…` utility, a custom class, or the component's own\n `dark:` class (when it IS generated) all take precedence — no !important,\n no need to target the data-attribute.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Every colour below reads a semantic token (`--fancy-<role>-dark`, see\n THEME_TOKENS / README \"Semantic tokens\") with today's value as the fallback,\n so a host that sets nothing sees exactly what it saw before. */\n\n/* Inputs / selects / textareas — darker bg for contrast against the page */\n:where(.dark [data-react-fancy-input] input, [data-theme=\"dark\"] [data-react-fancy-input] input),\n:where(.dark [data-react-fancy-textarea], [data-theme=\"dark\"] [data-react-fancy-textarea]),\n:where(.dark [data-react-fancy-select], [data-theme=\"dark\"] [data-react-fancy-select]),\n:where(.dark [data-react-fancy-date-picker], [data-theme=\"dark\"] [data-react-fancy-date-picker]),\n:where(.dark [data-react-fancy-autocomplete] input, [data-theme=\"dark\"] [data-react-fancy-autocomplete] input),\n:where(.dark [data-react-fancy-pillbox], [data-theme=\"dark\"] [data-react-fancy-pillbox]),\n:where(.dark [data-react-fancy-otp-input] input, [data-theme=\"dark\"] [data-react-fancy-otp-input] input),\n:where(.dark [data-react-fancy-time-picker] input, [data-theme=\"dark\"] [data-react-fancy-time-picker] input) {\n background-color: var(--fancy-input-dark, #1e1e24);\n border-color: var(--fancy-border-strong-dark, #3f3f46);\n}\n\n/* Focus ring — brighter border + subtle glow */\n:where(.dark [data-react-fancy-input] input:focus, [data-theme=\"dark\"] [data-react-fancy-input] input:focus),\n:where(.dark [data-react-fancy-textarea]:focus, [data-theme=\"dark\"] [data-react-fancy-textarea]:focus),\n:where(.dark [data-react-fancy-select]:focus, [data-theme=\"dark\"] [data-react-fancy-select]:focus),\n:where(.dark [data-react-fancy-date-picker]:focus, [data-theme=\"dark\"] [data-react-fancy-date-picker]:focus),\n:where(.dark [data-react-fancy-autocomplete] input:focus, [data-theme=\"dark\"] [data-react-fancy-autocomplete] input:focus),\n:where(.dark [data-react-fancy-otp-input] input:focus, [data-theme=\"dark\"] [data-react-fancy-otp-input] input:focus),\n:where(.dark [data-react-fancy-time-picker] input:focus, [data-theme=\"dark\"] [data-react-fancy-time-picker] input:focus) {\n border-color: var(--fancy-focus-dark, #60a5fa);\n /* = rgba(96, 165, 250, 0.15) when the token is unset */\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--fancy-focus-dark, #60a5fa) 15%, transparent);\n}\n\n/* Field labels — brighter for readability */\n:where(.dark [data-react-fancy-field] > label:first-child, [data-theme=\"dark\"] [data-react-fancy-field] > label:first-child) {\n color: var(--fancy-text-dark, #f4f4f5);\n}\n\n/* Checkbox & radio */\n:where(.dark [data-react-fancy-checkbox] input, [data-theme=\"dark\"] [data-react-fancy-checkbox] input),\n:where(.dark [data-react-fancy-radio-group] input, [data-theme=\"dark\"] [data-react-fancy-radio-group] input) {\n background-color: var(--fancy-input-dark, #1e1e24);\n border-color: var(--fancy-border-strong-dark, #3f3f46);\n}\n\n/* Switch unchecked track */\n:where(.dark [data-react-fancy-switch] button[aria-checked=\"false\"], [data-theme=\"dark\"] [data-react-fancy-switch] button[aria-checked=\"false\"]) {\n background-color: var(--fancy-border-dark, #3f3f46);\n}\n\n/* Input wrapper affixes */\n:where(.dark [data-react-fancy-input-wrapper] > span:first-child, [data-theme=\"dark\"] [data-react-fancy-input-wrapper] > span:first-child),\n:where(.dark [data-react-fancy-input-wrapper] > span:last-child, [data-theme=\"dark\"] [data-react-fancy-input-wrapper] > span:last-child) {\n border-color: var(--fancy-border-strong-dark, #3f3f46);\n background-color: var(--fancy-surface-muted-dark, #27272a);\n}\n\n/* Date picker icon (calendar, clock) */\n:where(.dark [data-react-fancy-date-picker]::-webkit-calendar-picker-indicator, [data-theme=\"dark\"] [data-react-fancy-date-picker]::-webkit-calendar-picker-indicator) {\n filter: invert(0.8);\n}\n\n/* ─── Overlays — inherent dark surfaces ──────────────────────────────────────\n Dropdown / Menu / Popover / ContextMenu / MobileMenu flyout / Modal / Toast.\n Mirrors the components' own `dark:` utilities (zinc-900 surface, zinc-700\n border, zinc-300 text) so overlays render correctly in dark mode WITHOUT the\n consumer @sourcing react-fancy. When those utilities ARE generated they win\n (specificity 0 here), so there's no drift or double-styling. */\n:where(.dark [data-react-fancy-dropdown], [data-theme=\"dark\"] [data-react-fancy-dropdown]),\n:where(.dark [data-react-fancy-menu], [data-theme=\"dark\"] [data-react-fancy-menu]),\n:where(.dark [data-react-fancy-popover], [data-theme=\"dark\"] [data-react-fancy-popover]),\n:where(.dark [data-react-fancy-context-menu], [data-theme=\"dark\"] [data-react-fancy-context-menu]),\n:where(.dark [data-react-fancy-context-menu-sub-content], [data-theme=\"dark\"] [data-react-fancy-context-menu-sub-content]),\n:where(.dark [data-react-fancy-mobile-menu-flyout], [data-theme=\"dark\"] [data-react-fancy-mobile-menu-flyout]),\n:where(.dark [data-react-fancy-modal], [data-theme=\"dark\"] [data-react-fancy-modal]),\n:where(.dark [data-react-fancy-toast-item], [data-theme=\"dark\"] [data-react-fancy-toast-item]) {\n background-color: var(--fancy-surface-dark, #18181b); /* zinc-900 */\n border-color: var(--fancy-border-dark, #3f3f46); /* zinc-700 */\n color: var(--fancy-text-soft-dark, #d4d4d8); /* zinc-300 */\n}\n\n/* Overlay item hover states */\n:where(.dark [data-react-fancy-dropdown-item]:hover, [data-theme=\"dark\"] [data-react-fancy-dropdown-item]:hover),\n:where(.dark [data-react-fancy-menu-item]:hover, [data-theme=\"dark\"] [data-react-fancy-menu-item]:hover),\n:where(.dark [data-react-fancy-context-menu-item]:hover, [data-theme=\"dark\"] [data-react-fancy-context-menu-item]:hover) {\n background-color: var(--fancy-surface-muted-dark, #27272a); /* zinc-800 */\n}\n\n/* Overlay separators */\n:where(.dark [data-react-fancy-dropdown-separator], [data-theme=\"dark\"] [data-react-fancy-dropdown-separator]),\n:where(.dark [data-react-fancy-context-menu-separator], [data-theme=\"dark\"] [data-react-fancy-context-menu-separator]) {\n background-color: var(--fancy-border-dark, #3f3f46); /* zinc-700 */\n}\n\n/* ─── Media viewer — transparency checkerboard ───────────────────────────────\n Backdrop for <ImageViewer> / <MediaViewer> so transparent images read clearly.\n Light + dark variants; the dark rule is wrapped in :where() (zero specificity)\n so it ships out of the box without the consumer @sourcing react-fancy. */\n.fancy-checkerboard {\n background-color: #ffffff;\n background-image:\n linear-gradient(45deg, #e5e7eb 25%, transparent 25%),\n linear-gradient(-45deg, #e5e7eb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #e5e7eb 75%),\n linear-gradient(-45deg, transparent 75%, #e5e7eb 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n}\n\n:where(.dark, [data-theme=\"dark\"]) .fancy-checkerboard {\n background-color: #18181b; /* zinc-900 */\n background-image:\n linear-gradient(45deg, #27272a 25%, transparent 25%),\n linear-gradient(-45deg, #27272a 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #27272a 75%),\n linear-gradient(-45deg, transparent 75%, #27272a 75%);\n}\n}\n\n\n@keyframes fancy-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-left {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-right {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@layer base {\n\n\n.fancy-fade-in {\n animation: fancy-fade-in 0.2s ease-out;\n}\n\n.fancy-slide-left {\n animation: fancy-slide-left 0.3s ease-out;\n}\n\n.fancy-slide-right {\n animation: fancy-slide-right 0.3s ease-out;\n}\n}\n\n\n/* Overlay / floating animations */\n\n@keyframes fancy-scale-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes fancy-slide-up {\n from {\n opacity: 0;\n transform: translateY(16px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-fade-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n@keyframes fancy-toast-in {\n from {\n opacity: 0;\n transform: translateX(100%);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-collapse-open {\n from {\n grid-template-rows: 0fr;\n }\n to {\n grid-template-rows: 1fr;\n }\n}\n\n@keyframes fancy-collapse-close {\n from {\n grid-template-rows: 1fr;\n }\n to {\n grid-template-rows: 0fr;\n }\n}\n\n@layer base {\n\n\n.fancy-scale-in {\n animation: fancy-scale-in 0.15s ease-out;\n}\n\n.fancy-slide-up {\n animation: fancy-slide-up 0.2s ease-out;\n}\n\n.fancy-fade-out {\n animation: fancy-fade-out 0.15s ease-in forwards;\n}\n\n.fancy-toast-in {\n animation: fancy-toast-in 0.3s ease-out;\n}\n\n.fancy-collapse-open {\n animation: fancy-collapse-open 0.2s ease-out forwards;\n}\n\n.fancy-collapse-close {\n animation: fancy-collapse-close 0.15s ease-in forwards;\n}\n}\n\n\n/* Mobile flyout slide animations */\n\n@keyframes fancy-slide-in-left {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-out-left {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-100%);\n }\n}\n\n@keyframes fancy-slide-in-right {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n/* Avatar glow — a looping halo ring (box-shadow only, no reflow). Color comes\n from the --fancy-glow custom property set on the element. */\n@keyframes fancy-avatar-glow {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 55%, transparent);\n opacity: 0.9;\n }\n 70% {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.5;\n }\n 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.9;\n }\n}\n\n@layer base {\n\n\n.fancy-avatar-glow {\n position: absolute;\n inset: 0;\n border-radius: 9999px;\n pointer-events: none;\n box-shadow:\n 0 0 0 2px color-mix(in srgb, var(--fancy-glow, #a855f7) 70%, transparent),\n 0 0 10px 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 45%, transparent);\n animation: fancy-avatar-glow 1.6s ease-out infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fancy-avatar-glow {\n animation: none;\n }\n}\n}\n\n\n@keyframes fancy-slide-out-right {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n@layer base {\n\n\n.fancy-slide-in-left {\n animation: fancy-slide-in-left 0.25s ease-out;\n}\n\n.fancy-slide-out-left {\n animation: fancy-slide-out-left 0.2s ease-in forwards;\n}\n\n.fancy-slide-in-right {\n animation: fancy-slide-in-right 0.25s ease-out;\n}\n\n.fancy-slide-out-right {\n animation: fancy-slide-out-right 0.2s ease-in forwards;\n}\n}\n\n\n/* Vertical drawer edges. The horizontal pair above predates Drawer (it was\n built for MobileMenu.Flyout, which only ever opened left/right); these\n complete the set so `side=\"top\"`/`side=\"bottom\"` animate rather than pop. */\n\n@keyframes fancy-slide-in-top {\n from {\n transform: translateY(-100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-out-top {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(-100%);\n }\n}\n\n@keyframes fancy-slide-in-bottom {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-out-bottom {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n\n@layer base {\n\n\n.fancy-slide-in-top {\n animation: fancy-slide-in-top 0.25s ease-out;\n}\n\n.fancy-slide-out-top {\n animation: fancy-slide-out-top 0.2s ease-in forwards;\n}\n\n.fancy-slide-in-bottom {\n animation: fancy-slide-in-bottom 0.25s ease-out;\n}\n\n.fancy-slide-out-bottom {\n animation: fancy-slide-out-bottom 0.2s ease-in forwards;\n}\n\n/* Reduced motion collapses the travel to a ~0 duration. Since 5.51.0\n `useAnimation` also unmounts when no animation runs at all, so this is no\n longer what keeps a closed drawer from staying in the DOM — but a ~0 duration\n keeps the exit on the same path as every other close. */\n@media (prefers-reduced-motion: reduce) {\n .fancy-slide-in-left,\n .fancy-slide-out-left,\n .fancy-slide-in-right,\n .fancy-slide-out-right,\n .fancy-slide-in-top,\n .fancy-slide-out-top,\n .fancy-slide-in-bottom,\n .fancy-slide-out-bottom {\n animation-duration: 0.01ms;\n }\n}\n\n/* ─── Marquee ────────────────────────────────────────────────────────────────\n Edge-to-edge auto-scrolling strip. The track holds two identical copies of\n the content; translateX(-50%) over one loop shifts exactly one copy, so the\n wrap is seamless. Duration/gap/fade arrive as custom properties set by the\n component. No animation under prefers-reduced-motion.\n ──────────────────────────────────────────────────────────────────────────── */\n\n[data-react-fancy-marquee] {\n overflow: hidden;\n width: 100%;\n}\n\n.fancy-marquee--fade {\n -webkit-mask-image: linear-gradient(\n to right,\n transparent,\n black var(--fancy-marquee-fade, 48px),\n black calc(100% - var(--fancy-marquee-fade, 48px)),\n transparent\n );\n mask-image: linear-gradient(\n to right,\n transparent,\n black var(--fancy-marquee-fade, 48px),\n black calc(100% - var(--fancy-marquee-fade, 48px)),\n transparent\n );\n}\n\n.fancy-marquee__track {\n display: flex;\n width: max-content;\n animation: fancy-marquee var(--fancy-marquee-duration, 40s) linear infinite;\n will-change: transform;\n}\n\n[data-react-fancy-marquee][data-direction=\"right\"] .fancy-marquee__track {\n animation-direction: reverse;\n}\n\n.fancy-marquee--pause-hover:hover .fancy-marquee__track,\n[data-react-fancy-marquee][data-paused] .fancy-marquee__track {\n animation-play-state: paused;\n}\n\n.fancy-marquee__group {\n display: flex;\n flex: none;\n}\n\n.fancy-marquee__unit {\n display: flex;\n flex: none;\n align-items: center;\n gap: var(--fancy-marquee-gap, 40px);\n padding-inline-end: var(--fancy-marquee-gap, 40px);\n white-space: nowrap;\n}\n\n.fancy-marquee__item,\n.fancy-marquee__separator {\n flex: none;\n}\n}\n\n\n@keyframes fancy-marquee {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-50%);\n }\n}\n\n@layer base {\n\n\n@media (prefers-reduced-motion: reduce) {\n .fancy-marquee__track {\n animation: none;\n }\n}\n}\n\n"],"mappings":"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","names":[]}
package/docs/CodeBlock.md CHANGED
@@ -76,15 +76,23 @@ The button copies **exactly the `code` prop**: no highlight markup, no line numb
76
76
 
77
77
  ## Theming
78
78
 
79
- The same palette as `CodeView` (`LIGHT_COLORS` / `DARK_COLORS` from `fancy-file-commons`), so the two sit together. Dark is chosen when `<html>` has the `dark` class or the OS prefers dark. On the server, and during hydration, the light palette is used, then the real theme.
79
+ The same palette as `CodeView` (`LIGHT_COLORS` / `DARK_COLORS` from `fancy-file-commons`), so the two sit together. **The markup carries both palettes and CSS picks one**, so server-rendered HTML is right in either theme and a dark site does not flash light on hydration:
80
+
81
+ - the root declares `--fc-<slot>-l` and `--fc-<slot>-d` (for example `--fc-keyword-l`, `--fc-keyword-d`), and everything coloured reads `var(--fc-<slot>, var(--fc-<slot>-l))`;
82
+ - the dark value applies under **your Tailwind `dark` variant** (the root's `dark:[--fc-<slot>:...]` classes, compiled from the `@source`d dist: class strategy, `dark-variant.css`, or Tailwind's default media query), **or** under a `.dark` / `[data-theme="dark"]` ancestor through `styles.css`, for a host that does not scan the package;
83
+ - with neither, it renders the light palette.
84
+
85
+ To change a colour, override its variable on the block: `style={{ "--fc-keyword-l": "#7c3aed", "--fc-keyword-d": "#a78bfa" }}`.
86
+
87
+ PHP is read as a **snippet**: code with no `<?php` open tag (`use Foo\Bar;`) is highlighted as PHP, and a `?>` switches to HTML. Code that opens with `<?php` highlights exactly as a file does.
80
88
 
81
89
  ## Security
82
90
 
83
- Code is escaped before it reaches `dangerouslySetInnerHTML`: `highlightCode` escapes `&`, `<` and `>` in every slice it emits, highlighted or plain, and token colours pass an allow-list. `<script>` in `code` renders as the text `<script>`.
91
+ Code is escaped before it reaches `dangerouslySetInnerHTML`: `highlightCodeWithVariables` escapes `&`, `<` and `>` in every slice it emits, highlighted or plain, and writes no colour value into the token markup; the palette values on the root pass `fancy-file-commons`' colour allow-list. `<script>` in `code` renders as the text `<script>`.
84
92
 
85
93
  ## Server rendering
86
94
 
87
- No `window`, `document` or `navigator` access during render. Tested with `renderToString` with all three undefined.
95
+ No `window`, `document` or `navigator` access during render. Tested with `renderToString` with all three undefined. The server output is identical to the client's in both themes.
88
96
 
89
97
  ## Agent handles
90
98
 
package/docs/CodeView.md CHANGED
@@ -75,6 +75,10 @@ Read-only (omit `onChange` or pass `readOnly`):
75
75
 
76
76
  ## Theme
77
77
 
78
- The view resolves light/dark itself (the highlight colors are inlined). It
79
- follows both the `.dark` class and the `prefers-color-scheme` media query, so it
80
- matches whatever drives your Tailwind `dark:` variants.
78
+ The view carries both palettes as CSS variables (`--fc-<slot>-l` /
79
+ `--fc-<slot>-d`) and CSS picks one, so server-rendered HTML is right in either
80
+ theme with no flash. The dark palette applies under your Tailwind `dark` variant
81
+ (its `dark:` classes compile from the `@source`d dist, so it matches whatever
82
+ drives your other `dark:` utilities) or under a `.dark` / `[data-theme="dark"]`
83
+ ancestor via `styles.css`. See `CodeBlock`'s Theming section for overrides. PHP
84
+ without a `<?php` open tag is highlighted as PHP (snippet mode).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/react-fancy",
3
- "version": "6.5.0",
3
+ "version": "6.6.0",
4
4
  "description": "React UI component library for Human+ UX — controlled, agent-bridgeable primitives",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1054,7 +1054,7 @@
1054
1054
  "tailwindcss": "^4.0.0"
1055
1055
  },
1056
1056
  "dependencies": {
1057
- "@particle-academy/fancy-file-commons": ">=0.4 <2.0",
1057
+ "@particle-academy/fancy-file-commons": ">=0.5 <2.0",
1058
1058
  "lucide-react": "^0.511.0",
1059
1059
  "marked": "^15.0.0",
1060
1060
  "tailwind-merge": "^3.0.0"
@@ -1,29 +0,0 @@
1
- import { useSyncExternalStore } from 'react';
2
-
3
- // src/components/CodeView/use-is-dark.ts
4
- function darkQuery() {
5
- return typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
6
- }
7
- function subscribeDark(callback) {
8
- const mq = darkQuery();
9
- mq?.addEventListener?.("change", callback);
10
- const observer = new MutationObserver(callback);
11
- observer.observe(document.documentElement, {
12
- attributes: true,
13
- attributeFilter: ["class"]
14
- });
15
- return () => {
16
- mq?.removeEventListener?.("change", callback);
17
- observer.disconnect();
18
- };
19
- }
20
- function darkSnapshot() {
21
- return document.documentElement.classList.contains("dark") || (darkQuery()?.matches ?? false);
22
- }
23
- function useIsDark() {
24
- return useSyncExternalStore(subscribeDark, darkSnapshot, () => false);
25
- }
26
-
27
- export { useIsDark };
28
- //# sourceMappingURL=chunk-6BB32POL.js.map
29
- //# sourceMappingURL=chunk-6BB32POL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/CodeView/use-is-dark.ts"],"names":[],"mappings":";;;AAWA,SAAS,SAAA,GAAmC;AAC1C,EAAA,OAAO,OAAO,MAAA,CAAO,UAAA,KAAe,aAChC,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,GAChD,IAAA;AACN;AAEA,SAAS,cAAc,QAAA,EAAkC;AACvD,EAAA,MAAM,KAAK,SAAA,EAAU;AACrB,EAAA,EAAA,EAAI,gBAAA,GAAmB,UAAU,QAAQ,CAAA;AACzC,EAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,QAAQ,CAAA;AAC9C,EAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,eAAA,EAAiB;AAAA,IACzC,UAAA,EAAY,IAAA;AAAA,IACZ,eAAA,EAAiB,CAAC,OAAO;AAAA,GAC1B,CAAA;AACD,EAAA,OAAO,MAAM;AACX,IAAA,EAAA,EAAI,mBAAA,GAAsB,UAAU,QAAQ,CAAA;AAC5C,IAAA,QAAA,CAAS,UAAA,EAAW;AAAA,EACtB,CAAA;AACF;AAEA,SAAS,YAAA,GAAwB;AAC/B,EAAA,OAAO,QAAA,CAAS,gBAAgB,SAAA,CAAU,QAAA,CAAS,MAAM,CAAA,KAAM,SAAA,IAAa,OAAA,IAAW,KAAA,CAAA;AACzF;AAGO,SAAS,SAAA,GAAqB;AACnC,EAAA,OAAO,oBAAA,CAAqB,aAAA,EAAe,YAAA,EAAc,MAAM,KAAK,CAAA;AACtE","file":"chunk-6BB32POL.js","sourcesContent":["import { useSyncExternalStore } from \"react\";\n\n// ── Dark-mode detection ────────────────────────────────────────────────────\n// The highlight palette is baked in as inline colors, so we resolve light/dark\n// ourselves. Follow BOTH signals so we match whatever drives the surrounding\n// `dark:` Tailwind variants: the `.dark` class (class strategy) OR the\n// prefers-color-scheme media query (media strategy). Shared by CodeView and\n// CodeBlock so the two always agree on the palette.\n\n// `matchMedia` is optional: jsdom (and so a consumer's component tests) has\n// none, and a missing media API must cost the media signal, not the render.\nfunction darkQuery(): MediaQueryList | null {\n return typeof window.matchMedia === \"function\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n : null;\n}\n\nfunction subscribeDark(callback: () => void): () => void {\n const mq = darkQuery();\n mq?.addEventListener?.(\"change\", callback);\n const observer = new MutationObserver(callback);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n return () => {\n mq?.removeEventListener?.(\"change\", callback);\n observer.disconnect();\n };\n}\n\nfunction darkSnapshot(): boolean {\n return document.documentElement.classList.contains(\"dark\") || (darkQuery()?.matches ?? false);\n}\n\n/** Light on the server (and during hydration), then the real theme. */\nexport function useIsDark(): boolean {\n return useSyncExternalStore(subscribeDark, darkSnapshot, () => false);\n}\n"]}
@@ -1,31 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- // src/components/CodeView/use-is-dark.ts
6
- function darkQuery() {
7
- return typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
8
- }
9
- function subscribeDark(callback) {
10
- const mq = darkQuery();
11
- mq?.addEventListener?.("change", callback);
12
- const observer = new MutationObserver(callback);
13
- observer.observe(document.documentElement, {
14
- attributes: true,
15
- attributeFilter: ["class"]
16
- });
17
- return () => {
18
- mq?.removeEventListener?.("change", callback);
19
- observer.disconnect();
20
- };
21
- }
22
- function darkSnapshot() {
23
- return document.documentElement.classList.contains("dark") || (darkQuery()?.matches ?? false);
24
- }
25
- function useIsDark() {
26
- return react.useSyncExternalStore(subscribeDark, darkSnapshot, () => false);
27
- }
28
-
29
- exports.useIsDark = useIsDark;
30
- //# sourceMappingURL=chunk-HZUKPYR3.cjs.map
31
- //# sourceMappingURL=chunk-HZUKPYR3.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/CodeView/use-is-dark.ts"],"names":["useSyncExternalStore"],"mappings":";;;;;AAWA,SAAS,SAAA,GAAmC;AAC1C,EAAA,OAAO,OAAO,MAAA,CAAO,UAAA,KAAe,aAChC,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,GAChD,IAAA;AACN;AAEA,SAAS,cAAc,QAAA,EAAkC;AACvD,EAAA,MAAM,KAAK,SAAA,EAAU;AACrB,EAAA,EAAA,EAAI,gBAAA,GAAmB,UAAU,QAAQ,CAAA;AACzC,EAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,QAAQ,CAAA;AAC9C,EAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,eAAA,EAAiB;AAAA,IACzC,UAAA,EAAY,IAAA;AAAA,IACZ,eAAA,EAAiB,CAAC,OAAO;AAAA,GAC1B,CAAA;AACD,EAAA,OAAO,MAAM;AACX,IAAA,EAAA,EAAI,mBAAA,GAAsB,UAAU,QAAQ,CAAA;AAC5C,IAAA,QAAA,CAAS,UAAA,EAAW;AAAA,EACtB,CAAA;AACF;AAEA,SAAS,YAAA,GAAwB;AAC/B,EAAA,OAAO,QAAA,CAAS,gBAAgB,SAAA,CAAU,QAAA,CAAS,MAAM,CAAA,KAAM,SAAA,IAAa,OAAA,IAAW,KAAA,CAAA;AACzF;AAGO,SAAS,SAAA,GAAqB;AACnC,EAAA,OAAOA,0BAAA,CAAqB,aAAA,EAAe,YAAA,EAAc,MAAM,KAAK,CAAA;AACtE","file":"chunk-HZUKPYR3.cjs","sourcesContent":["import { useSyncExternalStore } from \"react\";\n\n// ── Dark-mode detection ────────────────────────────────────────────────────\n// The highlight palette is baked in as inline colors, so we resolve light/dark\n// ourselves. Follow BOTH signals so we match whatever drives the surrounding\n// `dark:` Tailwind variants: the `.dark` class (class strategy) OR the\n// prefers-color-scheme media query (media strategy). Shared by CodeView and\n// CodeBlock so the two always agree on the palette.\n\n// `matchMedia` is optional: jsdom (and so a consumer's component tests) has\n// none, and a missing media API must cost the media signal, not the render.\nfunction darkQuery(): MediaQueryList | null {\n return typeof window.matchMedia === \"function\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n : null;\n}\n\nfunction subscribeDark(callback: () => void): () => void {\n const mq = darkQuery();\n mq?.addEventListener?.(\"change\", callback);\n const observer = new MutationObserver(callback);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n return () => {\n mq?.removeEventListener?.(\"change\", callback);\n observer.disconnect();\n };\n}\n\nfunction darkSnapshot(): boolean {\n return document.documentElement.classList.contains(\"dark\") || (darkQuery()?.matches ?? false);\n}\n\n/** Light on the server (and during hydration), then the real theme. */\nexport function useIsDark(): boolean {\n return useSyncExternalStore(subscribeDark, darkSnapshot, () => false);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/CodeView/CodeView.tsx"],"names":[],"mappings":"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","file":"chunk-PVHZO4T3.js","sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport {\n highlightCode,\n tokenize,\n LIGHT_COLORS,\n DARK_COLORS,\n type ThemeColors,\n} from \"@particle-academy/fancy-file-commons\";\nimport { cn } from \"../../utils/cn\";\nimport { useIsDark } from \"./use-is-dark\";\nimport type { CodeViewProps } from \"./CodeView.types\";\n\n// Shared text metrics — the overlay and the textarea MUST match exactly (font,\n// size, line-height, padding, wrapping) so the highlighted glyphs sit under the\n// caret. Keep this string identical on both layers.\nconst TEXT_METRICS = \"m-0 p-3 font-mono text-xs leading-relaxed\";\n\n/**\n * A lightweight, syntax-highlighted source view built on the pure highlight\n * primitives in `@particle-academy/fancy-file-commons` — a highlight overlay\n * with a transparent, auto-growing textarea on top; the container scrolls both\n * together. Fills its parent's height (`h-full`) and grows with content down to\n * `minHeight`. Highlights every language fancy-file-commons ships (see\n * `CodeViewProps.language`); anything else renders as plain text.\n */\nexport function CodeView({\n value,\n onChange,\n language = \"plaintext\",\n readOnly = false,\n placeholder,\n minHeight = 120,\n maxHeight,\n className,\n}: CodeViewProps) {\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const isDark = useIsDark();\n const colors: ThemeColors = isDark ? DARK_COLORS : LIGHT_COLORS;\n\n const highlighted = useMemo(() => {\n const tokens = tokenize(value, language) ?? [];\n return highlightCode(value, tokens, colors);\n }, [value, language, colors]);\n\n // Grow the textarea to its content height so it never scrolls internally —\n // the outer container owns scrolling and moves overlay + textarea in lockstep.\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = \"auto\";\n el.style.height = `${el.scrollHeight}px`;\n }, [value]);\n\n const editable = !readOnly && !!onChange;\n\n return (\n <div\n data-react-fancy-code-view=\"\"\n // No baked-in height: the consumer picks the fill mechanism — `flex-1`\n // inside a flex column (the Editor source body), or `h-full` when the\n // parent has a definite height. A hard-coded `h-full` here collapses to\n // content height under a flex-computed (indefinite) parent.\n className={cn(\"relative overflow-auto\", className)}\n style={{ backgroundColor: colors.background, color: colors.foreground, minHeight, maxHeight }}\n >\n <div className=\"relative min-h-full\">\n {/* Highlight overlay */}\n <pre\n aria-hidden=\"true\"\n className={cn(\"pointer-events-none absolute inset-0 overflow-hidden border-none\", TEXT_METRICS)}\n style={{ whiteSpace: \"pre-wrap\", overflowWrap: \"break-word\" }}\n >\n <code dangerouslySetInnerHTML={{ __html: highlighted + \"\\n\" }} />\n </pre>\n\n {/* Placeholder */}\n {placeholder && value.length === 0 && (\n <div className={cn(\"pointer-events-none absolute left-0 top-0 opacity-40\", TEXT_METRICS)}>\n {placeholder}\n </div>\n )}\n\n {/* Transparent input layer (caret + selection visible, glyphs from overlay) */}\n <textarea\n ref={textareaRef}\n data-react-fancy-code-view-input=\"\"\n value={value}\n onChange={editable ? (e) => onChange!(e.target.value) : undefined}\n readOnly={!editable}\n spellCheck={false}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n aria-label={placeholder}\n className={cn(\n \"relative block w-full resize-none border-none bg-transparent text-transparent outline-none\",\n TEXT_METRICS,\n )}\n style={{\n caretColor: colors.cursorColor,\n overflow: \"hidden\",\n whiteSpace: \"pre-wrap\",\n overflowWrap: \"break-word\",\n minHeight,\n }}\n />\n </div>\n </div>\n );\n}\n\nCodeView.displayName = \"CodeView\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/CodeBlock/CodeBlock.tsx"],"names":["tokenize","highlightCode","forwardRef","CodeBlock","useIsDark","DARK_COLORS","LIGHT_COLORS","useMemo","useState","useRef","useEffect","useCallback","runWriter","defaultClipboardWriter","jsx","Button","cn","jsxs","visuallyHidden"],"mappings":"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","file":"chunk-QH4YSG7C.cjs","sourcesContent":["import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n highlightCode,\n tokenize,\n LIGHT_COLORS,\n DARK_COLORS,\n type ThemeColors,\n type Token,\n} from \"@particle-academy/fancy-file-commons\";\nimport { cn } from \"../../utils/cn\";\nimport { visuallyHidden } from \"../../utils/visually-hidden\";\nimport { Button } from \"../Button/Button\";\nimport { defaultClipboardWriter, runWriter } from \"../ContentRenderer/copy\";\nimport { useIsDark } from \"../CodeView/use-is-dark\";\nimport type { CodeBlockProps } from \"./CodeBlock.types\";\n\n/** How long \"Copied\" / \"Copy failed\" stays before the button resets. */\nconst FEEDBACK_MS = 2000;\n\n/**\n * Tokens for any language fancy-file-commons can highlight (aliases included,\n * case-insensitive); none for anything else, which renders as plain text.\n * `tokenize` returns sorted, non-overlapping, in-bounds tokens, which\n * `highlightLines` relies on.\n */\nfunction tokensFor(code: string, language: string): Token[] {\n return tokenize(code, language) ?? [];\n}\n\n/**\n * Highlight one line at a time, clipping each token to the line it falls on, so\n * a token that spans lines (an HTML comment) keeps its colour on every line.\n * `highlightCode` escapes every slice it emits, highlighted or not.\n */\nfunction highlightLines(code: string, tokens: Token[], colors: ThemeColors): string[] {\n const out: string[] = [];\n let start = 0;\n let ti = 0;\n for (const line of code.split(\"\\n\")) {\n const end = start + line.length;\n while (ti < tokens.length && tokens[ti].end <= start) ti++;\n const clipped: Token[] = [];\n for (let j = ti; j < tokens.length && tokens[j].start < end; j++) {\n const s = Math.max(tokens[j].start, start) - start;\n const e = Math.min(tokens[j].end, end) - start;\n if (e > s) clipped.push({ type: tokens[j].type, start: s, end: e });\n }\n out.push(highlightCode(line, clipped, colors));\n start = end + 1;\n }\n return out;\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\n// Matches CodeView's text metrics so the two sit together.\nconst TEXT_METRICS = \"m-0 p-3 font-mono text-xs leading-relaxed\";\n\n/**\n * A display-only code block: `<pre><code>`, syntax-highlighted where a grammar\n * exists, with an optional copy button. It contains no textarea, input, select\n * or contenteditable element, so it is safe on pages that must not accept\n * input. For an editable or selectable source surface, use `CodeView`.\n */\nexport const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(function CodeBlock(\n {\n code,\n language = \"plaintext\",\n copyable = true,\n title,\n showLineNumbers = false,\n wrap = false,\n copyLabels,\n onCopyCode,\n className,\n style,\n ...rest\n },\n ref,\n) {\n const isDark = useIsDark();\n const colors: ThemeColors = isDark ? DARK_COLORS : LIGHT_COLORS;\n\n const tokens = useMemo(() => tokensFor(code, language), [code, language]);\n const html = useMemo(\n () => (showLineNumbers ? null : highlightCode(code, tokens, colors)),\n [code, tokens, colors, showLineNumbers],\n );\n const lines = useMemo(() => {\n if (!showLineNumbers) return null;\n const all = highlightLines(code, tokens, colors);\n // A trailing newline ends the last line; it does not start a new one.\n if (all.length > 1 && code.endsWith(\"\\n\")) all.pop();\n return all;\n }, [code, tokens, colors, showLineNumbers]);\n\n const [copyState, setCopyState] = useState<CopyState>(\"idle\");\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => () => clearTimeout(timer.current), []);\n\n // Latest props at click time, without re-creating the handler.\n const latest = useRef({ code, onCopyCode });\n latest.current = { code, onCopyCode };\n\n const onCopyClick = useCallback(async () => {\n const { code: text, onCopyCode: report } = latest.current;\n // Raw `code`, never the highlighted HTML. `defaultClipboardWriter` throws\n // when `navigator.clipboard` is absent (SSR, insecure context), and\n // `runWriter` turns a throw, rejection or hang into `false`.\n const ok = await runWriter(defaultClipboardWriter, { kind: \"code\", text, html: \"\" });\n setCopyState(ok ? \"copied\" : \"failed\");\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopyState(\"idle\"), FEEDBACK_MS);\n report?.({ text, ok });\n }, []);\n\n const labels = {\n copy: copyLabels?.copy ?? \"Copy code\",\n copied: copyLabels?.copied ?? \"Copied\",\n failed: copyLabels?.failed ?? \"Copy failed\",\n };\n const label = copyState === \"copied\" ? labels.copied : copyState === \"failed\" ? labels.failed : labels.copy;\n const hasHeader = title != null && title !== false;\n const floating = copyable && !hasHeader;\n\n const copyButton = copyable ? (\n <Button\n type=\"button\"\n size=\"xs\"\n variant=\"ghost\"\n icon={copyState === \"copied\" ? \"check\" : copyState === \"failed\" ? \"x\" : \"copy\"}\n aria-label={label}\n title={label}\n data-react-fancy-code-block-copy=\"\"\n data-copy-state={copyState}\n onClick={onCopyClick}\n className={cn(\n floating && \"opacity-80 group-hover:opacity-100 focus-visible:opacity-100\",\n )}\n style={floating ? { backgroundColor: colors.background } : undefined}\n >\n {/* Visible feedback; idle is icon-only when floating over the code. */}\n {copyState !== \"idle\" ? label : hasHeader ? \"Copy\" : undefined}\n </Button>\n ) : null;\n\n const gutterWidth = lines ? `${String(lines.length).length}ch` : undefined;\n\n return (\n <div\n ref={ref}\n data-react-fancy-code-block=\"\"\n data-language={language}\n data-wrap={wrap ? \"true\" : \"false\"}\n className={cn(\n \"group relative overflow-hidden rounded-lg border\",\n className,\n )}\n style={{\n backgroundColor: colors.background,\n color: colors.foreground,\n borderColor: colors.gutterBorder,\n // `relative` inline too: the floating button and the live region are\n // absolute, and must not escape a host whose Tailwind lacks the class.\n position: \"relative\",\n ...style,\n }}\n {...rest}\n >\n {hasHeader && (\n <div\n data-react-fancy-code-block-header=\"\"\n className=\"flex items-center justify-between gap-2 border-b py-1 pl-3 pr-1 text-xs\"\n style={{\n backgroundColor: colors.gutterBackground,\n color: colors.gutterForeground,\n borderColor: colors.gutterBorder,\n }}\n >\n <span data-react-fancy-code-block-title=\"\" className=\"min-w-0 truncate font-mono\">\n {title}\n </span>\n {copyButton}\n </div>\n )}\n\n <pre\n data-react-fancy-code-block-pre=\"\"\n className={cn(TEXT_METRICS, \"border-none\", wrap ? \"overflow-x-hidden\" : \"overflow-x-auto\", floating && \"pr-12\")}\n style={{\n whiteSpace: wrap ? \"pre-wrap\" : \"pre\",\n overflowWrap: wrap ? \"break-word\" : \"normal\",\n backgroundColor: \"transparent\",\n color: \"inherit\",\n }}\n >\n {lines ? (\n <code\n data-react-fancy-code-block-code=\"\"\n style={{ display: wrap ? \"block\" : \"inline-block\", minWidth: \"100%\" }}\n >\n {lines.map((lineHtml, i) => (\n <span key={i} data-react-fancy-code-block-line={i + 1} style={{ display: \"flex\" }}>\n <span\n data-react-fancy-code-block-line-number=\"\"\n aria-hidden=\"true\"\n className=\"select-none\"\n style={{\n flex: \"none\",\n width: gutterWidth,\n marginRight: \"1.5ch\",\n textAlign: \"right\",\n color: colors.gutterForeground,\n userSelect: \"none\",\n }}\n >\n {i + 1}\n </span>\n <span\n data-react-fancy-code-block-line-content=\"\"\n style={{ flex: \"1 1 auto\", minWidth: 0 }}\n dangerouslySetInnerHTML={{ __html: lineHtml }}\n />\n </span>\n ))}\n </code>\n ) : (\n <code data-react-fancy-code-block-code=\"\" dangerouslySetInnerHTML={{ __html: html ?? \"\" }} />\n )}\n </pre>\n\n {floating && (\n <div\n data-react-fancy-code-block-actions=\"\"\n className=\"absolute right-2 top-2\"\n style={{ position: \"absolute\", right: \"0.5rem\", top: \"0.5rem\" }}\n >\n {copyButton}\n </div>\n )}\n\n {copyable && (\n <span role=\"status\" aria-live=\"polite\" className=\"sr-only\" style={visuallyHidden}>\n {copyState === \"idle\" ? \"\" : label}\n </span>\n )}\n </div>\n );\n});\n\nCodeBlock.displayName = \"CodeBlock\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/CodeView/CodeView.tsx"],"names":["useRef","useIsDark","DARK_COLORS","LIGHT_COLORS","useMemo","tokenize","highlightCode","useEffect","jsx","cn","jsxs"],"mappings":"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","file":"chunk-TQL3QW7F.cjs","sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport {\n highlightCode,\n tokenize,\n LIGHT_COLORS,\n DARK_COLORS,\n type ThemeColors,\n} from \"@particle-academy/fancy-file-commons\";\nimport { cn } from \"../../utils/cn\";\nimport { useIsDark } from \"./use-is-dark\";\nimport type { CodeViewProps } from \"./CodeView.types\";\n\n// Shared text metrics — the overlay and the textarea MUST match exactly (font,\n// size, line-height, padding, wrapping) so the highlighted glyphs sit under the\n// caret. Keep this string identical on both layers.\nconst TEXT_METRICS = \"m-0 p-3 font-mono text-xs leading-relaxed\";\n\n/**\n * A lightweight, syntax-highlighted source view built on the pure highlight\n * primitives in `@particle-academy/fancy-file-commons` — a highlight overlay\n * with a transparent, auto-growing textarea on top; the container scrolls both\n * together. Fills its parent's height (`h-full`) and grows with content down to\n * `minHeight`. Highlights every language fancy-file-commons ships (see\n * `CodeViewProps.language`); anything else renders as plain text.\n */\nexport function CodeView({\n value,\n onChange,\n language = \"plaintext\",\n readOnly = false,\n placeholder,\n minHeight = 120,\n maxHeight,\n className,\n}: CodeViewProps) {\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const isDark = useIsDark();\n const colors: ThemeColors = isDark ? DARK_COLORS : LIGHT_COLORS;\n\n const highlighted = useMemo(() => {\n const tokens = tokenize(value, language) ?? [];\n return highlightCode(value, tokens, colors);\n }, [value, language, colors]);\n\n // Grow the textarea to its content height so it never scrolls internally —\n // the outer container owns scrolling and moves overlay + textarea in lockstep.\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = \"auto\";\n el.style.height = `${el.scrollHeight}px`;\n }, [value]);\n\n const editable = !readOnly && !!onChange;\n\n return (\n <div\n data-react-fancy-code-view=\"\"\n // No baked-in height: the consumer picks the fill mechanism — `flex-1`\n // inside a flex column (the Editor source body), or `h-full` when the\n // parent has a definite height. A hard-coded `h-full` here collapses to\n // content height under a flex-computed (indefinite) parent.\n className={cn(\"relative overflow-auto\", className)}\n style={{ backgroundColor: colors.background, color: colors.foreground, minHeight, maxHeight }}\n >\n <div className=\"relative min-h-full\">\n {/* Highlight overlay */}\n <pre\n aria-hidden=\"true\"\n className={cn(\"pointer-events-none absolute inset-0 overflow-hidden border-none\", TEXT_METRICS)}\n style={{ whiteSpace: \"pre-wrap\", overflowWrap: \"break-word\" }}\n >\n <code dangerouslySetInnerHTML={{ __html: highlighted + \"\\n\" }} />\n </pre>\n\n {/* Placeholder */}\n {placeholder && value.length === 0 && (\n <div className={cn(\"pointer-events-none absolute left-0 top-0 opacity-40\", TEXT_METRICS)}>\n {placeholder}\n </div>\n )}\n\n {/* Transparent input layer (caret + selection visible, glyphs from overlay) */}\n <textarea\n ref={textareaRef}\n data-react-fancy-code-view-input=\"\"\n value={value}\n onChange={editable ? (e) => onChange!(e.target.value) : undefined}\n readOnly={!editable}\n spellCheck={false}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n aria-label={placeholder}\n className={cn(\n \"relative block w-full resize-none border-none bg-transparent text-transparent outline-none\",\n TEXT_METRICS,\n )}\n style={{\n caretColor: colors.cursorColor,\n overflow: \"hidden\",\n whiteSpace: \"pre-wrap\",\n overflowWrap: \"break-word\",\n minHeight,\n }}\n />\n </div>\n </div>\n );\n}\n\nCodeView.displayName = \"CodeView\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/CodeBlock/CodeBlock.tsx"],"names":["CodeBlock"],"mappings":"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","file":"chunk-YRI6OFLY.js","sourcesContent":["import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n highlightCode,\n tokenize,\n LIGHT_COLORS,\n DARK_COLORS,\n type ThemeColors,\n type Token,\n} from \"@particle-academy/fancy-file-commons\";\nimport { cn } from \"../../utils/cn\";\nimport { visuallyHidden } from \"../../utils/visually-hidden\";\nimport { Button } from \"../Button/Button\";\nimport { defaultClipboardWriter, runWriter } from \"../ContentRenderer/copy\";\nimport { useIsDark } from \"../CodeView/use-is-dark\";\nimport type { CodeBlockProps } from \"./CodeBlock.types\";\n\n/** How long \"Copied\" / \"Copy failed\" stays before the button resets. */\nconst FEEDBACK_MS = 2000;\n\n/**\n * Tokens for any language fancy-file-commons can highlight (aliases included,\n * case-insensitive); none for anything else, which renders as plain text.\n * `tokenize` returns sorted, non-overlapping, in-bounds tokens, which\n * `highlightLines` relies on.\n */\nfunction tokensFor(code: string, language: string): Token[] {\n return tokenize(code, language) ?? [];\n}\n\n/**\n * Highlight one line at a time, clipping each token to the line it falls on, so\n * a token that spans lines (an HTML comment) keeps its colour on every line.\n * `highlightCode` escapes every slice it emits, highlighted or not.\n */\nfunction highlightLines(code: string, tokens: Token[], colors: ThemeColors): string[] {\n const out: string[] = [];\n let start = 0;\n let ti = 0;\n for (const line of code.split(\"\\n\")) {\n const end = start + line.length;\n while (ti < tokens.length && tokens[ti].end <= start) ti++;\n const clipped: Token[] = [];\n for (let j = ti; j < tokens.length && tokens[j].start < end; j++) {\n const s = Math.max(tokens[j].start, start) - start;\n const e = Math.min(tokens[j].end, end) - start;\n if (e > s) clipped.push({ type: tokens[j].type, start: s, end: e });\n }\n out.push(highlightCode(line, clipped, colors));\n start = end + 1;\n }\n return out;\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\n// Matches CodeView's text metrics so the two sit together.\nconst TEXT_METRICS = \"m-0 p-3 font-mono text-xs leading-relaxed\";\n\n/**\n * A display-only code block: `<pre><code>`, syntax-highlighted where a grammar\n * exists, with an optional copy button. It contains no textarea, input, select\n * or contenteditable element, so it is safe on pages that must not accept\n * input. For an editable or selectable source surface, use `CodeView`.\n */\nexport const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(function CodeBlock(\n {\n code,\n language = \"plaintext\",\n copyable = true,\n title,\n showLineNumbers = false,\n wrap = false,\n copyLabels,\n onCopyCode,\n className,\n style,\n ...rest\n },\n ref,\n) {\n const isDark = useIsDark();\n const colors: ThemeColors = isDark ? DARK_COLORS : LIGHT_COLORS;\n\n const tokens = useMemo(() => tokensFor(code, language), [code, language]);\n const html = useMemo(\n () => (showLineNumbers ? null : highlightCode(code, tokens, colors)),\n [code, tokens, colors, showLineNumbers],\n );\n const lines = useMemo(() => {\n if (!showLineNumbers) return null;\n const all = highlightLines(code, tokens, colors);\n // A trailing newline ends the last line; it does not start a new one.\n if (all.length > 1 && code.endsWith(\"\\n\")) all.pop();\n return all;\n }, [code, tokens, colors, showLineNumbers]);\n\n const [copyState, setCopyState] = useState<CopyState>(\"idle\");\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => () => clearTimeout(timer.current), []);\n\n // Latest props at click time, without re-creating the handler.\n const latest = useRef({ code, onCopyCode });\n latest.current = { code, onCopyCode };\n\n const onCopyClick = useCallback(async () => {\n const { code: text, onCopyCode: report } = latest.current;\n // Raw `code`, never the highlighted HTML. `defaultClipboardWriter` throws\n // when `navigator.clipboard` is absent (SSR, insecure context), and\n // `runWriter` turns a throw, rejection or hang into `false`.\n const ok = await runWriter(defaultClipboardWriter, { kind: \"code\", text, html: \"\" });\n setCopyState(ok ? \"copied\" : \"failed\");\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopyState(\"idle\"), FEEDBACK_MS);\n report?.({ text, ok });\n }, []);\n\n const labels = {\n copy: copyLabels?.copy ?? \"Copy code\",\n copied: copyLabels?.copied ?? \"Copied\",\n failed: copyLabels?.failed ?? \"Copy failed\",\n };\n const label = copyState === \"copied\" ? labels.copied : copyState === \"failed\" ? labels.failed : labels.copy;\n const hasHeader = title != null && title !== false;\n const floating = copyable && !hasHeader;\n\n const copyButton = copyable ? (\n <Button\n type=\"button\"\n size=\"xs\"\n variant=\"ghost\"\n icon={copyState === \"copied\" ? \"check\" : copyState === \"failed\" ? \"x\" : \"copy\"}\n aria-label={label}\n title={label}\n data-react-fancy-code-block-copy=\"\"\n data-copy-state={copyState}\n onClick={onCopyClick}\n className={cn(\n floating && \"opacity-80 group-hover:opacity-100 focus-visible:opacity-100\",\n )}\n style={floating ? { backgroundColor: colors.background } : undefined}\n >\n {/* Visible feedback; idle is icon-only when floating over the code. */}\n {copyState !== \"idle\" ? label : hasHeader ? \"Copy\" : undefined}\n </Button>\n ) : null;\n\n const gutterWidth = lines ? `${String(lines.length).length}ch` : undefined;\n\n return (\n <div\n ref={ref}\n data-react-fancy-code-block=\"\"\n data-language={language}\n data-wrap={wrap ? \"true\" : \"false\"}\n className={cn(\n \"group relative overflow-hidden rounded-lg border\",\n className,\n )}\n style={{\n backgroundColor: colors.background,\n color: colors.foreground,\n borderColor: colors.gutterBorder,\n // `relative` inline too: the floating button and the live region are\n // absolute, and must not escape a host whose Tailwind lacks the class.\n position: \"relative\",\n ...style,\n }}\n {...rest}\n >\n {hasHeader && (\n <div\n data-react-fancy-code-block-header=\"\"\n className=\"flex items-center justify-between gap-2 border-b py-1 pl-3 pr-1 text-xs\"\n style={{\n backgroundColor: colors.gutterBackground,\n color: colors.gutterForeground,\n borderColor: colors.gutterBorder,\n }}\n >\n <span data-react-fancy-code-block-title=\"\" className=\"min-w-0 truncate font-mono\">\n {title}\n </span>\n {copyButton}\n </div>\n )}\n\n <pre\n data-react-fancy-code-block-pre=\"\"\n className={cn(TEXT_METRICS, \"border-none\", wrap ? \"overflow-x-hidden\" : \"overflow-x-auto\", floating && \"pr-12\")}\n style={{\n whiteSpace: wrap ? \"pre-wrap\" : \"pre\",\n overflowWrap: wrap ? \"break-word\" : \"normal\",\n backgroundColor: \"transparent\",\n color: \"inherit\",\n }}\n >\n {lines ? (\n <code\n data-react-fancy-code-block-code=\"\"\n style={{ display: wrap ? \"block\" : \"inline-block\", minWidth: \"100%\" }}\n >\n {lines.map((lineHtml, i) => (\n <span key={i} data-react-fancy-code-block-line={i + 1} style={{ display: \"flex\" }}>\n <span\n data-react-fancy-code-block-line-number=\"\"\n aria-hidden=\"true\"\n className=\"select-none\"\n style={{\n flex: \"none\",\n width: gutterWidth,\n marginRight: \"1.5ch\",\n textAlign: \"right\",\n color: colors.gutterForeground,\n userSelect: \"none\",\n }}\n >\n {i + 1}\n </span>\n <span\n data-react-fancy-code-block-line-content=\"\"\n style={{ flex: \"1 1 auto\", minWidth: 0 }}\n dangerouslySetInnerHTML={{ __html: lineHtml }}\n />\n </span>\n ))}\n </code>\n ) : (\n <code data-react-fancy-code-block-code=\"\" dangerouslySetInnerHTML={{ __html: html ?? \"\" }} />\n )}\n </pre>\n\n {floating && (\n <div\n data-react-fancy-code-block-actions=\"\"\n className=\"absolute right-2 top-2\"\n style={{ position: \"absolute\", right: \"0.5rem\", top: \"0.5rem\" }}\n >\n {copyButton}\n </div>\n )}\n\n {copyable && (\n <span role=\"status\" aria-live=\"polite\" className=\"sr-only\" style={visuallyHidden}>\n {copyState === \"idle\" ? \"\" : label}\n </span>\n )}\n </div>\n );\n});\n\nCodeBlock.displayName = \"CodeBlock\";\n"]}