@sableui/react 0.0.0-stage → 0.1.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 (247) hide show
  1. package/AGENTS.md +157 -0
  2. package/CHANGELOG.md +50 -0
  3. package/CONTRIBUTING.md +221 -0
  4. package/DESIGN.md +548 -0
  5. package/LICENSE +21 -0
  6. package/README.md +194 -2
  7. package/THIRD_PARTY_NOTICES.md +44 -0
  8. package/bin/sable-lint.mjs +0 -0
  9. package/bin/sable.mjs +1223 -0
  10. package/dist/_contract-CYScOdf5.d.ts +150 -0
  11. package/dist/chunk-3IWZYBGH.js +398 -0
  12. package/dist/chunk-5Z5KLOAU.js +167 -0
  13. package/dist/chunk-7MG4SHYX.js +15 -0
  14. package/dist/chunk-ADLLDWLW.js +15 -0
  15. package/dist/chunk-EP55KSYA.js +14 -0
  16. package/dist/chunk-J23ELQQZ.js +9396 -0
  17. package/dist/chunk-JI7WJP2L.js +286 -0
  18. package/dist/chunk-K7RUHUGC.js +14 -0
  19. package/dist/chunk-KO3NAEBF.js +15 -0
  20. package/dist/chunk-L4IEIQQA.js +14 -0
  21. package/dist/chunk-L6Y46C62.js +270 -0
  22. package/dist/chunk-NEQNXI2G.js +25 -0
  23. package/dist/chunk-PAOZBZME.js +40 -0
  24. package/dist/chunk-RWP4XBSK.js +139 -0
  25. package/dist/chunk-SRQWQUTW.js +63 -0
  26. package/dist/chunk-YXBOYWBN.js +15 -0
  27. package/dist/foundations/index.d.ts +88 -0
  28. package/dist/foundations/index.js +792 -0
  29. package/dist/icon/index.d.ts +60 -0
  30. package/dist/icon/index.js +2 -0
  31. package/dist/icon-sets/brands.d.ts +44 -0
  32. package/dist/icon-sets/brands.js +147 -0
  33. package/dist/icon-sets/reicon.d.ts +8 -0
  34. package/dist/icon-sets/reicon.js +1 -0
  35. package/dist/index.d.ts +7013 -0
  36. package/dist/index.js +15462 -0
  37. package/dist/ios/chrome.css +83 -0
  38. package/dist/ios/frame.css +5 -0
  39. package/dist/ios/index.d.ts +70 -0
  40. package/dist/ios/index.js +313 -0
  41. package/dist/ios/preview.d.ts +64 -0
  42. package/dist/ios/preview.js +133 -0
  43. package/dist/ios/styles.css +77 -0
  44. package/dist/layout/index.d.ts +280 -0
  45. package/dist/layout/index.js +2 -0
  46. package/dist/meta-6dUzgC6M.d.ts +205 -0
  47. package/dist/patterns/index.d.ts +36 -0
  48. package/dist/patterns/index.js +934 -0
  49. package/dist/presets/index.d.ts +37 -0
  50. package/dist/presets/index.js +117 -0
  51. package/dist/registry-CyL28OzJ.d.ts +28 -0
  52. package/dist/styles.css +1893 -0
  53. package/dist/theme-provider-BWcizhAt.d.ts +105 -0
  54. package/dist/themes/atelier/atelier.css +213 -0
  55. package/dist/themes/atelier/index.d.ts +9 -0
  56. package/dist/themes/atelier/index.js +1 -0
  57. package/dist/themes/base/base.css +443 -0
  58. package/dist/themes/base/index.d.ts +9 -0
  59. package/dist/themes/base/index.js +1 -0
  60. package/dist/themes/ember/ember.css +270 -0
  61. package/dist/themes/ember/index.d.ts +9 -0
  62. package/dist/themes/ember/index.js +1 -0
  63. package/dist/themes/index.d.ts +10 -0
  64. package/dist/themes/index.js +8 -0
  65. package/dist/themes/meridian/index.d.ts +9 -0
  66. package/dist/themes/meridian/index.js +1 -0
  67. package/dist/themes/meridian/meridian.css +255 -0
  68. package/dist/themes/poppy/index.d.ts +6 -0
  69. package/dist/themes/poppy/index.js +1 -0
  70. package/dist/themes/poppy/poppy.css +174 -0
  71. package/dist/themes/prism/index.d.ts +6 -0
  72. package/dist/themes/prism/index.js +1 -0
  73. package/dist/themes/prism/prism.css +183 -0
  74. package/dist/themes/verdant/index.d.ts +9 -0
  75. package/dist/themes/verdant/index.js +1 -0
  76. package/dist/themes/verdant/verdant.css +210 -0
  77. package/dist/themes.css +30 -0
  78. package/llms/components/accordion.md +93 -0
  79. package/llms/components/app-header.md +70 -0
  80. package/llms/components/app-shell.md +117 -0
  81. package/llms/components/attachment.md +105 -0
  82. package/llms/components/avatar.md +141 -0
  83. package/llms/components/badge.md +117 -0
  84. package/llms/components/banner.md +119 -0
  85. package/llms/components/bottom-nav.md +80 -0
  86. package/llms/components/breadcrumbs.md +75 -0
  87. package/llms/components/browser.md +67 -0
  88. package/llms/components/bubble.md +119 -0
  89. package/llms/components/button.md +199 -0
  90. package/llms/components/calendar.md +75 -0
  91. package/llms/components/card.md +135 -0
  92. package/llms/components/carousel.md +87 -0
  93. package/llms/components/chat-composer.md +126 -0
  94. package/llms/components/checkbox-card.md +98 -0
  95. package/llms/components/checkbox.md +90 -0
  96. package/llms/components/code-block.md +81 -0
  97. package/llms/components/code.md +62 -0
  98. package/llms/components/collapsible.md +83 -0
  99. package/llms/components/color-field.md +100 -0
  100. package/llms/components/combobox.md +119 -0
  101. package/llms/components/command-menu.md +158 -0
  102. package/llms/components/context-card.md +73 -0
  103. package/llms/components/context-menu.md +79 -0
  104. package/llms/components/data-table.md +99 -0
  105. package/llms/components/date-picker.md +97 -0
  106. package/llms/components/description.md +96 -0
  107. package/llms/components/destructive-action-modal.md +76 -0
  108. package/llms/components/dialog.md +127 -0
  109. package/llms/components/dots-menu.md +64 -0
  110. package/llms/components/empty-state.md +113 -0
  111. package/llms/components/entity.md +67 -0
  112. package/llms/components/feedback.md +63 -0
  113. package/llms/components/fieldset.md +106 -0
  114. package/llms/components/file-dropzone.md +103 -0
  115. package/llms/components/form.md +111 -0
  116. package/llms/components/gliding-highlight.md +84 -0
  117. package/llms/components/inline-status.md +62 -0
  118. package/llms/components/input.md +127 -0
  119. package/llms/components/kbd.md +57 -0
  120. package/llms/components/label.md +73 -0
  121. package/llms/components/marker.md +99 -0
  122. package/llms/components/marquee.md +66 -0
  123. package/llms/components/menu.md +122 -0
  124. package/llms/components/message-scroller.md +110 -0
  125. package/llms/components/message.md +114 -0
  126. package/llms/components/meter.md +124 -0
  127. package/llms/components/middle-truncate.md +62 -0
  128. package/llms/components/note.md +81 -0
  129. package/llms/components/notification-badge.md +67 -0
  130. package/llms/components/number-field.md +70 -0
  131. package/llms/components/otp-field.md +101 -0
  132. package/llms/components/page-header.md +76 -0
  133. package/llms/components/page-loader.md +67 -0
  134. package/llms/components/pagination.md +92 -0
  135. package/llms/components/panel-group.md +120 -0
  136. package/llms/components/panel-section.md +122 -0
  137. package/llms/components/phone.md +70 -0
  138. package/llms/components/pill.md +73 -0
  139. package/llms/components/popover.md +79 -0
  140. package/llms/components/progress.md +98 -0
  141. package/llms/components/radio-card.md +90 -0
  142. package/llms/components/radio.md +86 -0
  143. package/llms/components/relative-time.md +60 -0
  144. package/llms/components/scroller.md +88 -0
  145. package/llms/components/scrub-field.md +97 -0
  146. package/llms/components/search-input.md +84 -0
  147. package/llms/components/select.md +106 -0
  148. package/llms/components/separator.md +70 -0
  149. package/llms/components/settings-menu.md +139 -0
  150. package/llms/components/sheet.md +97 -0
  151. package/llms/components/show-more.md +59 -0
  152. package/llms/components/side-nav.md +106 -0
  153. package/llms/components/sidebar.md +87 -0
  154. package/llms/components/skeleton.md +62 -0
  155. package/llms/components/slider.md +114 -0
  156. package/llms/components/spinner.md +87 -0
  157. package/llms/components/status-bar.md +91 -0
  158. package/llms/components/status-dot.md +70 -0
  159. package/llms/components/stepper.md +125 -0
  160. package/llms/components/streaming-text.md +86 -0
  161. package/llms/components/switch.md +87 -0
  162. package/llms/components/table.md +112 -0
  163. package/llms/components/tabs.md +84 -0
  164. package/llms/components/textarea.md +88 -0
  165. package/llms/components/theme-selector.md +95 -0
  166. package/llms/components/theme-switcher.md +71 -0
  167. package/llms/components/thinking-orb.md +91 -0
  168. package/llms/components/toast.md +130 -0
  169. package/llms/components/toggle.md +95 -0
  170. package/llms/components/toolbar.md +168 -0
  171. package/llms/components/tooltip.md +93 -0
  172. package/llms/components/tree.md +227 -0
  173. package/llms/components/video.md +66 -0
  174. package/llms/components/workspace.md +138 -0
  175. package/llms/foundations/accessibility.md +60 -0
  176. package/llms/foundations/motion.md +96 -0
  177. package/llms/foundations/scrolling.md +41 -0
  178. package/llms/foundations/shape.md +73 -0
  179. package/llms/foundations/spacing.md +82 -0
  180. package/llms/foundations/surfaces.md +69 -0
  181. package/llms/foundations/typography.md +120 -0
  182. package/llms/layout/aspect-box.md +37 -0
  183. package/llms/layout/bleed.md +31 -0
  184. package/llms/layout/center.md +37 -0
  185. package/llms/layout/columns.md +51 -0
  186. package/llms/layout/grid-overlay.md +40 -0
  187. package/llms/layout/grid.md +47 -0
  188. package/llms/layout/page.md +39 -0
  189. package/llms/layout/region.md +49 -0
  190. package/llms/layout/row.md +40 -0
  191. package/llms/layout/safe-area.md +37 -0
  192. package/llms/layout/spacer.md +39 -0
  193. package/llms/layout/split-pane.md +41 -0
  194. package/llms/layout/stack.md +39 -0
  195. package/llms/patterns/auth-page.md +68 -0
  196. package/llms/patterns/brand-landing-page.md +423 -0
  197. package/llms/patterns/chat-panel.md +210 -0
  198. package/llms/patterns/dashboard-page.md +170 -0
  199. package/llms/patterns/feed-page.md +103 -0
  200. package/llms/patterns/landing-page.md +122 -0
  201. package/llms/patterns/list-detail-page.md +100 -0
  202. package/llms/patterns/settings-page.md +121 -0
  203. package/llms/reference/token-intent.md +324 -0
  204. package/llms/reference/utilities.md +129 -0
  205. package/llms/tasks/adding-a-component.md +113 -0
  206. package/llms/tasks/auditing-an-app.md +216 -0
  207. package/llms/tasks/building-a-page.md +109 -0
  208. package/llms/tasks/building-a-tool.md +141 -0
  209. package/llms/tasks/building-an-ios-prototype.md +105 -0
  210. package/llms/tasks/building-with-sable.md +73 -0
  211. package/llms/tasks/choosing-a-component.md +109 -0
  212. package/llms/tasks/converting-an-app.md +139 -0
  213. package/llms/tasks/creating-a-preset.md +43 -0
  214. package/llms/tasks/creating-design-assets.md +96 -0
  215. package/llms/tasks/designing-a-surface.md +115 -0
  216. package/llms/tasks/developing-taste.md +157 -0
  217. package/llms/tasks/getting-started.md +63 -0
  218. package/llms/tasks/learning-from-builds.md +74 -0
  219. package/llms/tasks/reviewing-a-design.md +114 -0
  220. package/llms/tasks/reviewing-a-journey.md +84 -0
  221. package/llms/tasks/reviewing-motion.md +92 -0
  222. package/llms/tasks/using-presets.md +87 -0
  223. package/llms/taste/asset-plan.template.json +53 -0
  224. package/llms/taste/composition-follows-content.md +20 -0
  225. package/llms/taste/hierarchy-is-a-relationship.md +22 -0
  226. package/llms/taste/lessons.json +57 -0
  227. package/llms/taste/motion-needs-a-reason.md +21 -0
  228. package/llms/taste/surface-states-travel-together.md +20 -0
  229. package/llms-full.txt +14906 -0
  230. package/llms.txt +405 -0
  231. package/package.json +185 -3
  232. package/registry.json +18812 -0
  233. package/scripts/agent-setup.mjs +54 -0
  234. package/scripts/design-atlas.mjs +221 -0
  235. package/scripts/design-directions.mjs +123 -0
  236. package/scripts/design-memory.mjs +166 -0
  237. package/scripts/design-preferences.mjs +227 -0
  238. package/scripts/design-presets.mjs +48 -0
  239. package/scripts/grade.mjs +509 -0
  240. package/scripts/lint-rules.mjs +1065 -0
  241. package/scripts/review-evidence.mjs +120 -0
  242. package/scripts/skeleton.mjs +248 -0
  243. package/skills/entry/SKILL.md +34 -0
  244. package/skills/sable/SKILL.md +187 -0
  245. package/skills/sable/agents/openai.yaml +6 -0
  246. package/targets/ios.json +982 -0
  247. package/third-party/reicon-LICENSE.txt +20 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * The theme contract. Every Sable theme MUST define a value (light + dark) for
