@hex-core/components 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/_tsup-dts-rollup.d.ts +1566 -5
  2. package/dist/arc.d.ts +4 -0
  3. package/dist/arc.js +147 -0
  4. package/dist/arc.js.map +1 -0
  5. package/dist/audio-player.d.ts +2 -0
  6. package/dist/audio-player.js +119 -0
  7. package/dist/audio-player.js.map +1 -0
  8. package/dist/audio-waveform.d.ts +2 -0
  9. package/dist/audio-waveform.js +72 -0
  10. package/dist/audio-waveform.js.map +1 -0
  11. package/dist/canvas.d.ts +2 -0
  12. package/dist/canvas.js +73 -0
  13. package/dist/canvas.js.map +1 -0
  14. package/dist/chord.d.ts +4 -0
  15. package/dist/chord.js +230 -0
  16. package/dist/chord.js.map +1 -0
  17. package/dist/cloze.d.ts +3 -0
  18. package/dist/cloze.js +98 -0
  19. package/dist/cloze.js.map +1 -0
  20. package/dist/color-picker.js.map +1 -1
  21. package/dist/compare-table.d.ts +4 -0
  22. package/dist/compare-table.js +109 -0
  23. package/dist/compare-table.js.map +1 -0
  24. package/dist/data-table.js.map +1 -1
  25. package/dist/deck.d.ts +3 -0
  26. package/dist/deck.js +231 -0
  27. package/dist/deck.js.map +1 -0
  28. package/dist/dendrogram.d.ts +3 -0
  29. package/dist/dendrogram.js +162 -0
  30. package/dist/dendrogram.js.map +1 -0
  31. package/dist/diagram.d.ts +2 -0
  32. package/dist/diagram.js +70 -0
  33. package/dist/diagram.js.map +1 -0
  34. package/dist/flashcard.d.ts +2 -0
  35. package/dist/flashcard.js +107 -0
  36. package/dist/flashcard.js.map +1 -0
  37. package/dist/flowchart.d.ts +4 -0
  38. package/dist/flowchart.js +275 -0
  39. package/dist/flowchart.js.map +1 -0
  40. package/dist/funnel.d.ts +3 -0
  41. package/dist/funnel.js +157 -0
  42. package/dist/funnel.js.map +1 -0
  43. package/dist/gantt.d.ts +3 -0
  44. package/dist/gantt.js +279 -0
  45. package/dist/gantt.js.map +1 -0
  46. package/dist/image-occlusion.d.ts +3 -0
  47. package/dist/image-occlusion.js +106 -0
  48. package/dist/image-occlusion.js.map +1 -0
  49. package/dist/index.d.ts +84 -0
  50. package/dist/index.js +3946 -2
  51. package/dist/index.js.map +1 -1
  52. package/dist/matrix.d.ts +3 -0
  53. package/dist/matrix.js +155 -0
  54. package/dist/matrix.js.map +1 -0
  55. package/dist/mind-map.d.ts +3 -0
  56. package/dist/mind-map.js +167 -0
  57. package/dist/mind-map.js.map +1 -0
  58. package/dist/org-chart.d.ts +3 -0
  59. package/dist/org-chart.js +215 -0
  60. package/dist/org-chart.js.map +1 -0
  61. package/dist/pyramid.d.ts +3 -0
  62. package/dist/pyramid.js +150 -0
  63. package/dist/pyramid.js.map +1 -0
  64. package/dist/quiz.d.ts +3 -0
  65. package/dist/quiz.js +128 -0
  66. package/dist/quiz.js.map +1 -0
  67. package/dist/sankey.d.ts +4 -0
  68. package/dist/sankey.js +190 -0
  69. package/dist/sankey.js.map +1 -0
  70. package/dist/schemas.d.ts +23 -0
  71. package/dist/schemas.js +2210 -3
  72. package/dist/schemas.js.map +1 -1
  73. package/dist/sequence.d.ts +4 -0
  74. package/dist/sequence.js +229 -0
  75. package/dist/sequence.js.map +1 -0
  76. package/dist/sonner.js.map +1 -1
  77. package/dist/spaced-repetition.d.ts +3 -0
  78. package/dist/spaced-repetition.js +73 -0
  79. package/dist/spaced-repetition.js.map +1 -0
  80. package/dist/sunburst.d.ts +3 -0
  81. package/dist/sunburst.js +205 -0
  82. package/dist/sunburst.js.map +1 -0
  83. package/dist/terminal.d.ts +2 -0
  84. package/dist/terminal.js +153 -0
  85. package/dist/terminal.js.map +1 -0
  86. package/dist/textarea.js.map +1 -1
  87. package/dist/time-axis.d.ts +3 -0
  88. package/dist/time-axis.js +233 -0
  89. package/dist/time-axis.js.map +1 -0
  90. package/dist/tool-call.js +6 -1
  91. package/dist/tool-call.js.map +1 -1
  92. package/dist/tree-map.d.ts +3 -0
  93. package/dist/tree-map.js +171 -0
  94. package/dist/tree-map.js.map +1 -0
  95. package/dist/venn.d.ts +3 -0
  96. package/dist/venn.js +196 -0
  97. package/dist/venn.js.map +1 -0
  98. package/package.json +49 -5
