@particle-academy/react-fancy 5.66.0 → 5.68.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 (70) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/dist/ContentRenderer.types-RO_l7_6N.d.cts +137 -0
  3. package/dist/ContentRenderer.types-RO_l7_6N.d.ts +137 -0
  4. package/dist/button.cjs +3 -4
  5. package/dist/button.js +1 -2
  6. package/dist/{chunk-J44EV6SP.js → chunk-23AVEYUP.js} +3 -3
  7. package/dist/{chunk-J44EV6SP.js.map → chunk-23AVEYUP.js.map} +1 -1
  8. package/dist/{chunk-L24LUSEE.js → chunk-2LQR4EAN.js} +553 -35
  9. package/dist/chunk-2LQR4EAN.js.map +1 -0
  10. package/dist/{chunk-C5YX5XVL.cjs → chunk-3U7PUZLI.cjs} +214 -4
  11. package/dist/chunk-3U7PUZLI.cjs.map +1 -0
  12. package/dist/{chunk-MCQJFMDP.cjs → chunk-464QSZ4A.cjs} +553 -35
  13. package/dist/chunk-464QSZ4A.cjs.map +1 -0
  14. package/dist/{chunk-QP35Z2WB.js → chunk-BL5IKSB3.js} +3 -3
  15. package/dist/{chunk-QP35Z2WB.js.map → chunk-BL5IKSB3.js.map} +1 -1
  16. package/dist/{chunk-4EUDW2WU.js → chunk-DCAD2JPP.js} +3 -3
  17. package/dist/{chunk-4EUDW2WU.js.map → chunk-DCAD2JPP.js.map} +1 -1
  18. package/dist/{chunk-ATIDUWY6.cjs → chunk-E4DXICU3.cjs} +19 -13
  19. package/dist/chunk-E4DXICU3.cjs.map +1 -0
  20. package/dist/{chunk-TLRRMYNV.js → chunk-OXERDFFF.js} +212 -4
  21. package/dist/chunk-OXERDFFF.js.map +1 -0
  22. package/dist/{chunk-SYEHWUM5.cjs → chunk-RALJMI7C.cjs} +4 -4
  23. package/dist/{chunk-SYEHWUM5.cjs.map → chunk-RALJMI7C.cjs.map} +1 -1
  24. package/dist/{chunk-UM4JXBRZ.cjs → chunk-S3NB6LDV.cjs} +4 -4
  25. package/dist/{chunk-UM4JXBRZ.cjs.map → chunk-S3NB6LDV.cjs.map} +1 -1
  26. package/dist/{chunk-MCQWTOTV.cjs → chunk-SAG6DHQK.cjs} +6 -6
  27. package/dist/{chunk-MCQWTOTV.cjs.map → chunk-SAG6DHQK.cjs.map} +1 -1
  28. package/dist/{chunk-CAUEKGMR.js → chunk-TQ77ZWBD.js} +11 -5
  29. package/dist/chunk-TQ77ZWBD.js.map +1 -0
  30. package/dist/{chunk-7HXFEYOV.cjs → chunk-U5LKNGHU.cjs} +15 -15
  31. package/dist/{chunk-7HXFEYOV.cjs.map → chunk-U5LKNGHU.cjs.map} +1 -1
  32. package/dist/{chunk-M52S3TFI.js → chunk-WFR7HKJL.js} +3 -3
  33. package/dist/{chunk-M52S3TFI.js.map → chunk-WFR7HKJL.js.map} +1 -1
  34. package/dist/content-renderer.cjs +7 -5
  35. package/dist/content-renderer.d.cts +4 -21
  36. package/dist/content-renderer.d.ts +4 -21
  37. package/dist/content-renderer.js +4 -2
  38. package/dist/editor.cjs +6 -5
  39. package/dist/editor.d.cts +19 -2
  40. package/dist/editor.d.ts +19 -2
  41. package/dist/editor.js +4 -3
  42. package/dist/index.cjs +37 -38
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +2 -2
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.js +7 -8
  47. package/dist/index.js.map +1 -1
  48. package/dist/json-editor.cjs +13 -14
  49. package/dist/json-editor.js +2 -3
  50. package/dist/magic-wand.cjs +3 -4
  51. package/dist/magic-wand.js +2 -3
  52. package/dist/prompt-input.cjs +5 -6
  53. package/dist/prompt-input.js +2 -3
  54. package/dist/reason-tag.cjs +3 -4
  55. package/dist/reason-tag.js +2 -3
  56. package/docs/ContentRenderer.md +192 -3
  57. package/docs/Editor.md +38 -0
  58. package/package.json +1 -1
  59. package/dist/chunk-6TBRBN7H.js +0 -212
  60. package/dist/chunk-6TBRBN7H.js.map +0 -1
  61. package/dist/chunk-ATIDUWY6.cjs.map +0 -1
  62. package/dist/chunk-C5YX5XVL.cjs.map +0 -1
  63. package/dist/chunk-CAUEKGMR.js.map +0 -1
  64. package/dist/chunk-L24LUSEE.js.map +0 -1
  65. package/dist/chunk-MCQJFMDP.cjs.map +0 -1
  66. package/dist/chunk-TLRRMYNV.js.map +0 -1
  67. package/dist/chunk-X2FC7ODX.cjs +0 -215
  68. package/dist/chunk-X2FC7ODX.cjs.map +0 -1
  69. package/dist/extensions-6PVd3-vB.d.cts +0 -38
  70. package/dist/extensions-6PVd3-vB.d.ts +0 -38
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme-tokens.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Semantic theme tokens — the small set of colours the kit's DOM components\n * read, so a host can repaint the whole kit with its own palette WITHOUT\n * remapping Tailwind's `zinc` or `violet`.\n *\n * Each role is two CSS custom properties, one per mode:\n *\n * --fancy-surface the light value\n * --fancy-surface-dark the dark value\n *\n * Components read them through their var() FALLBACK, which is the colour the\n * component used before these existed:\n *\n * bg-[color:var(--fancy-surface,var(--color-white))]\n * dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\n *\n * So:\n * - **Set nothing and nothing changes.** An unset custom property resolves to\n * its fallback, which is the exact declaration the old `bg-white` produced.\n * - **Set one and every surface follows**, wherever the variable is in scope:\n * `:root`, `body`, or any wrapper element. No selector to match, no layer or\n * specificity to win — a custom property is inherited, not cascaded against.\n * - **Both modes are stated, not derived.** The dark value is a separate\n * variable rather than a flip under `.dark`, so which one applies is decided\n * by the host's own `dark:` variant — the same switch that drives every\n * other `dark:` utility in the kit. (See `dark-variant.css` for a variant\n * that follows `[data-theme=\"dark\"]` as well as `.dark`.)\n *\n * NOT covered, deliberately: colours that ENCODE DATA — chart series,\n * file-type marks, mood and confidence scales, event kinds. Repainting those\n * with a host's neutral palette would erase what they mean. A component's\n * explicit `color` prop (Badge, Button, Callout …) is also untouched: that is\n * the host choosing a hue, not the kit choosing one for it.\n *\n * `light` / `dark` are the defaults exactly as components write them in their\n * fallbacks. `tests/theme-tokens.test.tsx` fails if a component's fallback\n * disagrees with this table, so the table is the contract rather than a\n * description of it.\n */\nexport const THEME_TOKENS = {\n surface: {\n variable: \"--fancy-surface\",\n darkVariable: \"--fancy-surface-dark\",\n light: \"var(--color-white)\",\n dark: \"var(--color-zinc-900)\",\n description: \"Panels, cards, overlays (menus, modals, popovers, toasts), sidebars and navbars.\",\n },\n \"surface-muted\": {\n variable: \"--fancy-surface-muted\",\n darkVariable: \"--fancy-surface-muted-dark\",\n light: \"var(--color-zinc-100)\",\n dark: \"var(--color-zinc-800)\",\n description: \"Hovered and selected rows, chips, inset wells, toolbar buttons.\",\n },\n border: {\n variable: \"--fancy-border\",\n darkVariable: \"--fancy-border-dark\",\n light: \"var(--color-zinc-200)\",\n dark: \"var(--color-zinc-700)\",\n description: \"Outlines, dividers, separators and tracks (skeletons, progress, sliders).\",\n },\n \"border-strong\": {\n variable: \"--fancy-border-strong\",\n darkVariable: \"--fancy-border-strong-dark\",\n light: \"var(--color-zinc-300)\",\n dark: \"var(--color-zinc-700)\",\n description: \"The firmer outline on form controls (inputs, checkboxes, radios) and keycaps.\",\n },\n input: {\n variable: \"--fancy-input\",\n darkVariable: \"--fancy-input-dark\",\n light: \"var(--color-white)\",\n dark: \"#1e1e24\",\n description: \"The field surface of text inputs, checkboxes, radios, OTP cells and pickers.\",\n },\n text: {\n variable: \"--fancy-text\",\n darkVariable: \"--fancy-text-dark\",\n light: \"var(--color-zinc-900)\",\n dark: \"var(--color-zinc-100)\",\n description: \"Strongest foreground: headings, values, field text, active items.\",\n },\n \"text-soft\": {\n variable: \"--fancy-text-soft\",\n darkVariable: \"--fancy-text-soft-dark\",\n light: \"var(--color-zinc-700)\",\n dark: \"var(--color-zinc-300)\",\n description: \"Body copy and menu items: readable, one step back from text.\",\n },\n \"text-muted\": {\n variable: \"--fancy-text-muted\",\n darkVariable: \"--fancy-text-muted-dark\",\n light: \"var(--color-zinc-500)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Descriptions, captions, secondary labels, axis labels.\",\n },\n \"text-faint\": {\n variable: \"--fancy-text-faint\",\n darkVariable: \"--fancy-text-faint-dark\",\n light: \"var(--color-zinc-400)\",\n dark: \"var(--color-zinc-500)\",\n description: \"Placeholders, disabled hints, decorative icons.\",\n },\n \"text-subtle\": {\n variable: \"--fancy-text-subtle\",\n darkVariable: \"--fancy-text-subtle-dark\",\n light: \"var(--color-zinc-600)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Inactive nav labels (Sidebar, Menu, Navbar, MultiSwitch) and secondary prose. Added 5.53.1.\",\n },\n \"surface-hover\": {\n variable: \"--fancy-surface-hover\",\n darkVariable: \"--fancy-surface-hover-dark\",\n light: \"var(--color-zinc-50)\",\n // Tailwind's `bg-zinc-800/50`, written out so a host's value is used as-is.\n dark: \"color-mix(in oklab, var(--color-zinc-800) 50%, transparent)\",\n description: \"The hover fill on nav items, list options and table rows. Added 5.53.1.\",\n },\n focus: {\n variable: \"--fancy-focus\",\n darkVariable: \"--fancy-focus-dark\",\n light: \"var(--color-blue-500)\",\n dark: \"var(--color-blue-400)\",\n description: \"The focus border and ring on form controls.\",\n },\n} as const;\n\nexport type ThemeTokenRole = keyof typeof THEME_TOKENS;\n"]}
1
+ {"version":3,"sources":["../src/theme-tokens.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Semantic theme tokens — the small set of colours the kit's DOM components\n * read, so a host can repaint the whole kit with its own palette WITHOUT\n * remapping Tailwind's `zinc` or `violet`.\n *\n * Each role is two CSS custom properties, one per mode:\n *\n * --fancy-surface the light value\n * --fancy-surface-dark the dark value\n *\n * Components read them through their var() FALLBACK, which is the colour the\n * component used before these existed:\n *\n * bg-[color:var(--fancy-surface,var(--color-white))]\n * dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\n *\n * So:\n * - **Set nothing and nothing changes.** An unset custom property resolves to\n * its fallback, which is the exact declaration the old `bg-white` produced.\n * - **Set one and every surface follows**, wherever the variable is in scope:\n * `:root`, `body`, or any wrapper element. No selector to match, no layer or\n * specificity to win — a custom property is inherited, not cascaded against.\n * - **Both modes are stated, not derived.** The dark value is a separate\n * variable rather than a flip under `.dark`, so which one applies is decided\n * by the host's own `dark:` variant — the same switch that drives every\n * other `dark:` utility in the kit. (See `dark-variant.css` for a variant\n * that follows `[data-theme=\"dark\"]` as well as `.dark`.)\n *\n * NOT covered, deliberately: colours that ENCODE DATA — chart series,\n * file-type marks, mood and confidence scales, event kinds. Repainting those\n * with a host's neutral palette would erase what they mean. A component's\n * explicit `color` prop (Badge, Button, Callout …) is also untouched: that is\n * the host choosing a hue, not the kit choosing one for it.\n *\n * `light` / `dark` are the defaults exactly as components write them in their\n * fallbacks. `tests/theme-tokens.test.tsx` fails if a component's fallback\n * disagrees with this table, so the table is the contract rather than a\n * description of it.\n */\nexport const THEME_TOKENS = {\n surface: {\n variable: \"--fancy-surface\",\n darkVariable: \"--fancy-surface-dark\",\n light: \"var(--color-white)\",\n dark: \"var(--color-zinc-900)\",\n description: \"Panels, cards, overlays (menus, modals, popovers, toasts), sidebars and navbars.\",\n },\n \"surface-muted\": {\n variable: \"--fancy-surface-muted\",\n darkVariable: \"--fancy-surface-muted-dark\",\n light: \"var(--color-zinc-100)\",\n dark: \"var(--color-zinc-800)\",\n description: \"Hovered and selected rows, chips, inset wells, toolbar buttons.\",\n },\n border: {\n variable: \"--fancy-border\",\n darkVariable: \"--fancy-border-dark\",\n light: \"var(--color-zinc-200)\",\n dark: \"var(--color-zinc-700)\",\n description: \"Outlines, dividers, separators and tracks (skeletons, progress, sliders).\",\n },\n \"border-strong\": {\n variable: \"--fancy-border-strong\",\n darkVariable: \"--fancy-border-strong-dark\",\n light: \"var(--color-zinc-300)\",\n dark: \"var(--color-zinc-700)\",\n description: \"The firmer outline on form controls (inputs, checkboxes, radios) and keycaps.\",\n },\n input: {\n variable: \"--fancy-input\",\n darkVariable: \"--fancy-input-dark\",\n light: \"var(--color-white)\",\n dark: \"#1e1e24\",\n description: \"The field surface of text inputs, checkboxes, radios, OTP cells and pickers.\",\n },\n text: {\n variable: \"--fancy-text\",\n darkVariable: \"--fancy-text-dark\",\n light: \"var(--color-zinc-900)\",\n dark: \"var(--color-zinc-100)\",\n description: \"Strongest foreground: headings, values, field text, active items.\",\n },\n \"text-soft\": {\n variable: \"--fancy-text-soft\",\n darkVariable: \"--fancy-text-soft-dark\",\n light: \"var(--color-zinc-700)\",\n dark: \"var(--color-zinc-300)\",\n description: \"Body copy and menu items: readable, one step back from text.\",\n },\n \"text-muted\": {\n variable: \"--fancy-text-muted\",\n darkVariable: \"--fancy-text-muted-dark\",\n light: \"var(--color-zinc-500)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Descriptions, captions, secondary labels, axis labels.\",\n },\n \"text-faint\": {\n variable: \"--fancy-text-faint\",\n darkVariable: \"--fancy-text-faint-dark\",\n light: \"var(--color-zinc-400)\",\n dark: \"var(--color-zinc-500)\",\n description: \"Placeholders, disabled hints, decorative icons.\",\n },\n \"text-subtle\": {\n variable: \"--fancy-text-subtle\",\n darkVariable: \"--fancy-text-subtle-dark\",\n light: \"var(--color-zinc-600)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Inactive nav labels (Sidebar, Menu, Navbar, MultiSwitch) and secondary prose. Added 5.53.1.\",\n },\n \"surface-hover\": {\n variable: \"--fancy-surface-hover\",\n darkVariable: \"--fancy-surface-hover-dark\",\n light: \"var(--color-zinc-50)\",\n // Tailwind's `bg-zinc-800/50`, written out so a host's value is used as-is.\n dark: \"color-mix(in oklab, var(--color-zinc-800) 50%, transparent)\",\n description: \"The hover fill on nav items, list options and table rows. Added 5.53.1.\",\n },\n focus: {\n variable: \"--fancy-focus\",\n darkVariable: \"--fancy-focus-dark\",\n light: \"var(--color-blue-500)\",\n dark: \"var(--color-blue-400)\",\n description: \"The focus border and ring on form controls.\",\n },\n} as const;\n\nexport type ThemeTokenRole = keyof typeof THEME_TOKENS;\n"]}
package/dist/index.d.cts CHANGED
@@ -78,8 +78,8 @@ export { I as InlinePasteEditor, a as InlinePasteEditorHandle, P as PastedFilesI
78
78
  export { Chart, ChartAreaProps, ChartBarData, ChartBarProps, ChartCommonProps, ChartDonutData, ChartDonutProps, ChartHorizontalBarProps, ChartLineProps, ChartPieData, ChartPieProps, ChartSeries, ChartSparklineProps, ChartStackedBarProps } from './chart.cjs';
79
79
  export { Editor, EditorAction, EditorContentProps, EditorContextValue, EditorFullScreenToggleProps, EditorProps, EditorSourceToggleProps, EditorToolbarProps, useEditor } from './editor.cjs';
80
80
  export { CodeView, CodeViewProps } from './code-view.cjs';
81
- export { ContentRenderer, ContentRendererProps } from './content-renderer.cjs';
82
- export { R as RenderExtension, a as RenderExtensionProps, r as registerExtension, b as registerExtensions } from './extensions-6PVd3-vB.cjs';
81
+ export { ContentRenderer } from './content-renderer.cjs';
82
+ export { C as ContentClipboardPayload, a as ContentClipboardWriter, b as ContentCopyEvent, c as ContentCopyKind, d as ContentRendererProps, R as RenderExtension, e as RenderExtensionProps, r as registerExtension, f as registerExtensions } from './ContentRenderer.types-RO_l7_6N.cjs';
83
83
  export { Menu, MenuContextValue, MenuGroupProps, MenuItemProps, MenuOrientation, MenuProps, MenuSubmenuProps, useMenu } from './menu.cjs';
84
84
  export { Sidebar, SidebarCollapseMode, SidebarContextValue, SidebarGroupProps, SidebarItemProps, SidebarProps, SidebarSubmenuProps, SidebarToggleProps, useSidebar } from './sidebar.cjs';
85
85
  export { MobileMenu, MobileMenuBottomBarProps, MobileMenuContextValue, MobileMenuFlyoutProps, MobileMenuItemProps, MobileMenuSide, MobileMenuVariant, useMobileMenu } from './mobile-menu.cjs';
package/dist/index.d.ts CHANGED
@@ -78,8 +78,8 @@ export { I as InlinePasteEditor, a as InlinePasteEditorHandle, P as PastedFilesI
78
78
  export { Chart, ChartAreaProps, ChartBarData, ChartBarProps, ChartCommonProps, ChartDonutData, ChartDonutProps, ChartHorizontalBarProps, ChartLineProps, ChartPieData, ChartPieProps, ChartSeries, ChartSparklineProps, ChartStackedBarProps } from './chart.js';
79
79
  export { Editor, EditorAction, EditorContentProps, EditorContextValue, EditorFullScreenToggleProps, EditorProps, EditorSourceToggleProps, EditorToolbarProps, useEditor } from './editor.js';
80
80
  export { CodeView, CodeViewProps } from './code-view.js';
81
- export { ContentRenderer, ContentRendererProps } from './content-renderer.js';
82
- export { R as RenderExtension, a as RenderExtensionProps, r as registerExtension, b as registerExtensions } from './extensions-6PVd3-vB.js';
81
+ export { ContentRenderer } from './content-renderer.js';
82
+ export { C as ContentClipboardPayload, a as ContentClipboardWriter, b as ContentCopyEvent, c as ContentCopyKind, d as ContentRendererProps, R as RenderExtension, e as RenderExtensionProps, r as registerExtension, f as registerExtensions } from './ContentRenderer.types-RO_l7_6N.js';
83
83
  export { Menu, MenuContextValue, MenuGroupProps, MenuItemProps, MenuOrientation, MenuProps, MenuSubmenuProps, useMenu } from './menu.js';
84
84
  export { Sidebar, SidebarCollapseMode, SidebarContextValue, SidebarGroupProps, SidebarItemProps, SidebarProps, SidebarSubmenuProps, SidebarToggleProps, useSidebar } from './sidebar.js';
85
85
  export { MobileMenu, MobileMenuBottomBarProps, MobileMenuContextValue, MobileMenuFlyoutProps, MobileMenuItemProps, MobileMenuSide, MobileMenuVariant, useMobileMenu } from './mobile-menu.js';
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ import './chunk-TMR56BBE.js';
25
25
  export { TimeGrid } from './chunk-MLZGGAXQ.js';
26
26
  export { PullQuote } from './chunk-44VYWOCG.js';
27
27
  export { QrCode, encodeQr, selectMode } from './chunk-RLE5WYY6.js';
28
- export { ReasonTag } from './chunk-QP35Z2WB.js';
28
+ export { ReasonTag } from './chunk-BL5IKSB3.js';
29
29
  export { ReorderableGrid, moveItem } from './chunk-DTOIO42M.js';
30
30
  export { ResizablePanels } from './chunk-GDF6XTHC.js';
31
31
  export { Section } from './chunk-SLJD25VV.js';
@@ -34,7 +34,7 @@ export { Sidebar, useSidebar } from './chunk-YJHP5FVA.js';
34
34
  export { Pillbox } from './chunk-G35XN5WV.js';
35
35
  export { Profile } from './chunk-GOE36IXL.js';
36
36
  export { Progress } from './chunk-UE3QO7R3.js';
37
- export { PromptInput, browserPlatformHints, detectPlatform, modifierKeyLabel, promptDataUrlToFile, promptFileToDataUrl } from './chunk-J44EV6SP.js';
37
+ export { PromptInput, browserPlatformHints, detectPlatform, modifierKeyLabel, promptDataUrlToFile, promptFileToDataUrl } from './chunk-23AVEYUP.js';
38
38
  export { Tooltip } from './chunk-GR2WKBER.js';
39
39
  import './chunk-SV5BW3IA.js';
40
40
  export { MediaViewer, resolveMediaType } from './chunk-5PHPJL7Z.js';
@@ -50,14 +50,14 @@ export { Pagination } from './chunk-LKN7FYW6.js';
50
50
  export { ImageViewer } from './chunk-ICMLLZKZ.js';
51
51
  export { IndexList } from './chunk-BLOX7MRO.js';
52
52
  export { InputTag, contentEditableAdapter, controlledAdapter, inputAdapter, textareaAdapter } from './chunk-BX7EDTL4.js';
53
- export { JSON_FIELD_TYPES, JsonEditor, applyJsonEdit, describeEdit, findJsonConflicts, getAtPath, inferType, parseKeyMap, parsePath, pathToString, resolveKeyRule, typeMatches } from './chunk-4EUDW2WU.js';
53
+ export { JSON_FIELD_TYPES, JsonEditor, applyJsonEdit, describeEdit, findJsonConflicts, getAtPath, inferType, parseKeyMap, parsePath, pathToString, resolveKeyRule, typeMatches } from './chunk-DCAD2JPP.js';
54
54
  export { Switch } from './chunk-DXZCKDYS.js';
55
55
  export { DatePicker } from './chunk-2UTN3EFK.js';
56
56
  export { Input } from './chunk-B4LVQ4QI.js';
57
57
  export { Select } from './chunk-FVI4JDLA.js';
58
58
  export { Kanban, useKanban } from './chunk-2HPADT4X.js';
59
59
  export { Kbd } from './chunk-OTSVOPKP.js';
60
- export { MagicWand } from './chunk-M52S3TFI.js';
60
+ export { MagicWand } from './chunk-WFR7HKJL.js';
61
61
  export { Textarea } from './chunk-UVUBV4VZ.js';
62
62
  import './chunk-KXYMMNNV.js';
63
63
  export { DisplayValue } from './chunk-WX5XYDVN.js';
@@ -76,12 +76,12 @@ import './chunk-AUTW5O4W.js';
76
76
  export { ContextMenu, useContextMenu } from './chunk-NSJBVV7R.js';
77
77
  export { Drawer, useDrawer } from './chunk-PXZRYL5I.js';
78
78
  export { Dropdown, useDropdown } from './chunk-BXPLERIJ.js';
79
- export { Editor, useEditor } from './chunk-CAUEKGMR.js';
79
+ export { Editor, useEditor } from './chunk-TQ77ZWBD.js';
80
80
  export { THEME_STORAGE_KEY, getThemePreference, initTheme, resolveTheme, setThemePreference, subscribeTheme, useId, useNodeRegistry, useTheme } from './chunk-2BXMMVQS.js';
81
81
  export { usePanZoom } from './chunk-CPY7NHXM.js';
82
82
  export { FullScreenContext, FullScreenProvider, FullScreenToggle, useFullScreenContext } from './chunk-RP43ZFZP.js';
83
83
  export { useFullScreen } from './chunk-ZQ3VXRUY.js';
84
- export { ContentRenderer, registerExtension, registerExtensions, renderMarkdown } from './chunk-L24LUSEE.js';
84
+ export { ContentRenderer, registerExtension, registerExtensions, renderMarkdown } from './chunk-2LQR4EAN.js';
85
85
  export { Emoji } from './chunk-YTMQ2K64.js';
86
86
  export { EmojiSelect } from './chunk-WGRLNXNB.js';
87
87
  export { Card } from './chunk-2XO6EYZ7.js';
@@ -114,8 +114,7 @@ export { Breadcrumbs } from './chunk-A67EDGC7.js';
114
114
  export { useOutsideClick } from './chunk-RGANGU7X.js';
115
115
  export { EscapeLayerContext, useEscapeKey, useEscapeLayer } from './chunk-YX6FTJ6N.js';
116
116
  import './chunk-LQ4ICCN2.js';
117
- export { Action, Button } from './chunk-TLRRMYNV.js';
118
- export { sanitizeHref, sanitizeHtml } from './chunk-6TBRBN7H.js';
117
+ export { Action, Button, sanitizeHref, sanitizeHtml } from './chunk-OXERDFFF.js';
119
118
  export { EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, SKIN_TONES, applyTone, find, hasSkinTones, resolve, search, skinTones } from './chunk-45BBNJQD.js';
120
119
  export { Icon, configureIcons, registerIconAddendum, registerIconSet, registerIcons } from './chunk-J3A4Z2P7.js';
121
120
  export { Calendar } from './chunk-X2A3NAJW.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme-tokens.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCO,IAAM,YAAA,GAAe;AAAA,EAC1B,OAAA,EAAS;AAAA,IACP,QAAA,EAAU,iBAAA;AAAA,IACV,YAAA,EAAc,sBAAA;AAAA,IACd,KAAA,EAAO,oBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,eAAA,EAAiB;AAAA,IACf,QAAA,EAAU,uBAAA;AAAA,IACV,YAAA,EAAc,4BAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,QAAA,EAAU,gBAAA;AAAA,IACV,YAAA,EAAc,qBAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,eAAA,EAAiB;AAAA,IACf,QAAA,EAAU,uBAAA;AAAA,IACV,YAAA,EAAc,4BAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,KAAA,EAAO;AAAA,IACL,QAAA,EAAU,eAAA;AAAA,IACV,YAAA,EAAc,oBAAA;AAAA,IACd,KAAA,EAAO,oBAAA;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,QAAA,EAAU,cAAA;AAAA,IACV,YAAA,EAAc,mBAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,WAAA,EAAa;AAAA,IACX,QAAA,EAAU,mBAAA;AAAA,IACV,YAAA,EAAc,wBAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,QAAA,EAAU,oBAAA;AAAA,IACV,YAAA,EAAc,yBAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,QAAA,EAAU,oBAAA;AAAA,IACV,YAAA,EAAc,yBAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,aAAA,EAAe;AAAA,IACb,QAAA,EAAU,qBAAA;AAAA,IACV,YAAA,EAAc,0BAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,eAAA,EAAiB;AAAA,IACf,QAAA,EAAU,uBAAA;AAAA,IACV,YAAA,EAAc,4BAAA;AAAA,IACd,KAAA,EAAO,sBAAA;AAAA;AAAA,IAEP,IAAA,EAAM,6DAAA;AAAA,IACN,WAAA,EAAa;AAAA,GACf;AAAA,EACA,KAAA,EAAO;AAAA,IACL,QAAA,EAAU,eAAA;AAAA,IACV,YAAA,EAAc,oBAAA;AAAA,IACd,KAAA,EAAO,uBAAA;AAAA,IACP,IAAA,EAAM,uBAAA;AAAA,IACN,WAAA,EAAa;AAAA;AAEjB","file":"index.js","sourcesContent":["/**\n * Semantic theme tokens — the small set of colours the kit's DOM components\n * read, so a host can repaint the whole kit with its own palette WITHOUT\n * remapping Tailwind's `zinc` or `violet`.\n *\n * Each role is two CSS custom properties, one per mode:\n *\n * --fancy-surface the light value\n * --fancy-surface-dark the dark value\n *\n * Components read them through their var() FALLBACK, which is the colour the\n * component used before these existed:\n *\n * bg-[color:var(--fancy-surface,var(--color-white))]\n * dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\n *\n * So:\n * - **Set nothing and nothing changes.** An unset custom property resolves to\n * its fallback, which is the exact declaration the old `bg-white` produced.\n * - **Set one and every surface follows**, wherever the variable is in scope:\n * `:root`, `body`, or any wrapper element. No selector to match, no layer or\n * specificity to win — a custom property is inherited, not cascaded against.\n * - **Both modes are stated, not derived.** The dark value is a separate\n * variable rather than a flip under `.dark`, so which one applies is decided\n * by the host's own `dark:` variant — the same switch that drives every\n * other `dark:` utility in the kit. (See `dark-variant.css` for a variant\n * that follows `[data-theme=\"dark\"]` as well as `.dark`.)\n *\n * NOT covered, deliberately: colours that ENCODE DATA — chart series,\n * file-type marks, mood and confidence scales, event kinds. Repainting those\n * with a host's neutral palette would erase what they mean. A component's\n * explicit `color` prop (Badge, Button, Callout …) is also untouched: that is\n * the host choosing a hue, not the kit choosing one for it.\n *\n * `light` / `dark` are the defaults exactly as components write them in their\n * fallbacks. `tests/theme-tokens.test.tsx` fails if a component's fallback\n * disagrees with this table, so the table is the contract rather than a\n * description of it.\n */\nexport const THEME_TOKENS = {\n surface: {\n variable: \"--fancy-surface\",\n darkVariable: \"--fancy-surface-dark\",\n light: \"var(--color-white)\",\n dark: \"var(--color-zinc-900)\",\n description: \"Panels, cards, overlays (menus, modals, popovers, toasts), sidebars and navbars.\",\n },\n \"surface-muted\": {\n variable: \"--fancy-surface-muted\",\n darkVariable: \"--fancy-surface-muted-dark\",\n light: \"var(--color-zinc-100)\",\n dark: \"var(--color-zinc-800)\",\n description: \"Hovered and selected rows, chips, inset wells, toolbar buttons.\",\n },\n border: {\n variable: \"--fancy-border\",\n darkVariable: \"--fancy-border-dark\",\n light: \"var(--color-zinc-200)\",\n dark: \"var(--color-zinc-700)\",\n description: \"Outlines, dividers, separators and tracks (skeletons, progress, sliders).\",\n },\n \"border-strong\": {\n variable: \"--fancy-border-strong\",\n darkVariable: \"--fancy-border-strong-dark\",\n light: \"var(--color-zinc-300)\",\n dark: \"var(--color-zinc-700)\",\n description: \"The firmer outline on form controls (inputs, checkboxes, radios) and keycaps.\",\n },\n input: {\n variable: \"--fancy-input\",\n darkVariable: \"--fancy-input-dark\",\n light: \"var(--color-white)\",\n dark: \"#1e1e24\",\n description: \"The field surface of text inputs, checkboxes, radios, OTP cells and pickers.\",\n },\n text: {\n variable: \"--fancy-text\",\n darkVariable: \"--fancy-text-dark\",\n light: \"var(--color-zinc-900)\",\n dark: \"var(--color-zinc-100)\",\n description: \"Strongest foreground: headings, values, field text, active items.\",\n },\n \"text-soft\": {\n variable: \"--fancy-text-soft\",\n darkVariable: \"--fancy-text-soft-dark\",\n light: \"var(--color-zinc-700)\",\n dark: \"var(--color-zinc-300)\",\n description: \"Body copy and menu items: readable, one step back from text.\",\n },\n \"text-muted\": {\n variable: \"--fancy-text-muted\",\n darkVariable: \"--fancy-text-muted-dark\",\n light: \"var(--color-zinc-500)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Descriptions, captions, secondary labels, axis labels.\",\n },\n \"text-faint\": {\n variable: \"--fancy-text-faint\",\n darkVariable: \"--fancy-text-faint-dark\",\n light: \"var(--color-zinc-400)\",\n dark: \"var(--color-zinc-500)\",\n description: \"Placeholders, disabled hints, decorative icons.\",\n },\n \"text-subtle\": {\n variable: \"--fancy-text-subtle\",\n darkVariable: \"--fancy-text-subtle-dark\",\n light: \"var(--color-zinc-600)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Inactive nav labels (Sidebar, Menu, Navbar, MultiSwitch) and secondary prose. Added 5.53.1.\",\n },\n \"surface-hover\": {\n variable: \"--fancy-surface-hover\",\n darkVariable: \"--fancy-surface-hover-dark\",\n light: \"var(--color-zinc-50)\",\n // Tailwind's `bg-zinc-800/50`, written out so a host's value is used as-is.\n dark: \"color-mix(in oklab, var(--color-zinc-800) 50%, transparent)\",\n description: \"The hover fill on nav items, list options and table rows. Added 5.53.1.\",\n },\n focus: {\n variable: \"--fancy-focus\",\n darkVariable: \"--fancy-focus-dark\",\n light: \"var(--color-blue-500)\",\n dark: \"var(--color-blue-400)\",\n description: \"The focus border and ring on form controls.\",\n },\n} as const;\n\nexport type ThemeTokenRole = keyof typeof THEME_TOKENS;\n"]}
1
+ {"version":3,"sources":["../src/theme-tokens.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Semantic theme tokens — the small set of colours the kit's DOM components\n * read, so a host can repaint the whole kit with its own palette WITHOUT\n * remapping Tailwind's `zinc` or `violet`.\n *\n * Each role is two CSS custom properties, one per mode:\n *\n * --fancy-surface the light value\n * --fancy-surface-dark the dark value\n *\n * Components read them through their var() FALLBACK, which is the colour the\n * component used before these existed:\n *\n * bg-[color:var(--fancy-surface,var(--color-white))]\n * dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\n *\n * So:\n * - **Set nothing and nothing changes.** An unset custom property resolves to\n * its fallback, which is the exact declaration the old `bg-white` produced.\n * - **Set one and every surface follows**, wherever the variable is in scope:\n * `:root`, `body`, or any wrapper element. No selector to match, no layer or\n * specificity to win — a custom property is inherited, not cascaded against.\n * - **Both modes are stated, not derived.** The dark value is a separate\n * variable rather than a flip under `.dark`, so which one applies is decided\n * by the host's own `dark:` variant — the same switch that drives every\n * other `dark:` utility in the kit. (See `dark-variant.css` for a variant\n * that follows `[data-theme=\"dark\"]` as well as `.dark`.)\n *\n * NOT covered, deliberately: colours that ENCODE DATA — chart series,\n * file-type marks, mood and confidence scales, event kinds. Repainting those\n * with a host's neutral palette would erase what they mean. A component's\n * explicit `color` prop (Badge, Button, Callout …) is also untouched: that is\n * the host choosing a hue, not the kit choosing one for it.\n *\n * `light` / `dark` are the defaults exactly as components write them in their\n * fallbacks. `tests/theme-tokens.test.tsx` fails if a component's fallback\n * disagrees with this table, so the table is the contract rather than a\n * description of it.\n */\nexport const THEME_TOKENS = {\n surface: {\n variable: \"--fancy-surface\",\n darkVariable: \"--fancy-surface-dark\",\n light: \"var(--color-white)\",\n dark: \"var(--color-zinc-900)\",\n description: \"Panels, cards, overlays (menus, modals, popovers, toasts), sidebars and navbars.\",\n },\n \"surface-muted\": {\n variable: \"--fancy-surface-muted\",\n darkVariable: \"--fancy-surface-muted-dark\",\n light: \"var(--color-zinc-100)\",\n dark: \"var(--color-zinc-800)\",\n description: \"Hovered and selected rows, chips, inset wells, toolbar buttons.\",\n },\n border: {\n variable: \"--fancy-border\",\n darkVariable: \"--fancy-border-dark\",\n light: \"var(--color-zinc-200)\",\n dark: \"var(--color-zinc-700)\",\n description: \"Outlines, dividers, separators and tracks (skeletons, progress, sliders).\",\n },\n \"border-strong\": {\n variable: \"--fancy-border-strong\",\n darkVariable: \"--fancy-border-strong-dark\",\n light: \"var(--color-zinc-300)\",\n dark: \"var(--color-zinc-700)\",\n description: \"The firmer outline on form controls (inputs, checkboxes, radios) and keycaps.\",\n },\n input: {\n variable: \"--fancy-input\",\n darkVariable: \"--fancy-input-dark\",\n light: \"var(--color-white)\",\n dark: \"#1e1e24\",\n description: \"The field surface of text inputs, checkboxes, radios, OTP cells and pickers.\",\n },\n text: {\n variable: \"--fancy-text\",\n darkVariable: \"--fancy-text-dark\",\n light: \"var(--color-zinc-900)\",\n dark: \"var(--color-zinc-100)\",\n description: \"Strongest foreground: headings, values, field text, active items.\",\n },\n \"text-soft\": {\n variable: \"--fancy-text-soft\",\n darkVariable: \"--fancy-text-soft-dark\",\n light: \"var(--color-zinc-700)\",\n dark: \"var(--color-zinc-300)\",\n description: \"Body copy and menu items: readable, one step back from text.\",\n },\n \"text-muted\": {\n variable: \"--fancy-text-muted\",\n darkVariable: \"--fancy-text-muted-dark\",\n light: \"var(--color-zinc-500)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Descriptions, captions, secondary labels, axis labels.\",\n },\n \"text-faint\": {\n variable: \"--fancy-text-faint\",\n darkVariable: \"--fancy-text-faint-dark\",\n light: \"var(--color-zinc-400)\",\n dark: \"var(--color-zinc-500)\",\n description: \"Placeholders, disabled hints, decorative icons.\",\n },\n \"text-subtle\": {\n variable: \"--fancy-text-subtle\",\n darkVariable: \"--fancy-text-subtle-dark\",\n light: \"var(--color-zinc-600)\",\n dark: \"var(--color-zinc-400)\",\n description: \"Inactive nav labels (Sidebar, Menu, Navbar, MultiSwitch) and secondary prose. Added 5.53.1.\",\n },\n \"surface-hover\": {\n variable: \"--fancy-surface-hover\",\n darkVariable: \"--fancy-surface-hover-dark\",\n light: \"var(--color-zinc-50)\",\n // Tailwind's `bg-zinc-800/50`, written out so a host's value is used as-is.\n dark: \"color-mix(in oklab, var(--color-zinc-800) 50%, transparent)\",\n description: \"The hover fill on nav items, list options and table rows. Added 5.53.1.\",\n },\n focus: {\n variable: \"--fancy-focus\",\n darkVariable: \"--fancy-focus-dark\",\n light: \"var(--color-blue-500)\",\n dark: \"var(--color-blue-400)\",\n description: \"The focus border and ring on form controls.\",\n },\n} as const;\n\nexport type ThemeTokenRole = keyof typeof THEME_TOKENS;\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk7HXFEYOV_cjs = require('./chunk-7HXFEYOV.cjs');
3
+ var chunkU5LKNGHU_cjs = require('./chunk-U5LKNGHU.cjs');
4
4
  require('./chunk-2O5UXH5R.cjs');
5
5
  require('./chunk-TLRFXSPA.cjs');
6
6
  require('./chunk-6CAXLP7D.cjs');
@@ -22,8 +22,7 @@ require('./chunk-TI7D4QDM.cjs');
22
22
  require('./chunk-MOU6O324.cjs');
23
23
  require('./chunk-57FQGQJK.cjs');
24
24
  require('./chunk-OUYC6EIL.cjs');
25
- require('./chunk-C5YX5XVL.cjs');
26
- require('./chunk-X2FC7ODX.cjs');
25
+ require('./chunk-3U7PUZLI.cjs');
27
26
  require('./chunk-XCZZVRBY.cjs');
28
27
  require('./chunk-MXWR3T3N.cjs');
29
28
  require('./chunk-LCNHEYIM.cjs');
@@ -34,47 +33,47 @@ require('./chunk-ZU5Q77OT.cjs');
34
33
 
35
34
  Object.defineProperty(exports, "JsonEditor", {
36
35
  enumerable: true,
37
- get: function () { return chunk7HXFEYOV_cjs.JsonEditor; }
36
+ get: function () { return chunkU5LKNGHU_cjs.JsonEditor; }
38
37
  });
39
38
  Object.defineProperty(exports, "applyJsonEdit", {
40
39
  enumerable: true,
41
- get: function () { return chunk7HXFEYOV_cjs.applyJsonEdit; }
40
+ get: function () { return chunkU5LKNGHU_cjs.applyJsonEdit; }
42
41
  });
43
42
  Object.defineProperty(exports, "describeEdit", {
44
43
  enumerable: true,
45
- get: function () { return chunk7HXFEYOV_cjs.describeEdit; }
44
+ get: function () { return chunkU5LKNGHU_cjs.describeEdit; }
46
45
  });
47
46
  Object.defineProperty(exports, "findJsonConflicts", {
48
47
  enumerable: true,
49
- get: function () { return chunk7HXFEYOV_cjs.findJsonConflicts; }
48
+ get: function () { return chunkU5LKNGHU_cjs.findJsonConflicts; }
50
49
  });
51
50
  Object.defineProperty(exports, "getAtPath", {
52
51
  enumerable: true,
53
- get: function () { return chunk7HXFEYOV_cjs.getAtPath; }
52
+ get: function () { return chunkU5LKNGHU_cjs.getAtPath; }
54
53
  });
55
54
  Object.defineProperty(exports, "inferType", {
56
55
  enumerable: true,
57
- get: function () { return chunk7HXFEYOV_cjs.inferType; }
56
+ get: function () { return chunkU5LKNGHU_cjs.inferType; }
58
57
  });
59
58
  Object.defineProperty(exports, "parseKeyMap", {
60
59
  enumerable: true,
61
- get: function () { return chunk7HXFEYOV_cjs.parseKeyMap; }
60
+ get: function () { return chunkU5LKNGHU_cjs.parseKeyMap; }
62
61
  });
63
62
  Object.defineProperty(exports, "parsePath", {
64
63
  enumerable: true,
65
- get: function () { return chunk7HXFEYOV_cjs.parsePath; }
64
+ get: function () { return chunkU5LKNGHU_cjs.parsePath; }
66
65
  });
67
66
  Object.defineProperty(exports, "pathToString", {
68
67
  enumerable: true,
69
- get: function () { return chunk7HXFEYOV_cjs.pathToString; }
68
+ get: function () { return chunkU5LKNGHU_cjs.pathToString; }
70
69
  });
71
70
  Object.defineProperty(exports, "resolveKeyRule", {
72
71
  enumerable: true,
73
- get: function () { return chunk7HXFEYOV_cjs.resolveKeyRule; }
72
+ get: function () { return chunkU5LKNGHU_cjs.resolveKeyRule; }
74
73
  });
75
74
  Object.defineProperty(exports, "typeMatches", {
76
75
  enumerable: true,
77
- get: function () { return chunk7HXFEYOV_cjs.typeMatches; }
76
+ get: function () { return chunkU5LKNGHU_cjs.typeMatches; }
78
77
  });
79
78
  //# sourceMappingURL=json-editor.cjs.map
80
79
  //# sourceMappingURL=json-editor.cjs.map
@@ -1,4 +1,4 @@
1
- export { JsonEditor, applyJsonEdit, describeEdit, findJsonConflicts, getAtPath, inferType, parseKeyMap, parsePath, pathToString, resolveKeyRule, typeMatches } from './chunk-4EUDW2WU.js';
1
+ export { JsonEditor, applyJsonEdit, describeEdit, findJsonConflicts, getAtPath, inferType, parseKeyMap, parsePath, pathToString, resolveKeyRule, typeMatches } from './chunk-DCAD2JPP.js';
2
2
  import './chunk-DXZCKDYS.js';
3
3
  import './chunk-2UTN3EFK.js';
4
4
  import './chunk-B4LVQ4QI.js';
@@ -20,8 +20,7 @@ import './chunk-RBCMKPBX.js';
20
20
  import './chunk-6FCQD2KQ.js';
21
21
  import './chunk-RGANGU7X.js';
22
22
  import './chunk-YX6FTJ6N.js';
23
- import './chunk-TLRRMYNV.js';
24
- import './chunk-6TBRBN7H.js';
23
+ import './chunk-OXERDFFF.js';
25
24
  import './chunk-45BBNJQD.js';
26
25
  import './chunk-J3A4Z2P7.js';
27
26
  import './chunk-ZXZJYVWP.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkUM4JXBRZ_cjs = require('./chunk-UM4JXBRZ.cjs');
3
+ var chunkS3NB6LDV_cjs = require('./chunk-S3NB6LDV.cjs');
4
4
  require('./chunk-MAZEX4EZ.cjs');
5
5
  require('./chunk-MRZXTL46.cjs');
6
6
  require('./chunk-P53432AK.cjs');
@@ -13,8 +13,7 @@ require('./chunk-TI7D4QDM.cjs');
13
13
  require('./chunk-VBWRH4UW.cjs');
14
14
  require('./chunk-MOU6O324.cjs');
15
15
  require('./chunk-M5MUGSON.cjs');
16
- require('./chunk-C5YX5XVL.cjs');
17
- require('./chunk-X2FC7ODX.cjs');
16
+ require('./chunk-3U7PUZLI.cjs');
18
17
  require('./chunk-XCZZVRBY.cjs');
19
18
  require('./chunk-MXWR3T3N.cjs');
20
19
  require('./chunk-ZU5Q77OT.cjs');
@@ -23,7 +22,7 @@ require('./chunk-ZU5Q77OT.cjs');
23
22
 
24
23
  Object.defineProperty(exports, "MagicWand", {
25
24
  enumerable: true,
26
- get: function () { return chunkUM4JXBRZ_cjs.MagicWand; }
25
+ get: function () { return chunkS3NB6LDV_cjs.MagicWand; }
27
26
  });
28
27
  //# sourceMappingURL=magic-wand.cjs.map
29
28
  //# sourceMappingURL=magic-wand.cjs.map
@@ -1,4 +1,4 @@
1
- export { MagicWand } from './chunk-M52S3TFI.js';
1
+ export { MagicWand } from './chunk-WFR7HKJL.js';
2
2
  import './chunk-UVUBV4VZ.js';
3
3
  import './chunk-KXYMMNNV.js';
4
4
  import './chunk-WX5XYDVN.js';
@@ -11,8 +11,7 @@ import './chunk-RBCMKPBX.js';
11
11
  import './chunk-IQ4KQJAO.js';
12
12
  import './chunk-6FCQD2KQ.js';
13
13
  import './chunk-LQ4ICCN2.js';
14
- import './chunk-TLRRMYNV.js';
15
- import './chunk-6TBRBN7H.js';
14
+ import './chunk-OXERDFFF.js';
16
15
  import './chunk-45BBNJQD.js';
17
16
  import './chunk-J3A4Z2P7.js';
18
17
  import './chunk-MMW2JGKZ.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkMCQWTOTV_cjs = require('./chunk-MCQWTOTV.cjs');
3
+ var chunkSAG6DHQK_cjs = require('./chunk-SAG6DHQK.cjs');
4
4
  require('./chunk-OASSZI6M.cjs');
5
5
  require('./chunk-I27K6NLX.cjs');
6
6
  require('./chunk-AIA5UNQ5.cjs');
@@ -12,8 +12,7 @@ require('./chunk-TI7D4QDM.cjs');
12
12
  require('./chunk-57FQGQJK.cjs');
13
13
  require('./chunk-OUYC6EIL.cjs');
14
14
  require('./chunk-M5MUGSON.cjs');
15
- require('./chunk-C5YX5XVL.cjs');
16
- require('./chunk-X2FC7ODX.cjs');
15
+ require('./chunk-3U7PUZLI.cjs');
17
16
  require('./chunk-XCZZVRBY.cjs');
18
17
  require('./chunk-MXWR3T3N.cjs');
19
18
  require('./chunk-SNHU2AI4.cjs');
@@ -23,15 +22,15 @@ require('./chunk-ZU5Q77OT.cjs');
23
22
 
24
23
  Object.defineProperty(exports, "PromptInput", {
25
24
  enumerable: true,
26
- get: function () { return chunkMCQWTOTV_cjs.PromptInput; }
25
+ get: function () { return chunkSAG6DHQK_cjs.PromptInput; }
27
26
  });
28
27
  Object.defineProperty(exports, "promptDataUrlToFile", {
29
28
  enumerable: true,
30
- get: function () { return chunkMCQWTOTV_cjs.promptDataUrlToFile; }
29
+ get: function () { return chunkSAG6DHQK_cjs.promptDataUrlToFile; }
31
30
  });
32
31
  Object.defineProperty(exports, "promptFileToDataUrl", {
33
32
  enumerable: true,
34
- get: function () { return chunkMCQWTOTV_cjs.promptFileToDataUrl; }
33
+ get: function () { return chunkSAG6DHQK_cjs.promptFileToDataUrl; }
35
34
  });
36
35
  //# sourceMappingURL=prompt-input.cjs.map
37
36
  //# sourceMappingURL=prompt-input.cjs.map
@@ -1,4 +1,4 @@
1
- export { PromptInput, promptDataUrlToFile, promptFileToDataUrl } from './chunk-J44EV6SP.js';
1
+ export { PromptInput, promptDataUrlToFile, promptFileToDataUrl } from './chunk-23AVEYUP.js';
2
2
  import './chunk-GR2WKBER.js';
3
3
  import './chunk-SV5BW3IA.js';
4
4
  import './chunk-TJ66S5K6.js';
@@ -10,8 +10,7 @@ import './chunk-RBCMKPBX.js';
10
10
  import './chunk-RGANGU7X.js';
11
11
  import './chunk-YX6FTJ6N.js';
12
12
  import './chunk-LQ4ICCN2.js';
13
- import './chunk-TLRRMYNV.js';
14
- import './chunk-6TBRBN7H.js';
13
+ import './chunk-OXERDFFF.js';
15
14
  import './chunk-45BBNJQD.js';
16
15
  import './chunk-J3A4Z2P7.js';
17
16
  import './chunk-EDYAXGUM.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSYEHWUM5_cjs = require('./chunk-SYEHWUM5.cjs');
3
+ var chunkRALJMI7C_cjs = require('./chunk-RALJMI7C.cjs');
4
4
  require('./chunk-MKGWHSNV.cjs');
5
5
  require('./chunk-J2DI6RMR.cjs');
6
6
  require('./chunk-MKHYENKR.cjs');
@@ -8,8 +8,7 @@ require('./chunk-TI7D4QDM.cjs');
8
8
  require('./chunk-57FQGQJK.cjs');
9
9
  require('./chunk-OUYC6EIL.cjs');
10
10
  require('./chunk-M5MUGSON.cjs');
11
- require('./chunk-C5YX5XVL.cjs');
12
- require('./chunk-X2FC7ODX.cjs');
11
+ require('./chunk-3U7PUZLI.cjs');
13
12
  require('./chunk-XCZZVRBY.cjs');
14
13
  require('./chunk-MXWR3T3N.cjs');
15
14
  require('./chunk-ZU5Q77OT.cjs');
@@ -18,7 +17,7 @@ require('./chunk-ZU5Q77OT.cjs');
18
17
 
19
18
  Object.defineProperty(exports, "ReasonTag", {
20
19
  enumerable: true,
21
- get: function () { return chunkSYEHWUM5_cjs.ReasonTag; }
20
+ get: function () { return chunkRALJMI7C_cjs.ReasonTag; }
22
21
  });
23
22
  //# sourceMappingURL=reason-tag.cjs.map
24
23
  //# sourceMappingURL=reason-tag.cjs.map
@@ -1,4 +1,4 @@
1
- export { ReasonTag } from './chunk-QP35Z2WB.js';
1
+ export { ReasonTag } from './chunk-BL5IKSB3.js';
2
2
  import './chunk-QTS4Q2NK.js';
3
3
  import './chunk-MQ6VGG62.js';
4
4
  import './chunk-5VMILVWD.js';
@@ -6,8 +6,7 @@ import './chunk-RBCMKPBX.js';
6
6
  import './chunk-RGANGU7X.js';
7
7
  import './chunk-YX6FTJ6N.js';
8
8
  import './chunk-LQ4ICCN2.js';
9
- import './chunk-TLRRMYNV.js';
10
- import './chunk-6TBRBN7H.js';
9
+ import './chunk-OXERDFFF.js';
11
10
  import './chunk-45BBNJQD.js';
12
11
  import './chunk-J3A4Z2P7.js';
13
12
  import './chunk-MMW2JGKZ.js';
@@ -24,6 +24,143 @@ import { ContentRenderer } from "@particle-academy/react-fancy";
24
24
  | extensions | `RenderExtension[]` | - | Per-instance render extensions (merged with global) |
25
25
  | className | `string` | - | Additional CSS classes |
26
26
  | unsafe | `boolean` | `false` | Skip HTML sanitization. See **Sanitization** below. |
27
+ | copyButtons | `boolean \| { code?: boolean; table?: boolean }` | `true` | Copy buttons on code blocks and tables. See **Copy buttons**. |
28
+ | onCopy | `(event: ContentCopyEvent) => void` | - | Called after every copy attempt, successful or not |
29
+ | clipboardWriter | `ContentClipboardWriter` | - | Host-supplied clipboard writer. See **Clipboard writer**. |
30
+ | streaming | `boolean \| "progressive"` | `false` | The value is still arriving. `true` holds back an unfinished trailing tag or fence; `"progressive"` shows it as it fills. See **Streaming**. |
31
+
32
+ ## Copy buttons
33
+
34
+ Every code block and table gets a react-fancy `Button` (icon `copy`, then
35
+ `check` for two seconds after a copy, `x` after a failure). What is copied:
36
+
37
+ - **Code**: exactly the code between the fences. No language label, no
38
+ trailing newline added. (Marked itself drops trailing blank lines inside a
39
+ fence, so they are not in the copy either; indentation, inner blank lines and
40
+ characters like `<` and `&` are.)
41
+ - **Table**: TSV. A tab between cells, a newline between rows, no trailing
42
+ newline. Tabs and line breaks inside a cell become spaces, so the shape
43
+ survives a paste into a spreadsheet.
44
+
45
+ Each copy is announced as `Copied` or `Copy failed` through a polite
46
+ `aria-live` region (`[data-react-fancy-content-renderer-live]`).
47
+
48
+ ```tsx
49
+ <ContentRenderer value={reply} copyButtons={false} /> // none
50
+ <ContentRenderer value={reply} copyButtons={{ table: false }} /> // code only
51
+ ```
52
+
53
+ The button sits beside the block, never inside it, so its own text never ends
54
+ up in the copy. Buttons are added after mount, so server-rendered HTML has none
55
+ until hydration.
56
+
57
+ ### Clipboard writer
58
+
59
+ The default writer puts **text/html and text/plain** on the clipboard with a
60
+ `ClipboardItem`, so a table pastes as a table into a rich editor and as cells
61
+ into a spreadsheet. If `ClipboardItem` is missing or that write is refused, it
62
+ falls back to `navigator.clipboard.writeText`.
63
+
64
+ `navigator.clipboard` can fail silently in some hosts (Genie found it does in a
65
+ sandboxed Electron window). Pass your own writer there:
66
+
67
+ ```tsx
68
+ import { clipboard } from "electron";
69
+
70
+ <ContentRenderer
71
+ value={reply}
72
+ clipboardWriter={({ text, html }) => clipboard.write({ text, html })}
73
+ />
74
+ ```
75
+
76
+ A writer receives `{ kind, text, html }`. **Throwing, rejecting, or returning
77
+ `false` means the copy failed**, and so does a write that has not settled after
78
+ 5 seconds. A failure is never silent: the button shows `x`, the live region says
79
+ `Copy failed`, and `onCopy` reports `ok: false`.
80
+
81
+ ### Observing copies (Human+)
82
+
83
+ ContentRenderer is a read-only surface: it exposes stable DOM handles rather
84
+ than state. Copy follows that:
85
+
86
+ | Handle | On |
87
+ |--------|----|
88
+ | `data-react-fancy-content-copy="code" \| "table"` | the copy button |
89
+ | `data-copy-state="idle" \| "copied" \| "failed"` | the copy button |
90
+ | `data-react-fancy-content-copy-block="code" \| "table"` | the wrapper around the block |
91
+ | `data-react-fancy-content-renderer-live` | the live region |
92
+ | `data-streaming="true"` | the root, while `streaming` (either mode) |
93
+ | `data-streaming-mode="progressive"` | the root, while `streaming="progressive"` |
94
+
95
+ `onCopy` receives `{ kind, index, text, html, ok }`, where `index` is the
96
+ button's position among this renderer's copy buttons in document order. Wire it
97
+ to your activity feed if agents should see copies.
98
+
99
+ ## Streaming
100
+
101
+ While a reply is still arriving, pass `streaming`:
102
+
103
+ ```tsx
104
+ <ContentRenderer value={partial} streaming={!done} extensions={[resultTag]} />
105
+ ```
106
+
107
+ Held back until it is complete:
108
+
109
+ - an opened tag of a **registered extension** with no closing tag yet, from its
110
+ opening tag onwards (`<result>` + half a body, or `<result>body</res`);
111
+ - a partial tag at the very end that could still become one: `<`, `</`,
112
+ `<res`, `<result title="Do`;
113
+ - an open code fence, from its fence line, and a fence marker still arriving
114
+ (` `` `).
115
+
116
+ A `<` that cannot become a registered tag is prose and always renders
117
+ (`a < b`, `a<b`, `3 <= 4`), as do unknown tags and anything in inline code.
118
+ A lone `<` at the very end is held for one chunk, because it may be the start of
119
+ a tag. When `streaming` goes back to `false`, everything renders.
120
+
121
+ ### Progressive streaming
122
+
123
+ `streaming={true}` hides an open block until it closes. Pass
124
+ `streaming="progressive"` to show it as it fills instead:
125
+
126
+ ```tsx
127
+ <ContentRenderer
128
+ value={partial}
129
+ streaming={done ? false : "progressive"}
130
+ extensions={[resultTag]}
131
+ />
132
+ ```
133
+
134
+ - An open tag of a registered extension whose **opening tag is complete**
135
+ renders its component straight away, with the body that has arrived so far.
136
+ A `markdown` extension gets that body as `content` and rendered as
137
+ `children`, through the same pipeline as the final render: converted,
138
+ sanitised, nested extensions, copy buttons on finished blocks.
139
+ - An open code fence renders as a code block of what has arrived, in its
140
+ language. It gets **no copy button until it closes**; copying half a block
141
+ is never what anyone means, and a disabled button would still invite the
142
+ click. Finished code blocks and tables before it keep theirs.
143
+ - Still held back, exactly as in `streaming={true}`: a **partial opening tag**
144
+ (`<`, `<res`, `<result title="Do`), so it never flashes raw; a partial
145
+ closing tag (`</res`), with the body above it still showing; a fence marker
146
+ still arriving (` `` `). Also held: a fence opener line with no newline yet
147
+ (` ```ja `), because its language may be cut off.
148
+ - Inside an open fence, `<` is code and is never held.
149
+
150
+ It works by closing what is open: the open fence gets its own closing marker
151
+ and every open registered tag gets its closing tag, innermost first, and the
152
+ result renders normally. So the rendered body is the same one the final render
153
+ produces once the real closing tags arrive; only what is still to come is
154
+ missing.
155
+
156
+ The lifting rules below do not change in this mode. A `markdown` tag whose
157
+ opening tag is mid-line is not lifted while streaming, any more than it is once
158
+ it closes: it is matched in the HTML, as the final render will match it.
159
+
160
+ **Why a value of `streaming` rather than a second prop:** progressive is a way
161
+ of streaming, not something separate, and a separate boolean would add a
162
+ combination that means nothing (progressive while not streaming). A host that
163
+ already writes `streaming={!done}` changes one expression.
27
164
 
28
165
  ## Sanitization
29
166
 
@@ -45,7 +182,7 @@ The helpers are also exported for use elsewhere:
45
182
  import { sanitizeHtml, sanitizeHref } from "@particle-academy/react-fancy";
46
183
  ```
47
184
 
48
- > **Render extensions still need to sanitize their own input.** The `content` prop passed to your extension component is the raw text inside the matched tag — treat it as untrusted and call `sanitizeHtml(content)` if you render it as HTML.
185
+ > **Render extensions still need to sanitize their own input.** The `content` prop passed to your extension component is the raw text inside the matched tag — treat it as untrusted and call `sanitizeHtml(content)` if you render it as HTML. A `markdown` extension gets an already-sanitised `children` instead; use that.
49
186
 
50
187
  ## Render Extensions
51
188
 
@@ -78,13 +215,65 @@ registerExtension({
78
215
  | tag | `string` | - | Tag name to match (case-insensitive) |
79
216
  | component | `ComponentType<RenderExtensionProps>` | - | React component to render the tag |
80
217
  | block | `boolean` | `true` | Block-level (`<div>`) vs inline (`<span>`) wrapping |
218
+ | markdown | `boolean` | `false` | The body is markdown. See **Tags with a markdown body**. |
81
219
 
82
220
  ### RenderExtensionProps
83
221
 
84
222
  | Prop | Type | Description |
85
223
  |------|------|-------------|
86
- | content | `string` | Inner content of the custom tag |
87
- | attributes | `Record<string, string>` | Parsed HTML attributes from the opening tag |
224
+ | content | `string` | Inner content of the custom tag. Raw markdown for a `markdown` extension in markdown content. Untrusted. |
225
+ | attributes | `Record<string, string>` | Parsed attributes from the opening tag, with `on*`, `srcdoc` and unsafe URLs removed |
226
+ | children | `ReactNode` | `markdown` extensions only: the body, rendered and sanitised |
227
+
228
+ ### Tags with a markdown body
229
+
230
+ Custom tags are normally found after the markdown has become HTML, and a
231
+ CommonMark HTML block keeps the markdown inside it as literal text, so
232
+ `<result>**done**</result>` would show its asterisks. Mark the extension
233
+ `markdown: true` and the tag is lifted out of the markdown **source** first:
234
+
235
+ ```tsx
236
+ const resultTag: RenderExtension = {
237
+ tag: "result",
238
+ markdown: true,
239
+ component: ({ attributes, children }) => (
240
+ <Card>
241
+ <Card.Header>{attributes.title}</Card.Header>
242
+ <Card.Body>{children}</Card.Body>
243
+ </Card>
244
+ ),
245
+ };
246
+
247
+ <ContentRenderer
248
+ value={'Here it is:\n\n<result title="Build">\n**Passed**, `12/12`\n\n- lint\n- test\n</result>'}
249
+ extensions={[resultTag]}
250
+ />
251
+ ```
252
+
253
+ - `content` is the raw markdown body; `children` is that body rendered through
254
+ the same pipeline as everything else: sanitised, with nested extensions and
255
+ copy buttons. **Render `children`, not `content`.**
256
+ - A tag is lifted **only** when its opening tag starts a line (after at most
257
+ three spaces) **and** it has a matching closing tag. Same-name nesting is
258
+ balanced, other markdown tags nest inside it, and a tag inside a code fence
259
+ or inline code is left alone.
260
+ - Anywhere else (mid-line, unclosed, or in HTML content) it is matched in the
261
+ HTML as before, and `children` renders that HTML body.
262
+ - **Both conditions are deliberate and will stay.** A tag that starts a line
263
+ and closes is an unambiguous block. A mid-line `<result>` is text that
264
+ happens to contain a tag name, and an unclosed one has no end to its body, so
265
+ lifting either would turn prose (or a model quoting the tag) into a
266
+ component. To get a block, put the opening tag on its own line and close it.
267
+ `streaming="progressive"` renders an open block early, but it does so by
268
+ supplying the close the final render will see; it does not relax either
269
+ rule.
270
+ - Nesting stops at depth 8: deeper bodies render as plain sanitised content.
271
+
272
+ Sanitisation is unchanged by lifting. Every piece of markdown, including each
273
+ body, is converted and then run through `sanitizeHtml` before it is injected,
274
+ and the tag's attributes lose `on*`, `srcdoc` and unsafe URLs before the
275
+ component sees them. Unknown tags stay in the markdown and are sanitised like
276
+ any HTML. `unsafe` turns all of this off, as it always has.
88
277
 
89
278
  ## Markdown Rendering
90
279