3
+ * each semantic token below. Components reference ONLY these semantic roles —
4
+ * never a theme's internal palette steps — which is what makes the system
5
+ * re-themeable without touching component code.
6
+ *
7
+ * To author a new theme: copy `themes/base/`, keep these token names, and
8
+ * supply your own palette + values. See CONTRIBUTING.md → "Theme contract".
9
+ */
10
+ declare const SEMANTIC_TOKENS: readonly ["background", "foreground", "card", "card-foreground", "popover", "popover-foreground", "muted", "muted-foreground", "border", "border-strong", "input", "ring", "primary", "primary-foreground", "secondary", "secondary-foreground", "accent", "accent-foreground", "destructive", "destructive-foreground", "success", "success-foreground", "tone-standard", "tone-collectible", "tone-edition", "tone-info", "tone-warning", "highlight", "tone-standard-foreground", "tone-collectible-foreground", "tone-edition-foreground", "tone-info-foreground", "tone-warning-foreground", "highlight-foreground", "overlay", "overlay-foreground", "sidebar", "sidebar-foreground", "sidebar-primary", "sidebar-primary-foreground", "sidebar-accent", "sidebar-accent-foreground", "sidebar-border", "sidebar-ring"];
11
+ type SemanticToken = (typeof SEMANTIC_TOKENS)[number];
12
+ /**
13
+ * Motion tokens (mode-independent). A theme MAY override these to retune its
14
+ * motion feel; if omitted, the Base defaults apply. Components reference
15
+ * them via `duration-(--motion-duration-*)` + the `ease-*` utilities, or — far
16
+ * more often — via the named motion recipes (`motion-pop`, `motion-press`, …)
17
+ * defined in styles.css. Every duration is multiplied by `--motion-scale`, the
18
+ * single lever the reduced-motion policy and <MotionProvider> collapse to 0.
19
+ * See DESIGN.md → Motion.
20
+ */
21
+ declare const MOTION_TOKENS: readonly ["motion-scale", "motion-duration-instant", "motion-duration-fast", "motion-duration-base", "motion-duration-slow", "motion-duration-slower", "motion-duration-enter", "motion-duration-exit", "motion-ease-standard", "motion-ease-decelerate", "motion-ease-emphasized", "motion-ease-spring", "motion-ease-bounce", "motion-ease-linear"];
22
+ type MotionToken = (typeof MOTION_TOKENS)[number];
23
+ /**
24
+ * Radius tokens (mode-independent). A theme MAY override these to retune its
25
+ * shape language (soft-square, rectilinear, full-pill, …); if omitted, the
26
+ * Base defaults apply (see styles.css → `@theme inline`, which bridges
27
+ * each `--theme-radius-*` var to the `radius-*` Tailwind scale). Components
28
+ * never reference these directly — they use the derived `rounded-*`
29
+ * utilities.
30
+ */
31
+ declare const RADIUS_TOKENS: readonly ["theme-radius-none", "theme-radius-xs", "theme-radius-sm", "theme-radius-md", "theme-radius-lg", "theme-radius-xl", "theme-radius-full"];
32
+ type RadiusToken = (typeof RADIUS_TOKENS)[number];
33
+ /**
34
+ * Type-scale tokens (mode-independent). A theme MAY override these to retune
35
+ * its typographic voice (weight, leading, tracking, and — for heading/display
36
+ * tiers — size); if omitted, the Base defaults baked into styles.css's
37
+ * paired `text-*` utilities apply. Additional body/label/caption/mono and size
38
+ * hooks are advertised separately in TYPE_REFINEMENT_TOKENS: they are optional,
39
+ * so a theme can retune its reading voice without duplicating every default.
40
+ */
41
+ declare const TYPE_SCALE_TOKENS: readonly ["type-display-4xl-weight", "type-display-4xl-leading", "type-display-4xl-tracking", "type-display-3xl-size", "type-display-3xl-weight", "type-display-3xl-leading", "type-display-3xl-tracking", "type-display-2xl-size", "type-display-2xl-weight", "type-display-2xl-leading", "type-display-2xl-tracking", "type-display-xl-size", "type-display-xl-weight", "type-display-xl-leading", "type-display-xl-tracking", "type-display-lg-size", "type-display-lg-weight", "type-display-lg-leading", "type-display-lg-tracking", "type-heading-weight", "type-heading-1-size", "type-heading-1-leading", "type-heading-1-tracking", "type-heading-2-size", "type-heading-2-leading", "type-heading-2-tracking", "type-heading-3-size", "type-heading-3-leading", "type-heading-3-tracking", "type-heading-4-size", "type-heading-4-leading", "type-heading-4-tracking", "type-title-weight", "type-title-leading", "type-title-tracking", "type-title-sm-tracking"];
42
+ type TypeScaleToken = (typeof TYPE_SCALE_TOKENS)[number];
43
+ /**
44
+ * Optional art-direction overrides for the paired typography utilities.
45
+ * Every hook has a CSS fallback; existing themes need not declare any of these.
46
+ * Set them at a theme or region scope, then keep consuming whole `text-*` tiers.
47
+ * Compact controls still follow TYPE_UI_TOKENS for the workspace register.
48
+ */
49
+ declare const TYPE_REFINEMENT_TOKENS: readonly ["type-display-4xl-size", "type-title-lg-size", "type-title-sm-size", "type-body-lg-size", "type-body-lg-weight", "type-body-lg-leading", "type-body-lg-tracking", "type-body-md-size", "type-body-md-weight", "type-body-md-leading", "type-body-md-tracking", "type-body-sm-size", "type-body-sm-weight", "type-body-sm-leading", "type-body-sm-tracking", "type-body-xs-size", "type-body-xs-weight", "type-body-xs-leading", "type-body-xs-tracking", "type-label-lg-size", "type-label-lg-weight", "type-label-lg-leading", "type-label-lg-tracking", "type-label-md-size", "type-label-md-weight", "type-label-md-leading", "type-label-md-tracking", "type-label-sm-size", "type-label-sm-weight", "type-label-sm-leading", "type-label-sm-tracking", "type-label-xs-size", "type-label-xs-weight", "type-label-xs-leading", "type-label-xs-tracking", "type-label-xs-transform", "type-caption-size", "type-caption-weight", "type-caption-leading", "type-caption-tracking", "type-mono-xl-size", "type-mono-xl-weight", "type-mono-xl-leading", "type-mono-xl-tracking", "type-mono-lg-size", "type-mono-lg-weight", "type-mono-lg-leading", "type-mono-lg-tracking", "type-mono-md-size", "type-mono-md-weight", "type-mono-md-leading", "type-mono-md-tracking", "type-mono-caption-size", "type-mono-caption-weight", "type-mono-caption-leading", "type-mono-caption-tracking", "type-mono-sm-size", "type-mono-sm-weight", "type-mono-sm-leading", "type-mono-sm-tracking"];
50
+ type TypeRefinementToken = (typeof TYPE_REFINEMENT_TOKENS)[number];
51
+ /**
52
+ * Overline/eyebrow/kicker type tokens (mode-independent). A theme MAY override
53
+ * these to retune its annotation voice; if omitted, styles.css's fallback
54
+ * defaults apply. Covers the small, uppercase, letter-spaced text role used
55
+ * for badge labels, section eyebrows, and stat captions — a distinct
56
+ * typographic tier from `TYPE_SCALE_TOKENS`'s display/heading/title ramp.
57
+ * `type-overline-transform` is themeable (not hardcoded `uppercase`) so a
58
+ * theme can opt a reference's quieter eyebrow style out of all-caps.
59
+ */
60
+ declare const TYPE_OVERLINE_TOKENS: readonly ["type-overline-size", "type-overline-weight", "type-overline-leading", "type-overline-tracking", "type-overline-transform"];
61
+ type TypeOverlineToken = (typeof TYPE_OVERLINE_TOKENS)[number];
62
+ /**
63
+ * Density tokens (mode-independent) — the control ladder every sized component
64
+ * renders from.
65
+ *
66
+ * This is the mechanism behind the two REGISTERS (see DESIGN.md → Registers).
67
+ * Components never hardcode a height; they read `--control-*`. A density scope
68
+ * (`data-density="compact"`) redefines those vars, so the same `size="md"`
69
+ * Button is 40px in the page register and 32px in a tool panel — without any
70
+ * selector reaching into rendered output to override a height after the fact.
71
+ *
72
+ * Values are set by `styles.css`; a theme MAY override them to retune its own
73
+ * control rhythm, the same as MOTION_TOKENS and RADIUS_TOKENS.
74
+ *
75
+ * The compact values are measured, not invented: the Figma and Paper editors
76
+ * run their chrome at 24/28/32/36 with a ~40px numeric field. See DESIGN.md →
77
+ * Registers for the full audit.
78
+ */
79
+ declare const DENSITY_TOKENS: readonly ["control-xs", "control-sm", "control-md", "control-cta", "control-lg", "field-numeric-width", "panel-width", "panel-width-min", "panel-width-max", "chrome-bar-height", "status-bar-height", "button-radius", "control-gap", "item-px", "item-gap", "tree-rail", "tree-column", "tree-indent"];
80
+ type DensityToken = (typeof DENSITY_TOKENS)[number];
81
+ /**
82
+ * Workspace surface tokens (light + dark) — the surface roles a tool shell needs
83
+ * that the page register has no use for.
84
+ *
85
+ * OPTIONAL: `styles.css` derives every one of these from the theme's existing
86
+ * semantic tokens, so a theme inherits a sane workspace band for free and only
87
+ * declares `--theme-*` overrides where it wants to tune. That's deliberate —
88
+ * requiring five hand-authored values per mode per theme would have been ten
89
+ * times the work for values that derive cleanly.
90
+ *
91
+ * Why these exist at all, rather than reusing `background`/`card`:
92
+ * - `canvas` is the WORK surface (the artboard). It is not `background`, because
93
+ * the thing being edited is not the page behind the UI.
94
+ * - `panel` / `panel-raised` are docked chrome, and they sit in a deliberately
95
+ * COMPRESSED tonal band — Paper's whole ladder spans 249→242→238, about 3-7
96
+ * RGB units, with a low-contrast hairline doing the structural work. `card` is
97
+ * tuned for the opposite job (lifting content off a page).
98
+ * - `hairline` / `hairline-strong` are that structural edge. In this register
99
+ * hairlines carry structure INSTEAD of tonal steps — a deliberate reversal of
100
+ * the page register's "prefer a tonal step or space over a divider line".
101
+ */
102
+ declare const WORKSPACE_SURFACE_TOKENS: readonly ["canvas", "canvas-foreground", "panel", "panel-foreground", "panel-raised", "hairline", "hairline-strong"];
103
+ type WorkspaceSurfaceToken = (typeof WORKSPACE_SURFACE_TOKENS)[number];
104
+ /**
105
+ * UI type tiers (mode-independent) — the chrome typography register.
106
+ *
107
+ * A separate ramp from TYPE_SCALE_TOKENS on purpose. Tool chrome runs 10-12px at
108
+ * weight 450-550 (measured: Figma 11/400 and 11/550, Paper 12/500 and 12/465),
109
+ * where the page register's 14-16px at 400/600 reads as shouting. `ui-num` is
110
+ * tabular so a column of values doesn't dance while a slider drags.
111
+ *
112
+ * These back the paired `text-ui-*` utilities in styles.css. Like every other
113
+ * paired tier they must be registered in `lib/cn.ts`'s `ds-typography` group —
114
+ * an unrecognised `text-*` class falls into tailwind-merge's COLOUR group and
115
+ * silently evicts the real colour class, which is a genuinely hard bug to see.
116
+ */
117
+ declare const TYPE_UI_TOKENS: readonly ["type-ui-md-size", "type-ui-md-weight", "type-ui-sm-size", "type-ui-sm-weight", "type-ui-leading", "type-ui-section-weight", "type-ui-micro-size", "type-ui-micro-weight"];
118
+ type TypeUiToken = (typeof TYPE_UI_TOKENS)[number];
119
+ type ThemeMode = "light" | "dark";
120
+ /** Lightweight, typed description of a theme (the TS manifest each theme ships). */
121
+ interface ThemeManifest {
122
+ /** Retained for existing imports; omitted from the featured preset picker. */
123
+ deprecated?: {
124
+ replacement: string;
125
+ };
126
+ /** Stable id, e.g. "verdant". */
127
+ id: string;
128
+ /** Human label, e.g. "Verdant". */
129
+ label: string;
130
+ /** Modes this theme supports. */
131
+ modes: ThemeMode[];
132
+ /** Mode used when none is specified. */
133
+ defaultMode: ThemeMode;
134
+ /**
135
+ * Font stacks the theme expects the host app to provide.
136
+ * `display` is optional — a distinct display/heading typeface separate from
137
+ * `sans` (e.g. a reference that uses a headline face like "Chalet" for
138
+ * display/heading type but a different sans for body). When omitted, the
139
+ * `text-display-*`/`text-heading-*` utilities in styles.css fall back to
140
+ * `--font-sans` via `var(--font-display, var(--font-sans))` — a theme that
141
+ * doesn't set it renders identically to today.
142
+ */
143
+ fonts: {
144
+ sans: string;
145
+ mono: string;
146
+ display?: string;
147
+ };
148
+ }
149
+
150
+ export { DENSITY_TOKENS as D, MOTION_TOKENS as M, RADIUS_TOKENS as R, SEMANTIC_TOKENS as S, type ThemeManifest as T, WORKSPACE_SURFACE_TOKENS as W, type ThemeMode as a, type DensityToken as b, type MotionToken as c, type RadiusToken as d, type SemanticToken as e, TYPE_OVERLINE_TOKENS as f, TYPE_REFINEMENT_TOKENS as g, TYPE_SCALE_TOKENS as h, TYPE_UI_TOKENS as i, type TypeOverlineToken as j, type TypeRefinementToken as k, type TypeScaleToken as l, type TypeUiToken as m, type WorkspaceSurfaceToken as n };
@@ -0,0 +1,398 @@
1
+ import { cn } from './chunk-SRQWQUTW.js';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+
4
+ // src/layout/_safeArea.ts
5
+ var EDGE_PROP = {
6
+ top: "paddingTop",
7
+ bottom: "paddingBottom",
8
+ left: "paddingLeft",
9
+ right: "paddingRight"
10
+ };
11
+ function safeAreaInsets(edges) {
12
+ const out = {};
13
+ for (const edge of edges) {
14
+ out[EDGE_PROP[edge]] = `env(safe-area-inset-${edge}, 0px)`;
15
+ }
16
+ return out;
17
+ }
18
+ var NAMED_MAX = {
19
+ prose: "var(--measure-prose)",
20
+ form: "var(--region-form)",
21
+ feed: "var(--region-feed)",
22
+ content: "var(--region-content)",
23
+ wide: "var(--region-wide)",
24
+ full: "var(--region-full)",
25
+ ultrawide: "var(--region-ultrawide)"
26
+ };
27
+ function Region({
28
+ as,
29
+ inset = true,
30
+ max,
31
+ bleed = false,
32
+ safeArea = false,
33
+ className,
34
+ style,
35
+ children,
36
+ ref,
37
+ ...rest
38
+ }) {
39
+ const Comp = as ?? "div";
40
+ const maxWidth = max ? NAMED_MAX[max] ?? max : void 0;
41
+ const safeEdges = safeArea === true ? ["top", "bottom"] : Array.isArray(safeArea) ? safeArea : [];
42
+ const mergedStyle = {
43
+ ...maxWidth ? { maxWidth, marginInline: "auto" } : null,
44
+ ...!bleed && inset ? { paddingInline: "var(--page-inset)" } : null,
45
+ ...safeAreaInsets(safeEdges),
46
+ ...style
47
+ };
48
+ return /* @__PURE__ */ jsx(Comp, { ref, className: cn("w-full", className), style: mergedStyle, ...rest, children });
49
+ }
50
+ var ALIGN = {
51
+ start: "flex-start",
52
+ center: "center",
53
+ end: "flex-end",
54
+ stretch: "stretch"
55
+ };
56
+ var JUSTIFY = {
57
+ start: "flex-start",
58
+ center: "center",
59
+ end: "flex-end",
60
+ between: "space-between",
61
+ around: "space-around"
62
+ };
63
+ function resolveGap(gap) {
64
+ return typeof gap === "number" ? `calc(var(--rhythm-unit) * ${gap})` : gap;
65
+ }
66
+ function Stack({
67
+ gap = 2,
68
+ align = "stretch",
69
+ justify = "start",
70
+ className,
71
+ style,
72
+ children,
73
+ ref,
74
+ ...rest
75
+ }) {
76
+ const mergedStyle = {
77
+ display: "flex",
78
+ flexDirection: "column",
79
+ alignItems: ALIGN[align],
80
+ justifyContent: JUSTIFY[justify],
81
+ gap: resolveGap(gap),
82
+ ...style
83
+ };
84
+ return /* @__PURE__ */ jsx("div", { ref, className: cn(className), style: mergedStyle, ...rest, children });
85
+ }
86
+ function Page({ gap = 4, align, children, ...regionProps }) {
87
+ return /* @__PURE__ */ jsx(Region, { ...regionProps, children: /* @__PURE__ */ jsx(Stack, { gap, align, children }) });
88
+ }
89
+ Page.displayName = "Page";
90
+
91
+ // src/layout/_responsive.ts
92
+ var BREAKPOINTS = ["base", "sm", "md", "lg", "xl", "2xl"];
93
+ function responsiveVars(prefix, value) {
94
+ if (value === void 0) return {};
95
+ if (typeof value === "number") return { [`${prefix}-base`]: value };
96
+ const out = {};
97
+ for (const bp of BREAKPOINTS) {
98
+ const v = value[bp];
99
+ if (v != null) out[`${prefix}-${bp}`] = v;
100
+ }
101
+ return out;
102
+ }
103
+ function resolveGap2(gap) {
104
+ if (gap === void 0) return "var(--grid-gutter)";
105
+ if (typeof gap === "number") return `calc(var(--rhythm-unit) * ${gap})`;
106
+ return gap;
107
+ }
108
+ function Grid({
109
+ cols = 12,
110
+ minItemWidth,
111
+ gap,
112
+ className,
113
+ style,
114
+ children,
115
+ ref,
116
+ ...rest
117
+ }) {
118
+ if (minItemWidth) {
119
+ const mergedStyle2 = {
120
+ display: "grid",
121
+ gridTemplateColumns: `repeat(auto-fit, minmax(min(${minItemWidth}, 100%), 1fr))`,
122
+ gap: resolveGap2(gap),
123
+ ...style
124
+ };
125
+ return /* @__PURE__ */ jsx("div", { ref, className: cn(className), style: mergedStyle2, ...rest, children });
126
+ }
127
+ const mergedStyle = {
128
+ gap: resolveGap2(gap),
129
+ ...responsiveVars("--cols", cols),
130
+ ...style
131
+ };
132
+ return /* @__PURE__ */ jsx(
133
+ "div",
134
+ {
135
+ ref,
136
+ "data-sable-grid-cols": true,
137
+ className: cn(className),
138
+ style: mergedStyle,
139
+ ...rest,
140
+ children
141
+ }
142
+ );
143
+ }
144
+ function resolveGap3(gap) {
145
+ if (gap === void 0) return "var(--grid-gutter)";
146
+ if (typeof gap === "number") return `calc(var(--rhythm-unit) * ${gap})`;
147
+ return gap;
148
+ }
149
+ function cappedColumnGap(gap) {
150
+ return `min(${gap}, calc(75% / max(var(--cols, var(--grid-columns)) - 1, 1)))`;
151
+ }
152
+ function Columns({
153
+ count,
154
+ gap,
155
+ className,
156
+ style,
157
+ children,
158
+ ref,
159
+ ...rest
160
+ }) {
161
+ const resolvedGap = resolveGap3(gap);
162
+ const mergedStyle = {
163
+ rowGap: resolvedGap,
164
+ columnGap: cappedColumnGap(resolvedGap),
165
+ ...responsiveVars("--cols", count),
166
+ ...style
167
+ };
168
+ return /* @__PURE__ */ jsx(
169
+ "div",
170
+ {
171
+ ref,
172
+ "data-sable-grid-cols": true,
173
+ className: cn(className),
174
+ style: mergedStyle,
175
+ ...rest,
176
+ children
177
+ }
178
+ );
179
+ }
180
+ function Col({
181
+ span = 1,
182
+ start,
183
+ className,
184
+ style,
185
+ children,
186
+ ref,
187
+ ...rest
188
+ }) {
189
+ const mergedStyle = {
190
+ ...responsiveVars("--col-span", span),
191
+ ...responsiveVars("--col-start", start),
192
+ ...style
193
+ };
194
+ return /* @__PURE__ */ jsx(
195
+ "div",
196
+ {
197
+ ref,
198
+ "data-sable-col": true,
199
+ className: cn(className),
200
+ style: mergedStyle,
201
+ ...rest,
202
+ children
203
+ }
204
+ );
205
+ }
206
+ var ALIGN2 = {
207
+ start: "flex-start",
208
+ center: "center",
209
+ end: "flex-end",
210
+ stretch: "stretch",
211
+ baseline: "baseline"
212
+ };
213
+ var JUSTIFY2 = {
214
+ start: "flex-start",
215
+ center: "center",
216
+ end: "flex-end",
217
+ between: "space-between",
218
+ around: "space-around"
219
+ };
220
+ function resolveGap4(gap) {
221
+ return typeof gap === "number" ? `calc(var(--rhythm-unit) * ${gap})` : gap;
222
+ }
223
+ function Row({
224
+ gap = 2,
225
+ align = "center",
226
+ justify = "start",
227
+ wrap = false,
228
+ className,
229
+ style,
230
+ children,
231
+ ref,
232
+ ...rest
233
+ }) {
234
+ const mergedStyle = {
235
+ display: "flex",
236
+ flexDirection: "row",
237
+ alignItems: ALIGN2[align],
238
+ justifyContent: JUSTIFY2[justify],
239
+ flexWrap: wrap ? "wrap" : "nowrap",
240
+ gap: resolveGap4(gap),
241
+ ...style
242
+ };
243
+ return /* @__PURE__ */ jsx("div", { ref, className: cn(className), style: mergedStyle, ...rest, children });
244
+ }
245
+ function Spacer({ size = 1, axis = "vertical", grow, className }) {
246
+ const style = grow ? { flex: "1 1 0%" } : axis === "vertical" ? { height: `calc(var(--rhythm-unit) * ${size})`, flexShrink: 0 } : { width: `calc(var(--rhythm-unit) * ${size})`, flexShrink: 0 };
247
+ return /* @__PURE__ */ jsx("div", { "aria-hidden": true, className, style });
248
+ }
249
+ var NAMED_MAX2 = {
250
+ prose: "var(--measure-prose)",
251
+ feed: "var(--region-feed)",
252
+ wide: "var(--region-wide)",
253
+ ultrawide: "var(--region-ultrawide)"
254
+ };
255
+ function Center({ max, className, style, children, ref, ...rest }) {
256
+ const maxWidth = max ? NAMED_MAX2[max] ?? max : void 0;
257
+ const mergedStyle = {
258
+ marginInline: "auto",
259
+ ...maxWidth ? { maxWidth } : null,
260
+ ...style
261
+ };
262
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("w-full", className), style: mergedStyle, ...rest, children });
263
+ }
264
+ function AspectBox({
265
+ ratio = 16 / 9,
266
+ className,
267
+ style,
268
+ children,
269
+ ...rest
270
+ }) {
271
+ const mergedStyle = {
272
+ aspectRatio: String(ratio),
273
+ ...style
274
+ };
275
+ return /* @__PURE__ */ jsx(
276
+ "div",
277
+ {
278
+ className: cn("relative w-full overflow-hidden", className),
279
+ style: mergedStyle,
280
+ ...rest,
281
+ children
282
+ }
283
+ );
284
+ }
285
+ function Bleed({ className, style, children, ref, ...rest }) {
286
+ const mergedStyle = {
287
+ width: "100cqw",
288
+ marginInline: "calc(50% - 50cqw)",
289
+ ...style
290
+ };
291
+ return /* @__PURE__ */ jsx("div", { ref, className: cn(className), style: mergedStyle, ...rest, children });
292
+ }
293
+ Bleed.displayName = "Bleed";
294
+ function parseRatio(ratio) {
295
+ const [a, b] = ratio.split("/");
296
+ const pa = Number(a);
297
+ const pb = Number(b);
298
+ if (!Number.isFinite(pa) || pa <= 0 || !Number.isFinite(pb) || pb <= 0) {
299
+ return { primary: "1fr", secondary: "1fr" };
300
+ }
301
+ return { primary: `${pa}fr`, secondary: `${pb}fr` };
302
+ }
303
+ function resolveGap5(gap) {
304
+ if (gap === void 0) return void 0;
305
+ return typeof gap === "number" ? `calc(var(--rhythm-unit) * ${gap})` : gap;
306
+ }
307
+ function SplitPane({
308
+ primary,
309
+ secondary,
310
+ collapseBelow = "lg",
311
+ ratio = "1/1",
312
+ gap,
313
+ className,
314
+ style,
315
+ ref,
316
+ ...rest
317
+ }) {
318
+ const { primary: p, secondary: s } = parseRatio(ratio);
319
+ const splitGap = resolveGap5(gap);
320
+ const mergedStyle = {
321
+ "--split-primary": p,
322
+ "--split-secondary": s,
323
+ ...splitGap ? { "--split-gap": splitGap } : null,
324
+ ...style
325
+ };
326
+ return /* @__PURE__ */ jsxs(
327
+ "div",
328
+ {
329
+ ref,
330
+ "data-sable-split": true,
331
+ "data-collapse": collapseBelow,
332
+ className: cn(className),
333
+ style: mergedStyle,
334
+ ...rest,
335
+ children: [
336
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: primary }),
337
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: secondary })
338
+ ]
339
+ }
340
+ );
341
+ }
342
+ SplitPane.displayName = "SplitPane";
343
+ function SafeArea({
344
+ edges = ["top", "bottom", "left", "right"],
345
+ className,
346
+ style,
347
+ children,
348
+ ref,
349
+ ...rest
350
+ }) {
351
+ return /* @__PURE__ */ jsx(
352
+ "div",
353
+ {
354
+ ref,
355
+ className: cn(className),
356
+ style: { ...safeAreaInsets(edges), ...style },
357
+ ...rest,
358
+ children
359
+ }
360
+ );
361
+ }
362
+ function GridOverlay({
363
+ columns = 12,
364
+ gap = "var(--grid-gutter)",
365
+ inset = true,
366
+ show = true,
367
+ className
368
+ }) {
369
+ if (!show) return null;
370
+ const style = {
371
+ position: "absolute",
372
+ inset: 0,
373
+ display: "grid",
374
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
375
+ gap,
376
+ paddingInline: inset ? "var(--page-inset)" : void 0
377
+ };
378
+ return /* @__PURE__ */ jsx(
379
+ "div",
380
+ {
381
+ "aria-hidden": true,
382
+ className: cn("pointer-events-none z-(--z-overlay)", className),
383
+ style,
384
+ children: Array.from({ length: columns }, (_, i) => /* @__PURE__ */ jsx(
385
+ "div",
386
+ {
387
+ style: {
388
+ background: "color-mix(in oklab, var(--highlight) 9%, transparent)",
389
+ borderInline: "1px solid color-mix(in oklab, var(--highlight) 22%, transparent)"
390
+ }
391
+ },
392
+ i
393
+ ))
394
+ }
395
+ );
396
+ }
397
+
398
+ export { AspectBox, Bleed, Center, Col, Columns, Grid, GridOverlay, Page, Region, Row, SafeArea, Spacer, SplitPane, Stack };