decantr 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/AGENTS.md +868 -0
  2. package/CHANGELOG.md +255 -0
  3. package/CLAUDE.md +178 -0
  4. package/LICENSE +21 -0
  5. package/README.md +229 -0
  6. package/cli/art.js +127 -0
  7. package/cli/commands/a11y.js +61 -0
  8. package/cli/commands/audit.js +225 -0
  9. package/cli/commands/build.js +38 -0
  10. package/cli/commands/dev.js +18 -0
  11. package/cli/commands/doctor.js +197 -0
  12. package/cli/commands/figma-sync.js +48 -0
  13. package/cli/commands/figma-tokens.js +55 -0
  14. package/cli/commands/generate.js +26 -0
  15. package/cli/commands/init.js +116 -0
  16. package/cli/commands/lint.js +209 -0
  17. package/cli/commands/mcp.js +530 -0
  18. package/cli/commands/migrate.js +175 -0
  19. package/cli/commands/test.js +38 -0
  20. package/cli/commands/validate.js +354 -0
  21. package/cli/index.js +113 -0
  22. package/package.json +95 -0
  23. package/reference/atoms.md +517 -0
  24. package/reference/behaviors.md +384 -0
  25. package/reference/build-tooling.md +275 -0
  26. package/reference/color-guidelines.md +965 -0
  27. package/reference/component-lifecycle.md +137 -0
  28. package/reference/compound-spacing.md +95 -0
  29. package/reference/decantation-process.md +499 -0
  30. package/reference/dev-server-routes.md +93 -0
  31. package/reference/form-system.md +253 -0
  32. package/reference/i18n.md +336 -0
  33. package/reference/icons.md +576 -0
  34. package/reference/llm-primer.md +953 -0
  35. package/reference/plugins.md +252 -0
  36. package/reference/registry-consumption.md +76 -0
  37. package/reference/router.md +217 -0
  38. package/reference/shells.md +116 -0
  39. package/reference/spatial-guidelines.md +541 -0
  40. package/reference/ssr.md +234 -0
  41. package/reference/state-data.md +215 -0
  42. package/reference/state-patterns.md +166 -0
  43. package/reference/state.md +194 -0
  44. package/reference/style-system.md +110 -0
  45. package/reference/tokens.md +460 -0
  46. package/src/app.js +19 -0
  47. package/src/chart/_animate.js +266 -0
  48. package/src/chart/_base.js +109 -0
  49. package/src/chart/_data.js +209 -0
  50. package/src/chart/_format.js +106 -0
  51. package/src/chart/_interact.js +364 -0
  52. package/src/chart/_palette.js +105 -0
  53. package/src/chart/_renderer.js +52 -0
  54. package/src/chart/_scene.js +262 -0
  55. package/src/chart/_shared.js +371 -0
  56. package/src/chart/index.js +637 -0
  57. package/src/chart/layouts/_layout-base.js +328 -0
  58. package/src/chart/layouts/cartesian.js +148 -0
  59. package/src/chart/layouts/hierarchy.js +562 -0
  60. package/src/chart/layouts/polar.js +101 -0
  61. package/src/chart/renderers/canvas.js +179 -0
  62. package/src/chart/renderers/svg.js +256 -0
  63. package/src/chart/renderers/webgpu.js +715 -0
  64. package/src/chart/types/_type-base.js +26 -0
  65. package/src/chart/types/area.js +134 -0
  66. package/src/chart/types/bar.js +173 -0
  67. package/src/chart/types/box-plot.js +125 -0
  68. package/src/chart/types/bubble.js +63 -0
  69. package/src/chart/types/candlestick.js +115 -0
  70. package/src/chart/types/chord.js +85 -0
  71. package/src/chart/types/combination.js +108 -0
  72. package/src/chart/types/funnel.js +68 -0
  73. package/src/chart/types/gauge.js +163 -0
  74. package/src/chart/types/heatmap.js +98 -0
  75. package/src/chart/types/histogram.js +71 -0
  76. package/src/chart/types/line.js +111 -0
  77. package/src/chart/types/org-chart.js +93 -0
  78. package/src/chart/types/pie.js +81 -0
  79. package/src/chart/types/radar.js +96 -0
  80. package/src/chart/types/radial.js +68 -0
  81. package/src/chart/types/range-area.js +55 -0
  82. package/src/chart/types/range-bar.js +61 -0
  83. package/src/chart/types/sankey.js +73 -0
  84. package/src/chart/types/scatter.js +66 -0
  85. package/src/chart/types/sparkline.js +81 -0
  86. package/src/chart/types/sunburst.js +69 -0
  87. package/src/chart/types/swimlane.js +88 -0
  88. package/src/chart/types/treemap.js +62 -0
  89. package/src/chart/types/waterfall.js +100 -0
  90. package/src/components/_base.js +1658 -0
  91. package/src/components/_behaviors.js +1140 -0
  92. package/src/components/_primitives.js +534 -0
  93. package/src/components/_qr-encoder.js +539 -0
  94. package/src/components/accordion.js +207 -0
  95. package/src/components/affix.js +62 -0
  96. package/src/components/alert-dialog.js +75 -0
  97. package/src/components/alert.js +47 -0
  98. package/src/components/aspect-ratio.js +24 -0
  99. package/src/components/avatar-group.js +55 -0
  100. package/src/components/avatar.js +38 -0
  101. package/src/components/back-top.js +75 -0
  102. package/src/components/badge.js +74 -0
  103. package/src/components/banner.js +68 -0
  104. package/src/components/breadcrumb.js +162 -0
  105. package/src/components/button.js +115 -0
  106. package/src/components/calendar.js +131 -0
  107. package/src/components/card.js +192 -0
  108. package/src/components/carousel.js +98 -0
  109. package/src/components/cascader.js +261 -0
  110. package/src/components/checkbox.js +80 -0
  111. package/src/components/chip.js +81 -0
  112. package/src/components/code-block.js +82 -0
  113. package/src/components/collapsible.js +50 -0
  114. package/src/components/color-palette.js +438 -0
  115. package/src/components/color-picker.js +314 -0
  116. package/src/components/combobox.js +181 -0
  117. package/src/components/command.js +174 -0
  118. package/src/components/comment.js +206 -0
  119. package/src/components/context-menu.js +76 -0
  120. package/src/components/data-table.js +724 -0
  121. package/src/components/date-picker.js +217 -0
  122. package/src/components/date-range-picker.js +244 -0
  123. package/src/components/datetime-picker.js +271 -0
  124. package/src/components/descriptions.js +68 -0
  125. package/src/components/drawer.js +179 -0
  126. package/src/components/dropdown.js +88 -0
  127. package/src/components/empty.js +41 -0
  128. package/src/components/float-button.js +90 -0
  129. package/src/components/form.js +106 -0
  130. package/src/components/hover-card.js +49 -0
  131. package/src/components/icon.js +87 -0
  132. package/src/components/image.js +97 -0
  133. package/src/components/index.js +117 -0
  134. package/src/components/input-group.js +75 -0
  135. package/src/components/input-number.js +155 -0
  136. package/src/components/input-otp.js +178 -0
  137. package/src/components/input.js +91 -0
  138. package/src/components/kbd.js +36 -0
  139. package/src/components/label.js +25 -0
  140. package/src/components/list.js +118 -0
  141. package/src/components/masked-input.js +236 -0
  142. package/src/components/mentions.js +165 -0
  143. package/src/components/menu.js +259 -0
  144. package/src/components/message.js +80 -0
  145. package/src/components/modal.js +147 -0
  146. package/src/components/navigation-menu.js +166 -0
  147. package/src/components/notification.js +84 -0
  148. package/src/components/pagination.js +104 -0
  149. package/src/components/placeholder.js +132 -0
  150. package/src/components/popconfirm.js +70 -0
  151. package/src/components/popover.js +58 -0
  152. package/src/components/progress.js +61 -0
  153. package/src/components/qrcode.js +251 -0
  154. package/src/components/radiogroup.js +120 -0
  155. package/src/components/range-slider.js +176 -0
  156. package/src/components/rate.js +186 -0
  157. package/src/components/resizable.js +83 -0
  158. package/src/components/result.js +57 -0
  159. package/src/components/scroll-area.js +43 -0
  160. package/src/components/segmented.js +97 -0
  161. package/src/components/select.js +165 -0
  162. package/src/components/separator.js +31 -0
  163. package/src/components/shell.js +407 -0
  164. package/src/components/skeleton.js +39 -0
  165. package/src/components/slider.js +141 -0
  166. package/src/components/sortable-list.js +176 -0
  167. package/src/components/space.js +42 -0
  168. package/src/components/spinner.js +112 -0
  169. package/src/components/splitter.js +147 -0
  170. package/src/components/statistic.js +136 -0
  171. package/src/components/steps.js +99 -0
  172. package/src/components/switch.js +95 -0
  173. package/src/components/table.js +44 -0
  174. package/src/components/tabs.js +216 -0
  175. package/src/components/tag.js +115 -0
  176. package/src/components/textarea.js +82 -0
  177. package/src/components/time-picker.js +153 -0
  178. package/src/components/time-range-picker.js +170 -0
  179. package/src/components/timeline.js +226 -0
  180. package/src/components/toast.js +71 -0
  181. package/src/components/toggle.js +213 -0
  182. package/src/components/tooltip.js +57 -0
  183. package/src/components/tour.js +159 -0
  184. package/src/components/transfer.js +163 -0
  185. package/src/components/tree-select.js +274 -0
  186. package/src/components/tree.js +141 -0
  187. package/src/components/typography.js +136 -0
  188. package/src/components/upload.js +118 -0
  189. package/src/components/visually-hidden.js +20 -0
  190. package/src/components/watermark.js +124 -0
  191. package/src/core/index.js +539 -0
  192. package/src/core/lifecycle.js +69 -0
  193. package/src/css/atoms.js +651 -0
  194. package/src/css/components.js +940 -0
  195. package/src/css/derive.js +1296 -0
  196. package/src/css/index.js +265 -0
  197. package/src/css/runtime.js +268 -0
  198. package/src/css/styles/addons/bioluminescent.js +93 -0
  199. package/src/css/styles/addons/clay.js +70 -0
  200. package/src/css/styles/addons/clean.js +57 -0
  201. package/src/css/styles/addons/command-center.js +143 -0
  202. package/src/css/styles/addons/dopamine.js +83 -0
  203. package/src/css/styles/addons/editorial.js +80 -0
  204. package/src/css/styles/addons/glassmorphism.js +99 -0
  205. package/src/css/styles/addons/liquid-glass.js +105 -0
  206. package/src/css/styles/addons/prismatic.js +100 -0
  207. package/src/css/styles/addons/retro.js +63 -0
  208. package/src/css/styles/auradecantism.js +96 -0
  209. package/src/css/theme-registry.js +444 -0
  210. package/src/data/entity.js +281 -0
  211. package/src/data/index.js +13 -0
  212. package/src/data/persist.js +225 -0
  213. package/src/data/query.js +839 -0
  214. package/src/data/realtime.js +299 -0
  215. package/src/data/url.js +177 -0
  216. package/src/data/worker.js +134 -0
  217. package/src/explorer/archetypes.js +243 -0
  218. package/src/explorer/atoms.js +228 -0
  219. package/src/explorer/charts.js +497 -0
  220. package/src/explorer/components.js +129 -0
  221. package/src/explorer/foundations.js +949 -0
  222. package/src/explorer/icons.js +178 -0
  223. package/src/explorer/patterns.js +247 -0
  224. package/src/explorer/recipes.js +194 -0
  225. package/src/explorer/shared/pattern-examples.js +1337 -0
  226. package/src/explorer/shared/showcase-renderer.js +958 -0
  227. package/src/explorer/shared/spec-table.js +41 -0
  228. package/src/explorer/shared/usage-links.js +87 -0
  229. package/src/explorer/shell-config.js +10 -0
  230. package/src/explorer/shells.js +551 -0
  231. package/src/explorer/styles.js +161 -0
  232. package/src/explorer/tokens.js +262 -0
  233. package/src/explorer/tools.js +525 -0
  234. package/src/form/index.js +804 -0
  235. package/src/i18n/index.js +251 -0
  236. package/src/icons/essential.js +479 -0
  237. package/src/icons/index.js +53 -0
  238. package/src/plugins/index.js +282 -0
  239. package/src/registry/archetypes/content-site.json +71 -0
  240. package/src/registry/archetypes/docs-explorer.json +23 -0
  241. package/src/registry/archetypes/ecommerce.json +104 -0
  242. package/src/registry/archetypes/financial-dashboard.json +77 -0
  243. package/src/registry/archetypes/index.json +41 -0
  244. package/src/registry/archetypes/portfolio.json +82 -0
  245. package/src/registry/archetypes/recipe-community.json +159 -0
  246. package/src/registry/archetypes/saas-dashboard.json +86 -0
  247. package/src/registry/architect/cross-cutting.json +45 -0
  248. package/src/registry/architect/domains/ecommerce.json +294 -0
  249. package/src/registry/architect/domains/financial-services.json +302 -0
  250. package/src/registry/architect/index.json +26 -0
  251. package/src/registry/architect/traits.json +379 -0
  252. package/src/registry/atoms.json +16 -0
  253. package/src/registry/chart-showcase.json +160 -0
  254. package/src/registry/chart.json +136 -0
  255. package/src/registry/components.json +8616 -0
  256. package/src/registry/core.json +216 -0
  257. package/src/registry/css.json +319 -0
  258. package/src/registry/data.json +135 -0
  259. package/src/registry/foundations.json +11 -0
  260. package/src/registry/icons.json +463 -0
  261. package/src/registry/index.json +101 -0
  262. package/src/registry/patterns/activity-feed.json +37 -0
  263. package/src/registry/patterns/article-content.json +27 -0
  264. package/src/registry/patterns/auth-form.json +37 -0
  265. package/src/registry/patterns/author-card.json +20 -0
  266. package/src/registry/patterns/card-grid.json +127 -0
  267. package/src/registry/patterns/category-nav.json +26 -0
  268. package/src/registry/patterns/chart-grid.json +36 -0
  269. package/src/registry/patterns/chat-interface.json +37 -0
  270. package/src/registry/patterns/checklist-card.json +55 -0
  271. package/src/registry/patterns/comparison-panel.json +27 -0
  272. package/src/registry/patterns/component-showcase.json +24 -0
  273. package/src/registry/patterns/contact-form.json +31 -0
  274. package/src/registry/patterns/cta-section.json +20 -0
  275. package/src/registry/patterns/data-table.json +37 -0
  276. package/src/registry/patterns/detail-header.json +83 -0
  277. package/src/registry/patterns/detail-panel.json +27 -0
  278. package/src/registry/patterns/explorer-shell.json +22 -0
  279. package/src/registry/patterns/filter-bar.json +33 -0
  280. package/src/registry/patterns/filter-sidebar.json +27 -0
  281. package/src/registry/patterns/form-sections.json +110 -0
  282. package/src/registry/patterns/goal-tracker.json +27 -0
  283. package/src/registry/patterns/hero.json +107 -0
  284. package/src/registry/patterns/index.json +47 -0
  285. package/src/registry/patterns/kpi-grid.json +36 -0
  286. package/src/registry/patterns/media-gallery.json +20 -0
  287. package/src/registry/patterns/order-history.json +20 -0
  288. package/src/registry/patterns/pagination.json +19 -0
  289. package/src/registry/patterns/photo-to-recipe.json +36 -0
  290. package/src/registry/patterns/pipeline-tracker.json +28 -0
  291. package/src/registry/patterns/post-list.json +27 -0
  292. package/src/registry/patterns/pricing-table.json +32 -0
  293. package/src/registry/patterns/scorecard.json +28 -0
  294. package/src/registry/patterns/search-bar.json +20 -0
  295. package/src/registry/patterns/specimen-grid.json +19 -0
  296. package/src/registry/patterns/stat-card.json +55 -0
  297. package/src/registry/patterns/stats-bar.json +55 -0
  298. package/src/registry/patterns/steps-card.json +55 -0
  299. package/src/registry/patterns/table-of-contents.json +19 -0
  300. package/src/registry/patterns/testimonials.json +21 -0
  301. package/src/registry/patterns/timeline.json +27 -0
  302. package/src/registry/patterns/token-inspector.json +21 -0
  303. package/src/registry/patterns/wizard.json +27 -0
  304. package/src/registry/recipe-auradecantism.json +69 -0
  305. package/src/registry/recipe-clean.json +65 -0
  306. package/src/registry/recipe-command-center.json +78 -0
  307. package/src/registry/router.json +73 -0
  308. package/src/registry/schema/README.md +197 -0
  309. package/src/registry/skeletons.json +259 -0
  310. package/src/registry/state.json +137 -0
  311. package/src/registry/tokens.json +40 -0
  312. package/src/router/hash.js +17 -0
  313. package/src/router/history.js +18 -0
  314. package/src/router/index.js +598 -0
  315. package/src/ssr/index.js +922 -0
  316. package/src/state/arrays.js +181 -0
  317. package/src/state/devtools.js +647 -0
  318. package/src/state/index.js +498 -0
  319. package/src/state/middleware.js +288 -0
  320. package/src/state/scheduler.js +206 -0
  321. package/src/state/store.js +300 -0
  322. package/src/tags/index.js +19 -0
  323. package/src/tannins/auth.js +396 -0
  324. package/src/test/dom.js +352 -0
  325. package/src/test/index.js +62 -0
  326. package/src/test/state.js +306 -0
  327. package/tools/a11y-audit.js +487 -0
  328. package/tools/analyzer.js +315 -0
  329. package/tools/audit.js +706 -0
  330. package/tools/builder.js +1422 -0
  331. package/tools/css-extract.js +188 -0
  332. package/tools/dev-server.js +316 -0
  333. package/tools/dts-gen.js +1260 -0
  334. package/tools/figma-components.js +329 -0
  335. package/tools/figma-patterns.js +516 -0
  336. package/tools/figma-plugin/code.js +453 -0
  337. package/tools/figma-plugin/manifest.json +14 -0
  338. package/tools/figma-plugin/ui.html +268 -0
  339. package/tools/figma-render.js +293 -0
  340. package/tools/figma-tokens.js +712 -0
  341. package/tools/figma-upload.js +318 -0
  342. package/tools/generate.js +738 -0
  343. package/tools/icons.js +133 -0
  344. package/tools/init-templates.js +265 -0
  345. package/tools/install-hooks.sh +5 -0
  346. package/tools/migrations/0.5.0.js +53 -0
  347. package/tools/migrations/0.6.0.js +95 -0
  348. package/tools/minify.js +170 -0
  349. package/tools/pre-commit +4 -0
  350. package/tools/registry.js +662 -0
  351. package/tools/reset-playground.js +61 -0
  352. package/tools/starter-templates/content-site/app.js +49 -0
  353. package/tools/starter-templates/content-site/essence.js +19 -0
  354. package/tools/starter-templates/content-site/pages.js +31 -0
  355. package/tools/starter-templates/ecommerce/app.js +50 -0
  356. package/tools/starter-templates/ecommerce/essence.js +19 -0
  357. package/tools/starter-templates/ecommerce/pages.js +31 -0
  358. package/tools/starter-templates/landing-page/app.js +38 -0
  359. package/tools/starter-templates/landing-page/essence.js +18 -0
  360. package/tools/starter-templates/landing-page/pages.js +21 -0
  361. package/tools/starter-templates/portfolio/app.js +45 -0
  362. package/tools/starter-templates/portfolio/essence.js +19 -0
  363. package/tools/starter-templates/portfolio/pages.js +33 -0
  364. package/tools/starter-templates/saas-dashboard/app.js +70 -0
  365. package/tools/starter-templates/saas-dashboard/essence.js +19 -0
  366. package/tools/starter-templates/saas-dashboard/pages.js +31 -0
  367. package/tools/verify-pack.js +203 -0
  368. package/types/chart.d.ts +77 -0
  369. package/types/components.d.ts +587 -0
  370. package/types/core.d.ts +89 -0
  371. package/types/css.d.ts +149 -0
  372. package/types/data.d.ts +238 -0
  373. package/types/form.d.ts +164 -0
  374. package/types/i18n.d.ts +51 -0
  375. package/types/icons.d.ts +27 -0
  376. package/types/index.d.ts +13 -0
  377. package/types/router.d.ts +116 -0
  378. package/types/ssr.d.ts +102 -0
  379. package/types/state.d.ts +83 -0
  380. package/types/tags.d.ts +62 -0
  381. package/types/tannins.d.ts +63 -0
  382. package/types/test.d.ts +48 -0
