@keyfunc/keybricks-ds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/DEPLOY.md +204 -0
  2. package/DESIGN.md +269 -0
  3. package/INTEGRATION.md +417 -0
  4. package/SKILL.md +32 -0
  5. package/_adherence.oxlintrc.json +1469 -0
  6. package/_scripts/build-index.mjs +80 -0
  7. package/_scripts/build-tokens.mjs +135 -0
  8. package/assets/icons/icon-index.js +1 -0
  9. package/assets/icons/icon-index.json +1 -0
  10. package/assets/icons/unicons-index.js +1 -0
  11. package/assets/icons/unicons-index.json +1 -0
  12. package/assets/keybricks-logo.png +0 -0
  13. package/components/_cards/accordion.card.html +32 -0
  14. package/components/_cards/action-chip.card.html +22 -0
  15. package/components/_cards/activity.card.html +34 -0
  16. package/components/_cards/alert.card.html +32 -0
  17. package/components/_cards/app-chrome.card.html +36 -0
  18. package/components/_cards/banner.card.html +21 -0
  19. package/components/_cards/brand-visual.card.html +43 -0
  20. package/components/_cards/breadcrumb.card.html +23 -0
  21. package/components/_cards/button-1-base.card.html +39 -0
  22. package/components/_cards/button-2-states.card.html +56 -0
  23. package/components/_cards/button-3-sizes-icons.card.html +32 -0
  24. package/components/_cards/button-4-group.card.html +47 -0
  25. package/components/_cards/canvas-zoom-controls.card.html +19 -0
  26. package/components/_cards/cards-indicators.card.html +59 -0
  27. package/components/_cards/charts-1-sparkline.card.html +55 -0
  28. package/components/_cards/charts-10-gauge.card.html +31 -0
  29. package/components/_cards/charts-11-funnel.card.html +28 -0
  30. package/components/_cards/charts-12-treemap.card.html +23 -0
  31. package/components/_cards/charts-14-radar.card.html +31 -0
  32. package/components/_cards/charts-15-distribution.card.html +32 -0
  33. package/components/_cards/charts-16-pareto.card.html +25 -0
  34. package/components/_cards/charts-17-candlestick.card.html +34 -0
  35. package/components/_cards/charts-18-sankey.card.html +29 -0
  36. package/components/_cards/charts-19-chord.card.html +31 -0
  37. package/components/_cards/charts-2-line.card.html +46 -0
  38. package/components/_cards/charts-20-sunburst.card.html +38 -0
  39. package/components/_cards/charts-21-worldmap.card.html +33 -0
  40. package/components/_cards/charts-22-gantt.card.html +37 -0
  41. package/components/_cards/charts-23-bar3d.card.html +26 -0
  42. package/components/_cards/charts-24-pie3d.card.html +32 -0
  43. package/components/_cards/charts-25-surface3d.card.html +24 -0
  44. package/components/_cards/charts-26-scatter3d.card.html +24 -0
  45. package/components/_cards/charts-27-ribbon3d.card.html +23 -0
  46. package/components/_cards/charts-3-bar.card.html +71 -0
  47. package/components/_cards/charts-4-barlist.card.html +30 -0
  48. package/components/_cards/charts-5-donut.card.html +35 -0
  49. package/components/_cards/charts-6-scatter.card.html +26 -0
  50. package/components/_cards/charts-7-heatmap.card.html +28 -0
  51. package/components/_cards/charts-8-waterfall.card.html +25 -0
  52. package/components/_cards/charts-9-bullet.card.html +31 -0
  53. package/components/_cards/charts-99-fullpage.card.html +194 -0
  54. package/components/_cards/checkbox.card.html +34 -0
  55. package/components/_cards/codeblock.card.html +19 -0
  56. package/components/_cards/combobox.card.html +25 -0
  57. package/components/_cards/context-menu.card.html +21 -0
  58. package/components/_cards/datatable.card.html +48 -0
  59. package/components/_cards/date-picker.card.html +31 -0
  60. package/components/_cards/diffvalue.card.html +21 -0
  61. package/components/_cards/divider.card.html +24 -0
  62. package/components/_cards/drawer.card.html +30 -0
  63. package/components/_cards/dropdown-menu.card.html +38 -0
  64. package/components/_cards/dropzone.card.html +22 -0
  65. package/components/_cards/empty-state.card.html +29 -0
  66. package/components/_cards/filter-bar.card.html +34 -0
  67. package/components/_cards/icon-button.card.html +27 -0
  68. package/components/_cards/icons-1-core.card.html +49 -0
  69. package/components/_cards/icons-2-feather.card.html +39 -0
  70. package/components/_cards/icons-3-unicons.card.html +44 -0
  71. package/components/_cards/input.card.html +25 -0
  72. package/components/_cards/kbd.card.html +20 -0
  73. package/components/_cards/keyvalue.card.html +23 -0
  74. package/components/_cards/listrow.card.html +30 -0
  75. package/components/_cards/loading.card.html +33 -0
  76. package/components/_cards/log-viewer.card.html +23 -0
  77. package/components/_cards/modal.card.html +35 -0
  78. package/components/_cards/multi-select.card.html +26 -0
  79. package/components/_cards/number-stepper.card.html +24 -0
  80. package/components/_cards/pagination.card.html +25 -0
  81. package/components/_cards/people.card.html +46 -0
  82. package/components/_cards/pipeline-node.card.html +76 -0
  83. package/components/_cards/pipeline-palette.card.html +54 -0
  84. package/components/_cards/search.card.html +23 -0
  85. package/components/_cards/select.card.html +23 -0
  86. package/components/_cards/slider.card.html +25 -0
  87. package/components/_cards/smart-table.card.html +37 -0
  88. package/components/_cards/spreadsheet.card.html +31 -0
  89. package/components/_cards/stepper.card.html +25 -0
  90. package/components/_cards/tabs.card.html +25 -0
  91. package/components/_cards/tag.card.html +26 -0
  92. package/components/_cards/textarea.card.html +27 -0
  93. package/components/_cards/timeline.card.html +32 -0
  94. package/components/_cards/toast.card.html +33 -0
  95. package/components/_cards/toggles.card.html +68 -0
  96. package/components/_cards/tooltip.card.html +22 -0
  97. package/components/_cards/tree.card.html +150 -0
  98. package/components/_shared/frame-theme.js +16 -0
  99. package/components/_shared/src-brand.js +1 -0
  100. package/components/_shared/src-buttons.js +1 -0
  101. package/components/_shared/src-charts.js +1 -0
  102. package/components/_shared/src-data.js +1 -0
  103. package/components/_shared/src-display.js +1 -0
  104. package/components/_shared/src-feedback.js +1 -0
  105. package/components/_shared/src-forms.js +1 -0
  106. package/components/_shared/src-icons.js +1 -0
  107. package/components/_shared/src-navigation.js +1 -0
  108. package/components/_shared/src-pipeline.js +1 -0
  109. package/components/_shared/src-tabs.js +1 -0
  110. package/components/_shared/svg-download.js +19 -0
  111. package/components/_shared/view-source.js +185 -0
  112. package/components/_vue/index.mjs +114 -0
  113. package/components/brand/BrandVisual.d.ts +17 -0
  114. package/components/brand/BrandVisual.jsx +29 -0
  115. package/components/brand/BrandVisual.vue +34 -0
  116. package/components/brand/_dir.card.html +13 -0
  117. package/components/brand/brandMotifs.js +210 -0
  118. package/components/buttons/ActionChip.d.ts +10 -0
  119. package/components/buttons/ActionChip.jsx +20 -0
  120. package/components/buttons/ActionChip.vue +18 -0
  121. package/components/buttons/Button.d.ts +40 -0
  122. package/components/buttons/Button.jsx +101 -0
  123. package/components/buttons/Button.vue +87 -0
  124. package/components/buttons/IconButton.d.ts +26 -0
  125. package/components/buttons/IconButton.jsx +28 -0
  126. package/components/buttons/IconButton.vue +21 -0
  127. package/components/buttons/_dir.card.html +13 -0
  128. package/components/buttons/buttons.prompt.md +19 -0
  129. package/components/charts/Bar3D.d.ts +15 -0
  130. package/components/charts/Bar3D.jsx +93 -0
  131. package/components/charts/Bar3D.vue +79 -0
  132. package/components/charts/BarChart.d.ts +23 -0
  133. package/components/charts/BarChart.jsx +135 -0
  134. package/components/charts/BarChart.vue +139 -0
  135. package/components/charts/BarList.d.ts +13 -0
  136. package/components/charts/BarList.jsx +31 -0
  137. package/components/charts/BarList.vue +25 -0
  138. package/components/charts/BoxPlot.d.ts +18 -0
  139. package/components/charts/BoxPlot.jsx +62 -0
  140. package/components/charts/BoxPlot.vue +58 -0
  141. package/components/charts/BulletChart.d.ts +12 -0
  142. package/components/charts/BulletChart.jsx +41 -0
  143. package/components/charts/BulletChart.vue +33 -0
  144. package/components/charts/CandlestickChart.d.ts +15 -0
  145. package/components/charts/CandlestickChart.jsx +63 -0
  146. package/components/charts/CandlestickChart.vue +62 -0
  147. package/components/charts/ChartKit.d.ts +8 -0
  148. package/components/charts/ChartKit.jsx +76 -0
  149. package/components/charts/ChartKit.vue +47 -0
  150. package/components/charts/ChordChart.d.ts +13 -0
  151. package/components/charts/ChordChart.jsx +55 -0
  152. package/components/charts/ChordChart.vue +54 -0
  153. package/components/charts/DonutChart.d.ts +15 -0
  154. package/components/charts/DonutChart.jsx +73 -0
  155. package/components/charts/DonutChart.vue +61 -0
  156. package/components/charts/FunnelChart.d.ts +11 -0
  157. package/components/charts/FunnelChart.jsx +37 -0
  158. package/components/charts/FunnelChart.vue +29 -0
  159. package/components/charts/GanttChart.d.ts +20 -0
  160. package/components/charts/GanttChart.jsx +80 -0
  161. package/components/charts/GanttChart.vue +60 -0
  162. package/components/charts/GaugeChart.d.ts +13 -0
  163. package/components/charts/GaugeChart.jsx +33 -0
  164. package/components/charts/GaugeChart.vue +29 -0
  165. package/components/charts/HeatmapChart.d.ts +13 -0
  166. package/components/charts/HeatmapChart.jsx +62 -0
  167. package/components/charts/HeatmapChart.vue +38 -0
  168. package/components/charts/Histogram.d.ts +16 -0
  169. package/components/charts/Histogram.jsx +56 -0
  170. package/components/charts/Histogram.vue +53 -0
  171. package/components/charts/LineChart.d.ts +17 -0
  172. package/components/charts/LineChart.jsx +84 -0
  173. package/components/charts/LineChart.vue +86 -0
  174. package/components/charts/ParetoChart.d.ts +13 -0
  175. package/components/charts/ParetoChart.jsx +54 -0
  176. package/components/charts/ParetoChart.vue +55 -0
  177. package/components/charts/Pie3D.d.ts +17 -0
  178. package/components/charts/Pie3D.jsx +145 -0
  179. package/components/charts/Pie3D.vue +115 -0
  180. package/components/charts/RadarChart.d.ts +14 -0
  181. package/components/charts/RadarChart.jsx +79 -0
  182. package/components/charts/RadarChart.vue +73 -0
  183. package/components/charts/Ribbon3D.d.ts +13 -0
  184. package/components/charts/Ribbon3D.jsx +89 -0
  185. package/components/charts/Ribbon3D.vue +79 -0
  186. package/components/charts/SankeyChart.d.ts +15 -0
  187. package/components/charts/SankeyChart.jsx +59 -0
  188. package/components/charts/SankeyChart.vue +53 -0
  189. package/components/charts/Scatter3D.d.ts +12 -0
  190. package/components/charts/Scatter3D.jsx +69 -0
  191. package/components/charts/Scatter3D.vue +59 -0
  192. package/components/charts/ScatterChart.d.ts +12 -0
  193. package/components/charts/ScatterChart.jsx +53 -0
  194. package/components/charts/ScatterChart.vue +57 -0
  195. package/components/charts/Sparkline.d.ts +19 -0
  196. package/components/charts/Sparkline.jsx +63 -0
  197. package/components/charts/Sparkline.vue +54 -0
  198. package/components/charts/SunburstChart.d.ts +12 -0
  199. package/components/charts/SunburstChart.jsx +61 -0
  200. package/components/charts/SunburstChart.vue +60 -0
  201. package/components/charts/Surface3D.d.ts +13 -0
  202. package/components/charts/Surface3D.jsx +70 -0
  203. package/components/charts/Surface3D.vue +63 -0
  204. package/components/charts/TreemapChart.d.ts +11 -0
  205. package/components/charts/TreemapChart.jsx +35 -0
  206. package/components/charts/TreemapChart.vue +27 -0
  207. package/components/charts/WaterfallChart.d.ts +11 -0
  208. package/components/charts/WaterfallChart.jsx +59 -0
  209. package/components/charts/WaterfallChart.vue +46 -0
  210. package/components/charts/WorldMap.d.ts +21 -0
  211. package/components/charts/WorldMap.jsx +107 -0
  212. package/components/charts/WorldMap.vue +73 -0
  213. package/components/charts/_dir.card.html +7 -0
  214. package/components/charts/chart-3d.js +84 -0
  215. package/components/charts/chart-geometry.js +223 -0
  216. package/components/charts/charts.prompt.md +24 -0
  217. package/components/data/CodeBlock.d.ts +9 -0
  218. package/components/data/CodeBlock.jsx +19 -0
  219. package/components/data/CodeBlock.vue +22 -0
  220. package/components/data/DataTable.d.ts +28 -0
  221. package/components/data/DataTable.jsx +32 -0
  222. package/components/data/DataTable.vue +25 -0
  223. package/components/data/DiffValue.d.ts +11 -0
  224. package/components/data/DiffValue.jsx +15 -0
  225. package/components/data/DiffValue.vue +13 -0
  226. package/components/data/FilterBar.d.ts +16 -0
  227. package/components/data/FilterBar.jsx +22 -0
  228. package/components/data/FilterBar.vue +23 -0
  229. package/components/data/KeyValue.d.ts +16 -0
  230. package/components/data/KeyValue.jsx +25 -0
  231. package/components/data/KeyValue.vue +26 -0
  232. package/components/data/ListRow.d.ts +14 -0
  233. package/components/data/ListRow.jsx +25 -0
  234. package/components/data/ListRow.vue +25 -0
  235. package/components/data/Pagination.d.ts +12 -0
  236. package/components/data/Pagination.jsx +27 -0
  237. package/components/data/Pagination.vue +24 -0
  238. package/components/data/SmartTable.d.ts +30 -0
  239. package/components/data/SmartTable.jsx +73 -0
  240. package/components/data/SmartTable.vue +74 -0
  241. package/components/data/Spreadsheet.d.ts +33 -0
  242. package/components/data/Spreadsheet.jsx +110 -0
  243. package/components/data/Spreadsheet.vue +95 -0
  244. package/components/data/_dir.card.html +13 -0
  245. package/components/data/data.prompt.md +33 -0
  246. package/components/display/Avatar.d.ts +21 -0
  247. package/components/display/Avatar.jsx +31 -0
  248. package/components/display/Avatar.vue +34 -0
  249. package/components/display/Badge.d.ts +27 -0
  250. package/components/display/Badge.jsx +40 -0
  251. package/components/display/Badge.vue +47 -0
  252. package/components/display/Card.d.ts +27 -0
  253. package/components/display/Card.jsx +27 -0
  254. package/components/display/Card.vue +28 -0
  255. package/components/display/Divider.d.ts +8 -0
  256. package/components/display/Divider.jsx +14 -0
  257. package/components/display/Divider.vue +13 -0
  258. package/components/display/Kbd.d.ts +7 -0
  259. package/components/display/Kbd.jsx +12 -0
  260. package/components/display/Kbd.vue +9 -0
  261. package/components/display/ProgressBar.d.ts +42 -0
  262. package/components/display/ProgressBar.jsx +70 -0
  263. package/components/display/ProgressBar.vue +69 -0
  264. package/components/display/Tag.d.ts +9 -0
  265. package/components/display/Tag.jsx +15 -0
  266. package/components/display/Tag.vue +15 -0
  267. package/components/display/_dir.card.html +13 -0
  268. package/components/display/display.prompt.md +30 -0
  269. package/components/feedback/Accordion.d.ts +13 -0
  270. package/components/feedback/Accordion.jsx +21 -0
  271. package/components/feedback/Accordion.vue +22 -0
  272. package/components/feedback/ActivityItem.d.ts +25 -0
  273. package/components/feedback/ActivityItem.jsx +39 -0
  274. package/components/feedback/ActivityItem.vue +46 -0
  275. package/components/feedback/Alert.d.ts +36 -0
  276. package/components/feedback/Alert.jsx +48 -0
  277. package/components/feedback/Alert.vue +59 -0
  278. package/components/feedback/Banner.d.ts +15 -0
  279. package/components/feedback/Banner.jsx +25 -0
  280. package/components/feedback/Banner.vue +25 -0
  281. package/components/feedback/ContextMenu.d.ts +8 -0
  282. package/components/feedback/ContextMenu.jsx +18 -0
  283. package/components/feedback/ContextMenu.vue +19 -0
  284. package/components/feedback/Drawer.d.ts +18 -0
  285. package/components/feedback/Drawer.jsx +26 -0
  286. package/components/feedback/Drawer.vue +24 -0
  287. package/components/feedback/Menu.d.ts +10 -0
  288. package/components/feedback/Menu.jsx +24 -0
  289. package/components/feedback/Menu.vue +21 -0
  290. package/components/feedback/Modal.d.ts +38 -0
  291. package/components/feedback/Modal.jsx +69 -0
  292. package/components/feedback/Modal.vue +65 -0
  293. package/components/feedback/Stepper.d.ts +9 -0
  294. package/components/feedback/Stepper.jsx +24 -0
  295. package/components/feedback/Stepper.vue +18 -0
  296. package/components/feedback/Timeline.d.ts +15 -0
  297. package/components/feedback/Timeline.jsx +27 -0
  298. package/components/feedback/Timeline.vue +21 -0
  299. package/components/feedback/_dir.card.html +13 -0
  300. package/components/feedback/feedback.prompt.md +35 -0
  301. package/components/forms/Checkbox.d.ts +13 -0
  302. package/components/forms/Checkbox.jsx +17 -0
  303. package/components/forms/Checkbox.vue +18 -0
  304. package/components/forms/Combobox.d.ts +13 -0
  305. package/components/forms/Combobox.jsx +34 -0
  306. package/components/forms/Combobox.vue +35 -0
  307. package/components/forms/DatePicker.d.ts +12 -0
  308. package/components/forms/DatePicker.jsx +48 -0
  309. package/components/forms/DatePicker.vue +46 -0
  310. package/components/forms/Dropzone.d.ts +20 -0
  311. package/components/forms/Dropzone.jsx +36 -0
  312. package/components/forms/Dropzone.vue +28 -0
  313. package/components/forms/Field.d.ts +13 -0
  314. package/components/forms/Field.jsx +13 -0
  315. package/components/forms/Field.vue +12 -0
  316. package/components/forms/Input.d.ts +18 -0
  317. package/components/forms/Input.jsx +35 -0
  318. package/components/forms/Input.vue +38 -0
  319. package/components/forms/MultiSelect.d.ts +14 -0
  320. package/components/forms/MultiSelect.jsx +33 -0
  321. package/components/forms/MultiSelect.vue +36 -0
  322. package/components/forms/NumberStepper.d.ts +13 -0
  323. package/components/forms/NumberStepper.jsx +15 -0
  324. package/components/forms/NumberStepper.vue +17 -0
  325. package/components/forms/Radio.vue +16 -0
  326. package/components/forms/RadioGroup.vue +11 -0
  327. package/components/forms/SearchInput.d.ts +12 -0
  328. package/components/forms/SearchInput.jsx +17 -0
  329. package/components/forms/SearchInput.vue +14 -0
  330. package/components/forms/Select.d.ts +14 -0
  331. package/components/forms/Select.jsx +17 -0
  332. package/components/forms/Select.vue +16 -0
  333. package/components/forms/Slider.d.ts +15 -0
  334. package/components/forms/Slider.jsx +21 -0
  335. package/components/forms/Slider.vue +23 -0
  336. package/components/forms/Switch.d.ts +31 -0
  337. package/components/forms/Switch.jsx +40 -0
  338. package/components/forms/Switch.vue +16 -0
  339. package/components/forms/_dir.card.html +13 -0
  340. package/components/forms/forms.prompt.md +23 -0
  341. package/components/icons/Icon.d.ts +19 -0
  342. package/components/icons/Icon.jsx +93 -0
  343. package/components/icons/Icon.prompt.md +8 -0
  344. package/components/icons/Icon.vue +12 -0
  345. package/components/icons/Unicon.d.ts +12 -0
  346. package/components/icons/Unicon.jsx +16 -0
  347. package/components/icons/Unicon.vue +15 -0
  348. package/components/icons/_dir.card.html +13 -0
  349. package/components/icons/feather-paths.js +2 -0
  350. package/components/icons/icon-paths.js +73 -0
  351. package/components/index.d.ts +87 -0
  352. package/components/index.js +110 -0
  353. package/components/navigation/Breadcrumb.d.ts +24 -0
  354. package/components/navigation/Breadcrumb.jsx +120 -0
  355. package/components/navigation/Breadcrumb.vue +94 -0
  356. package/components/navigation/DocTree.d.ts +18 -0
  357. package/components/navigation/DocTree.jsx +37 -0
  358. package/components/navigation/DocTree.vue +25 -0
  359. package/components/navigation/Sidebar.d.ts +29 -0
  360. package/components/navigation/Sidebar.jsx +75 -0
  361. package/components/navigation/Sidebar.vue +54 -0
  362. package/components/navigation/TopBar.d.ts +27 -0
  363. package/components/navigation/TopBar.jsx +44 -0
  364. package/components/navigation/TopBar.vue +51 -0
  365. package/components/navigation/Tree.d.ts +83 -0
  366. package/components/navigation/Tree.jsx +347 -0
  367. package/components/navigation/Tree.vue +258 -0
  368. package/components/navigation/_dir.card.html +13 -0
  369. package/components/navigation/navigation.prompt.md +22 -0
  370. package/components/pipeline/ConfigPanel.d.ts +18 -0
  371. package/components/pipeline/ConfigPanel.jsx +30 -0
  372. package/components/pipeline/ConfigPanel.vue +32 -0
  373. package/components/pipeline/DataPreview.d.ts +14 -0
  374. package/components/pipeline/DataPreview.jsx +24 -0
  375. package/components/pipeline/DataPreview.vue +21 -0
  376. package/components/pipeline/NodeCard.d.ts +47 -0
  377. package/components/pipeline/NodeCard.jsx +97 -0
  378. package/components/pipeline/NodeCard.vue +75 -0
  379. package/components/pipeline/PaletteItem.vue +15 -0
  380. package/components/pipeline/PaletteListItem.vue +15 -0
  381. package/components/pipeline/PalettePanel.d.ts +20 -0
  382. package/components/pipeline/PalettePanel.jsx +74 -0
  383. package/components/pipeline/PalettePanel.vue +45 -0
  384. package/components/pipeline/PipelineCanvas.d.ts +25 -0
  385. package/components/pipeline/PipelineCanvas.jsx +94 -0
  386. package/components/pipeline/PipelineCanvas.vue +73 -0
  387. package/components/pipeline/ZoomControls.d.ts +9 -0
  388. package/components/pipeline/ZoomControls.jsx +15 -0
  389. package/components/pipeline/ZoomControls.vue +15 -0
  390. package/components/pipeline/_dir.card.html +13 -0
  391. package/components/pipeline/pipeline.prompt.md +22 -0
  392. package/components/tabs/SegmentedControl.d.ts +11 -0
  393. package/components/tabs/SegmentedControl.jsx +21 -0
  394. package/components/tabs/SegmentedControl.vue +15 -0
  395. package/components/tabs/Tabs.d.ts +13 -0
  396. package/components/tabs/Tabs.jsx +52 -0
  397. package/components/tabs/Tabs.vue +39 -0
  398. package/components/tabs/ViewToggle.d.ts +8 -0
  399. package/components/tabs/ViewToggle.jsx +12 -0
  400. package/components/tabs/ViewToggle.vue +12 -0
  401. package/components/tabs/_dir.card.html +13 -0
  402. package/components/tabs/tabs.prompt.md +14 -0
  403. package/package.json +76 -0
  404. package/readme.md +150 -0
  405. package/styles.css +10 -0
  406. package/tokens/alpha.css +27 -0
  407. package/tokens/charts.css +55 -0
  408. package/tokens/colors-extended.css +40 -0
  409. package/tokens/colors.css +39 -0
  410. package/tokens/dark.css +96 -0
  411. package/tokens/fonts.css +4 -0
  412. package/tokens/interaction.css +48 -0
  413. package/tokens/layout.css +30 -0
  414. package/tokens/motion.css +22 -0
  415. package/tokens/tokens.d.ts +680 -0
  416. package/tokens/tokens.js +1018 -0
  417. package/tokens/tokens.json +2928 -0
  418. package/tokens/typography.css +22 -0