package/dist/schemas.js CHANGED
@@ -2984,7 +2984,7 @@ var tableSchema = {
2984
2984
  var dataTableSchema = {
2985
2985
  name: "data-table",
2986
2986
  displayName: "Data Table",
2987
- description: "Generic data-driven table built on TanStack Table + Hex UI Table primitives. Pass columns + data; add sorting/filtering/pagination via TanStack hooks.",
2987
+ description: "Generic data-driven table built on TanStack Table + Hex Core Table primitives. Pass columns + data; add sorting/filtering/pagination via TanStack hooks.",
2988
2988
  category: "component",
2989
2989
  subcategory: "data",
2990
2990
  props: [
@@ -3468,7 +3468,7 @@ var commandSchema = {
3468
3468
  "Giving CommandItem non-unique values (breaks filtering and controlled state)",
3469
3469
  "Overriding CommandInput className to remove the border/padding \u2014 breaks the \u2318K icon layout",
3470
3470
  "Not rendering CommandEmpty \u2014 the list looks broken when a search has no matches",
3471
- "Querying CommandSeparator via cmdk's internal Separator state \u2014 Hex UI renders it as a presentational div with role='none' (and the `data-cmdk-separator` attribute preserved for selector compatibility) so it can sit inside CommandList's role=listbox without violating ARIA"
3471
+ "Querying CommandSeparator via cmdk's internal Separator state \u2014 Hex Core renders it as a presentational div with role='none' (and the `data-cmdk-separator` attribute preserved for selector compatibility) so it can sit inside CommandList's role=listbox without violating ARIA"
3472
3472
  ],
3473
3473
  relatedComponents: ["combobox", "dialog", "dropdown-menu"],
3474
3474
  accessibilityNotes: "cmdk wires role=listbox/option and aria-activedescendant. Use the `label` prop on Command for a screen-reader-only name when no visible heading exists. CommandSeparator renders with role='none' (still selectable via `[data-cmdk-separator]`) so listbox-children rules are satisfied.",
@@ -6286,6 +6286,2213 @@ var codeBlockSchema = {
6286
6286
  tags: ["ai", "code", "shiki", "highlight", "copy", "rsc"]
6287
6287
  };
6288
6288
 
6289
- export { accordionSchema, alertDialogSchema, alertSchema, aspectRatioSchema, attachmentSchema, avatarSchema, badgeSchema, breadcrumbSchema, buttonSchema, calendarSchema, cardSchema, checkboxSchema, citationSchema, clusterSchema, codeBlockSchema, collapsibleSchema, colorPickerSchema, comboboxSchema, commandSchema, composerSchema, containerSchema, contextMenuSchema, dataTableSchema, datePickerSchema, dialogSchema, drawerSchema, dropdownMenuSchema, dropzoneSchema, emptySchema, errorStateSchema, fileTreeSchema, formSchema, gridSchema, hoverCardSchema, inputOTPSchema, inputSchema, labelSchema, loadingIndicatorSchema, loadingSchema, markdownSchema, menubarSchema, messageActionsSchema, messageListSchema, messageSchema, multiComboboxSchema, navigationMenuSchema, paginationSchema, popoverSchema, progressSchema, radioGroupSchema, reasoningSchema, resizableSchema, scrollAreaSchema, selectSchema, separatorSchema, sheetSchema, sidebarSchema, skeletonSchema, sliderSchema, sonnerSchema, spacerSchema, stackSchema, stepperSchema, suggestionSchema, switchSchema, tableSchema, tabsSchema, tagSchema, textareaSchema, timePickerSchema, timelineSchema, toggleGroupSchema, toggleSchema, toolCallSchema, toolbarSchema, tooltipSchema, treeSchema };
6289
+ // src/artifacts/mind-map/mind-map.schema.ts
6290
+ var mindMapSchema = {
6291
+ name: "mind-map",
6292
+ displayName: "MindMap",
6293
+ description: "Typed React mind map. Pass a hierarchical root node and the component lays children out radially (or horizontally) using d3-hierarchy's tree layout \u2014 no Mermaid string DSL required.",
6294
+ category: "artifact",
6295
+ subcategory: "hierarchy",
6296
+ props: [
6297
+ {
6298
+ name: "root",
6299
+ type: "object",
6300
+ required: true,
6301
+ description: "Hierarchy root: { id, label, children?, data? }. Children are laid out radially around the root."
6302
+ },
6303
+ {
6304
+ name: "orientation",
6305
+ type: "enum",
6306
+ required: false,
6307
+ default: "radial",
6308
+ description: 'Layout direction \u2014 "radial" (children orbit the root) or "horizontal" (left-to-right tree).',
6309
+ enumValues: ["radial", "horizontal"]
6310
+ },
6311
+ {
6312
+ name: "width",
6313
+ type: "number",
6314
+ required: false,
6315
+ default: 600,
6316
+ description: "SVG pixel width."
6317
+ },
6318
+ {
6319
+ name: "height",
6320
+ type: "number",
6321
+ required: false,
6322
+ default: 400,
6323
+ description: "SVG pixel height."
6324
+ },
6325
+ {
6326
+ name: "onNodeClick",
6327
+ type: "function",
6328
+ required: false,
6329
+ description: "Called with the clicked MindMapNode when a user clicks any node."
6330
+ },
6331
+ {
6332
+ name: "className",
6333
+ type: "string",
6334
+ required: false,
6335
+ description: "Additional CSS classes on the SVG element."
6336
+ }
6337
+ ],
6338
+ variants: [],
6339
+ slots: [],
6340
+ dependencies: {
6341
+ npm: ["clsx", "tailwind-merge"],
6342
+ internal: ["lib/utils"],
6343
+ peer: ["react", "react-dom"],
6344
+ heavyPeer: [
6345
+ {
6346
+ name: "d3-hierarchy",
6347
+ version: "^3.1.2",
6348
+ bundleKbGzip: 3,
6349
+ reason: "Computes the radial / horizontal tree layout; the component renders SVG with the result"
6350
+ }
6351
+ ]
6352
+ },
6353
+ tokensUsed: ["primary", "background", "foreground", "muted"],
6354
+ examples: [
6355
+ {
6356
+ title: "Radial mind map",
6357
+ description: "Default radial layout with three branches.",
6358
+ code: '<MindMap root={{\n id: "root",\n label: "Project",\n children: [\n { id: "ui", label: "UI", children: [{ id: "btn", label: "Button" }] },\n { id: "api", label: "API" },\n { id: "db", label: "DB" },\n ],\n}} />',
6359
+ composition: ["mind-map", "hierarchy", "radial"]
6360
+ },
6361
+ {
6362
+ title: "Horizontal mind map with click handler",
6363
+ description: "Left-to-right tree useful for sidebars and detail panes.",
6364
+ code: '<MindMap orientation="horizontal" onNodeClick={(n) => select(n.id)} root={data} />',
6365
+ composition: ["mind-map", "horizontal", "interactive"]
6366
+ }
6367
+ ],
6368
+ ai: {
6369
+ whenToUse: "Visualize a typed hierarchy when you have structured data (not a Mermaid string) \u2014 concept maps, knowledge graphs, project decompositions, agent plan trees. Use radial when the root is conceptually central; horizontal when the hierarchy is left-to-right (file trees, decision trees).",
6370
+ whenNotToUse: "Don't use for free-form node graphs with arbitrary edges (use Canvas with reactflow). Don't use to render Mermaid markdown from agents (use Diagram). Don't use for hierarchies sized by value (use TreeMap or Sunburst).",
6371
+ commonMistakes: [
6372
+ "Passing an unmemoized `root` object on every render \u2014 the layout pass re-runs and node positions thrash. Memoize",
6373
+ "Sizing the SVG to 0 (no explicit width/height and no parent layout) \u2014 the layout returns degenerate coordinates",
6374
+ "Mutating the root hierarchy in place between renders \u2014 d3-hierarchy mutates its own internal tree, but the input object should be treated as immutable"
6375
+ ],
6376
+ relatedComponents: ["tree-map", "org-chart", "sunburst", "dendrogram", "canvas", "diagram"],
6377
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing the node count and root label. For agent outputs, also expose a parallel text representation (a nested <ul> of node labels in a <details>) so screen-reader users get the structure.',
6378
+ tokenBudget: 320
6379
+ },
6380
+ tags: ["artifact", "diagram", "mind-map", "hierarchy", "tree", "radial"]
6381
+ };
6382
+
6383
+ // src/artifacts/tree-map/tree-map.schema.ts
6384
+ var treeMapSchema = {
6385
+ name: "tree-map",
6386
+ displayName: "TreeMap",
6387
+ description: "Nested rectangles sized by value \u2014 each leaf's area is proportional to its `value`. Squarified by default for legibility.",
6388
+ category: "artifact",
6389
+ subcategory: "hierarchy",
6390
+ props: [
6391
+ {
6392
+ name: "root",
6393
+ type: "object",
6394
+ required: true,
6395
+ description: "Hierarchy root: { id, label, value?, children? }. Leaves require a positive `value`; internal nodes are summed."
6396
+ },
6397
+ {
6398
+ name: "width",
6399
+ type: "number",
6400
+ required: false,
6401
+ default: 600,
6402
+ description: "SVG pixel width."
6403
+ },
6404
+ {
6405
+ name: "height",
6406
+ type: "number",
6407
+ required: false,
6408
+ default: 400,
6409
+ description: "SVG pixel height."
6410
+ },
6411
+ {
6412
+ name: "padding",
6413
+ type: "number",
6414
+ required: false,
6415
+ default: 2,
6416
+ description: "Inner padding between sibling rectangles, in pixels."
6417
+ },
6418
+ {
6419
+ name: "tile",
6420
+ type: "enum",
6421
+ required: false,
6422
+ default: "squarify",
6423
+ description: 'Tiling algorithm \u2014 "squarify" keeps rectangles close to square; "binary" is faster; "slice-dice" alternates direction by depth.',
6424
+ enumValues: ["squarify", "binary", "slice-dice"]
6425
+ },
6426
+ {
6427
+ name: "colorBy",
6428
+ type: "enum",
6429
+ required: false,
6430
+ default: "depth",
6431
+ description: 'Fill strategy \u2014 "depth" cycles palette tokens, "value" interpolates the primary token by value, or pass a (node, depth) => string.',
6432
+ enumValues: ["depth", "value"]
6433
+ },
6434
+ {
6435
+ name: "onLeafClick",
6436
+ type: "function",
6437
+ required: false,
6438
+ description: "Called with the clicked TreeMapNode when a user clicks any leaf."
6439
+ },
6440
+ {
6441
+ name: "className",
6442
+ type: "string",
6443
+ required: false,
6444
+ description: "Additional CSS classes on the SVG element."
6445
+ }
6446
+ ],
6447
+ variants: [],
6448
+ slots: [],
6449
+ dependencies: {
6450
+ npm: ["clsx", "tailwind-merge"],
6451
+ internal: ["lib/utils"],
6452
+ peer: ["react", "react-dom"],
6453
+ heavyPeer: [
6454
+ {
6455
+ name: "d3-hierarchy",
6456
+ version: "^3.1.2",
6457
+ bundleKbGzip: 3,
6458
+ reason: "Computes the squarified treemap layout; the component renders SVG rectangles with the result"
6459
+ }
6460
+ ]
6461
+ },
6462
+ tokensUsed: ["primary", "accent", "secondary", "muted", "background", "foreground"],
6463
+ examples: [
6464
+ {
6465
+ title: "File-size treemap",
6466
+ description: "Visualize the relative size of files in a folder.",
6467
+ code: '<TreeMap root={{\n id: "root", label: "src",\n children: [\n { id: "a", label: "app", value: 240 },\n { id: "l", label: "lib", value: 90 },\n { id: "t", label: "tests", value: 120 },\n ],\n}} />',
6468
+ composition: ["tree-map", "hierarchy", "value-scaled"]
6469
+ },
6470
+ {
6471
+ title: "Heatmap-style coloring by value",
6472
+ description: "Use the value-interpolated palette to highlight outliers.",
6473
+ code: '<TreeMap colorBy="value" root={budgetTree} />',
6474
+ composition: ["tree-map", "heatmap"]
6475
+ }
6476
+ ],
6477
+ ai: {
6478
+ whenToUse: 'Compare relative sizes inside a hierarchy \u2014 file sizes, budgets, market caps, allocations. Use when the user cares about "which slice of the whole is biggest" and the hierarchy is at most 2\u20133 levels deep.',
6479
+ whenNotToUse: "Don't use to show edges/relationships (use MindMap or Canvas). Don't use for time series (use a chart). Don't use when leaves all have similar values \u2014 area differences become invisible.",
6480
+ commonMistakes: [
6481
+ "Leaf values that don't sum to the parent \u2014 d3-hierarchy aggregates leaves; internal-node `value` props are ignored when children exist",
6482
+ "Negative or zero leaf values \u2014 produce zero-area rectangles or NaN positions. Filter or clamp upstream",
6483
+ "Passing the same root reference but mutating its children in place \u2014 React skips the re-layout. Provide a new root object on data change"
6484
+ ],
6485
+ relatedComponents: ["mind-map", "sunburst", "org-chart", "dendrogram", "diagram"],
6486
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing the leaf count and root label. For large or interactive treemaps, also expose a parallel <table> of label/value pairs for screen readers.',
6487
+ tokenBudget: 320
6488
+ },
6489
+ tags: ["artifact", "diagram", "tree-map", "hierarchy", "area", "squarify"]
6490
+ };
6491
+
6492
+ // src/artifacts/org-chart/org-chart.schema.ts
6493
+ var orgChartSchema = {
6494
+ name: "org-chart",
6495
+ displayName: "OrgChart",
6496
+ description: "Top-down organizational chart with collapsible subtrees. Each node renders as a rounded card showing label + subtitle; click any node with children to fold its subtree behind a +N badge.",
6497
+ category: "artifact",
6498
+ subcategory: "hierarchy",
6499
+ props: [
6500
+ {
6501
+ name: "root",
6502
+ type: "object",
6503
+ required: true,
6504
+ description: "Hierarchy root: { id, label, subtitle?, avatarUrl?, children? }."
6505
+ },
6506
+ {
6507
+ name: "collapsible",
6508
+ type: "boolean",
6509
+ required: false,
6510
+ default: true,
6511
+ description: "When true, clicking a node with children toggles its collapsed state."
6512
+ },
6513
+ {
6514
+ name: "defaultExpandedDepth",
6515
+ type: "number",
6516
+ required: false,
6517
+ description: "Nodes deeper than this depth render collapsed initially. Defaults to Infinity (all expanded)."
6518
+ },
6519
+ {
6520
+ name: "nodeWidth",
6521
+ type: "number",
6522
+ required: false,
6523
+ default: 180,
6524
+ description: "Pixel width of each node card."
6525
+ },
6526
+ {
6527
+ name: "nodeHeight",
6528
+ type: "number",
6529
+ required: false,
6530
+ default: 64,
6531
+ description: "Pixel height of each node card."
6532
+ },
6533
+ {
6534
+ name: "width",
6535
+ type: "number",
6536
+ required: false,
6537
+ default: 800,
6538
+ description: "SVG pixel width."
6539
+ },
6540
+ {
6541
+ name: "height",
6542
+ type: "number",
6543
+ required: false,
6544
+ default: 480,
6545
+ description: "SVG pixel height."
6546
+ },
6547
+ {
6548
+ name: "onNodeClick",
6549
+ type: "function",
6550
+ required: false,
6551
+ description: "Called with the clicked OrgNode. Fires before any internal collapse toggle."
6552
+ },
6553
+ {
6554
+ name: "className",
6555
+ type: "string",
6556
+ required: false,
6557
+ description: "Additional CSS classes on the SVG element."
6558
+ }
6559
+ ],
6560
+ variants: [],
6561
+ slots: [],
6562
+ dependencies: {
6563
+ npm: ["clsx", "tailwind-merge"],
6564
+ internal: ["lib/utils"],
6565
+ peer: ["react", "react-dom"],
6566
+ heavyPeer: [
6567
+ {
6568
+ name: "d3-hierarchy",
6569
+ version: "^3.1.2",
6570
+ bundleKbGzip: 3,
6571
+ reason: "Computes the top-down tree layout; the component renders SVG node cards with the result"
6572
+ }
6573
+ ]
6574
+ },
6575
+ tokensUsed: ["card", "border", "foreground", "muted-foreground", "primary", "primary-foreground", "background"],
6576
+ examples: [
6577
+ {
6578
+ title: "Three-level org chart",
6579
+ description: "CEO with two reports, one of whom has further reports.",
6580
+ code: '<OrgChart root={{\n id: "ceo", label: "Jane Doe", subtitle: "CEO",\n children: [\n { id: "cto", label: "Bob Smith", subtitle: "CTO",\n children: [{ id: "eng", label: "Eng Team", subtitle: "12 people" }] },\n { id: "cfo", label: "Sara Lin", subtitle: "CFO" },\n ],\n}} />',
6581
+ composition: ["org-chart", "hierarchy", "people"]
6582
+ },
6583
+ {
6584
+ title: "Initially collapsed past depth 1",
6585
+ description: "Render only the top two layers expanded; click +N badges to drill down.",
6586
+ code: "<OrgChart defaultExpandedDepth={1} root={orgTree} />",
6587
+ composition: ["org-chart", "collapsible"]
6588
+ }
6589
+ ],
6590
+ ai: {
6591
+ whenToUse: "Visualize people / team / department hierarchies, or any tree where each node is a labeled entity (not a value-sized bucket). Use when relationships are strictly parent-child and the user wants to drill into branches. `onNodeClick` fires for ALL nodes (root, internal, leaves) BEFORE the internal collapse toggle so consumers can observe pre-toggle state.",
6592
+ whenNotToUse: "Don't use for value-scaled hierarchies (use TreeMap or Sunburst). Don't use for arbitrary node graphs with cross-edges (use Canvas). Don't use for purely conceptual maps (use MindMap).",
6593
+ commonMistakes: [
6594
+ "Hierarchies thousands of nodes deep \u2014 d3.tree's horizontal spread becomes unreadable. Combine with `defaultExpandedDepth` and let users drill",
6595
+ "Mutating `root` in place when toggling expansion externally \u2014 internal collapse state keys off ids, so the controlled escape hatch should provide a stable id and a NEW root object",
6596
+ "Placing the SVG in a 0\xD70 container \u2014 the layout computes from `width`/`height`, but the rendered SVG inherits its container's dimensions"
6597
+ ],
6598
+ relatedComponents: ["mind-map", "tree-map", "sunburst", "dendrogram", "canvas", "diagram"],
6599
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing the visible node count and root label. Collapsed-count badges are visual; for screen readers, also expose a parallel <ul> listing label/subtitle/depth.',
6600
+ tokenBudget: 360
6601
+ },
6602
+ tags: ["artifact", "diagram", "org-chart", "hierarchy", "tree", "people"]
6603
+ };
6604
+
6605
+ // src/artifacts/sunburst/sunburst.schema.ts
6606
+ var sunburstSchema = {
6607
+ name: "sunburst",
6608
+ displayName: "Sunburst",
6609
+ description: "Radial hierarchy by value. Each ring is a deeper level of the tree; segment angles are proportional to summed values. Click a segment to drill in; click the center to zoom out.",
6610
+ category: "artifact",
6611
+ subcategory: "hierarchy",
6612
+ props: [
6613
+ {
6614
+ name: "root",
6615
+ type: "object",
6616
+ required: true,
6617
+ description: "Hierarchy root: { id, label, value?, children? }. Leaves require a positive `value`; internal nodes are summed."
6618
+ },
6619
+ {
6620
+ name: "drillable",
6621
+ type: "boolean",
6622
+ required: false,
6623
+ default: true,
6624
+ description: "When true, clicking a segment with children focuses it as the new center. Click the center to zoom back out."
6625
+ },
6626
+ {
6627
+ name: "centerLabel",
6628
+ type: "ReactNode",
6629
+ required: false,
6630
+ description: "Optional content rendered at the SVG center (e.g. a total). Falls back to the focused node's label."
6631
+ },
6632
+ {
6633
+ name: "size",
6634
+ type: "number",
6635
+ required: false,
6636
+ default: 400,
6637
+ description: "Pixel size of the rendered SVG (it's square)."
6638
+ },
6639
+ {
6640
+ name: "onSegmentClick",
6641
+ type: "function",
6642
+ required: false,
6643
+ description: "Called with the clicked SunburstNode. Fires before any internal drill."
6644
+ },
6645
+ {
6646
+ name: "className",
6647
+ type: "string",
6648
+ required: false,
6649
+ description: "Additional CSS classes on the SVG element."
6650
+ }
6651
+ ],
6652
+ variants: [],
6653
+ slots: [],
6654
+ dependencies: {
6655
+ npm: ["clsx", "tailwind-merge"],
6656
+ internal: ["lib/utils"],
6657
+ peer: ["react", "react-dom"],
6658
+ heavyPeer: [
6659
+ {
6660
+ name: "d3-hierarchy",
6661
+ version: "^3.1.2",
6662
+ bundleKbGzip: 3,
6663
+ reason: "Computes the partition layout that positions each ring segment"
6664
+ },
6665
+ {
6666
+ name: "d3-shape",
6667
+ version: "^3.2.0",
6668
+ bundleKbGzip: 6,
6669
+ reason: "Generates the SVG arc path for each segment"
6670
+ }
6671
+ ]
6672
+ },
6673
+ tokensUsed: ["primary", "accent", "secondary", "muted", "card", "border", "foreground", "background"],
6674
+ examples: [
6675
+ {
6676
+ title: "Two-level sunburst",
6677
+ description: "Visualize a portfolio split with sub-allocations.",
6678
+ code: '<Sunburst root={{\n id: "root", label: "Portfolio",\n children: [\n { id: "eq", label: "Equity", children: [\n { id: "us", label: "US", value: 60 },\n { id: "intl", label: "Intl", value: 20 },\n ]},\n { id: "fx", label: "Fixed Income", value: 20 },\n ],\n}} />',
6679
+ composition: ["sunburst", "hierarchy", "value-scaled"]
6680
+ },
6681
+ {
6682
+ title: "Custom center label with totals",
6683
+ description: "Use centerLabel to show the sum or other context.",
6684
+ code: "<Sunburst centerLabel={<strong>$1.2M</strong>} root={portfolio} />",
6685
+ composition: ["sunburst", "center-label"]
6686
+ }
6687
+ ],
6688
+ ai: {
6689
+ whenToUse: "Visualize a value-scaled hierarchy where the user wants to see both the parent share and child sub-shares at once \u2014 portfolio allocations, time spent by category \xD7 subcategory, file system disk usage. Drill-down lets users focus a branch. `onSegmentClick` fires for ALL segments BEFORE the internal drill so consumers can observe pre-drill focus.",
6690
+ whenNotToUse: "Don't use for hierarchies without meaningful values per leaf (use MindMap or OrgChart). Don't use for >4 levels \u2014 outer rings become unreadable. Don't use for arbitrary node-edge graphs (use Canvas).",
6691
+ commonMistakes: [
6692
+ "Leaf values that don't sum at internal nodes \u2014 d3-hierarchy aggregates leaves; internal-node `value` props are ignored when children exist",
6693
+ "Negative or zero leaf values \u2014 produce zero-width arcs or NaN angles. Filter or clamp upstream",
6694
+ "Forgetting the resetting effect \u2014 when the parent updates `root` to a different tree, the focused id may no longer exist; the component re-syncs to the new root automatically"
6695
+ ],
6696
+ relatedComponents: ["tree-map", "mind-map", "org-chart", "dendrogram", "diagram"],
6697
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing segment count and focused node. Drill-down is mouse-only by default; expose a parallel <table> or breadcrumb for keyboard / screen-reader users.',
6698
+ tokenBudget: 360
6699
+ },
6700
+ tags: ["artifact", "diagram", "sunburst", "hierarchy", "radial", "value-scaled"]
6701
+ };
6702
+
6703
+ // src/artifacts/dendrogram/dendrogram.schema.ts
6704
+ var dendrogramSchema = {
6705
+ name: "dendrogram",
6706
+ displayName: "Dendrogram",
6707
+ description: "Clustering tree where every leaf sits at the same depth, regardless of branch length \u2014 the visual signature of taxonomies, phylogenetic trees, and hierarchical-clustering output.",
6708
+ category: "artifact",
6709
+ subcategory: "hierarchy",
6710
+ props: [
6711
+ {
6712
+ name: "root",
6713
+ type: "object",
6714
+ required: true,
6715
+ description: "Hierarchy root: { id, label, children? }."
6716
+ },
6717
+ {
6718
+ name: "orientation",
6719
+ type: "enum",
6720
+ required: false,
6721
+ default: "horizontal",
6722
+ description: '"horizontal" runs root-to-leaves left\u2192right; "vertical" runs top\u2192bottom.',
6723
+ enumValues: ["horizontal", "vertical"]
6724
+ },
6725
+ {
6726
+ name: "linkShape",
6727
+ type: "enum",
6728
+ required: false,
6729
+ default: "step",
6730
+ description: '"step" draws right-angle elbow links (taxonomy aesthetic); "diagonal" uses smooth Bezier curves.',
6731
+ enumValues: ["step", "diagonal"]
6732
+ },
6733
+ {
6734
+ name: "width",
6735
+ type: "number",
6736
+ required: false,
6737
+ default: 600,
6738
+ description: "SVG pixel width."
6739
+ },
6740
+ {
6741
+ name: "height",
6742
+ type: "number",
6743
+ required: false,
6744
+ default: 400,
6745
+ description: "SVG pixel height."
6746
+ },
6747
+ {
6748
+ name: "onLeafClick",
6749
+ type: "function",
6750
+ required: false,
6751
+ description: "Called with the clicked DendrogramNode when a user clicks any leaf."
6752
+ },
6753
+ {
6754
+ name: "className",
6755
+ type: "string",
6756
+ required: false,
6757
+ description: "Additional CSS classes on the SVG element."
6758
+ }
6759
+ ],
6760
+ variants: [],
6761
+ slots: [],
6762
+ dependencies: {
6763
+ npm: ["clsx", "tailwind-merge"],
6764
+ internal: ["lib/utils"],
6765
+ peer: ["react", "react-dom"],
6766
+ heavyPeer: [
6767
+ {
6768
+ name: "d3-hierarchy",
6769
+ version: "^3.1.2",
6770
+ bundleKbGzip: 3,
6771
+ reason: "Computes the cluster layout (equal-depth leaves) used to position nodes"
6772
+ }
6773
+ ]
6774
+ },
6775
+ tokensUsed: ["primary", "muted-foreground", "foreground", "background"],
6776
+ examples: [
6777
+ {
6778
+ title: "Taxonomy dendrogram",
6779
+ description: "Equal-depth leaves arranged horizontally with step links.",
6780
+ code: '<Dendrogram root={{\n id: "root", label: "Animals",\n children: [\n { id: "mammals", label: "Mammals", children: [\n { id: "cat", label: "Cat" },\n { id: "dog", label: "Dog" },\n ]},\n { id: "birds", label: "Birds", children: [{ id: "robin", label: "Robin" }] },\n ],\n}} />',
6781
+ composition: ["dendrogram", "hierarchy", "taxonomy"]
6782
+ },
6783
+ {
6784
+ title: "Vertical dendrogram with diagonal links",
6785
+ description: "Top-down orientation with smooth Bezier links.",
6786
+ code: '<Dendrogram orientation="vertical" linkShape="diagonal" root={tree} />',
6787
+ composition: ["dendrogram", "vertical", "diagonal"]
6788
+ }
6789
+ ],
6790
+ ai: {
6791
+ whenToUse: "Visualize taxonomic / phylogenetic / clustering hierarchies where the user expects every leaf to sit at the same depth. Ideal when the tree shape itself is the message (groupings, sibling relationships). `onLeafClick` fires for LEAVES ONLY \u2014 internal-node clicks are no-ops (use OrgChart if you need callbacks on every node).",
6792
+ whenNotToUse: "Don't use for value-scaled hierarchies (use TreeMap or Sunburst). Don't use for tree shapes where depth has meaning (use OrgChart, which uses d3.tree). Don't use for arbitrary node graphs (use Canvas).",
6793
+ commonMistakes: [
6794
+ "Confusing dendrogram with org chart \u2014 dendrogram aligns ALL leaves at a single edge regardless of branch depth, which is wrong for org structures where reporting depth is meaningful",
6795
+ "Hundreds of leaves on a fixed-size SVG \u2014 leaves overlap. Either grow the SVG or paginate the tree",
6796
+ "Mutating the root object in place \u2014 the layout pass treats input as immutable; always provide a new root reference on data change"
6797
+ ],
6798
+ relatedComponents: ["mind-map", "tree-map", "org-chart", "sunburst", "diagram"],
6799
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing the leaf count and root label. For agent outputs, expose a parallel <ul> grouping leaves by their parent so screen-reader users get the clustering structure.',
6800
+ tokenBudget: 320
6801
+ },
6802
+ tags: ["artifact", "diagram", "dendrogram", "hierarchy", "cluster", "taxonomy"]
6803
+ };
6804
+
6805
+ // src/artifacts/sankey/sankey.schema.ts
6806
+ var sankeySchema = {
6807
+ name: "sankey",
6808
+ displayName: "Sankey",
6809
+ description: 'Weighted-flow diagram. Nodes arranged in horizontal columns by topological depth; link thickness encodes flow value. Use for funnels, energy/material/money flows, and any "value moving from A to B" picture.',
6810
+ category: "artifact",
6811
+ subcategory: "flow",
6812
+ props: [
6813
+ {
6814
+ name: "nodes",
6815
+ type: "object",
6816
+ required: true,
6817
+ description: "Array of { id, label }. Every link's source/target MUST match an id here."
6818
+ },
6819
+ {
6820
+ name: "links",
6821
+ type: "object",
6822
+ required: true,
6823
+ description: "Array of { source, target, value }. Values must be positive."
6824
+ },
6825
+ {
6826
+ name: "width",
6827
+ type: "number",
6828
+ required: false,
6829
+ default: 720,
6830
+ description: "SVG pixel width."
6831
+ },
6832
+ {
6833
+ name: "height",
6834
+ type: "number",
6835
+ required: false,
6836
+ default: 420,
6837
+ description: "SVG pixel height."
6838
+ },
6839
+ {
6840
+ name: "nodeAlign",
6841
+ type: "enum",
6842
+ required: false,
6843
+ default: "justify",
6844
+ description: "Column alignment strategy.",
6845
+ enumValues: ["left", "right", "center", "justify"]
6846
+ },
6847
+ {
6848
+ name: "nodeWidth",
6849
+ type: "number",
6850
+ required: false,
6851
+ default: 12,
6852
+ description: "Pixel width of each node rectangle."
6853
+ },
6854
+ {
6855
+ name: "nodePadding",
6856
+ type: "number",
6857
+ required: false,
6858
+ default: 8,
6859
+ description: "Vertical pixel gap between nodes in the same column."
6860
+ },
6861
+ {
6862
+ name: "onLinkHover",
6863
+ type: "function",
6864
+ required: false,
6865
+ description: "Called with the hovered SankeyLink (or null when hover ends)."
6866
+ },
6867
+ {
6868
+ name: "onNodeClick",
6869
+ type: "function",
6870
+ required: false,
6871
+ description: "Called with the clicked SankeyNode."
6872
+ },
6873
+ {
6874
+ name: "className",
6875
+ type: "string",
6876
+ required: false,
6877
+ description: "Additional CSS classes on the SVG element."
6878
+ }
6879
+ ],
6880
+ variants: [],
6881
+ slots: [],
6882
+ dependencies: {
6883
+ npm: ["clsx", "tailwind-merge"],
6884
+ internal: ["lib/utils"],
6885
+ peer: ["react", "react-dom"],
6886
+ heavyPeer: [
6887
+ {
6888
+ name: "d3-sankey",
6889
+ version: "^0.12.3",
6890
+ bundleKbGzip: 6,
6891
+ reason: "Computes the column layout and link routing; the component renders SVG with the result"
6892
+ }
6893
+ ]
6894
+ },
6895
+ tokensUsed: ["primary", "background", "foreground", "muted"],
6896
+ examples: [
6897
+ {
6898
+ title: "Energy flow",
6899
+ description: "Two sources flowing into a single sink.",
6900
+ code: '<Sankey\n nodes={[\n { id: "coal", label: "Coal" },\n { id: "gas", label: "Gas" },\n { id: "grid", label: "Grid" },\n ]}\n links={[\n { source: "coal", target: "grid", value: 60 },\n { source: "gas", target: "grid", value: 30 },\n ]}\n/>',
6901
+ composition: ["sankey", "flow", "energy"]
6902
+ },
6903
+ {
6904
+ title: "Funnel-style with hover",
6905
+ description: "Surface link details on hover for tooltips.",
6906
+ code: "<Sankey\n nodes={steps}\n links={transitions}\n onLinkHover={(l) => setActive(l)}\n/>",
6907
+ composition: ["sankey", "interactive", "tooltip"]
6908
+ }
6909
+ ],
6910
+ ai: {
6911
+ whenToUse: "Visualize how a quantity is distributed and re-distributed across a multi-step pipeline \u2014 energy mix, marketing-funnel transitions, traffic referral flows, budget allocation by department \xD7 line-item. The thicker the link, the more value moves along it.",
6912
+ whenNotToUse: "Don't use for hierarchies (use TreeMap or Sunburst). Don't use for arbitrary node-edge graphs without a clear left-to-right flow (use Canvas). Don't use when total flow doesn't conserve from column to column \u2014 d3-sankey assumes a balanced graph.",
6913
+ commonMistakes: [
6914
+ "A link's source or target id not present in `nodes` \u2014 d3-sankey throws an opaque error. Validate ids upstream",
6915
+ "Negative or zero `value` \u2014 produces zero-width or NaN-positioned links. Filter or clamp upstream",
6916
+ "Cycles in the link graph \u2014 d3-sankey requires a DAG. If your data has feedback loops, collapse them or split into multiple Sankeys",
6917
+ "Mutating the input `nodes` / `links` between renders \u2014 the component clones internally to protect consumer arrays, but unmemoized inputs still trigger a full re-layout each render. Memoize"
6918
+ ],
6919
+ relatedComponents: ["funnel", "pyramid", "flowchart", "canvas", "diagram"],
6920
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing node and link counts. For agent outputs, also expose a parallel <table> of source / target / value triples so screen-reader users get the flow magnitudes.',
6921
+ tokenBudget: 360
6922
+ },
6923
+ tags: ["artifact", "diagram", "sankey", "flow", "weighted", "funnel"]
6924
+ };
6925
+
6926
+ // src/artifacts/funnel/funnel.schema.ts
6927
+ var funnelSchema = {
6928
+ name: "funnel",
6929
+ displayName: "Funnel",
6930
+ description: "Conversion funnel \u2014 vertical stack of trapezoidal stages whose width is proportional to each stage's value. Pure SVG; no heavy peer dep.",
6931
+ category: "artifact",
6932
+ subcategory: "flow",
6933
+ props: [
6934
+ {
6935
+ name: "stages",
6936
+ type: "object",
6937
+ required: true,
6938
+ description: "Ordered top-to-bottom array of { id, label, value }. Values must be non-negative."
6939
+ },
6940
+ {
6941
+ name: "width",
6942
+ type: "number",
6943
+ required: false,
6944
+ default: 480,
6945
+ description: "SVG pixel width."
6946
+ },
6947
+ {
6948
+ name: "height",
6949
+ type: "number",
6950
+ required: false,
6951
+ default: 360,
6952
+ description: "SVG pixel height."
6953
+ },
6954
+ {
6955
+ name: "gap",
6956
+ type: "number",
6957
+ required: false,
6958
+ default: 4,
6959
+ description: "Pixel gap between stages."
6960
+ },
6961
+ {
6962
+ name: "showConversion",
6963
+ type: "boolean",
6964
+ required: false,
6965
+ default: true,
6966
+ description: "Show stage-to-stage conversion percentages alongside the funnel."
6967
+ },
6968
+ {
6969
+ name: "onStageClick",
6970
+ type: "function",
6971
+ required: false,
6972
+ description: "Called with the clicked FunnelStage."
6973
+ },
6974
+ {
6975
+ name: "className",
6976
+ type: "string",
6977
+ required: false,
6978
+ description: "Additional CSS classes on the SVG element."
6979
+ }
6980
+ ],
6981
+ variants: [],
6982
+ slots: [],
6983
+ dependencies: {
6984
+ npm: ["clsx", "tailwind-merge"],
6985
+ internal: ["lib/utils"],
6986
+ peer: ["react", "react-dom"]
6987
+ },
6988
+ tokensUsed: ["primary", "primary-foreground", "muted-foreground", "background"],
6989
+ examples: [
6990
+ {
6991
+ title: "Signup funnel",
6992
+ description: "Standard top-of-funnel \u2192 conversion drop-off.",
6993
+ code: '<Funnel stages={[\n { id: "visit", label: "Visited", value: 10000 },\n { id: "signup", label: "Signed up", value: 1200 },\n { id: "active", label: "Active", value: 480 },\n { id: "paid", label: "Paid", value: 95 },\n]} />',
6994
+ composition: ["funnel", "conversion", "stages"]
6995
+ },
6996
+ {
6997
+ title: "Click stages to drill in",
6998
+ description: "Wire onStageClick to a route or modal for stage detail.",
6999
+ code: "<Funnel stages={data} onStageClick={(s) => router.push(`/stages/${s.id}`)} />",
7000
+ composition: ["funnel", "interactive"]
7001
+ }
7002
+ ],
7003
+ ai: {
7004
+ whenToUse: "Visualize linear conversion drop-off \u2014 onboarding step completion, marketing-funnel rates, sales pipeline stages, ETL row counts. Use when each stage is a strict subset of the previous and the magnitude of the drop is the message.",
7005
+ whenNotToUse: "Don't use for non-monotonic data where a later stage can exceed an earlier one (use a column chart). Don't use for branching funnels where flow splits across paths (use Sankey). Don't use for ranked categorical data without a flow concept (use Pyramid).",
7006
+ commonMistakes: [
7007
+ `Stage values that aren't monotonically non-increasing \u2014 visually misleads users into thinking the funnel "recovers". Validate upstream`,
7008
+ "Negative values \u2014 produce zero-width stages or NaN positions. Filter or clamp upstream",
7009
+ "More than ~8 stages \u2014 labels become unreadable. Group adjacent stages or use Sankey"
7010
+ ],
7011
+ relatedComponents: ["sankey", "pyramid", "flowchart", "diagram"],
7012
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing stage count and peak value. For agent outputs, also expose a parallel <table> of label/value/conversion-rate triples so screen-reader users get the magnitudes.',
7013
+ tokenBudget: 280
7014
+ },
7015
+ tags: ["artifact", "diagram", "funnel", "conversion", "flow"]
7016
+ };
7017
+
7018
+ // src/artifacts/pyramid/pyramid.schema.ts
7019
+ var pyramidSchema = {
7020
+ name: "pyramid",
7021
+ displayName: "Pyramid",
7022
+ description: "Ranked-tier pyramid. Tiers stack top-to-bottom; widths can grow toward the base (widening) or shrink (narrowing). Pure SVG; no heavy peer dep. Distinct from Funnel \u2014 Pyramid encodes RANK, Funnel encodes FLOW.",
7023
+ category: "artifact",
7024
+ subcategory: "flow",
7025
+ props: [
7026
+ {
7027
+ name: "tiers",
7028
+ type: "object",
7029
+ required: true,
7030
+ description: "Ordered top-to-bottom array of { id, label, value? }. The first entry is the apex."
7031
+ },
7032
+ {
7033
+ name: "shape",
7034
+ type: "enum",
7035
+ required: false,
7036
+ default: "widening",
7037
+ description: 'Tier-width direction \u2014 "widening" grows toward the base; "narrowing" shrinks toward it.',
7038
+ enumValues: ["widening", "narrowing"]
7039
+ },
7040
+ {
7041
+ name: "width",
7042
+ type: "number",
7043
+ required: false,
7044
+ default: 480,
7045
+ description: "SVG pixel width."
7046
+ },
7047
+ {
7048
+ name: "height",
7049
+ type: "number",
7050
+ required: false,
7051
+ default: 360,
7052
+ description: "SVG pixel height."
7053
+ },
7054
+ {
7055
+ name: "gap",
7056
+ type: "number",
7057
+ required: false,
7058
+ default: 4,
7059
+ description: "Pixel gap between tiers."
7060
+ },
7061
+ {
7062
+ name: "showValues",
7063
+ type: "boolean",
7064
+ required: false,
7065
+ default: true,
7066
+ description: "Show each tier's `value` next to its label when present."
7067
+ },
7068
+ {
7069
+ name: "onTierClick",
7070
+ type: "function",
7071
+ required: false,
7072
+ description: "Called with the clicked PyramidTier."
7073
+ },
7074
+ {
7075
+ name: "className",
7076
+ type: "string",
7077
+ required: false,
7078
+ description: "Additional CSS classes on the SVG element."
7079
+ }
7080
+ ],
7081
+ variants: [],
7082
+ slots: [],
7083
+ dependencies: {
7084
+ npm: ["clsx", "tailwind-merge"],
7085
+ internal: ["lib/utils"],
7086
+ peer: ["react", "react-dom"]
7087
+ },
7088
+ tokensUsed: ["primary", "primary-foreground", "background"],
7089
+ examples: [
7090
+ {
7091
+ title: "Maslow's hierarchy",
7092
+ description: "Classic widening pyramid with 5 tiers.",
7093
+ code: '<Pyramid tiers={[\n { id: "a", label: "Self-actualization" },\n { id: "e", label: "Esteem" },\n { id: "l", label: "Love & belonging" },\n { id: "s", label: "Safety" },\n { id: "p", label: "Physiological" },\n]} />',
7094
+ composition: ["pyramid", "rank", "hierarchy"]
7095
+ },
7096
+ {
7097
+ title: "Inverted pyramid (narrowing) for ranked output",
7098
+ description: 'Use "narrowing" when the most important tier sits at the top.',
7099
+ code: '<Pyramid shape="narrowing" tiers={[\n { id: "north-star", label: "North star" },\n { id: "okrs", label: "OKRs" },\n { id: "projects", label: "Projects" },\n { id: "tasks", label: "Tasks" },\n]} />',
7100
+ composition: ["pyramid", "narrowing"]
7101
+ }
7102
+ ],
7103
+ ai: {
7104
+ whenToUse: "Visualize a ranked categorical hierarchy where tier order is meaningful but each tier is a distinct level (not a subset of the previous). Maslow-style needs hierarchy, organizational tiers, content hierarchy (north star \u2192 tasks).",
7105
+ whenNotToUse: "Don't use for conversion drop-off where each stage is a strict subset of the previous (use Funnel \u2014 it shows the conversion ratio between stages). Don't use for value-scaled hierarchies (use TreeMap or Sunburst). Don't use for >7 tiers \u2014 labels become unreadable.",
7106
+ commonMistakes: [
7107
+ "Confusing Pyramid with Funnel \u2014 Funnel encodes FLOW (value moves between stages); Pyramid encodes RANK (each tier is a distinct level)",
7108
+ "Tier order matters \u2014 the first array element is the apex. Reversing the array flips the meaning",
7109
+ "Passing values that don't actually rank \u2014 Pyramid doesn't sort; it trusts your order"
7110
+ ],
7111
+ relatedComponents: ["funnel", "sankey", "tree-map", "sunburst"],
7112
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing tier count and shape. For agent outputs, also expose a parallel ordered list (<ol>) of labels so screen-reader users get the rank order without relying on visual position.',
7113
+ tokenBudget: 260
7114
+ },
7115
+ tags: ["artifact", "diagram", "pyramid", "rank", "hierarchy"]
7116
+ };
7117
+
7118
+ // src/artifacts/flowchart/flowchart.schema.ts
7119
+ var flowchartSchema = {
7120
+ name: "flowchart",
7121
+ displayName: "Flowchart",
7122
+ description: "Typed React flowchart. Pass nodes (with optional shape) and directional edges; the component runs a topological-rank auto-layout and renders top-to-bottom or left-to-right. Pure SVG; no heavy peer dep.",
7123
+ category: "artifact",
7124
+ subcategory: "flow",
7125
+ props: [
7126
+ {
7127
+ name: "nodes",
7128
+ type: "object",
7129
+ required: true,
7130
+ description: 'Array of { id, label, shape?, rank? }. shape \u2208 "rect" (default) | "round" | "diamond".'
7131
+ },
7132
+ {
7133
+ name: "edges",
7134
+ type: "object",
7135
+ required: true,
7136
+ description: "Array of { source, target, label? }. The graph MUST be a DAG (no cycles)."
7137
+ },
7138
+ {
7139
+ name: "direction",
7140
+ type: "enum",
7141
+ required: false,
7142
+ default: "vertical",
7143
+ description: "Layout direction \u2014 vertical (top-to-bottom) or horizontal (left-to-right).",
7144
+ enumValues: ["vertical", "horizontal"]
7145
+ },
7146
+ {
7147
+ name: "width",
7148
+ type: "number",
7149
+ required: false,
7150
+ default: 720,
7151
+ description: "SVG pixel width."
7152
+ },
7153
+ {
7154
+ name: "height",
7155
+ type: "number",
7156
+ required: false,
7157
+ default: 480,
7158
+ description: "SVG pixel height."
7159
+ },
7160
+ {
7161
+ name: "nodeWidth",
7162
+ type: "number",
7163
+ required: false,
7164
+ default: 140,
7165
+ description: "Pixel width of each node."
7166
+ },
7167
+ {
7168
+ name: "nodeHeight",
7169
+ type: "number",
7170
+ required: false,
7171
+ default: 48,
7172
+ description: "Pixel height of each node."
7173
+ },
7174
+ {
7175
+ name: "onNodeClick",
7176
+ type: "function",
7177
+ required: false,
7178
+ description: "Called with the clicked FlowchartNode."
7179
+ },
7180
+ {
7181
+ name: "className",
7182
+ type: "string",
7183
+ required: false,
7184
+ description: "Additional CSS classes on the SVG element."
7185
+ }
7186
+ ],
7187
+ variants: [],
7188
+ slots: [],
7189
+ dependencies: {
7190
+ npm: ["clsx", "tailwind-merge"],
7191
+ internal: ["lib/utils"],
7192
+ peer: ["react", "react-dom"]
7193
+ },
7194
+ tokensUsed: ["card", "border", "foreground", "muted-foreground", "background"],
7195
+ examples: [
7196
+ {
7197
+ title: "Authorization decision flow",
7198
+ description: "Diamond decision node + two outcomes.",
7199
+ code: '<Flowchart\n nodes={[\n { id: "start", label: "Start", shape: "round" },\n { id: "check", label: "Authorized?", shape: "diamond" },\n { id: "ok", label: "Continue" },\n { id: "denied", label: "Reject", shape: "round" },\n ]}\n edges={[\n { source: "start", target: "check" },\n { source: "check", target: "ok", label: "yes" },\n { source: "check", target: "denied", label: "no" },\n ]}\n/>',
7200
+ composition: ["flowchart", "decision", "branching"]
7201
+ },
7202
+ {
7203
+ title: "Horizontal pipeline with click handler",
7204
+ description: "Left-to-right ETL stages.",
7205
+ code: '<Flowchart\n direction="horizontal"\n nodes={stages}\n edges={transitions}\n onNodeClick={(n) => router.push(`/stages/${n.id}`)}\n/>',
7206
+ composition: ["flowchart", "horizontal", "pipeline"]
7207
+ }
7208
+ ],
7209
+ ai: {
7210
+ whenToUse: "Render structured process / decision / pipeline diagrams from typed application data \u2014 onboarding flows, decision trees, ETL pipelines, agent step-graphs. Use when consumers want an SVG without the bundle cost of `<Diagram>` (Mermaid) or the free-form interaction of `<Canvas>` (ReactFlow).",
7211
+ whenNotToUse: "Don't use for cyclic graphs (use Canvas \u2014 Flowchart's topological layout assumes a DAG). Don't use when consumers want to drag nodes around (use Canvas). Don't use when the diagram source is a Mermaid string from an LLM (use Diagram).",
7212
+ commonMistakes: [
7213
+ "Cycles in the edge graph \u2014 `computeRanks` short-circuits cycles to rank 0, which produces a degenerate layout. Validate the DAG upstream",
7214
+ "An edge whose source or target id is missing from `nodes` \u2014 the edge is silently skipped. Validate ids upstream",
7215
+ "Too many nodes at the same rank \u2014 the cross-axis spacing collapses. Either provide explicit `rank` overrides to balance the layout, or grow the SVG width",
7216
+ "Mutating nodes/edges in place between renders \u2014 the layout pass treats inputs as immutable and re-runs on identity change"
7217
+ ],
7218
+ relatedComponents: ["sankey", "funnel", "diagram", "canvas", "mind-map"],
7219
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing node and edge counts. For agent outputs, also expose a parallel ordered list (or tree) of nodes-by-rank so screen-reader users get the flow without relying on visual position.',
7220
+ tokenBudget: 380
7221
+ },
7222
+ tags: ["artifact", "diagram", "flowchart", "flow", "dag", "process"]
7223
+ };
7224
+
7225
+ // src/artifacts/venn/venn.schema.ts
7226
+ var vennSchema = {
7227
+ name: "venn",
7228
+ displayName: "Venn",
7229
+ description: "Set-overlap diagram for 2 or 3 sets. Pure SVG; no heavy peer dep. Shows categorical overlap (which sets intersect) \u2014 NOT exact intersection cardinality (use an Euler-diagram solver for that).",
7230
+ category: "artifact",
7231
+ subcategory: "relational",
7232
+ props: [
7233
+ {
7234
+ name: "sets",
7235
+ type: "object",
7236
+ required: true,
7237
+ description: "Array of { id, label, value? }. Must have 2 or 3 entries; other counts render a friendly fallback."
7238
+ },
7239
+ {
7240
+ name: "size",
7241
+ type: "number",
7242
+ required: false,
7243
+ default: 360,
7244
+ description: "Pixel size of the rendered SVG (it's square)."
7245
+ },
7246
+ {
7247
+ name: "onSetClick",
7248
+ type: "function",
7249
+ required: false,
7250
+ description: "Called with the clicked VennSet."
7251
+ },
7252
+ {
7253
+ name: "className",
7254
+ type: "string",
7255
+ required: false,
7256
+ description: "Additional CSS classes on the SVG element."
7257
+ }
7258
+ ],
7259
+ variants: [],
7260
+ slots: [],
7261
+ dependencies: {
7262
+ npm: ["clsx", "tailwind-merge"],
7263
+ internal: ["lib/utils"],
7264
+ peer: ["react", "react-dom"]
7265
+ },
7266
+ tokensUsed: ["primary", "accent", "secondary", "foreground", "muted-foreground", "background"],
7267
+ examples: [
7268
+ {
7269
+ title: "Three-set Venn",
7270
+ description: "Linux / Mac / Windows overlap.",
7271
+ code: '<Venn sets={[\n { id: "linux", label: "Linux" },\n { id: "mac", label: "Mac" },\n { id: "windows", label: "Windows" },\n]} />',
7272
+ composition: ["venn", "set-overlap"]
7273
+ },
7274
+ {
7275
+ title: "Two-set Venn with values",
7276
+ description: "Show set sizes alongside labels.",
7277
+ code: '<Venn sets={[\n { id: "paid", label: "Paid", value: 1200 },\n { id: "active", label: "Active", value: 480 },\n]} />',
7278
+ composition: ["venn", "with-values"]
7279
+ }
7280
+ ],
7281
+ ai: {
7282
+ whenToUse: "Show that two or three categorical sets overlap \u2014 feature support matrices (Linux \u2229 Mac), cohort intersections (paid \u2229 active), tag overlap. Use when the SHAPE of the overlap is the message.",
7283
+ whenNotToUse: "Don't use to communicate exact intersection sizes \u2014 circles are not area-scaled (use an Euler-diagram tool with a layout solver). Don't use for >3 sets \u2014 it stops being a Venn. Don't use for hierarchical / weighted / sequential relationships (use TreeMap, Sankey, Flowchart).",
7284
+ commonMistakes: [
7285
+ "Implying intersection cardinality from circle area \u2014 Venn circles are fixed-size visual references. The component does NOT solve for area-correct overlap regions; the schema documents this clearly",
7286
+ "Passing 4+ sets \u2014 strict Venn diagrams with 4+ sets aren't visually tractable. The component renders a friendly fallback in that case",
7287
+ "Mutating the sets array in place between renders \u2014 the layout pass is memoized on identity"
7288
+ ],
7289
+ relatedComponents: ["chord", "matrix", "arc", "tree-map"],
7290
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> listing the participating set labels. Interactive sets carry role="button", tabIndex, and Enter/Space activation. For agent outputs, also expose a parallel list of sets so screen-reader users get the labels without relying on the visual.',
7291
+ tokenBudget: 280
7292
+ },
7293
+ tags: ["artifact", "diagram", "venn", "set-overlap", "relational"]
7294
+ };
7295
+
7296
+ // src/artifacts/chord/chord.schema.ts
7297
+ var chordSchema = {
7298
+ name: "chord",
7299
+ displayName: "Chord",
7300
+ description: 'Chord diagram. Nodes sit on a ring; ribbons inside encode weighted bidirectional relationships. Use for trade flows, migration, citation networks \u2014 "A relates to B with weight w" at scale.',
7301
+ category: "artifact",
7302
+ subcategory: "relational",
7303
+ props: [
7304
+ {
7305
+ name: "nodes",
7306
+ type: "object",
7307
+ required: true,
7308
+ description: "Array of { id, label }. Order matches matrix rows/columns."
7309
+ },
7310
+ {
7311
+ name: "matrix",
7312
+ type: "object",
7313
+ required: true,
7314
+ description: "Square N\xD7N matrix of weights. matrix[i][j] = flow from node i to node j."
7315
+ },
7316
+ {
7317
+ name: "size",
7318
+ type: "number",
7319
+ required: false,
7320
+ default: 480,
7321
+ description: "Pixel size of the rendered SVG (it's square)."
7322
+ },
7323
+ {
7324
+ name: "padAngle",
7325
+ type: "number",
7326
+ required: false,
7327
+ default: 0.04,
7328
+ description: "Padding (in radians) between adjacent ring segments."
7329
+ },
7330
+ {
7331
+ name: "onChordHover",
7332
+ type: "function",
7333
+ required: false,
7334
+ description: "Called with the hovered ribbon's { source, target, value } (or null when hover ends)."
7335
+ },
7336
+ {
7337
+ name: "onNodeClick",
7338
+ type: "function",
7339
+ required: false,
7340
+ description: "Called with the clicked ChordNode."
7341
+ },
7342
+ {
7343
+ name: "className",
7344
+ type: "string",
7345
+ required: false,
7346
+ description: "Additional CSS classes on the SVG element."
7347
+ }
7348
+ ],
7349
+ variants: [],
7350
+ slots: [],
7351
+ dependencies: {
7352
+ npm: ["clsx", "tailwind-merge"],
7353
+ internal: ["lib/utils"],
7354
+ peer: ["react", "react-dom"],
7355
+ heavyPeer: [
7356
+ {
7357
+ name: "d3-chord",
7358
+ version: "^3.0.1",
7359
+ bundleKbGzip: 3,
7360
+ reason: "Computes the chord layout (group ranges + chord pairs from the input matrix)"
7361
+ },
7362
+ {
7363
+ name: "d3-shape",
7364
+ version: "^3.2.0",
7365
+ bundleKbGzip: 6,
7366
+ reason: "Generates the SVG arc and ribbon paths (already a peer of Sunburst)"
7367
+ }
7368
+ ]
7369
+ },
7370
+ tokensUsed: ["primary", "accent", "secondary", "muted", "background", "foreground"],
7371
+ examples: [
7372
+ {
7373
+ title: "Trade flow between four regions",
7374
+ description: "Bidirectional weighted relationships.",
7375
+ code: '<Chord\n nodes={[\n { id: "americas", label: "Americas" },\n { id: "emea", label: "EMEA" },\n { id: "apac", label: "APAC" },\n { id: "africa", label: "Africa" },\n ]}\n matrix={[\n [0, 12, 8, 1],\n [10, 0, 5, 2],\n [7, 4, 0, 3],\n [1, 1, 2, 0],\n ]}\n/>',
7376
+ composition: ["chord", "trade-flow", "weighted"]
7377
+ },
7378
+ {
7379
+ title: "Hover for ribbon details",
7380
+ description: "Wire `onChordHover` to populate a tooltip.",
7381
+ code: "<Chord nodes={people} matrix={interactions} onChordHover={(c) => setActive(c)} />",
7382
+ composition: ["chord", "interactive"]
7383
+ }
7384
+ ],
7385
+ ai: {
7386
+ whenToUse: "Visualize bidirectional weighted relationships among a small set of entities (typically 4\u201312). Trade flows, migration corridors, citation/hyperlink networks, character interactions in narratives.",
7387
+ whenNotToUse: "Don't use for hierarchical relationships (use TreeMap, Sunburst, OrgChart). Don't use for unidirectional flows where direction matters (use Sankey). Don't use for >~15 nodes \u2014 ribbons stack and become unreadable. Don't use for sparse matrices \u2014 most ribbons collapse to invisible.",
7388
+ commonMistakes: [
7389
+ "Non-square matrix \u2014 d3-chord requires N\xD7N where N matches `nodes.length`. Validate upstream",
7390
+ "Asymmetric weights expected to render symmetrically \u2014 the component honors per-direction weights as given (matrix[i][j] vs matrix[j][i])",
7391
+ "Mutating `nodes` / `matrix` between renders \u2014 the layout pass is memoized on identity. Memoize the matrix",
7392
+ "NaN entries in the matrix \u2014 the inline `descending` comparator treats NaN as equal (vs d3.descending which returns NaN). Sort positions for NaN entries are unstable; sanitize upstream",
7393
+ "Expecting `onChordHover.value` \u2014 the callback now exposes `{ sourceValue, targetValue }` so consumers see both directions of an asymmetric flow at once"
7394
+ ],
7395
+ relatedComponents: ["sankey", "matrix", "arc", "venn"],
7396
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing node and ribbon counts. Interactive ribbons and node arcs declare role="button", tabIndex, and Enter/Space activation. For agent outputs, also expose a parallel adjacency table so screen-reader users get the matrix without relying on the visual.',
7397
+ tokenBudget: 360
7398
+ },
7399
+ tags: ["artifact", "diagram", "chord", "relational", "weighted", "circular"]
7400
+ };
7401
+
7402
+ // src/artifacts/arc/arc.schema.ts
7403
+ var arcSchema = {
7404
+ name: "arc",
7405
+ displayName: "Arc",
7406
+ description: "Arc diagram. Nodes lie on a horizontal baseline; relationships are drawn as semicircle arcs above. Pure SVG; no heavy peer dep. Use when node ORDER matters (sequence, time, story position).",
7407
+ category: "artifact",
7408
+ subcategory: "relational",
7409
+ props: [
7410
+ {
7411
+ name: "nodes",
7412
+ type: "object",
7413
+ required: true,
7414
+ description: "Array of { id, label, value? }. Display order along the baseline matches array order."
7415
+ },
7416
+ {
7417
+ name: "edges",
7418
+ type: "object",
7419
+ required: true,
7420
+ description: "Array of { source, target, value? }. Edges with missing source/target are skipped."
7421
+ },
7422
+ {
7423
+ name: "width",
7424
+ type: "number",
7425
+ required: false,
7426
+ default: 720,
7427
+ description: "SVG pixel width."
7428
+ },
7429
+ {
7430
+ name: "height",
7431
+ type: "number",
7432
+ required: false,
7433
+ default: 360,
7434
+ description: "SVG pixel height."
7435
+ },
7436
+ {
7437
+ name: "nodeRadius",
7438
+ type: "number",
7439
+ required: false,
7440
+ default: 5,
7441
+ description: "Pixel radius of each node circle."
7442
+ },
7443
+ {
7444
+ name: "onEdgeHover",
7445
+ type: "function",
7446
+ required: false,
7447
+ description: "Called with the hovered ArcEdge (or null when hover ends)."
7448
+ },
7449
+ {
7450
+ name: "onNodeClick",
7451
+ type: "function",
7452
+ required: false,
7453
+ description: "Called with the clicked ArcNode."
7454
+ },
7455
+ {
7456
+ name: "className",
7457
+ type: "string",
7458
+ required: false,
7459
+ description: "Additional CSS classes on the SVG element."
7460
+ }
7461
+ ],
7462
+ variants: [],
7463
+ slots: [],
7464
+ dependencies: {
7465
+ npm: ["clsx", "tailwind-merge"],
7466
+ internal: ["lib/utils"],
7467
+ peer: ["react", "react-dom"]
7468
+ },
7469
+ tokensUsed: ["primary", "background", "foreground"],
7470
+ examples: [
7471
+ {
7472
+ title: "Character co-occurrence",
7473
+ description: "Nodes in narrative order, arcs connect characters in the same chapter.",
7474
+ code: "<Arc\n nodes={characters}\n edges={cooccurrences}\n onEdgeHover={(e) => setActive(e)}\n/>",
7475
+ composition: ["arc", "narrative", "cooccurrence"]
7476
+ },
7477
+ {
7478
+ title: "Train route transfer connections",
7479
+ description: "Stations on a baseline; arcs show transfer connections.",
7480
+ code: "<Arc\n nodes={stations}\n edges={transfers}\n/>",
7481
+ composition: ["arc", "transit", "sequence"]
7482
+ }
7483
+ ],
7484
+ ai: {
7485
+ whenToUse: "Visualize relationships among entities WHERE THE ORDER OF ENTITIES IS MEANINGFUL \u2014 narrative co-occurrence (chapters), transit transfer points (route order), genome interactions (chromosomal position), citation networks (publication time). Arcs encode pair relationships without breaking the linear node order.",
7486
+ whenNotToUse: "Don't use when node order is arbitrary (use Chord \u2014 it places nodes on a ring with no implied order). Don't use for hierarchical relationships (use TreeMap, Sunburst, OrgChart). Don't use for >50 nodes \u2014 arcs overlap heavily; consider Matrix.",
7487
+ commonMistakes: [
7488
+ "Confusing Arc with Chord \u2014 Chord = ring (no order); Arc = baseline (order matters)",
7489
+ "Edge source/target id missing from `nodes` \u2014 silently skipped. Validate ids upstream",
7490
+ "Mutating nodes / edges between renders \u2014 the layout pass is memoized on identity"
7491
+ ],
7492
+ relatedComponents: ["chord", "matrix", "venn", "sankey"],
7493
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing node and edge counts. Interactive nodes/edges declare role="button", tabIndex, and Enter/Space activation. For agent outputs, also expose a parallel ordered list of nodes plus an adjacency table.',
7494
+ tokenBudget: 320
7495
+ },
7496
+ tags: ["artifact", "diagram", "arc", "relational", "sequence", "ordered"]
7497
+ };
7498
+
7499
+ // src/artifacts/matrix/matrix.schema.ts
7500
+ var matrixSchema = {
7501
+ name: "matrix",
7502
+ displayName: "Matrix",
7503
+ description: "Adjacency-matrix diagram. Square grid where cell color intensity encodes the relationship from row to column. Pure SVG; no heavy peer dep. Best for dense graphs that turn into hairballs in node-link form.",
7504
+ category: "artifact",
7505
+ subcategory: "relational",
7506
+ props: [
7507
+ {
7508
+ name: "nodes",
7509
+ type: "object",
7510
+ required: true,
7511
+ description: "Array of { id, label }. Used as both rows AND columns. Order matches `matrix` rows/columns."
7512
+ },
7513
+ {
7514
+ name: "matrix",
7515
+ type: "object",
7516
+ required: true,
7517
+ description: "Square N\xD7N matrix. matrix[i][j] = relationship from node i to node j. Renamed from `values` to avoid colliding with the SVG `values` animation attribute."
7518
+ },
7519
+ {
7520
+ name: "size",
7521
+ type: "number",
7522
+ required: false,
7523
+ default: 480,
7524
+ description: "Pixel size of the rendered SVG (it's square)."
7525
+ },
7526
+ {
7527
+ name: "labelMargin",
7528
+ type: "number",
7529
+ required: false,
7530
+ default: 80,
7531
+ description: "Pixel reserved for row/column labels along the top and left edges."
7532
+ },
7533
+ {
7534
+ name: "showValues",
7535
+ type: "boolean",
7536
+ required: false,
7537
+ default: true,
7538
+ description: "Show numeric values inside cells when the cell is large enough (~28px+)."
7539
+ },
7540
+ {
7541
+ name: "onCellHover",
7542
+ type: "function",
7543
+ required: false,
7544
+ description: "Called with the hovered cell's { row, col, value } (or null when hover ends)."
7545
+ },
7546
+ {
7547
+ name: "onCellClick",
7548
+ type: "function",
7549
+ required: false,
7550
+ description: "Called with the clicked cell's { row, col, value }."
7551
+ },
7552
+ {
7553
+ name: "className",
7554
+ type: "string",
7555
+ required: false,
7556
+ description: "Additional CSS classes on the SVG element."
7557
+ }
7558
+ ],
7559
+ variants: [],
7560
+ slots: [],
7561
+ dependencies: {
7562
+ npm: ["clsx", "tailwind-merge"],
7563
+ internal: ["lib/utils"],
7564
+ peer: ["react", "react-dom"]
7565
+ },
7566
+ tokensUsed: ["primary", "background", "foreground"],
7567
+ examples: [
7568
+ {
7569
+ title: "Trade flow matrix",
7570
+ description: "Cell intensity reflects flow from row region to column region.",
7571
+ code: "<Matrix\n nodes={regions}\n matrix={tradeFlow}\n onCellHover={(c) => setActive(c)}\n/>",
7572
+ composition: ["matrix", "trade-flow", "heatmap"]
7573
+ },
7574
+ {
7575
+ title: "Confusion matrix for a classifier",
7576
+ description: "Predicted vs actual labels.",
7577
+ code: "<Matrix\n nodes={classes}\n matrix={confusion}\n showValues={true}\n/>",
7578
+ composition: ["matrix", "confusion", "ml"]
7579
+ }
7580
+ ],
7581
+ ai: {
7582
+ whenToUse: "Visualize a dense relationship between many pairs of entities \u2014 adjacency matrices, confusion matrices, correlation matrices, trade-flow matrices, citation-count matrices. Scales gracefully to ~100 nodes where node-link diagrams degenerate. Use when SCALE matters more than seeing individual edges.",
7583
+ whenNotToUse: "Don't use for sparse relationships (most cells empty \u2014 Sankey or Arc surfaces the actual edges better). Don't use when the user needs to follow paths from node to node (use Canvas, Flowchart). Don't use for hierarchical data (use TreeMap, Sunburst).",
7584
+ commonMistakes: [
7585
+ "Non-square `matrix` \u2014 the component reads matrix[i][j], so missing rows or short rows render as zero. Validate dimensions upstream",
7586
+ "Mismatched length: `nodes.length` \u2260 `matrix.length` \u2014 extra nodes get blank rows; extra rows are ignored. Validate upstream",
7587
+ "Mutating `nodes` / `matrix` between renders \u2014 the layout pass is memoized on identity",
7588
+ "Asymmetric values expected to render symmetrically \u2014 the component honors per-direction values exactly as given",
7589
+ "`labelMargin` smaller than the longest node label's pixel width \u2014 labels overflow the SVG. Set `labelMargin` \u2265 ~0.75\xD7 longestLabelPx, or shorten labels upstream"
7590
+ ],
7591
+ relatedComponents: ["chord", "arc", "venn", "sankey"],
7592
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing dimensions. Interactive cells declare role="button", tabIndex, and Enter/Space activation; hover/focus fire callback symmetrically. For agent outputs, also expose a parallel <table> so screen-reader users get the values without relying on color intensity.',
7593
+ tokenBudget: 360
7594
+ },
7595
+ tags: ["artifact", "diagram", "matrix", "adjacency", "relational", "heatmap"]
7596
+ };
7597
+
7598
+ // src/artifacts/time-axis/time-axis.schema.ts
7599
+ var timeAxisSchema = {
7600
+ name: "time-axis",
7601
+ displayName: "TimeAxis",
7602
+ description: "Events plotted along a horizontal time axis. Pure SVG; no heavy peer dep. Distinct from the existing event-list `<Timeline>` \u2014 TimeAxis encodes elapsed time as horizontal distance, so the *gap between events* is the message.",
7603
+ category: "artifact",
7604
+ subcategory: "time",
7605
+ props: [
7606
+ {
7607
+ name: "events",
7608
+ type: "object",
7609
+ required: true,
7610
+ description: "Array of { id, label, date, category? }. `date` accepts Date / ISO string / epoch ms."
7611
+ },
7612
+ {
7613
+ name: "start",
7614
+ type: "object",
7615
+ required: false,
7616
+ description: "Optional explicit axis start. Auto-derived from `events` if omitted."
7617
+ },
7618
+ {
7619
+ name: "end",
7620
+ type: "object",
7621
+ required: false,
7622
+ description: "Optional explicit axis end. Auto-derived from `events` if omitted."
7623
+ },
7624
+ {
7625
+ name: "width",
7626
+ type: "number",
7627
+ required: false,
7628
+ default: 720,
7629
+ description: "SVG pixel width."
7630
+ },
7631
+ {
7632
+ name: "height",
7633
+ type: "number",
7634
+ required: false,
7635
+ default: 200,
7636
+ description: "SVG pixel height."
7637
+ },
7638
+ {
7639
+ name: "tickCount",
7640
+ type: "number",
7641
+ required: false,
7642
+ default: 6,
7643
+ description: "Number of axis ticks to show."
7644
+ },
7645
+ {
7646
+ name: "onEventClick",
7647
+ type: "function",
7648
+ required: false,
7649
+ description: "Called with the clicked TimeAxisEvent."
7650
+ },
7651
+ {
7652
+ name: "className",
7653
+ type: "string",
7654
+ required: false,
7655
+ description: "Additional CSS classes on the SVG element."
7656
+ }
7657
+ ],
7658
+ variants: [],
7659
+ slots: [],
7660
+ dependencies: {
7661
+ npm: ["clsx", "tailwind-merge"],
7662
+ internal: ["lib/utils"],
7663
+ peer: ["react", "react-dom"]
7664
+ },
7665
+ tokensUsed: ["primary", "background", "foreground", "muted-foreground"],
7666
+ examples: [
7667
+ {
7668
+ title: "Release timeline",
7669
+ description: "Major version releases plotted across a year.",
7670
+ code: '<TimeAxis events={[\n { id: "v1", label: "v1.0", date: "2025-01-15" },\n { id: "v2", label: "v2.0", date: "2025-04-20" },\n { id: "v3", label: "v3.0", date: "2025-09-10" },\n]} />',
7671
+ composition: ["time-axis", "release"]
7672
+ },
7673
+ {
7674
+ title: "Incident frequency with explicit range",
7675
+ description: "Pin the axis to the quarter to compare incident clustering.",
7676
+ code: '<TimeAxis\n start="2025-07-01"\n end="2025-09-30"\n events={incidents}\n onEventClick={(e) => router.push(`/incidents/${e.id}`)}\n/>',
7677
+ composition: ["time-axis", "incidents"]
7678
+ }
7679
+ ],
7680
+ ai: {
7681
+ whenToUse: "Plot events along a horizontal time axis where the *gap between events* matters \u2014 release cadence, incident frequency, sparse-then-dense activity, project milestones across a year. Auto-stacks overlapping events into rows.",
7682
+ whenNotToUse: "Don't use when only event ORDER matters and absolute dates are secondary (use the existing event-list `<Timeline>` in `components/`). Don't use for tasks with duration (use Gantt). Don't use for actor-message interactions (use Sequence).",
7683
+ commonMistakes: [
7684
+ 'Passing dates as strings in non-ISO formats \u2014 `new Date("01/02/2025")` is locale-dependent. Pass ISO strings (`"2025-01-02"`), Date objects, or epoch ms',
7685
+ "Forgetting to set `start`/`end` when comparing two TimeAxis renders side-by-side \u2014 auto-range scales each axis to its own events, which makes magnitudes incomparable. Pin the range explicitly",
7686
+ "Mutating `events` between renders \u2014 the layout pass is memoized on identity",
7687
+ "Confusing TimeAxis with the existing `<Timeline>` in `components/` \u2014 they coexist intentionally; pick by whether elapsed-time spacing matters"
7688
+ ],
7689
+ relatedComponents: ["gantt", "sequence", "timeline"],
7690
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing event count and axis range. Interactive event markers declare role="button", tabIndex, and Enter/Space activation. For agent outputs, also expose a parallel chronologically-ordered list of label/date pairs.',
7691
+ tokenBudget: 320
7692
+ },
7693
+ tags: ["artifact", "diagram", "time-axis", "time", "events", "chronological"]
7694
+ };
7695
+
7696
+ // src/artifacts/gantt/gantt.schema.ts
7697
+ var ganttSchema = {
7698
+ name: "gantt",
7699
+ displayName: "Gantt",
7700
+ description: "Gantt chart \u2014 tasks as horizontal bars across a time axis with optional dependency arrows and progress fills. Pure SVG; no heavy peer dep.",
7701
+ category: "artifact",
7702
+ subcategory: "time",
7703
+ props: [
7704
+ {
7705
+ name: "tasks",
7706
+ type: "object",
7707
+ required: true,
7708
+ description: "Array of { id, label, start, end, progress?, dependencies? }. `start`/`end` accept Date / ISO string / epoch ms."
7709
+ },
7710
+ {
7711
+ name: "width",
7712
+ type: "number",
7713
+ required: false,
7714
+ default: 800,
7715
+ description: "SVG pixel width."
7716
+ },
7717
+ {
7718
+ name: "rowHeight",
7719
+ type: "number",
7720
+ required: false,
7721
+ default: 32,
7722
+ description: "Pixel height of each task row."
7723
+ },
7724
+ {
7725
+ name: "labelMargin",
7726
+ type: "number",
7727
+ required: false,
7728
+ default: 140,
7729
+ description: "Pixel reserved on the left for task labels."
7730
+ },
7731
+ {
7732
+ name: "tickCount",
7733
+ type: "number",
7734
+ required: false,
7735
+ default: 6,
7736
+ description: "Number of axis ticks to show across the top."
7737
+ },
7738
+ {
7739
+ name: "onTaskClick",
7740
+ type: "function",
7741
+ required: false,
7742
+ description: "Called with the clicked GanttTask."
7743
+ },
7744
+ {
7745
+ name: "className",
7746
+ type: "string",
7747
+ required: false,
7748
+ description: "Additional CSS classes on the SVG element."
7749
+ }
7750
+ ],
7751
+ variants: [],
7752
+ slots: [],
7753
+ dependencies: {
7754
+ npm: ["clsx", "tailwind-merge"],
7755
+ internal: ["lib/utils"],
7756
+ peer: ["react", "react-dom"]
7757
+ },
7758
+ tokensUsed: ["primary", "foreground", "muted-foreground", "background"],
7759
+ examples: [
7760
+ {
7761
+ title: "Project schedule with dependencies",
7762
+ description: "Sequential tasks with dependency arrows and a progress fill.",
7763
+ code: '<Gantt tasks={[\n { id: "design", label: "Design", start: "2025-01-01", end: "2025-01-15", progress: 1 },\n { id: "build", label: "Build", start: "2025-01-10", end: "2025-02-20", progress: 0.6, dependencies: ["design"] },\n { id: "ship", label: "Ship", start: "2025-02-15", end: "2025-02-28", dependencies: ["build"] },\n]} />',
7764
+ composition: ["gantt", "schedule", "dependencies"]
7765
+ },
7766
+ {
7767
+ title: "Sprint board across two weeks",
7768
+ description: "Click a bar to open the task detail.",
7769
+ code: "<Gantt\n tasks={sprint}\n onTaskClick={(t) => router.push(`/tasks/${t.id}`)}\n/>",
7770
+ composition: ["gantt", "sprint"]
7771
+ }
7772
+ ],
7773
+ ai: {
7774
+ whenToUse: "Visualize project schedules where each task has a START and END date, plus optional dependencies and progress. Sprint boards, release plans, ETL job schedules, content publishing calendars.",
7775
+ whenNotToUse: "Don't use for point events without duration (use TimeAxis). Don't use for cyclic / recurring tasks (Gantt assumes a DAG of dependencies). Don't use for actor-message interactions (use Sequence). Don't use when the task list isn't ordered top-to-bottom by intended display order \u2014 Gantt trusts the array order.",
7776
+ commonMistakes: [
7777
+ "`end` before `start` \u2014 produces zero-or-negative width bars. Validate ranges upstream",
7778
+ "Dependency cycles \u2014 `dependencies: ['x']` where `x` transitively depends on the current task. The component still renders bars, but the arrow paths cross awkwardly. Validate the dependency DAG upstream",
7779
+ "Missing dependency target \u2014 `dependencies: ['ghost']` where `ghost` isn't in `tasks`. The arrow is silently skipped",
7780
+ 'Passing dates as locale-dependent strings (`"01/02/2025"`) \u2014 pass ISO (`"2025-01-02"`), Date, or epoch ms',
7781
+ "Mutating tasks between renders \u2014 the layout pass is memoized on identity"
7782
+ ],
7783
+ relatedComponents: ["time-axis", "sequence", "timeline", "flowchart"],
7784
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing task count and date range. Interactive task bars declare role="button", tabIndex, and Enter/Space activation. The aria-label includes label, date range, and progress percent. For agent outputs, also expose a parallel ordered list of tasks with their dates.',
7785
+ tokenBudget: 360
7786
+ },
7787
+ tags: ["artifact", "diagram", "gantt", "time", "schedule", "tasks"]
7788
+ };
7789
+
7790
+ // src/artifacts/sequence/sequence.schema.ts
7791
+ var sequenceSchema = {
7792
+ name: "sequence",
7793
+ displayName: "Sequence",
7794
+ description: "UML-style sequence diagram. Actors as columns with vertical lifelines; messages as horizontal arrows in declaration order. Pure SVG; no heavy peer dep.",
7795
+ category: "artifact",
7796
+ subcategory: "time",
7797
+ props: [
7798
+ {
7799
+ name: "actors",
7800
+ type: "object",
7801
+ required: true,
7802
+ description: "Array of { id, label }. Display order matches array order (left-to-right columns)."
7803
+ },
7804
+ {
7805
+ name: "messages",
7806
+ type: "object",
7807
+ required: true,
7808
+ description: "Array of { from, to, label?, type? }. Chronological order matches array order (top-to-bottom). Messages whose `from` or `to` actor id is missing are silently skipped."
7809
+ },
7810
+ {
7811
+ name: "width",
7812
+ type: "number",
7813
+ required: false,
7814
+ default: 720,
7815
+ description: "SVG pixel width."
7816
+ },
7817
+ {
7818
+ name: "headerHeight",
7819
+ type: "number",
7820
+ required: false,
7821
+ default: 40,
7822
+ description: "Pixel height of each actor header."
7823
+ },
7824
+ {
7825
+ name: "messageGap",
7826
+ type: "number",
7827
+ required: false,
7828
+ default: 36,
7829
+ description: "Pixel vertical gap between consecutive messages."
7830
+ },
7831
+ {
7832
+ name: "onActorClick",
7833
+ type: "function",
7834
+ required: false,
7835
+ description: "Called with the clicked SequenceActor."
7836
+ },
7837
+ {
7838
+ name: "onMessageClick",
7839
+ type: "function",
7840
+ required: false,
7841
+ description: "Called with the clicked SequenceMessage."
7842
+ },
7843
+ {
7844
+ name: "className",
7845
+ type: "string",
7846
+ required: false,
7847
+ description: "Additional CSS classes on the SVG element."
7848
+ }
7849
+ ],
7850
+ variants: [],
7851
+ slots: [],
7852
+ dependencies: {
7853
+ npm: ["clsx", "tailwind-merge"],
7854
+ internal: ["lib/utils"],
7855
+ peer: ["react", "react-dom"]
7856
+ },
7857
+ tokensUsed: ["card", "border", "foreground", "muted-foreground", "background"],
7858
+ examples: [
7859
+ {
7860
+ title: "Signup flow",
7861
+ description: "User \u2192 API \u2192 DB with return arrows.",
7862
+ code: '<Sequence\n actors={[\n { id: "user", label: "User" },\n { id: "api", label: "API" },\n { id: "db", label: "DB" },\n ]}\n messages={[\n { from: "user", to: "api", label: "POST /signup" },\n { from: "api", to: "db", label: "INSERT user" },\n { from: "db", to: "api", label: "ok", type: "return" },\n { from: "api", to: "user", label: "201 Created", type: "return" },\n ]}\n/>',
7863
+ composition: ["sequence", "api-flow"]
7864
+ },
7865
+ {
7866
+ title: "Self-call (loopback) message",
7867
+ description: "An actor calling itself renders as a loopback arrow.",
7868
+ code: '<Sequence\n actors={[{ id: "worker", label: "Worker" }]}\n messages={[{ from: "worker", to: "worker", label: "retry" }]}\n/>',
7869
+ composition: ["sequence", "self-call"]
7870
+ }
7871
+ ],
7872
+ ai: {
7873
+ whenToUse: "Visualize WHO talks to WHO and IN WHAT ORDER \u2014 API request flows, distributed-system protocols, agent tool-call sequences, OAuth dance, message-queue choreography. Use when the order and direction of messages between actors is the message.",
7874
+ whenNotToUse: "Don't use for branching process diagrams (use Flowchart). Don't use for events along a real time axis (use TimeAxis). Don't use for tasks with duration (use Gantt). Don't use for >~8 actors \u2014 columns become too narrow to read messages on.",
7875
+ commonMistakes: [
7876
+ "`from` or `to` referencing an id missing from `actors` \u2014 the message is silently skipped. Validate ids upstream",
7877
+ "Mutating actors / messages between renders \u2014 the layout pass is memoized on identity",
7878
+ "Reordering `actors` to fix layout while keeping message ordering \u2014 that flips the visual flow direction. Order actors by their natural left-to-right reading order",
7879
+ 'Using `type: "return"` for forward-going messages \u2014 the dashed style implies a reply, so confused readers expect a prior outgoing message'
7880
+ ],
7881
+ relatedComponents: ["flowchart", "time-axis", "gantt", "canvas", "diagram"],
7882
+ accessibilityNotes: 'The SVG carries role="img" with a <title> and <desc> summarizing actor and message counts. Interactive actor headers and message arrows declare role="button", tabIndex, and Enter/Space activation. The aria-label on each message includes its index, source/target labels, and content. For agent outputs, also expose a parallel ordered list of messages with their from/to/label triples.',
7883
+ tokenBudget: 360
7884
+ },
7885
+ tags: ["artifact", "diagram", "sequence", "uml", "time", "messaging"]
7886
+ };
7887
+
7888
+ // src/artifacts/flashcard/flashcard.schema.ts
7889
+ var flashcardSchema = {
7890
+ name: "flashcard",
7891
+ displayName: "Flashcard",
7892
+ description: "Front/back card with a 3D flip animation on click. Pure CSS 3D transform; no animation peer. Headless on content \u2014 front and back accept any ReactNode. Pairs with Deck for session-level paging and SpacedRepetition for confidence rating.",
7893
+ category: "artifact",
7894
+ subcategory: "study",
7895
+ props: [
7896
+ {
7897
+ name: "front",
7898
+ type: "ReactNode",
7899
+ required: true,
7900
+ description: "Content of the front face."
7901
+ },
7902
+ {
7903
+ name: "back",
7904
+ type: "ReactNode",
7905
+ required: true,
7906
+ description: "Content of the back face."
7907
+ },
7908
+ {
7909
+ name: "defaultFlipped",
7910
+ type: "boolean",
7911
+ required: false,
7912
+ default: false,
7913
+ description: "Uncontrolled initial flipped state."
7914
+ },
7915
+ {
7916
+ name: "flipped",
7917
+ type: "boolean",
7918
+ required: false,
7919
+ description: "Controlled flipped state. When set, internal state is ignored."
7920
+ },
7921
+ {
7922
+ name: "onFlipChange",
7923
+ type: "function",
7924
+ required: false,
7925
+ description: "Called with the new flipped value when the user toggles."
7926
+ },
7927
+ {
7928
+ name: "width",
7929
+ type: "number",
7930
+ required: false,
7931
+ default: 360,
7932
+ description: "Pixel width."
7933
+ },
7934
+ {
7935
+ name: "height",
7936
+ type: "number",
7937
+ required: false,
7938
+ default: 240,
7939
+ description: "Pixel height."
7940
+ },
7941
+ {
7942
+ name: "flipDurationMs",
7943
+ type: "number",
7944
+ required: false,
7945
+ default: 500,
7946
+ description: "Flip animation duration in ms. Set to 0 to disable the animation entirely."
7947
+ },
7948
+ {
7949
+ name: "className",
7950
+ type: "string",
7951
+ required: false,
7952
+ description: "Additional CSS classes on the outer container."
7953
+ }
7954
+ ],
7955
+ variants: [],
7956
+ slots: [
7957
+ {
7958
+ name: "front",
7959
+ description: "Front face of the card \u2014 typically the prompt / question / term.",
7960
+ required: true
7961
+ },
7962
+ {
7963
+ name: "back",
7964
+ description: "Back face of the card \u2014 typically the answer / definition.",
7965
+ required: true
7966
+ }
7967
+ ],
7968
+ dependencies: {
7969
+ npm: ["clsx", "tailwind-merge"],
7970
+ internal: ["lib/utils"],
7971
+ peer: ["react", "react-dom"]
7972
+ },
7973
+ tokensUsed: ["card", "card-foreground", "border", "ring"],
7974
+ examples: [
7975
+ {
7976
+ title: "Capital city flashcard",
7977
+ description: "Classic question-answer card with default uncontrolled state.",
7978
+ code: '<Flashcard front="What is the capital of France?" back="Paris" />',
7979
+ composition: ["flashcard", "study", "qa"]
7980
+ },
7981
+ {
7982
+ title: "Controlled flashcard inside a Deck",
7983
+ description: "Parent owns the flipped state to coordinate with progress tracking.",
7984
+ code: "<Flashcard\n flipped={isFlipped}\n onFlipChange={setFlipped}\n front={term}\n back={definition}\n/>",
7985
+ composition: ["flashcard", "controlled"]
7986
+ }
7987
+ ],
7988
+ ai: {
7989
+ whenToUse: "Render a single self-test prompt where the user retrieves an answer from memory before checking. Vocabulary terms, formula reminders, anatomy labels, code snippets \u2014 anywhere the active-recall pattern (think first, then flip) fits.",
7990
+ whenNotToUse: "Don't use for multiple-choice questions (use Quiz). Don't use for fill-in-the-blank (use Cloze). Don't use for image regions (use ImageOcclusion). Don't use as a generic content card with no flip semantics (use the existing `Card` in components/).",
7991
+ commonMistakes: [
7992
+ "Putting the answer on the front \u2014 defeats the active-recall pattern. Front should be the prompt only",
7993
+ "Mixing controlled and uncontrolled use \u2014 pass either `flipped` (controlled) or rely on `defaultFlipped` + internal state, not both",
7994
+ "Wrapping a Flashcard in another clickable parent \u2014 Enter / Space activations bubble; the parent's onClick fires too. Stop propagation in the wrapper or move the click handler",
7995
+ "Sizing the card to 0\xD70 \u2014 the 3D transform requires non-zero dimensions to avoid the back face leaking through during the rotation"
7996
+ ],
7997
+ relatedComponents: ["cloze", "quiz", "image-occlusion", "deck", "spaced-repetition", "card"],
7998
+ accessibilityNotes: `The card declares role="button", tabIndex=0, aria-pressed reflecting flipped state, and an aria-label that announces the current side. Enter and Space toggle the flip; Space's default page-scroll is preventDefaulted. Screen readers see both faces in DOM at all times \u2014 that's intentional so the back face is announced after the flip without a content swap.`,
7999
+ tokenBudget: 280
8000
+ },
8001
+ tags: ["artifact", "study", "flashcard", "active-recall", "card"]
8002
+ };
8003
+
8004
+ // src/artifacts/cloze/cloze.schema.ts
8005
+ var clozeSchema = {
8006
+ name: "cloze",
8007
+ displayName: "Cloze",
8008
+ description: "Cloze-deletion text \u2014 sentences with redacted spans the learner reveals one at a time (or all at once). Pure HTML; no heavy peer.",
8009
+ category: "artifact",
8010
+ subcategory: "study",
8011
+ props: [
8012
+ {
8013
+ name: "parts",
8014
+ type: "object",
8015
+ required: true,
8016
+ description: "Mixed array of string fragments and { hidden, id? } cloze tokens. Each `hidden` value is the text the learner has to recall."
8017
+ },
8018
+ {
8019
+ name: "revealMode",
8020
+ type: "enum",
8021
+ required: false,
8022
+ default: "click",
8023
+ description: '"click" \u2014 reveals one blank at a time (default). "all" \u2014 adds a "Reveal all" toggle that flips every blank in one shot.',
8024
+ enumValues: ["click", "all"]
8025
+ },
8026
+ {
8027
+ name: "onReveal",
8028
+ type: "function",
8029
+ required: false,
8030
+ description: "Called with the cumulative array of revealed blank ids whenever a blank toggles."
8031
+ },
8032
+ {
8033
+ name: "className",
8034
+ type: "string",
8035
+ required: false,
8036
+ description: "Additional CSS classes on the outer container."
8037
+ }
8038
+ ],
8039
+ variants: [],
8040
+ slots: [],
8041
+ dependencies: {
8042
+ npm: ["clsx", "tailwind-merge"],
8043
+ internal: ["lib/utils"],
8044
+ peer: ["react", "react-dom"]
8045
+ },
8046
+ tokensUsed: ["primary", "muted", "foreground", "background", "border", "ring"],
8047
+ examples: [
8048
+ {
8049
+ title: "Single-blank biology fact",
8050
+ description: "Classic cloze with one redacted term.",
8051
+ code: '<Cloze parts={[\n "The mitochondria is the ",\n { hidden: "powerhouse" },\n " of the cell.",\n]} />',
8052
+ composition: ["cloze", "study", "fill-in"]
8053
+ },
8054
+ {
8055
+ title: "Multi-blank with reveal-all",
8056
+ description: 'Useful when consumers want a quick "show me everything" escape hatch.',
8057
+ code: '<Cloze\n revealMode="all"\n parts={[\n "The capital of ",\n { hidden: "France" },\n " is ",\n { hidden: "Paris" },\n ".",\n ]}\n/>',
8058
+ composition: ["cloze", "multi-blank"]
8059
+ }
8060
+ ],
8061
+ ai: {
8062
+ whenToUse: "Render a sentence-level fill-in-the-blank where the learner can target ANY missing piece independently \u2014 vocabulary in context, formula completion, code snippets with redacted operators. Especially strong when the surrounding context is the cue.",
8063
+ whenNotToUse: "Don't use for question-answer pairs (use Flashcard). Don't use for multiple-choice (use Quiz). Don't use for image labels (use ImageOcclusion). Don't use when blanks should be free-typed and graded \u2014 Cloze is reveal-only.",
8064
+ commonMistakes: [
8065
+ "Putting too much text in a single hidden token \u2014 the redacted block becomes the entire sentence and there's no context left to cue recall. Keep hidden segments to 1\u20133 words",
8066
+ "Forgetting that string fragments matter \u2014 `parts: [{hidden:'a'},{hidden:'b'}]` produces two adjacent blanks with no surrounding text. The cue context lives in the string fragments between blanks",
8067
+ "Reusing the same explicit `id` across multiple blanks \u2014 they reveal together because revealed-state keys off id. Either omit `id` (auto-numbered with a non-collidable prefix) or give each blank a unique id",
8068
+ "Mutating `parts` between renders \u2014 the layout pass is memoized on identity",
8069
+ "Treating Cloze as anti-cheating \u2014 the hidden text always lives in the DOM (transparent + user-select:none) so screen readers can announce it after reveal. A determined sighted user can still inspect element. Cloze is a recall *aid*, not a *secret*"
8070
+ ],
8071
+ relatedComponents: ["flashcard", "quiz", "image-occlusion", "deck", "spaced-repetition"],
8072
+ accessibilityNotes: `Each blank renders as a real <button> with type="button", aria-pressed reflecting reveal state, and an aria-label that names the blank's index and total. The hidden text always lives in the DOM (transparent when unrevealed) so screen readers announce the answer once aria-pressed flips. Enter and Space activate via the native button behavior.`,
8073
+ tokenBudget: 280
8074
+ },
8075
+ tags: ["artifact", "study", "cloze", "fill-in-the-blank", "active-recall"]
8076
+ };
8077
+
8078
+ // src/artifacts/image-occlusion/image-occlusion.schema.ts
8079
+ var imageOcclusionSchema = {
8080
+ name: "image-occlusion",
8081
+ displayName: "ImageOcclusion",
8082
+ description: "Image with rectangular regions hidden behind opaque overlays. Click any region to reveal what's underneath. Pure HTML; no heavy peer. Coordinates are 0\u20131 fractions so the layout stays correct at any rendered size.",
8083
+ category: "artifact",
8084
+ subcategory: "study",
8085
+ props: [
8086
+ {
8087
+ name: "src",
8088
+ type: "string",
8089
+ required: true,
8090
+ description: "Image source URL."
8091
+ },
8092
+ {
8093
+ name: "alt",
8094
+ type: "string",
8095
+ required: true,
8096
+ description: "Alt text for the underlying image."
8097
+ },
8098
+ {
8099
+ name: "regions",
8100
+ type: "object",
8101
+ required: true,
8102
+ description: "Array of { id, x, y, width, height, label? }. All coords are 0\u20131 fractions of the rendered image."
8103
+ },
8104
+ {
8105
+ name: "onRegionReveal",
8106
+ type: "function",
8107
+ required: false,
8108
+ description: "Called with the region id when a region is revealed (NOT when hidden again)."
8109
+ },
8110
+ {
8111
+ name: "className",
8112
+ type: "string",
8113
+ required: false,
8114
+ description: "Additional CSS classes on the outer container."
8115
+ }
8116
+ ],
8117
+ variants: [],
8118
+ slots: [],
8119
+ dependencies: {
8120
+ npm: ["clsx", "tailwind-merge"],
8121
+ internal: ["lib/utils"],
8122
+ peer: ["react", "react-dom"]
8123
+ },
8124
+ tokensUsed: ["primary", "ring"],
8125
+ examples: [
8126
+ {
8127
+ title: "Anatomy diagram",
8128
+ description: "Heart cross-section with named chambers occluded.",
8129
+ code: '<ImageOcclusion\n src="/anatomy/heart.png"\n alt="Cross-section of a human heart"\n regions={[\n { id: "lv", x: 0.42, y: 0.55, width: 0.18, height: 0.22, label: "Left ventricle" },\n { id: "ra", x: 0.58, y: 0.20, width: 0.16, height: 0.18, label: "Right atrium" },\n ]}\n/>',
8130
+ composition: ["image-occlusion", "anatomy"]
8131
+ },
8132
+ {
8133
+ title: "Code snippet with redacted operators",
8134
+ description: "Hide language operators and have the learner reveal them.",
8135
+ code: '<ImageOcclusion\n src="/code/snippet.png"\n alt="JavaScript array map"\n regions={[\n { id: "op1", x: 0.30, y: 0.10, width: 0.05, height: 0.08 },\n ]}\n onRegionReveal={(id) => track(id)}\n/>',
8136
+ composition: ["image-occlusion", "code"]
8137
+ }
8138
+ ],
8139
+ ai: {
8140
+ whenToUse: "Hide labels or sub-regions of a visual the learner needs to recall. Anatomy diagrams, geographic maps, code snippets, anatomical illustrations, mathematical figures \u2014 any image where the recall target is a region rather than the whole.",
8141
+ whenNotToUse: "Don't use for text-only fill-in-the-blank (use Cloze). Don't use when the entire image is the answer (use Flashcard with the image on `back`). Don't use when regions overlap heavily \u2014 overlapping overlays interfere with click targets.",
8142
+ commonMistakes: [
8143
+ "Passing pixel coordinates instead of fractions \u2014 `x: 168` instead of `x: 0.42`. The component warns in dev when any region's coords escape [0, 1]",
8144
+ "Region rectangles smaller than ~20px square \u2014 too tiny to hit on touch devices. Aim for \u226540 \xD7 40px at the rendered image size",
8145
+ "Heavily overlapping regions \u2014 later array entries get higher z-index and catch the click; regions earlier in the array are visible but unclickable underneath. Order regions back-to-front (largest/outermost first, smallest/innermost last)",
8146
+ "Mutating the regions array between renders \u2014 react re-runs reveal state, but the input identity matters for any downstream memoization. Memoize the regions array"
8147
+ ],
8148
+ relatedComponents: ["flashcard", "cloze", "quiz", "deck", "spaced-repetition"],
8149
+ accessibilityNotes: `Each overlay is a real <button> with type="button", aria-pressed reflecting reveal state, and an aria-label that names the region's index, total, and label (when provided). The underlying <img> carries the user-supplied alt text. The decorative overlay container is aria-hidden so screen readers don't double-announce regions.`,
8150
+ tokenBudget: 320
8151
+ },
8152
+ tags: ["artifact", "study", "image-occlusion", "active-recall", "visual"]
8153
+ };
8154
+
8155
+ // src/artifacts/quiz/quiz.schema.ts
8156
+ var quizSchema = {
8157
+ name: "quiz",
8158
+ displayName: "Quiz",
8159
+ description: 'Single-question multiple-choice quiz with submit + reveal. After submit, each option is tagged data-state="correct|incorrect|missed" so consumers can theme right / wrong / unselected-but-correct independently. Pure HTML; no heavy peer.',
8160
+ category: "artifact",
8161
+ subcategory: "study",
8162
+ props: [
8163
+ {
8164
+ name: "question",
8165
+ type: "ReactNode",
8166
+ required: true,
8167
+ description: "The question prompt \u2014 accepts any rich content."
8168
+ },
8169
+ {
8170
+ name: "options",
8171
+ type: "object",
8172
+ required: true,
8173
+ description: "Array of { id, label, correct?, explanation? }. `correct: true` flags the right answer(s); `explanation` renders below the option after submit."
8174
+ },
8175
+ {
8176
+ name: "selectionMode",
8177
+ type: "enum",
8178
+ required: false,
8179
+ default: "single",
8180
+ description: '"single" \u2014 radio inputs (one pick); "multi" \u2014 checkboxes (zero or more picks).',
8181
+ enumValues: ["single", "multi"]
8182
+ },
8183
+ {
8184
+ name: "submitLabel",
8185
+ type: "string",
8186
+ required: false,
8187
+ default: "Submit",
8188
+ description: "Custom Submit button text."
8189
+ },
8190
+ {
8191
+ name: "onAnswer",
8192
+ type: "function",
8193
+ required: false,
8194
+ description: "Called with (selectedIds, allCorrect) on submit. `allCorrect` is true only when the picked set equals the correct set exactly (multi-select must include all correct AND nothing extra)."
8195
+ },
8196
+ {
8197
+ name: "className",
8198
+ type: "string",
8199
+ required: false,
8200
+ description: "Additional CSS classes on the outer container."
8201
+ }
8202
+ ],
8203
+ variants: [],
8204
+ slots: [],
8205
+ dependencies: {
8206
+ npm: ["clsx", "tailwind-merge"],
8207
+ internal: ["lib/utils"],
8208
+ peer: ["react", "react-dom"]
8209
+ },
8210
+ tokensUsed: ["card", "card-foreground", "background", "border", "primary", "primary-foreground", "destructive", "muted", "muted-foreground", "ring"],
8211
+ examples: [
8212
+ {
8213
+ title: "Single-answer geography",
8214
+ description: "Standard one-correct multiple choice.",
8215
+ code: '<Quiz\n question="Which planet is closest to the sun?"\n options={[\n { id: "m", label: "Mercury", correct: true },\n { id: "v", label: "Venus" },\n { id: "e", label: "Earth" },\n { id: "ma", label: "Mars" },\n ]}\n/>',
8216
+ composition: ["quiz", "single-answer"]
8217
+ },
8218
+ {
8219
+ title: "Multi-answer with explanations",
8220
+ description: "Multiple correct options + per-option explanations after submit.",
8221
+ code: `<Quiz
8222
+ question="Which planets are gas giants?"
8223
+ selectionMode="multi"
8224
+ options={[
8225
+ { id: "j", label: "Jupiter", correct: true },
8226
+ { id: "v", label: "Venus" },
8227
+ { id: "s", label: "Saturn", correct: true, explanation: "Saturn's atmosphere is mostly H/He." },
8228
+ ]}
8229
+ />`,
8230
+ composition: ["quiz", "multi-answer", "explanation"]
8231
+ }
8232
+ ],
8233
+ ai: {
8234
+ whenToUse: "Render a single self-test question with N preset answers. Vocabulary multiple choice, fact-based questions, code-output predictions, comprehension checks. Use when answers are constrained to a finite set the consumer can author upfront.",
8235
+ whenNotToUse: "Don't use for free-form recall (use Flashcard or Cloze). Don't use for image regions (use ImageOcclusion). Don't use for multi-question quizzes \u2014 Quiz is a single-question primitive; consumers compose their own state to chain multiple instances. Don't use when the answer is graded server-side after submit \u2014 Quiz reveals correctness immediately on submit, no async hook.",
8236
+ commonMistakes: [
8237
+ "Forgetting `correct: true` on any option in multi-select mode \u2014 `allCorrect` will fire as `true` only if picked-set equals correct-set, so a quiz with no correct options reports allCorrect on an empty selection",
8238
+ "Putting the explanation on the wrong option \u2014 explanations are intentionally only shown for `correct` / `incorrect` / `missed` cells (not `unanswered`), so a learner sees the explanation for what they missed, what they got wrong, and what they got right",
8239
+ "Re-mounting the Quiz to reset state \u2014 that works, but it's cheaper to clear the parent's options key (or pass a controlled `selectedIds` prop in a future iteration)",
8240
+ "Long questions or labels exceeding ~60 characters \u2014 line-wrapping inside the option list shrinks the click target. Trim or break at a natural punctuation point"
8241
+ ],
8242
+ relatedComponents: ["flashcard", "cloze", "image-occlusion", "deck", "spaced-repetition", "radio-group", "checkbox"],
8243
+ accessibilityNotes: `The options list declares role="radiogroup" (single mode) or role="group" (multi mode). Native <input type="radio|checkbox"> handles keyboard navigation (arrow keys for radios, tab+space for checkboxes). The status line uses role="status" + aria-live="polite" so screen readers announce correctness after submit. Each option's data-state encodes correctness for theming AND offers a hook for screen-reader-only labels if a future iteration adds them.`,
8244
+ tokenBudget: 360
8245
+ },
8246
+ tags: ["artifact", "study", "quiz", "multiple-choice", "active-recall"]
8247
+ };
8248
+
8249
+ // src/artifacts/compare-table/compare-table.schema.ts
8250
+ var compareTableSchema = {
8251
+ name: "compare-table",
8252
+ displayName: "CompareTable",
8253
+ description: "Side-by-side comparison table. Subjects are columns; attributes are rows; cells render the per-subject value for each attribute. Optional difference highlighting flags cells that diverge from the row's reference. Pure HTML; no heavy peer.",
8254
+ category: "artifact",
8255
+ subcategory: "study",
8256
+ props: [
8257
+ {
8258
+ name: "subjects",
8259
+ type: "object",
8260
+ required: true,
8261
+ description: "Array of { id, label }. Renders as columns; display order matches array order."
8262
+ },
8263
+ {
8264
+ name: "attributes",
8265
+ type: "object",
8266
+ required: true,
8267
+ description: 'Array of { id, label, values }. Renders as rows; `values` is a subjectId \u2192 ReactNode map. Missing keys render as "\u2014".'
8268
+ },
8269
+ {
8270
+ name: "highlightDifferences",
8271
+ type: "boolean",
8272
+ required: false,
8273
+ default: false,
8274
+ description: "When true, cells whose value differs from the row's first non-empty cell get a subtle accent."
8275
+ },
8276
+ {
8277
+ name: "onCellClick",
8278
+ type: "function",
8279
+ required: false,
8280
+ description: "Called with (subjectId, attributeId) when a body cell is clicked."
8281
+ },
8282
+ {
8283
+ name: "className",
8284
+ type: "string",
8285
+ required: false,
8286
+ description: "Additional CSS classes on the outer container."
8287
+ }
8288
+ ],
8289
+ variants: [],
8290
+ slots: [],
8291
+ dependencies: {
8292
+ npm: ["clsx", "tailwind-merge"],
8293
+ internal: ["lib/utils"],
8294
+ peer: ["react", "react-dom"]
8295
+ },
8296
+ tokensUsed: ["card", "border", "muted", "muted-foreground", "accent", "accent-foreground"],
8297
+ examples: [
8298
+ {
8299
+ title: "Operating system comparison",
8300
+ description: "Three subjects, two attributes, with difference highlighting.",
8301
+ code: '<CompareTable\n highlightDifferences\n subjects={[\n { id: "linux", label: "Linux" },\n { id: "mac", label: "Mac" },\n { id: "win", label: "Windows" },\n ]}\n attributes={[\n { id: "kernel", label: "Kernel", values: { linux: "Linux", mac: "Darwin", win: "NT" } },\n { id: "fs", label: "Default FS", values: { linux: "ext4", mac: "APFS", win: "NTFS" } },\n ]}\n/>',
8302
+ composition: ["compare-table", "comparison", "feature-matrix"]
8303
+ },
8304
+ {
8305
+ title: "Vocabulary pairs",
8306
+ description: "Two-column term \u2194 translation table.",
8307
+ code: '<CompareTable\n subjects={[\n { id: "en", label: "English" },\n { id: "es", label: "Spanish" },\n ]}\n attributes={[\n { id: "1", label: "Hello", values: { en: "Hello", es: "Hola" } },\n { id: "2", label: "Thank you", values: { en: "Thank you", es: "Gracias" } },\n ]}\n/>',
8308
+ composition: ["compare-table", "vocabulary"]
8309
+ }
8310
+ ],
8311
+ ai: {
8312
+ whenToUse: "Compare 2\u20136 subjects across 2\u201320 attributes when the user wants to see same-row differences at a glance. Vocab translations, OS feature matrices, framework comparisons, before/after, drug-vs-drug. Use `highlightDifferences` whenever the row's *divergence* is the message.",
8313
+ whenNotToUse: "Don't use for 1 subject (use a regular description list). Don't use for >6 subjects \u2014 columns shrink past readability; use a card grid instead. Don't use when cells contain rich nested layouts (consider DataTable). Don't use for a single learner-recall task \u2014 use Flashcard, Cloze, or Quiz instead.",
8314
+ commonMistakes: [
8315
+ "Including a value with a subjectId that isn't in the subjects array \u2014 the cell silently doesn't render. The component warns in dev when this happens",
8316
+ 'Expecting `highlightDifferences` to compare ReactElement cells \u2014 diff is skipped automatically when either the raw value or the row\'s reference is non-primitive (object). Cells render but never flag as `data-differs="true"`. Stringify upstream if you need diffing on rich content',
8317
+ "Mutating subjects / attributes between renders \u2014 React re-renders fine, but downstream memoization in consumer code may cache stale references. Rebuild the arrays from immutable sources",
8318
+ "Long labels in subject headers (>20 chars) \u2014 they wrap and inflate the row height across the whole table. Use abbreviations + tooltips when needed"
8319
+ ],
8320
+ relatedComponents: ["flashcard", "quiz", "cloze", "data-table", "table"],
8321
+ accessibilityNotes: 'Renders a real <table> with semantic <thead>/<tbody>/<th scope="col|row">/<td>. The first column is sticky so attribute labels stay visible during horizontal scroll on narrow viewports. Each cell carries data-subject-id and data-attribute-id for any consumer-driven aria-label or selection behavior. The diff-highlighted cells rely on color alone today \u2014 pair with a per-row screen-reader-only summary for AA-strict consumers.',
8322
+ tokenBudget: 320
8323
+ },
8324
+ tags: ["artifact", "study", "compare-table", "comparison", "matrix"]
8325
+ };
8326
+
8327
+ // src/artifacts/deck/deck.schema.ts
8328
+ var deckSchema = {
8329
+ name: "deck",
8330
+ displayName: "Deck",
8331
+ description: "Paged sequence of flashcards with optional shuffle, prev/next navigation, a progress bar, and a render slot for per-card SRS rating. Composes Flashcard internally.",
8332
+ category: "artifact",
8333
+ subcategory: "study",
8334
+ props: [
8335
+ {
8336
+ name: "cards",
8337
+ type: "object",
8338
+ required: true,
8339
+ description: "Array of { id, front, back }. Display order matches array order unless `shuffle` is set."
8340
+ },
8341
+ {
8342
+ name: "shuffle",
8343
+ type: "boolean",
8344
+ required: false,
8345
+ default: false,
8346
+ description: "Initial shuffle. Order recomputes only when `cards` identity changes \u2014 not on every prev/next, so the user never gets re-shuffled mid-session."
8347
+ },
8348
+ {
8349
+ name: "ratingSlot",
8350
+ type: "function",
8351
+ required: false,
8352
+ description: "Optional render function called with the current card; renders below the deck. Used to compose SpacedRepetition under each card."
8353
+ },
8354
+ {
8355
+ name: "onCardChange",
8356
+ type: "function",
8357
+ required: false,
8358
+ description: "Called with (index, card) whenever the active card changes (after prev / next)."
8359
+ },
8360
+ {
8361
+ name: "cardWidth",
8362
+ type: "number",
8363
+ required: false,
8364
+ default: 360,
8365
+ description: "Pixel width of the inner Flashcard."
8366
+ },
8367
+ {
8368
+ name: "cardHeight",
8369
+ type: "number",
8370
+ required: false,
8371
+ default: 240,
8372
+ description: "Pixel height of the inner Flashcard."
8373
+ },
8374
+ {
8375
+ name: "className",
8376
+ type: "string",
8377
+ required: false,
8378
+ description: "Additional CSS classes on the outer container."
8379
+ }
8380
+ ],
8381
+ variants: [],
8382
+ slots: [
8383
+ {
8384
+ name: "ratingSlot",
8385
+ description: "Render-prop slot called with the current card; ideal for SpacedRepetition's onRate emission.",
8386
+ required: false
8387
+ }
8388
+ ],
8389
+ dependencies: {
8390
+ npm: ["clsx", "tailwind-merge"],
8391
+ internal: ["lib/utils", "artifacts/flashcard/flashcard"],
8392
+ peer: ["react", "react-dom"]
8393
+ },
8394
+ tokensUsed: ["card", "background", "muted", "muted-foreground", "primary", "border", "ring"],
8395
+ examples: [
8396
+ {
8397
+ title: "Vocabulary deck with shuffle",
8398
+ description: "Three cards, shuffled on first render.",
8399
+ code: '<Deck\n shuffle\n cards={[\n { id: "1", front: "Hello", back: "Hola" },\n { id: "2", front: "Thank you", back: "Gracias" },\n { id: "3", front: "Goodbye", back: "Adi\xF3s" },\n ]}\n/>',
8400
+ composition: ["deck", "vocabulary"]
8401
+ },
8402
+ {
8403
+ title: "Deck composed with SpacedRepetition rating",
8404
+ description: "Each card surfaces an Anki-style rating row after flip.",
8405
+ code: "<Deck\n cards={cards}\n ratingSlot={(card) => (\n <SpacedRepetition cardId={card.id} onRate={(r) => save(r, card.id)} />\n )}\n/>",
8406
+ composition: ["deck", "srs"]
8407
+ }
8408
+ ],
8409
+ ai: {
8410
+ whenToUse: "Render an ordered (or shuffled) study session of N flashcards with prev/next navigation and progress feedback. Use when the user is grinding through a deck end-to-end. Pair with SpacedRepetition via `ratingSlot` for Anki-style review sessions.",
8411
+ whenNotToUse: "Don't use for a single card (just render Flashcard directly). Don't use when navigation is non-linear (skip-around, jump-to-id) \u2014 Deck is strictly sequential. Don't use for grading multiple-question quizzes (use Quiz directly + your own state). Don't use when shuffle should be reproducible across sessions \u2014 `Math.random()` is non-seeded; pre-shuffle in your data layer and pass `shuffle={false}`.",
8412
+ commonMistakes: [
8413
+ "Toggling `shuffle` mid-session \u2014 the deck recomputes order and resets to card 1. Set `shuffle` once at mount or pre-shuffle in the consumer's data layer",
8414
+ "Mutating the cards array in place \u2014 internal layout treats `cards` as immutable; spread or rebuild from source on each change",
8415
+ "Card ids that aren't unique \u2014 React's reconciliation depends on the unique id key for Flashcard. Duplicate ids cause stale flip state to leak between cards",
8416
+ "Putting interactive content inside `front` / `back` that's also clickable \u2014 those click events bubble to Flashcard's flip handler. Stop propagation in the inner click handler"
8417
+ ],
8418
+ relatedComponents: ["flashcard", "spaced-repetition", "cloze", "quiz", "progress"],
8419
+ accessibilityNotes: `Prev / Next buttons declare aria-label including current and total positions ("Next card. Currently 3 of 12."). The progress bar is aria-hidden because the same information is in the visible '3 / 12' label and in the button labels. The inner Flashcard owns its own ARIA semantics; flipping it via Enter/Space works while the deck nav buttons remain accessible via tab order.`,
8420
+ tokenBudget: 320
8421
+ },
8422
+ tags: ["artifact", "study", "deck", "flashcard", "session"]
8423
+ };
8424
+
8425
+ // src/artifacts/spaced-repetition/spaced-repetition.schema.ts
8426
+ var spacedRepetitionSchema = {
8427
+ name: "spaced-repetition",
8428
+ displayName: "SpacedRepetition",
8429
+ description: "Anki-style confidence rating row \u2014 four buttons (Again / Hard / Good / Easy) that emit a rating signal. Headless on scheduling: consumers wire SM-2, FSRS, or any other algorithm; this primitive just captures the learner's signal.",
8430
+ category: "artifact",
8431
+ subcategory: "study",
8432
+ props: [
8433
+ {
8434
+ name: "cardId",
8435
+ type: "string",
8436
+ required: true,
8437
+ description: "Identifier of the card being rated. Passed back as the second argument to onRate."
8438
+ },
8439
+ {
8440
+ name: "onRate",
8441
+ type: "function",
8442
+ required: true,
8443
+ description: 'Called with (rating, cardId) when the learner picks a button. Rating is one of "again" | "hard" | "good" | "easy".'
8444
+ },
8445
+ {
8446
+ name: "labels",
8447
+ type: "object",
8448
+ required: false,
8449
+ description: 'Override the default button labels. Defaults: "Again" / "Hard" / "Good" / "Easy". Pass a partial object \u2014 unspecified ratings keep the defaults.'
8450
+ },
8451
+ {
8452
+ name: "className",
8453
+ type: "string",
8454
+ required: false,
8455
+ description: "Additional CSS classes on the outer container."
8456
+ }
8457
+ ],
8458
+ variants: [],
8459
+ slots: [],
8460
+ dependencies: {
8461
+ npm: ["clsx", "tailwind-merge"],
8462
+ internal: ["lib/utils"],
8463
+ peer: ["react", "react-dom"]
8464
+ },
8465
+ tokensUsed: ["destructive", "secondary", "secondary-foreground", "primary", "accent", "accent-foreground", "foreground", "ring"],
8466
+ examples: [
8467
+ {
8468
+ title: "Anki-default labels with a hand-rolled scheduler",
8469
+ description: "Forward the rating to a consumer-owned interval calculator.",
8470
+ code: "<SpacedRepetition\n cardId={card.id}\n onRate={(rating, id) => scheduler.update(id, rating)}\n/>",
8471
+ composition: ["spaced-repetition", "srs"]
8472
+ },
8473
+ {
8474
+ title: "Inside a Deck via ratingSlot",
8475
+ description: "Each card surfaces a rating row beneath it.",
8476
+ code: "<Deck\n cards={cards}\n ratingSlot={(card) => (\n <SpacedRepetition cardId={card.id} onRate={onRate} />\n )}\n/>",
8477
+ composition: ["spaced-repetition", "deck", "srs"]
8478
+ }
8479
+ ],
8480
+ ai: {
8481
+ whenToUse: "After a Flashcard / Cloze / ImageOcclusion has been revealed, surface a four-button row so the learner self-reports recall quality. Pair with a scheduler (Anki SM-2, FSRS, custom) on the consumer side. Best place: inside Deck's ratingSlot prop.",
8482
+ whenNotToUse: "Don't use as a generic rating widget \u2014 this is study-specific, with semantic Anki labels (Again / Hard / Good / Easy). Don't use when the rating is a continuous value or a star count (use a slider or a star-rating component). Don't use without a scheduler \u2014 the rating is meaningless without something that consumes it to schedule the next review.",
8483
+ commonMistakes: [
8484
+ "Forgetting to wire `onRate` \u2014 the buttons fire but nothing happens. There's no internal scheduler",
8485
+ "Calling SpacedRepetition before the card is revealed \u2014 the user hasn't seen the answer yet, so any rating is a guess. Render after Flashcard's flip event, after Cloze's reveal event, or after Quiz's submit",
8486
+ "Reusing the same cardId across multiple cards in a session \u2014 the consumer's scheduler will misroute interval updates. Pass each card's unique id",
8487
+ 'Overriding labels with non-Anki semantics \u2014 "Again / Hard / Good / Easy" map to standard SM-2/FSRS difficulty grades 1\u20134. Custom labels are fine, but the four buckets should still mean roughly forgot / barely / fluent / instant'
8488
+ ],
8489
+ relatedComponents: ["flashcard", "cloze", "image-occlusion", "quiz", "deck"],
8490
+ accessibilityNotes: `Outer container has role="group" with aria-label="Confidence rating". Each button is a real <button> with an aria-label that includes the rating label AND a hint about its effect on the next review ("Again: Couldn't recall \u2014 show this card again soon."). Native button focus + Enter/Space activation handle keyboard interaction.`,
8491
+ tokenBudget: 280
8492
+ },
8493
+ tags: ["artifact", "study", "spaced-repetition", "srs", "anki", "rating"]
8494
+ };
8495
+
8496
+ export { accordionSchema, alertDialogSchema, alertSchema, arcSchema, aspectRatioSchema, attachmentSchema, avatarSchema, badgeSchema, breadcrumbSchema, buttonSchema, calendarSchema, cardSchema, checkboxSchema, chordSchema, citationSchema, clozeSchema, clusterSchema, codeBlockSchema, collapsibleSchema, colorPickerSchema, comboboxSchema, commandSchema, compareTableSchema, composerSchema, containerSchema, contextMenuSchema, dataTableSchema, datePickerSchema, deckSchema, dendrogramSchema, dialogSchema, drawerSchema, dropdownMenuSchema, dropzoneSchema, emptySchema, errorStateSchema, fileTreeSchema, flashcardSchema, flowchartSchema, formSchema, funnelSchema, ganttSchema, gridSchema, hoverCardSchema, imageOcclusionSchema, inputOTPSchema, inputSchema, labelSchema, loadingIndicatorSchema, loadingSchema, markdownSchema, matrixSchema, menubarSchema, messageActionsSchema, messageListSchema, messageSchema, mindMapSchema, multiComboboxSchema, navigationMenuSchema, orgChartSchema, paginationSchema, popoverSchema, progressSchema, pyramidSchema, quizSchema, radioGroupSchema, reasoningSchema, resizableSchema, sankeySchema, scrollAreaSchema, selectSchema, separatorSchema, sequenceSchema, sheetSchema, sidebarSchema, skeletonSchema, sliderSchema, sonnerSchema, spacedRepetitionSchema, spacerSchema, stackSchema, stepperSchema, suggestionSchema, sunburstSchema, switchSchema, tableSchema, tabsSchema, tagSchema, textareaSchema, timeAxisSchema, timePickerSchema, timelineSchema, toggleGroupSchema, toggleSchema, toolCallSchema, toolbarSchema, tooltipSchema, treeMapSchema, treeSchema, vennSchema };
6290
8497
  //# sourceMappingURL=schemas.js.map
6291
8498
  //# sourceMappingURL=schemas.js.map