@@ -0,0 +1,137 @@
1
+ # Component Lifecycle & Cleanup
2
+
3
+ ## The Problem
4
+
5
+ Decantr components return raw `HTMLElement` nodes — not wrapper objects with lifecycle methods. This means cleanup (removing document listeners, clearing timers, disconnecting observers) requires explicit wiring. Without it, components leak resources when removed from the DOM.
6
+
7
+ ## Cleanup Contract
8
+
9
+ **Every component that adds document-level listeners, timers, or observers MUST clean them up.** This applies to:
10
+
11
+ - `document.addEventListener(...)` — click-outside, escape-to-close, resize, scroll
12
+ - `setTimeout` / `setInterval` — debounced actions, animation timers, polling
13
+ - `IntersectionObserver` / `ResizeObserver` / `MutationObserver`
14
+ - `window.addEventListener(...)` — resize, scroll, popstate
15
+
16
+ ## How Cleanup Works
17
+
18
+ ### Pattern 1: Use `_behaviors.js` primitives (preferred)
19
+
20
+ All behavioral primitives in `_behaviors.js` return `{ destroy() }`. Components MUST call `.destroy()` when removed.
21
+
22
+ ```javascript
23
+ import { createOverlay, createListbox, createFocusTrap } from './_behaviors.js';
24
+
25
+ export function Select(props) {
26
+ const trigger = /* ... */;
27
+ const panel = /* ... */;
28
+
29
+ const overlay = createOverlay(trigger, panel, { trigger: 'click' });
30
+ const listbox = createListbox(panel, { onSelect: /* ... */ });
31
+
32
+ // Wire cleanup to element removal
33
+ const el = h('div', { class: 'd-select' }, trigger, panel);
34
+ onDestroy(() => {
35
+ overlay.destroy();
36
+ listbox.destroy();
37
+ });
38
+ return el;
39
+ }
40
+ ```
41
+
42
+ ### Pattern 2: Manual cleanup collection
43
+
44
+ For components that add their own listeners (not via behaviors):
45
+
46
+ ```javascript
47
+ export function MyComponent(props) {
48
+ const cleanups = [];
49
+
50
+ const onResize = () => { /* ... */ };
51
+ window.addEventListener('resize', onResize);
52
+ cleanups.push(() => window.removeEventListener('resize', onResize));
53
+
54
+ const timer = setInterval(poll, 5000);
55
+ cleanups.push(() => clearInterval(timer));
56
+
57
+ const el = h('div', { /* ... */ });
58
+ onDestroy(() => cleanups.forEach(fn => fn()));
59
+ return el;
60
+ }
61
+ ```
62
+
63
+ ### Pattern 3: MutationObserver self-cleanup (last resort)
64
+
65
+ When `onDestroy` context is unavailable (e.g., dynamically created elements):
66
+
67
+ ```javascript
68
+ const observer = new MutationObserver((mutations) => {
69
+ for (const m of mutations) {
70
+ for (const node of m.removedNodes) {
71
+ if (node === el || node.contains(el)) {
72
+ cleanup();
73
+ observer.disconnect();
74
+ }
75
+ }
76
+ }
77
+ });
78
+ observer.observe(el.parentNode, { childList: true });
79
+ ```
80
+
81
+ ## Available `_behaviors.js` Primitives
82
+
83
+ | Primitive | Returns `destroy()`? | Use For |
84
+ |-----------|---------------------|---------|
85
+ | `createOverlay()` | Yes | Click-outside, escape, show/hide, ARIA expanded |
86
+ | `createListbox()` | Yes | Arrow-key navigation, selection, type-ahead |
87
+ | `createDisclosure()` | No (uses element listeners only) | Expand/collapse with animation |
88
+ | `createRovingTabindex()` | Yes | Tab navigation within groups |
89
+ | `createFocusTrap()` | Yes (via `deactivate()`) | Modal/drawer focus containment |
90
+ | `createDrag()` | Yes | Pointer-based drag interactions |
91
+ | `createVirtualScroll()` | Yes | Large list rendering |
92
+ | `createInfiniteScroll()` | Yes | Load-more sentinel |
93
+ | `createMasonry()` | Yes | Pinterest-style layout |
94
+ | `createScrollSpy()` | Yes (via `disconnect()`) | Section tracking |
95
+ | `createHotkey()` | Yes | Keyboard shortcuts |
96
+
97
+ ## Checklist Before Shipping a Component
98
+
99
+ 1. Does this component add `document.addEventListener`? -> Use `createOverlay` or collect cleanup
100
+ 2. Does this component use `setTimeout`/`setInterval`? -> Clear on destroy
101
+ 3. Does this component create an `Observer`? -> Disconnect on destroy
102
+ 4. Does this component use `createOverlay`/`createListbox`/etc.? -> Call `.destroy()` via `onDestroy`
103
+ 5. Does this component add `window.addEventListener`? -> Remove on destroy
104
+
105
+ ## Known Components Needing Cleanup Audit
106
+
107
+ **Completed** (have `onDestroy` wired — verified March 2026):
108
+ - `modal.js` — uses `createFocusTrap`, cleanup via `onDestroy`
109
+ - `select.js` — `onDestroy` added
110
+ - `combobox.js` — `onDestroy` added
111
+ - `context-menu.js` — `onDestroy` added
112
+ - `tooltip.js` — `onDestroy` added
113
+ - `slider.js` — `onDestroy` added
114
+ - `image.js` — `onDestroy` added
115
+ - `data-table.js` — `onDestroy` added
116
+ - `dropdown.js` — `onDestroy` added
117
+
118
+ **Remaining** — components that may still benefit from migrating to `_behaviors.js` primitives:
119
+ - `slider.js` — document pointermove/pointerup (candidate for `createDrag`)
120
+ - `data-table.js` — document pointermove/pointerup for column resize (candidate for `createDrag`)
121
+ - `tour.js` — document keydown, window resize (has manual cleanup, could use `createHotkey`)
122
+
123
+ ## Workbench & Tooling Lifecycle
124
+
125
+ The cleanup contract applies to **ALL code**, not just `src/components/`. Workbench explorer modules, docs site scripts, CLI preview tools — any code that adds event listeners, timers, or observers MUST wire `onDestroy` cleanup.
126
+
127
+ **Common violations in tooling code:**
128
+
129
+ - **Motion/animation demos** that add `mouseenter`/`mouseleave` listeners directly via `addEventListener` instead of element props (props are cleaned up with the element)
130
+ - **Search modals** that add `keydown` document listeners without cleanup
131
+ - **Live previews** that create `ResizeObserver` or `MutationObserver` without disconnecting
132
+
133
+ **Rule:** If a workbench explorer section adds listeners, it follows the same contract as a framework component. Use element event props (e.g. `onmouseenter`) for element-scoped events, and `onDestroy` + `_behaviors.js` for document-level listeners.
134
+
135
+ ---
136
+
137
+ **See also:** `reference/behaviors.md`, `reference/compound-spacing.md`
@@ -0,0 +1,95 @@
1
+ # Compound Spacing, Offsets & Density
2
+
3
+ > **Strategic guide**: For the full spatial design language — proximity tiers, density zones, responsive behavior, visual weight, and decision tables — see `reference/spatial-guidelines.md`. This document covers the implementation contracts for compound components.
4
+
5
+ ## Compound Spacing Contract
6
+
7
+ All compound components (Card, Modal, AlertDialog, Drawer) follow a unified spacing contract via `--d-compound-pad` and `--d-compound-gap`. This ensures consistent header/body/footer spacing across all overlay and container components.
8
+
9
+ | Section | Padding Rule |
10
+ |---------|-------------|
11
+ | **Header** | `var(--d-compound-pad) var(--d-compound-pad) 0` |
12
+ | **Body** | `var(--d-compound-gap) var(--d-compound-pad)` |
13
+ | **Body:last-child** | adds `padding-bottom: var(--d-compound-pad)` |
14
+ | **Footer** | `var(--d-compound-gap) var(--d-compound-pad) var(--d-compound-pad)` |
15
+
16
+ **Bordered footer exception:** When a compound footer has a visible `border-top` (e.g. Card), the border provides inter-section separation, so the footer uses `var(--d-compound-pad)` on all sides for vertical centering. The asymmetric `compound-gap` top is only appropriate when the gap alone is the separator (Modal, Drawer).
17
+
18
+ New compound components MUST follow this contract. Never hardcode padding in header/body/footer — use the compound tokens.
19
+
20
+ ## Popup Offset Hierarchy
21
+
22
+ > Full elevation hierarchy and offset strategy: `reference/spatial-guidelines.md` §11 Z-Axis Spatial Rules.
23
+
24
+ All floating elements use offset tokens for trigger->panel distance. The hierarchy reflects visual weight:
25
+
26
+ `--d-offset-dropdown` (2px) < `--d-offset-menu` (4px) < `--d-offset-tooltip` (6px) < `--d-offset-popover` (8px)
27
+
28
+ New floating components MUST use the appropriate offset token, never hardcoded pixel values.
29
+
30
+ ## Density Classes
31
+
32
+ > Full density rules, character mapping, and usage guidance: `reference/spatial-guidelines.md` §16 Density System Integration.
33
+
34
+ `.d-compact`, `.d-comfortable`, `.d-spacious` — cascade to children, override `--d-density-pad-x`, `--d-density-pad-y`, `--d-density-gap`, `--d-density-min-h`, `--d-density-text`, `--d-compound-pad`, `--d-compound-gap`
35
+
36
+ | Density | `--d-compound-pad` | `--d-compound-gap` | Controls | Interiors |
37
+ |---------|--------------------|--------------------|----------|-----------|
38
+ | compact | `var(--d-sp-3)` | `var(--d-sp-2)` | Tighter | Tighter |
39
+ | comfortable | `var(--d-sp-5)` | `var(--d-sp-3)` | Default | Default |
40
+ | spacious | `var(--d-sp-8)` | `var(--d-sp-4)` | Wider | Wider |
41
+
42
+ ## Field Sizing Contract
43
+
44
+ > Component sizing tiers, touch targets, and inset patterns: `reference/spatial-guidelines.md` §7 Component Sizing.
45
+
46
+ All form components support a unified 4-tier sizing system (xs/sm/md/lg). Height is the primary constraint; padding and font-size follow.
47
+
48
+ **Core components** (Button, Select, Input, Toggle, Combobox) use per-component size classes (`.d-btn-sm`, `.d-select-sm .d-select`, `.d-input-sm`, etc.) that include `min-height` overrides.
49
+
50
+ **Picker components** (DatePicker, TimePicker, Cascader, TreeSelect, ColorPicker, Mentions, InputNumber, DateRangePicker, TimeRangePicker) use `.d-field-{size}` utility classes that override density tokens locally:
51
+
52
+ ```css
53
+ .d-field-xs { --d-density-min-h:var(--d-field-h-xs); --d-density-pad-y:var(--d-field-py-xs); ... }
54
+ .d-field-sm { --d-density-min-h:var(--d-field-h-sm); ... }
55
+ .d-field-lg { --d-density-min-h:var(--d-field-h-lg); ... }
56
+ ```
57
+
58
+ Any child `.d-select`, `.d-input`, etc. inside a `.d-field-sm` wrapper inherits sm sizing via the density cascade — no per-component CSS needed.
59
+
60
+ **Tier ↔ density mapping:** compact defaults = sm tokens, comfortable defaults = md tokens, spacious defaults = lg tokens. This means setting density to "compact" automatically makes all form elements 28px height.
61
+
62
+ **Components with own size tokens:** Switch (`--d-switch-w/h/thumb-{tier}`), Checkbox/Radio (`--d-checkbox-size-{tier}`), InputOTP (`--d-otp-w/h/text-{tier}`).
63
+
64
+ ## Prose System
65
+
66
+ `.d-prose` — auto-applies vertical rhythm to child elements. Use for long-form content (articles, documentation, modal descriptions).
67
+
68
+ - Base: `font-size:var(--d-text-base); line-height:var(--d-lh-relaxed)`
69
+ - Between siblings: `> * + * { margin-top: var(--d-sp-4) }`
70
+ - Headings: graduated margin-top (sp-12->sp-10->sp-8->sp-6) + margin-bottom (sp-4->sp-3)
71
+ - Lists: left padding, per-item spacing
72
+ - Blockquote: left border + padding + italic
73
+ - Code/pre: mono font, padding, surface background
74
+ - Tables: cell padding, bottom borders
75
+
76
+ Usage: `div({ class: 'd-prose' }, h1('Title'), p('Body text...'), ul(li('Item')))`
77
+
78
+ ## Spacing Utilities
79
+
80
+ Child-spacing utilities use the `d-` prefix (not `_` atom prefix) because they require child combinators (`> * + *`) which cannot be expressed in the atom resolver.
81
+
82
+ | Class | Effect |
83
+ |-------|--------|
84
+ | `d-spacey-{1-24}` | `> * + * { margin-top: {scale} }` — vertical child spacing |
85
+ | `d-spacex-{1-24}` | `> * + * { margin-left: {scale} }` — horizontal child spacing |
86
+ | `d-dividey` | `> * + * { border-top: 1px solid var(--d-border) }` |
87
+ | `d-dividex` | `> * + * { border-left: 1px solid var(--d-border) }` |
88
+ | `d-dividey-strong` | `> * + * { border-top: 1px solid var(--d-border-strong) }` |
89
+ | `d-dividex-strong` | `> * + * { border-left: 1px solid var(--d-border-strong) }` |
90
+
91
+ Scale: 1 (0.25rem) through 24 (6rem). Same spacing scale as `_p`/`_m` atoms.
92
+
93
+ ---
94
+
95
+ **See also:** `reference/spatial-guidelines.md`, `reference/atoms.md`, `reference/tokens.md`