@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.
- package/AGENTS.md +157 -0
- package/CHANGELOG.md +50 -0
- package/CONTRIBUTING.md +221 -0
- package/DESIGN.md +548 -0
- package/LICENSE +21 -0
- package/README.md +194 -2
- package/THIRD_PARTY_NOTICES.md +44 -0
- package/bin/sable-lint.mjs +0 -0
- package/bin/sable.mjs +1223 -0
- package/dist/_contract-CYScOdf5.d.ts +150 -0
- package/dist/chunk-3IWZYBGH.js +398 -0
- package/dist/chunk-5Z5KLOAU.js +167 -0
- package/dist/chunk-7MG4SHYX.js +15 -0
- package/dist/chunk-ADLLDWLW.js +15 -0
- package/dist/chunk-EP55KSYA.js +14 -0
- package/dist/chunk-J23ELQQZ.js +9396 -0
- package/dist/chunk-JI7WJP2L.js +286 -0
- package/dist/chunk-K7RUHUGC.js +14 -0
- package/dist/chunk-KO3NAEBF.js +15 -0
- package/dist/chunk-L4IEIQQA.js +14 -0
- package/dist/chunk-L6Y46C62.js +270 -0
- package/dist/chunk-NEQNXI2G.js +25 -0
- package/dist/chunk-PAOZBZME.js +40 -0
- package/dist/chunk-RWP4XBSK.js +139 -0
- package/dist/chunk-SRQWQUTW.js +63 -0
- package/dist/chunk-YXBOYWBN.js +15 -0
- package/dist/foundations/index.d.ts +88 -0
- package/dist/foundations/index.js +792 -0
- package/dist/icon/index.d.ts +60 -0
- package/dist/icon/index.js +2 -0
- package/dist/icon-sets/brands.d.ts +44 -0
- package/dist/icon-sets/brands.js +147 -0
- package/dist/icon-sets/reicon.d.ts +8 -0
- package/dist/icon-sets/reicon.js +1 -0
- package/dist/index.d.ts +7013 -0
- package/dist/index.js +15462 -0
- package/dist/ios/chrome.css +83 -0
- package/dist/ios/frame.css +5 -0
- package/dist/ios/index.d.ts +70 -0
- package/dist/ios/index.js +313 -0
- package/dist/ios/preview.d.ts +64 -0
- package/dist/ios/preview.js +133 -0
- package/dist/ios/styles.css +77 -0
- package/dist/layout/index.d.ts +280 -0
- package/dist/layout/index.js +2 -0
- package/dist/meta-6dUzgC6M.d.ts +205 -0
- package/dist/patterns/index.d.ts +36 -0
- package/dist/patterns/index.js +934 -0
- package/dist/presets/index.d.ts +37 -0
- package/dist/presets/index.js +117 -0
- package/dist/registry-CyL28OzJ.d.ts +28 -0
- package/dist/styles.css +1893 -0
- package/dist/theme-provider-BWcizhAt.d.ts +105 -0
- package/dist/themes/atelier/atelier.css +213 -0
- package/dist/themes/atelier/index.d.ts +9 -0
- package/dist/themes/atelier/index.js +1 -0
- package/dist/themes/base/base.css +443 -0
- package/dist/themes/base/index.d.ts +9 -0
- package/dist/themes/base/index.js +1 -0
- package/dist/themes/ember/ember.css +270 -0
- package/dist/themes/ember/index.d.ts +9 -0
- package/dist/themes/ember/index.js +1 -0
- package/dist/themes/index.d.ts +10 -0
- package/dist/themes/index.js +8 -0
- package/dist/themes/meridian/index.d.ts +9 -0
- package/dist/themes/meridian/index.js +1 -0
- package/dist/themes/meridian/meridian.css +255 -0
- package/dist/themes/poppy/index.d.ts +6 -0
- package/dist/themes/poppy/index.js +1 -0
- package/dist/themes/poppy/poppy.css +174 -0
- package/dist/themes/prism/index.d.ts +6 -0
- package/dist/themes/prism/index.js +1 -0
- package/dist/themes/prism/prism.css +183 -0
- package/dist/themes/verdant/index.d.ts +9 -0
- package/dist/themes/verdant/index.js +1 -0
- package/dist/themes/verdant/verdant.css +210 -0
- package/dist/themes.css +30 -0
- package/llms/components/accordion.md +93 -0
- package/llms/components/app-header.md +70 -0
- package/llms/components/app-shell.md +117 -0
- package/llms/components/attachment.md +105 -0
- package/llms/components/avatar.md +141 -0
- package/llms/components/badge.md +117 -0
- package/llms/components/banner.md +119 -0
- package/llms/components/bottom-nav.md +80 -0
- package/llms/components/breadcrumbs.md +75 -0
- package/llms/components/browser.md +67 -0
- package/llms/components/bubble.md +119 -0
- package/llms/components/button.md +199 -0
- package/llms/components/calendar.md +75 -0
- package/llms/components/card.md +135 -0
- package/llms/components/carousel.md +87 -0
- package/llms/components/chat-composer.md +126 -0
- package/llms/components/checkbox-card.md +98 -0
- package/llms/components/checkbox.md +90 -0
- package/llms/components/code-block.md +81 -0
- package/llms/components/code.md +62 -0
- package/llms/components/collapsible.md +83 -0
- package/llms/components/color-field.md +100 -0
- package/llms/components/combobox.md +119 -0
- package/llms/components/command-menu.md +158 -0
- package/llms/components/context-card.md +73 -0
- package/llms/components/context-menu.md +79 -0
- package/llms/components/data-table.md +99 -0
- package/llms/components/date-picker.md +97 -0
- package/llms/components/description.md +96 -0
- package/llms/components/destructive-action-modal.md +76 -0
- package/llms/components/dialog.md +127 -0
- package/llms/components/dots-menu.md +64 -0
- package/llms/components/empty-state.md +113 -0
- package/llms/components/entity.md +67 -0
- package/llms/components/feedback.md +63 -0
- package/llms/components/fieldset.md +106 -0
- package/llms/components/file-dropzone.md +103 -0
- package/llms/components/form.md +111 -0
- package/llms/components/gliding-highlight.md +84 -0
- package/llms/components/inline-status.md +62 -0
- package/llms/components/input.md +127 -0
- package/llms/components/kbd.md +57 -0
- package/llms/components/label.md +73 -0
- package/llms/components/marker.md +99 -0
- package/llms/components/marquee.md +66 -0
- package/llms/components/menu.md +122 -0
- package/llms/components/message-scroller.md +110 -0
- package/llms/components/message.md +114 -0
- package/llms/components/meter.md +124 -0
- package/llms/components/middle-truncate.md +62 -0
- package/llms/components/note.md +81 -0
- package/llms/components/notification-badge.md +67 -0
- package/llms/components/number-field.md +70 -0
- package/llms/components/otp-field.md +101 -0
- package/llms/components/page-header.md +76 -0
- package/llms/components/page-loader.md +67 -0
- package/llms/components/pagination.md +92 -0
- package/llms/components/panel-group.md +120 -0
- package/llms/components/panel-section.md +122 -0
- package/llms/components/phone.md +70 -0
- package/llms/components/pill.md +73 -0
- package/llms/components/popover.md +79 -0
- package/llms/components/progress.md +98 -0
- package/llms/components/radio-card.md +90 -0
- package/llms/components/radio.md +86 -0
- package/llms/components/relative-time.md +60 -0
- package/llms/components/scroller.md +88 -0
- package/llms/components/scrub-field.md +97 -0
- package/llms/components/search-input.md +84 -0
- package/llms/components/select.md +106 -0
- package/llms/components/separator.md +70 -0
- package/llms/components/settings-menu.md +139 -0
- package/llms/components/sheet.md +97 -0
- package/llms/components/show-more.md +59 -0
- package/llms/components/side-nav.md +106 -0
- package/llms/components/sidebar.md +87 -0
- package/llms/components/skeleton.md +62 -0
- package/llms/components/slider.md +114 -0
- package/llms/components/spinner.md +87 -0
- package/llms/components/status-bar.md +91 -0
- package/llms/components/status-dot.md +70 -0
- package/llms/components/stepper.md +125 -0
- package/llms/components/streaming-text.md +86 -0
- package/llms/components/switch.md +87 -0
- package/llms/components/table.md +112 -0
- package/llms/components/tabs.md +84 -0
- package/llms/components/textarea.md +88 -0
- package/llms/components/theme-selector.md +95 -0
- package/llms/components/theme-switcher.md +71 -0
- package/llms/components/thinking-orb.md +91 -0
- package/llms/components/toast.md +130 -0
- package/llms/components/toggle.md +95 -0
- package/llms/components/toolbar.md +168 -0
- package/llms/components/tooltip.md +93 -0
- package/llms/components/tree.md +227 -0
- package/llms/components/video.md +66 -0
- package/llms/components/workspace.md +138 -0
- package/llms/foundations/accessibility.md +60 -0
- package/llms/foundations/motion.md +96 -0
- package/llms/foundations/scrolling.md +41 -0
- package/llms/foundations/shape.md +73 -0
- package/llms/foundations/spacing.md +82 -0
- package/llms/foundations/surfaces.md +69 -0
- package/llms/foundations/typography.md +120 -0
- package/llms/layout/aspect-box.md +37 -0
- package/llms/layout/bleed.md +31 -0
- package/llms/layout/center.md +37 -0
- package/llms/layout/columns.md +51 -0
- package/llms/layout/grid-overlay.md +40 -0
- package/llms/layout/grid.md +47 -0
- package/llms/layout/page.md +39 -0
- package/llms/layout/region.md +49 -0
- package/llms/layout/row.md +40 -0
- package/llms/layout/safe-area.md +37 -0
- package/llms/layout/spacer.md +39 -0
- package/llms/layout/split-pane.md +41 -0
- package/llms/layout/stack.md +39 -0
- package/llms/patterns/auth-page.md +68 -0
- package/llms/patterns/brand-landing-page.md +423 -0
- package/llms/patterns/chat-panel.md +210 -0
- package/llms/patterns/dashboard-page.md +170 -0
- package/llms/patterns/feed-page.md +103 -0
- package/llms/patterns/landing-page.md +122 -0
- package/llms/patterns/list-detail-page.md +100 -0
- package/llms/patterns/settings-page.md +121 -0
- package/llms/reference/token-intent.md +324 -0
- package/llms/reference/utilities.md +129 -0
- package/llms/tasks/adding-a-component.md +113 -0
- package/llms/tasks/auditing-an-app.md +216 -0
- package/llms/tasks/building-a-page.md +109 -0
- package/llms/tasks/building-a-tool.md +141 -0
- package/llms/tasks/building-an-ios-prototype.md +105 -0
- package/llms/tasks/building-with-sable.md +73 -0
- package/llms/tasks/choosing-a-component.md +109 -0
- package/llms/tasks/converting-an-app.md +139 -0
- package/llms/tasks/creating-a-preset.md +43 -0
- package/llms/tasks/creating-design-assets.md +96 -0
- package/llms/tasks/designing-a-surface.md +115 -0
- package/llms/tasks/developing-taste.md +157 -0
- package/llms/tasks/getting-started.md +63 -0
- package/llms/tasks/learning-from-builds.md +74 -0
- package/llms/tasks/reviewing-a-design.md +114 -0
- package/llms/tasks/reviewing-a-journey.md +84 -0
- package/llms/tasks/reviewing-motion.md +92 -0
- package/llms/tasks/using-presets.md +87 -0
- package/llms/taste/asset-plan.template.json +53 -0
- package/llms/taste/composition-follows-content.md +20 -0
- package/llms/taste/hierarchy-is-a-relationship.md +22 -0
- package/llms/taste/lessons.json +57 -0
- package/llms/taste/motion-needs-a-reason.md +21 -0
- package/llms/taste/surface-states-travel-together.md +20 -0
- package/llms-full.txt +14906 -0
- package/llms.txt +405 -0
- package/package.json +185 -3
- package/registry.json +18812 -0
- package/scripts/agent-setup.mjs +54 -0
- package/scripts/design-atlas.mjs +221 -0
- package/scripts/design-directions.mjs +123 -0
- package/scripts/design-memory.mjs +166 -0
- package/scripts/design-preferences.mjs +227 -0
- package/scripts/design-presets.mjs +48 -0
- package/scripts/grade.mjs +509 -0
- package/scripts/lint-rules.mjs +1065 -0
- package/scripts/review-evidence.mjs +120 -0
- package/scripts/skeleton.mjs +248 -0
- package/skills/entry/SKILL.md +34 -0
- package/skills/sable/SKILL.md +187 -0
- package/skills/sable/agents/openai.yaml +6 -0
- package/targets/ios.json +982 -0
- 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 };
|