@@ -0,0 +1,258 @@
1
+ <script setup>
2
+ import { ref, computed, watch } from 'vue'
3
+ import Icon from '../icons/Icon.vue'
4
+ import Checkbox from '../forms/Checkbox.vue'
5
+ // Nested tree view: expand/collapse, single or multiple selection, cascading checkboxes with
6
+ // indeterminate parents (checkStrictly opts out), disabled nodes, connector lines, async
7
+ // loadData, search highlight, drag to move, keyboard navigation.
8
+ const docHues = { orange: 'var(--cat-transform)', green: 'var(--cat-source)', purple: 'var(--cat-merge)', blue: 'var(--info-fg)', teal: 'var(--cat-output)', gray: 'var(--text-muted)' }
9
+ const INDENT = 18
10
+ const props = defineProps({
11
+ items: { type: Array, default: () => [] },
12
+ defaultExpanded: { type: Array, default: () => [] },
13
+ defaultActive: String,
14
+ defaultSelected: { type: Array, default: () => [] },
15
+ defaultChecked: { type: Array, default: () => [] },
16
+ checkable: Boolean, checkStrictly: Boolean, multiple: Boolean,
17
+ selectable: { type: Boolean, default: true },
18
+ showIcon: { type: Boolean, default: true },
19
+ showLine: Boolean, draggable: Boolean,
20
+ searchValue: { type: String, default: '' },
21
+ autoExpandOnSearch: { type: Boolean, default: true },
22
+ reorder: Boolean,
23
+ loadData: Function, rowActions: Function, style: Object,
24
+ })
25
+ const emit = defineEmits(['select', 'check', 'expand', 'drop'])
26
+
27
+ const data = ref(JSON.parse(JSON.stringify(props.items)))
28
+ // Compare by value: re-seeding on identity alone would wipe async-loaded children.
29
+ watch(() => JSON.stringify(props.items), (next, prev) => { if (next !== prev) data.value = JSON.parse(next) })
30
+ const expanded = ref([...props.defaultExpanded])
31
+ const selected = ref(props.defaultActive ? [props.defaultActive] : [...props.defaultSelected])
32
+ const checked = ref([...props.defaultChecked])
33
+ const loading = ref([]); const loaded = ref([]); const focus = ref(null)
34
+ const dragKey = ref(null); const drop = ref(null)
35
+
36
+ const keyOf = n => (n.key != null ? n.key : n.label)
37
+ const titleOf = n => (n.title != null ? n.title : n.label)
38
+ const kidsOf = n => n.children || []
39
+ const isBranch = n => kidsOf(n).length > 0 || n.isLeaf === false
40
+ function descendants(n, out = []) { for (const c of kidsOf(n)) { out.push(c); descendants(c, out) } return out }
41
+ /** Is `key` the dragged node itself, or anywhere inside its subtree? */
42
+ function inSubtree(rootKey, key) {
43
+ const root = index(data.value).byKey[rootKey]
44
+ if (!root) return false
45
+ return rootKey === key || descendants(root).some(d => keyOf(d) === key)
46
+ }
47
+ function index(nodes, parent = null, acc = { byKey: {}, parent: {} }) {
48
+ for (const n of nodes) { acc.byKey[keyOf(n)] = n; acc.parent[keyOf(n)] = parent; index(kidsOf(n), keyOf(n), acc) }
49
+ return acc
50
+ }
51
+ function ancestorsOfMatches(nodes, test, trail = [], hit = []) {
52
+ for (const n of nodes) {
53
+ if (test(n)) hit.push(...trail)
54
+ ancestorsOfMatches(kidsOf(n), test, [...trail, keyOf(n)], hit)
55
+ }
56
+ return [...new Set(hit)]
57
+ }
58
+ const searchExpanded = computed(() => props.searchValue && props.autoExpandOnSearch
59
+ ? ancestorsOfMatches(data.value, n => String(titleOf(n)).toLowerCase().includes(props.searchValue.toLowerCase()))
60
+ : [])
61
+ const openKeys = computed(() => [...new Set([...expanded.value, ...searchExpanded.value])])
62
+
63
+ const view = computed(() => {
64
+ const full = new Set(checked.value); const half = new Set()
65
+ if (!props.checkable || props.checkStrictly) return { full, half }
66
+ const visit = n => {
67
+ kidsOf(n).forEach(visit)
68
+ if (!kidsOf(n).length) return
69
+ const ds = descendants(n).filter(d => !d.disabled && !d.disableCheckbox)
70
+ if (!ds.length) return
71
+ const on = ds.filter(d => full.has(keyOf(d))).length
72
+ if (on === ds.length) full.add(keyOf(n))
73
+ else { full.delete(keyOf(n)); if (on > 0) half.add(keyOf(n)) }
74
+ }
75
+ data.value.forEach(visit)
76
+ return { full, half }
77
+ })
78
+
79
+ const rows = computed(() => {
80
+ const out = []
81
+ const push = (nodes, depth, trail) => {
82
+ nodes.forEach((n, i) => {
83
+ const isLast = i === nodes.length - 1
84
+ out.push({ n, key: keyOf(n), depth, trail, isLast })
85
+ if (kidsOf(n).length && openKeys.value.includes(keyOf(n))) push(kidsOf(n), depth + 1, [...trail, !isLast])
86
+ })
87
+ }
88
+ push(data.value, 0, [])
89
+ return out
90
+ })
91
+
92
+ function toggle(k) {
93
+ const open = openKeys.value.includes(k)
94
+ const { byKey } = index(data.value)
95
+ if (!open && props.loadData && !loaded.value.includes(k) && !kidsOf(byKey[k]).length) {
96
+ loading.value = [...loading.value, k]
97
+ expanded.value = [...expanded.value, k]
98
+ Promise.resolve(props.loadData(byKey[k])).then(kids => {
99
+ const clone = JSON.parse(JSON.stringify(data.value))
100
+ const t = index(clone).byKey[k]
101
+ if (t) t.children = kids || []
102
+ data.value = clone
103
+ loaded.value = [...loaded.value, k]
104
+ loading.value = loading.value.filter(x => x !== k)
105
+ })
106
+ return
107
+ }
108
+ expanded.value = open ? expanded.value.filter(x => x !== k) : [...expanded.value, k]
109
+ emit('expand', expanded.value)
110
+ }
111
+ function select(k) {
112
+ selected.value = props.multiple
113
+ ? (selected.value.includes(k) ? selected.value.filter(x => x !== k) : [...selected.value, k])
114
+ : [k]
115
+ emit('select', props.multiple ? selected.value : k, selected.value)
116
+ }
117
+ function check(k) {
118
+ const set = new Set(view.value.full)
119
+ const on = set.has(k)
120
+ on ? set.delete(k) : set.add(k)
121
+ if (!props.checkStrictly) {
122
+ const { byKey, parent } = index(data.value)
123
+ descendants(byKey[k]).forEach(d => {
124
+ if (d.disabled || d.disableCheckbox) return
125
+ on ? set.delete(keyOf(d)) : set.add(keyOf(d))
126
+ })
127
+ let p = parent[k]
128
+ while (p != null) {
129
+ const kids = kidsOf(byKey[p]).filter(c => !c.disabled && !c.disableCheckbox)
130
+ const hit = kids.filter(c => set.has(keyOf(c)))
131
+ hit.length && hit.length === kids.length ? set.add(p) : set.delete(p)
132
+ p = parent[p]
133
+ }
134
+ }
135
+ checked.value = [...set]
136
+ emit('check', checked.value, { key: k, checked: !on, half: [...view.value.half] })
137
+ }
138
+ function rowClick(n) {
139
+ if (n.disabled) return
140
+ focus.value = keyOf(n)
141
+ if (props.selectable && n.selectable !== false) select(keyOf(n))
142
+ if (isBranch(n)) toggle(keyOf(n))
143
+ }
144
+ function onDragOver(e, k) {
145
+ if (!props.draggable) return
146
+ e.preventDefault()
147
+ if (!dragKey.value) return
148
+ const n = index(data.value).byKey[k]
149
+ // Only folders are drop targets: hovering a file shows nothing, since it can't contain anything.
150
+ if (!n || n.disabled || !isBranch(n) || inSubtree(dragKey.value, k)) { drop.value = null; return }
151
+ const r = e.currentTarget.getBoundingClientRect()
152
+ const y = (e.clientY - r.top) / r.height
153
+ drop.value = { key: k, pos: props.reorder ? (y < 0.2 ? 'before' : y > 0.8 ? 'after' : 'inside') : 'inside' }
154
+ }
155
+ function onDrop(k) {
156
+ const info = drop.value && drop.value.key === k ? drop.value : null
157
+ drop.value = null
158
+ if (!dragKey.value || !info || inSubtree(dragKey.value, k)) { dragKey.value = null; return }
159
+ const clone = JSON.parse(JSON.stringify(data.value))
160
+ let moved = null
161
+ const prune = nodes => nodes.filter(n => {
162
+ if (keyOf(n) === dragKey.value) { moved = n; return false }
163
+ if (n.children) n.children = prune(n.children)
164
+ return true
165
+ })
166
+ const pruned = prune(clone)
167
+ if (!moved) { dragKey.value = null; return }
168
+ const insert = nodes => {
169
+ const out = []
170
+ for (const n of nodes) {
171
+ if (keyOf(n) === k && info.pos === 'before') out.push(moved)
172
+ if (keyOf(n) === k && info.pos === 'inside') n.children = [...(n.children || []), moved]
173
+ else if (n.children) n.children = insert(n.children)
174
+ out.push(n)
175
+ if (keyOf(n) === k && info.pos === 'after') out.push(moved)
176
+ }
177
+ return out
178
+ }
179
+ data.value = insert(pruned)
180
+ if (info.pos === 'inside' && !expanded.value.includes(k)) expanded.value = [...expanded.value, k]
181
+ emit('drop', { dragKey: dragKey.value, dropKey: k, position: info.pos, treeData: data.value })
182
+ dragKey.value = null
183
+ }
184
+ function keyDown(e, row) {
185
+ const i = rows.value.findIndex(r => r.key === row.key)
186
+ const go = n => { const t = rows.value[n]; if (t) focus.value = t.key }
187
+ if (e.key === 'ArrowDown') { e.preventDefault(); go(i + 1) }
188
+ else if (e.key === 'ArrowUp') { e.preventDefault(); go(i - 1) }
189
+ else if (e.key === 'ArrowRight') { e.preventDefault(); isBranch(row.n) && !openKeys.value.includes(row.key) ? toggle(row.key) : go(i + 1) }
190
+ else if (e.key === 'ArrowLeft') { e.preventDefault(); if (isBranch(row.n) && openKeys.value.includes(row.key)) toggle(row.key) }
191
+ else if (e.key === 'Enter') { e.preventDefault(); rowClick(row.n) }
192
+ else if (e.key === ' ') { e.preventDefault(); if (props.checkable && !row.n.disabled && row.n.checkable !== false && !row.n.disableCheckbox) check(row.key) }
193
+ }
194
+ function parts(text) {
195
+ const q = props.searchValue
196
+ const s = String(text)
197
+ if (!q) return [{ t: s, hit: false }]
198
+ const i = s.toLowerCase().indexOf(q.toLowerCase())
199
+ if (i < 0) return [{ t: s, hit: false }]
200
+ return [{ t: s.slice(0, i), hit: false }, { t: s.slice(i, i + q.length), hit: true }, { t: s.slice(i + q.length), hit: false }]
201
+ }
202
+ const dropAt = k => (drop.value && drop.value.key === k ? drop.value.pos : null)
203
+ </script>
204
+ <template>
205
+ <div role="tree" :style="{ display: 'flex', flexDirection: 'column', gap: showLine ? 0 : '1px', ...style }">
206
+ <div v-for="row in rows" :key="row.key" role="treeitem" class="kb-tree-row"
207
+ :tabindex="focus === row.key || (!focus && row === rows[0]) ? 0 : -1"
208
+ :aria-expanded="isBranch(row.n) ? openKeys.includes(row.key) : undefined"
209
+ :aria-selected="selected.includes(row.key)" :aria-disabled="row.n.disabled || undefined"
210
+ :draggable="draggable && !row.n.disabled"
211
+ @dragstart="dragKey = row.key" @dragover="onDragOver($event, row.key)" @dragleave="drop = null"
212
+ @drop.prevent="onDrop(row.key)" @dragend="dragKey = null; drop = null"
213
+ @click="rowClick(row.n)" @keydown="keyDown($event, row)"
214
+ :class="{ 'is-disabled': row.n.disabled }"
215
+ :style="{
216
+ minHeight: 'var(--h-tree-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: '6px',
217
+ padding: showLine ? '0 8px 0 2px' : '5px 8px', paddingLeft: showLine ? '2px' : (8 + row.depth * INDENT) + 'px', boxSizing: 'border-box',
218
+ cursor: row.n.disabled ? 'not-allowed' : 'pointer', opacity: row.n.disabled ? 0.45 : 1,
219
+ background: dropAt(row.key) === 'inside' ? 'var(--soft-bg)' : selected.includes(row.key) ? 'var(--bg-active)' : 'transparent',
220
+ outline: dropAt(row.key) === 'inside' ? '2px solid var(--action-primary)' : 'none',
221
+ outlineOffset: '-2px',
222
+ boxShadow: dropAt(row.key) === 'before' ? 'inset 0 2px 0 var(--action-primary)' : dropAt(row.key) === 'after' ? 'inset 0 -2px 0 var(--action-primary)' : 'none',
223
+ transition: 'var(--t-hover)' }">
224
+ <template v-if="showLine">
225
+ <span v-for="(hasNext, i) in row.trail" :key="i"
226
+ :style="{ width: INDENT + 'px', alignSelf: 'stretch', flexShrink: 0, marginLeft: i === 0 ? '6px' : 0, borderLeft: hasNext ? '1px solid var(--border-subtle)' : '1px solid transparent' }" />
227
+ <span :style="{ width: INDENT + 'px', alignSelf: 'stretch', flexShrink: 0, position: 'relative', marginLeft: row.trail.length ? 0 : '6px' }">
228
+ <span :style="{ position: 'absolute', left: 0, top: 0, height: row.isLast ? '50%' : '100%', borderLeft: '1px solid var(--border-subtle)' }" />
229
+ <span :style="{ position: 'absolute', left: 0, top: '50%', width: (isBranch(row.n) ? 6 : INDENT - 4) + 'px', borderTop: '1px solid var(--border-subtle)' }" />
230
+ </span>
231
+ </template>
232
+ <span v-if="isBranch(row.n)" @click.stop="toggle(row.key)"
233
+ :style="{ width: '14px', height: '14px', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-muted)', flexShrink: 0, cursor: 'pointer', transform: openKeys.includes(row.key) ? 'rotate(90deg)' : 'none', transition: 'transform var(--dur-fast) var(--ease-out)' }">
234
+ <Icon :name="loading.includes(row.key) ? 'loader' : 'chevron-right'" :size="13" :class="loading.includes(row.key) ? 'kb-tree-spin' : ''" />
235
+ </span>
236
+ <span v-else :style="{ width: showLine ? 0 : '14px', flexShrink: 0 }" />
237
+ <span v-if="checkable && row.n.checkable !== false" @click.stop style="display:inline-flex;flex-shrink:0">
238
+ <Checkbox size="sm" :checked="view.full.has(row.key)" :indeterminate="view.half.has(row.key)"
239
+ :disabled="row.n.disabled || row.n.disableCheckbox" @change="check(row.key)" />
240
+ </span>
241
+ <span v-if="showIcon" :style="{ color: isBranch(row.n) ? 'var(--text-muted)' : docHues[row.n.hue || 'gray'], display: 'inline-flex', flexShrink: 0 }">
242
+ <Icon :name="row.n.icon || (isBranch(row.n) ? (openKeys.includes(row.key) ? 'folder-open' : 'folder') : 'file-text')" :size="15" />
243
+ </span>
244
+ <span :style="{ fontFamily: 'var(--font-sans)', fontSize: 'var(--text-sm)', lineHeight: 'var(--leading-sm)', fontWeight: selected.includes(row.key) ? 'var(--weight-medium)' : 'var(--weight-regular)', color: row.n.disabled ? 'var(--text-muted)' : 'var(--text-heading)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }">
245
+ <template v-for="(p, i) in parts(titleOf(row.n))" :key="i"><mark v-if="p.hit" style="background:var(--soft-bg);color:var(--info-fg);font-weight:var(--weight-medium);padding:0;border-radius:2px">{{ p.t }}</mark><template v-else>{{ p.t }}</template></template>
246
+ </span>
247
+ <span v-if="row.n.tag" style="font-family:var(--font-sans);font-size:var(--text-2xs);line-height:1;padding:2px 5px;border-radius:var(--radius-sm);background:var(--bg-inset);color:var(--text-secondary);flex-shrink:0">{{ row.n.tag }}</span>
248
+ <span v-if="row.n.count != null" style="margin-left:auto;font-family:var(--font-mono);font-size:var(--text-2xs);color:var(--text-muted);padding-left:8px">{{ row.n.count }}</span>
249
+ </div>
250
+ <div v-if="!rows.length" style="padding:10px 8px;font-family:var(--font-sans);font-size:var(--text-sm);color:var(--text-muted)">No matching items</div>
251
+ </div>
252
+ </template>
253
+ <style scoped>
254
+ .kb-tree-row:not(.is-disabled):hover{background:var(--bg-hover)}
255
+ .kb-tree-row:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-2px}
256
+ .kb-tree-spin{animation:kb-tree-spin 900ms linear infinite}
257
+ @keyframes kb-tree-spin{to{transform:rotate(360deg)}}
258
+ </style>
@@ -0,0 +1,13 @@
1
+ <!-- @dsCard group="Directory Index" viewport="700x70" name="Navigation dir" subtitle="Full card: Components → App Chrome" -->
2
+ <!DOCTYPE html>
3
+ <html><head><meta charset="utf-8"><link rel="stylesheet" href="../../styles.css">
4
+ <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
5
+ <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
6
+ <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
7
+ <script src="../../_ds_bundle.js"></script>
8
+ <style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans)}</style></head>
9
+ <body><div id="root"></div>
10
+ <script type="text/babel">
11
+ const { Breadcrumb } = window.KeybricksDesignSystem_71231a;
12
+ ReactDOM.createRoot(document.getElementById("root")).render(<Breadcrumb items={["Management","System Migration","Import"]}/>);
13
+ </script></body></html>
@@ -0,0 +1,22 @@
1
+ App chrome: `Sidebar` (+`KEYBRICKS_NAV` model), `TopBar`, `PageToolbar` (editor header), `PageHeading`, `DocTree` (secondary panel).
2
+
3
+ ```jsx
4
+ <Sidebar items={KEYBRICKS_NAV} active="Home" collapsed={false} onToggleCollapse={...} logo="../../assets/keybricks-logo.png"/>
5
+ <TopBar/>
6
+ <PageToolbar title="Oracle Adapter" onBack={...} actions={<>
7
+ <Button variant="ghost" icon="settings-2">Custom Parameters</Button>
8
+ <Button variant="ghost" icon="play">Run Test</Button>
9
+ <Button icon="send">Submit</Button></>}/>
10
+ <DocTree items={[{label:"Q1 2026",kind:"folder"},{label:"财务分析",hue:"orange"},{label:"Revenue Analysis",hue:"green"}]}/>
11
+ ```
12
+
13
+ Set `logo` to the correct relative path to `assets/keybricks-logo.png`.
14
+
15
+ `Breadcrumb` and `ThemeToggle` (additions):
16
+
17
+ ```jsx
18
+ <Breadcrumb items={["Management","System Migration","Import"]}/>
19
+ <ThemeToggle/> // uncontrolled: writes html[data-theme] + localStorage
20
+ <ThemeToggle dark={dark} onToggle={setDark}/> // controlled
21
+ applyStoredTheme(); // call once at app start
22
+ ```
@@ -0,0 +1,18 @@
1
+ import * as React from "react";
2
+ /** 400px right node-configuration panel (header, preview-rows controls, tabs, scrolling body). */
3
+ export interface ConfigPanelProps {
4
+ title?: string;
5
+ /** "Data Source · Detail Sheet" */
6
+ subtitle?: string;
7
+ tabs?: string[];
8
+ activeTab?: string;
9
+ onTab?: (tab: string) => void;
10
+ previewRows?: number;
11
+ onPreviewRows?: (n: number) => void;
12
+ onSave?: () => void;
13
+ onPreview?: () => void;
14
+ children?: React.ReactNode;
15
+ height?: number | string;
16
+ style?: React.CSSProperties;
17
+ }
18
+ export declare function ConfigPanel(props: ConfigPanelProps): JSX.Element;
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { Button } from "../buttons/Button.jsx";
3
+ import { PanelTabs } from "../tabs/Tabs.jsx";
4
+ import { NumberStepper } from "../forms/NumberStepper.jsx";
5
+
6
+ /** Right node-config panel — 400px: title/subtitle + Save Settings, preview-rows row, PanelTabs, body slot. */
7
+ export function ConfigPanel({ title, subtitle, tabs = ["Node Info", "Calc Rules", "Output Fields", "SQL Preview"], activeTab, onTab, previewRows = 100, onPreviewRows, onSave, onPreview, children, height = "100%", style }) {
8
+ const [tab, setTab] = React.useState(tabs[0]);
9
+ const cur = activeTab != null ? activeTab : tab;
10
+ return (
11
+ <div style={{ width: "var(--panel-w)", height, background: "var(--bg-surface)", borderLeft: "1px solid var(--border-card)", display: "flex", flexDirection: "column", boxSizing: "border-box", flexShrink: 0, ...style }}>
12
+ <div style={{ padding: "12px 16px 0", borderBottom: "1px solid var(--border-card)", flexShrink: 0 }}>
13
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
14
+ <div style={{ display: "flex", flexDirection: "column" }}>
15
+ <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-md)", lineHeight: "17.5px", letterSpacing: "var(--tracking-md)", color: "var(--text-heading)" }}>{title}</span>
16
+ <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", letterSpacing: "var(--tracking-xs)", color: "var(--text-muted)", paddingTop: 5 }}>{subtitle}</span>
17
+ </div>
18
+ <Button size="sm" onClick={onSave}>Save Settings</Button>
19
+ </div>
20
+ <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "8px 0" }}>
21
+ <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-secondary)" }}>Preview rows</span>
22
+ <NumberStepper value={previewRows} onChange={onPreviewRows} />
23
+ <Button variant="primary-soft" size="sm" icon="eye" style={{ height: 28, borderRadius: "var(--radius-sm)", padding: "4px 10px" }} onClick={onPreview}>Data Preview</Button>
24
+ </div>
25
+ <PanelTabs tabs={tabs} active={cur} onChange={(t) => { setTab(t); onTab && onTab(t); }} style={{ margin: "0 -16px", padding: "0 16px", borderBottom: "none" }} />
26
+ </div>
27
+ <div style={{ flex: 1, overflowY: "auto", padding: 16, display: "flex", flexDirection: "column", gap: 16 }}>{children}</div>
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,32 @@
1
+ <script setup>
2
+ import { ref, computed } from 'vue'
3
+ import Button from '../buttons/Button.vue'
4
+ import PanelTabs from '../tabs/Tabs.vue'
5
+ import NumberStepper from '../forms/NumberStepper.vue'
6
+ // Right node-config panel — 400px: title/subtitle + Save Settings, preview-rows row, PanelTabs, body slot.
7
+ const props = defineProps({ title: String, subtitle: String, tabs: { type: Array, default: () => ['Node Info', 'Calc Rules', 'Output Fields', 'SQL Preview'] }, activeTab: String, previewRows: { type: Number, default: 100 }, height: { type: [String, Number], default: '100%' }, style: Object })
8
+ const emit = defineEmits(['tab', 'update:previewRows', 'save', 'preview'])
9
+ const tabState = ref(props.tabs[0])
10
+ const cur = computed(() => props.activeTab != null ? props.activeTab : tabState.value)
11
+ function setTab(t) { tabState.value = t; emit('tab', t) }
12
+ </script>
13
+ <template>
14
+ <div :style="{ width: 'var(--panel-w)', height, background: 'var(--bg-surface)', borderLeft: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', flexShrink: 0, ...style }">
15
+ <div style="padding:12px 16px 0;border-bottom:1px solid var(--border-card);flex-shrink:0">
16
+ <div style="display:flex;justify-content:space-between;align-items:flex-start">
17
+ <div style="display:flex;flex-direction:column">
18
+ <span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-md);line-height:17.5px;letter-spacing:var(--tracking-md);color:var(--text-heading)">{{ title }}</span>
19
+ <span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:var(--leading-xs);letter-spacing:var(--tracking-xs);color:var(--text-muted);padding-top:5px">{{ subtitle }}</span>
20
+ </div>
21
+ <Button size="sm" @click="emit('save')">Save Settings</Button>
22
+ </div>
23
+ <div style="display:flex;align-items:center;gap:8px;padding:8px 0">
24
+ <span style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-secondary)">Preview rows</span>
25
+ <NumberStepper :model-value="previewRows" @update:modelValue="v => emit('update:previewRows', v)" />
26
+ <Button variant="primary-soft" size="sm" icon="eye" style="height:28px;border-radius:var(--radius-sm);padding:4px 10px" @click="emit('preview')">Data Preview</Button>
27
+ </div>
28
+ <PanelTabs :tabs="tabs" :active="cur" @change="setTab" style="margin:0 -16px;padding:0 16px;border-bottom:none" />
29
+ </div>
30
+ <div style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:16px"><slot /></div>
31
+ </div>
32
+ </template>
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { DataTableColumn } from "../data/DataTable";
3
+ /** Bottom 250px data-preview drawer with Debug Mode checkbox and dense table. */
4
+ export interface DataPreviewProps {
5
+ title?: string;
6
+ columns?: DataTableColumn[];
7
+ rows?: Record<string, any>[];
8
+ debug?: boolean;
9
+ onDebug?: (v: boolean) => void;
10
+ collapsed?: boolean;
11
+ onCollapse?: () => void;
12
+ style?: React.CSSProperties;
13
+ }
14
+ export declare function DataPreview(props: DataPreviewProps): JSX.Element;
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ import { Icon } from "../icons/Icon.jsx";
3
+ import { IconButton } from "../buttons/IconButton.jsx";
4
+ import { Checkbox } from "../forms/Checkbox.jsx";
5
+ import { DataTable } from "../data/DataTable.jsx";
6
+
7
+ /** Bottom data-preview drawer — 250px: 40px header (title, Debug Mode, collapse) + dense table. */
8
+ export function DataPreview({ title = "Data Preview", columns = [], rows = [], debug = false, onDebug, collapsed, onCollapse, style }) {
9
+ return (
10
+ <div style={{ background: "var(--bg-surface)", borderTop: "1px solid var(--border-card)", display: "flex", flexDirection: "column", height: collapsed ? 40 : "var(--drawer-h)", overflow: "hidden", boxSizing: "border-box", flexShrink: 0, transition: "height .15s ease", ...style }}>
11
+ <div style={{ height: 40, display: "flex", alignItems: "center", gap: 12, padding: "0 16px", boxSizing: "border-box", flexShrink: 0 }}>
12
+ <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)" }}>{title}</span>
13
+ <span style={{ flex: 1 }} />
14
+ <Checkbox label="Debug Mode" checked={debug} onChange={onDebug} />
15
+ <IconButton icon={collapsed ? "chevron-up" : "chevron-down"} size="xs" muted onClick={onCollapse} />
16
+ </div>
17
+ {!collapsed ? (
18
+ <div style={{ overflowY: "auto", borderTop: "1px solid var(--border-subtle)" }}>
19
+ <DataTable dense columns={columns} rows={rows} headerBorder={false} />
20
+ </div>
21
+ ) : null}
22
+ </div>
23
+ );
24
+ }
@@ -0,0 +1,21 @@
1
+ <script setup>
2
+ import IconButton from '../buttons/IconButton.vue'
3
+ import Checkbox from '../forms/Checkbox.vue'
4
+ import DataTable from '../data/DataTable.vue'
5
+ // Bottom data-preview drawer — 250px: 40px header (title, Debug Mode, collapse) + dense table.
6
+ defineProps({ title: { type: String, default: 'Data Preview' }, columns: { type: Array, default: () => [] }, rows: { type: Array, default: () => [] }, debug: Boolean, collapsed: Boolean, style: Object })
7
+ const emit = defineEmits(['update:debug', 'toggleCollapse'])
8
+ </script>
9
+ <template>
10
+ <div :style="{ background: 'var(--bg-surface)', borderTop: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', height: collapsed ? 40 : 'var(--drawer-h)', overflow: 'hidden', boxSizing: 'border-box', flexShrink: 0, transition: 'height .15s ease', ...style }">
11
+ <div style="height:40px;display:flex;align-items:center;gap:12px;padding:0 16px;box-sizing:border-box;flex-shrink:0">
12
+ <span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-heading)">{{ title }}</span>
13
+ <span style="flex:1" />
14
+ <Checkbox label="Debug Mode" :checked="debug" @change="v => emit('update:debug', v)" />
15
+ <IconButton :icon="collapsed ? 'chevron-up' : 'chevron-down'" size="xs" muted @click="emit('toggleCollapse')" />
16
+ </div>
17
+ <div v-if="!collapsed" style="overflow-y:auto;border-top:1px solid var(--border-subtle)">
18
+ <DataTable dense :columns="columns" :rows="rows" :header-border="false" />
19
+ </div>
20
+ </div>
21
+ </template>
@@ -0,0 +1,47 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Canvas pipeline node — 220×90 r16 with tinted 48px icon tile, ports, status badges.
4
+ */
5
+ export interface NodeCardProps {
6
+ title?: string;
7
+ /** e.g. "Detail Sheet", "Association Match" */
8
+ subtitle?: string;
9
+ icon?: string;
10
+ /** 13px glyph before the subtitle (default "info"); false hides it */
11
+ subtitleIcon?: string | false;
12
+ hue?: "source" | "join" | "transform" | "merge" | "output";
13
+ selected?: boolean;
14
+ /** Icon-tile overlay dot */
15
+ badge?: "error" | "warning" | "clock";
16
+ /** [] no input · [null] plain port · ["A","B"] labeled pills */
17
+ inputs?: (string | null)[];
18
+ output?: boolean;
19
+ showMenu?: boolean;
20
+ onClick?: () => void;
21
+ onMenu?: (e: React.MouseEvent) => void;
22
+ /** Pointer-down on the output port — the canvas uses this to start a wire */
23
+ onOutputDown?: (e: React.PointerEvent) => void;
24
+ /** Pointer-up on input port `i` */
25
+ onInputUp?: (i: number, e: React.PointerEvent) => void;
26
+ onInputEnter?: (i: number) => void;
27
+ onInputLeave?: (i: number) => void;
28
+ /** "active" while a wire is being dragged out of this node */
29
+ outputTone?: PortTone;
30
+ /** Per-input tone; "target" marks the port under the cursor mid-drag */
31
+ inputTones?: PortTone[];
32
+ style?: React.CSSProperties;
33
+ }
34
+ export declare function NodeCard(props: NodeCardProps): JSX.Element;
35
+
36
+ /** default = grey · active = dragging from it · target = valid drop, shows a crosshair */
37
+ export type PortTone = "default" | "active" | "target";
38
+ export interface PortProps {
39
+ tone?: PortTone;
40
+ /** Enables hover lighting and the grab cursor */
41
+ interactive?: boolean;
42
+ style?: React.CSSProperties;
43
+ }
44
+ /** 22px round port. */
45
+ export declare function Port(props: PortProps): JSX.Element;
46
+ /** 28×22 "A >" input pill. */
47
+ export declare function PortLabel(props: PortProps & { label?: string }): JSX.Element;
@@ -0,0 +1,97 @@
1
+ import React from "react";
2
+ import { Icon } from "../icons/Icon.jsx";
3
+ import { IconTile, StatusBadge } from "../display/Badge.jsx";
4
+
5
+ /* Ports are the connection handles: they light up on hover, stay lit while a wire is
6
+ being dragged out of them, and show a crosshair when they're a valid drop target. */
7
+ function portSkin(tone, hover, interactive) {
8
+ const hot = tone === "active" || tone === "target" || (interactive && hover);
9
+ return {
10
+ background: tone === "target" ? "var(--soft-bg)" : "var(--bg-surface)",
11
+ border: `2px solid ${hot ? "var(--action-primary)" : "var(--port-border)"}`,
12
+ boxShadow: tone === "active" || tone === "target" ? "0 0 0 3px var(--focus-ring)" : "none",
13
+ color: hot ? "var(--action-primary)" : "var(--text-muted)",
14
+ cursor: interactive ? (tone === "active" ? "grabbing" : "grab") : "default",
15
+ transition: "var(--t-hover)",
16
+ };
17
+ }
18
+
19
+ /** Round output/input port — 22px. tone: "default" | "active" (dragging from it) | "target" (drop here). */
20
+ export function Port({ tone = "default", interactive = false, style, onMouseEnter, onMouseLeave, ...rest }) {
21
+ const [hover, setHover] = React.useState(false);
22
+ return (
23
+ <span {...rest}
24
+ onMouseEnter={(e) => { setHover(true); onMouseEnter && onMouseEnter(e); }}
25
+ onMouseLeave={(e) => { setHover(false); onMouseLeave && onMouseLeave(e); }}
26
+ style={{ width: 22, height: 22, borderRadius: "var(--radius-full)", boxSizing: "border-box", display: "inline-flex", alignItems: "center", justifyContent: "center", ...portSkin(tone, hover, interactive), ...style }}>
27
+ <Icon name={tone === "target" ? "plus" : "arrow-right"} size={12} strokeWidth={2.2} />
28
+ </span>
29
+ );
30
+ }
31
+
32
+ /** Labeled input port pill ("A >", "B >") — 28×22, same three tones as Port. */
33
+ export function PortLabel({ label = "A", tone = "default", interactive = false, style, onMouseEnter, onMouseLeave, ...rest }) {
34
+ const [hover, setHover] = React.useState(false);
35
+ return (
36
+ <span {...rest}
37
+ onMouseEnter={(e) => { setHover(true); onMouseEnter && onMouseEnter(e); }}
38
+ onMouseLeave={(e) => { setHover(false); onMouseLeave && onMouseLeave(e); }}
39
+ style={{ width: 28, height: 22, borderRadius: "var(--radius-full)", boxSizing: "border-box", display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 2, fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", letterSpacing: "var(--tracking-xs)", lineHeight: 1, ...portSkin(tone, hover, interactive), ...style }}>
40
+ {tone === "target" ? <Icon name="plus" size={12} strokeWidth={2.2} /> : <>{label}<Icon name="chevron-right" size={9} strokeWidth={2.5} /></>}
41
+ </span>
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Canvas node card — 220×90, r16, soft shadow. Selected = blue border + blue-100 ring.
47
+ * badge: "error" | "warning" | "clock" overlay on the icon tile.
48
+ * Port interaction is driven by the canvas: onOutputDown starts a wire, onInputUp lands it,
49
+ * and outputTone / inputTones light the handles.
50
+ */
51
+ export function NodeCard({ title, subtitle, icon = "table", subtitleIcon, hue = "source", selected, badge, inputs = [], output = true, showMenu = true, onClick, onMenu, onOutputDown, onInputUp, onInputEnter, onInputLeave, outputTone = "default", inputTones = [], style }) {
52
+ const live = !!(onOutputDown || onInputUp);
53
+ return (
54
+ <div onClick={onClick} style={{ position: "relative", width: 220, height: 90, borderRadius: "var(--radius-node)", background: "var(--bg-surface)", border: `1px solid ${selected ? "var(--selected-border)" : "var(--border-control)"}`, boxShadow: selected ? "var(--shadow-selected)" : "var(--shadow-node)", boxSizing: "border-box", cursor: "pointer", ...style }}>
55
+ <div style={{ display: "flex", alignItems: "center", gap: 12, padding: 16, height: "100%", boxSizing: "border-box" }}>
56
+ <span style={{ position: "relative", flexShrink: 0 }}>
57
+ <IconTile icon={icon} hue={hue} kind="node" />
58
+ {badge === "error" ? <StatusBadge tone="danger" icon="bug" size={20} style={{ position: "absolute", top: -6, right: -6 }} /> : null}
59
+ {badge === "warning" ? <StatusBadge tone="warning" icon="triangle-alert" size={20} style={{ position: "absolute", top: -6, right: -6 }} /> : null}
60
+ {badge === "clock" ? <StatusBadge tone="pending" icon="clock" size={20} style={{ position: "absolute", top: -6, right: -6 }} /> : null}
61
+ </span>
62
+ <div style={{ display: "flex", flexDirection: "column", minWidth: 0, flex: 1, paddingRight: 18 }}>
63
+ <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-base)", lineHeight: "17.875px", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{title}</span>
64
+ <span style={{ display: "flex", alignItems: "flex-start", gap: 4, paddingTop: 4, minWidth: 0 }}>
65
+ {subtitleIcon !== false ? <span style={{ color: "var(--text-muted)", display: "inline-flex", flexShrink: 0, paddingTop: 1 }}><Icon name={subtitleIcon || "info"} size={13} /></span> : null}
66
+ {/* Node types run long ("Field Value Calculation"), so the subtitle wraps to a
67
+ second line and only then clamps — the card size never changes. */}
68
+ <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "13.75px", letterSpacing: "var(--tracking-xs)", color: "var(--text-muted)", minWidth: 0, overflow: "hidden", display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: 2, overflowWrap: "break-word" }}>{subtitle}</span>
69
+ </span>
70
+ </div>
71
+ </div>
72
+ {showMenu ? (
73
+ <button type="button" onClick={(e) => { e.stopPropagation(); onMenu && onMenu(e); }} style={{ position: "absolute", top: 10, right: 12, width: 23, height: 23, borderRadius: "var(--radius-md)", border: "none", background: "transparent", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-muted)", padding: 0 }}
74
+ onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-hover)"} onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
75
+ <Icon name="ellipsis" size={15} />
76
+ </button>
77
+ ) : null}
78
+ {inputs.length === 0 ? null : inputs.length === 1 && !inputs[0] ? (
79
+ <Port tone={inputTones[0] || "default"} interactive={live}
80
+ onMouseEnter={onInputEnter ? () => onInputEnter(0) : undefined} onMouseLeave={onInputLeave ? () => onInputLeave(0) : undefined}
81
+ onPointerUp={onInputUp ? (e) => onInputUp(0, e) : undefined}
82
+ style={{ position: "absolute", left: -11, top: 33 }} />
83
+ ) : inputs.map((l, i) => (
84
+ <PortLabel key={i} label={l} tone={inputTones[i] || "default"} interactive={live}
85
+ onMouseEnter={onInputEnter ? () => onInputEnter(i) : undefined} onMouseLeave={onInputLeave ? () => onInputLeave(i) : undefined}
86
+ onPointerUp={onInputUp ? (e) => onInputUp(i, e) : undefined}
87
+ style={{ position: "absolute", left: -14, top: inputs.length === 1 ? 33 : 12 + i * 38 }} />
88
+ ))}
89
+ {output ? (
90
+ <Port tone={outputTone} interactive={live}
91
+ onPointerDown={onOutputDown ? (e) => { e.stopPropagation(); onOutputDown(e); } : undefined}
92
+ onClick={onOutputDown ? (e) => e.stopPropagation() : undefined}
93
+ style={{ position: "absolute", right: -11, top: 33 }} />
94
+ ) : null}
95
+ </div>
96
+ );
97
+ }