@supertype.ai/foundations 0.1.29 → 0.1.31
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/README.md +26 -22
- package/bin/foundations.mjs +5 -2
- package/dist/blocks/accordion.js +2 -1
- package/dist/blocks/anchor.d.ts +27 -0
- package/dist/blocks/anchor.js +28 -0
- package/dist/blocks/badge.d.ts +7 -2
- package/dist/blocks/badge.js +10 -4
- package/dist/blocks/button.d.ts +25 -4
- package/dist/blocks/button.js +16 -6
- package/dist/blocks/card.d.ts +5 -6
- package/dist/blocks/card.js +8 -12
- package/dist/blocks/index.d.ts +1 -0
- package/dist/blocks/index.js +1 -0
- package/dist/blocks/tabs.d.ts +5 -5
- package/dist/blocks/tabs.js +3 -3
- package/dist/cjs/eslint.js +37 -11
- package/dist/contrast.d.ts +34 -0
- package/dist/contrast.js +208 -10
- package/dist/eslint.d.ts +20 -4
- package/dist/eslint.js +36 -11
- package/dist/essay/layout.d.ts +1 -1
- package/dist/essay/layout.js +1 -1
- package/dist/essay/rail.d.ts +11 -1
- package/dist/essay/scroll.js +1 -1
- package/dist/href.d.ts +42 -0
- package/dist/href.js +63 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +6 -2
- package/dist/tone.d.ts +58 -9
- package/dist/tone.js +60 -12
- package/dist/typography/header.d.ts +2 -2
- package/dist/typography/header.js +4 -4
- package/dist/typography/highlight.d.ts +3 -2
- package/dist/typography/highlight.js +11 -5
- package/dist/typography/paragraph.d.ts +9 -12
- package/dist/typography/paragraph.js +29 -22
- package/llms.txt +97 -33
- package/package.json +2 -2
- package/src/theme.css +73 -20
- package/src/tokens.css +5 -4
- package/src/type.css +1 -1
package/llms.txt
CHANGED
|
@@ -5,8 +5,8 @@ content blocks, a long-form essay shell, token and theme CSS, and build-time
|
|
|
5
5
|
tooling for SEO, OG cards, lint rules and contrast checks.
|
|
6
6
|
|
|
7
7
|
This file is for coding agents working in an app that consumes the package. It
|
|
8
|
-
covers what to import
|
|
9
|
-
reference: https://github.com/supertypeai/foundations
|
|
8
|
+
covers what to import, how the copy should read, and the mistakes that pass
|
|
9
|
+
silently. Full reference: https://github.com/supertypeai/foundations
|
|
10
10
|
|
|
11
11
|
## Rules
|
|
12
12
|
|
|
@@ -21,6 +21,15 @@ reference: https://github.com/supertypeai/foundations
|
|
|
21
21
|
4. **Use colour tokens, never literal colours.** `bg-card`, `text-foreground`,
|
|
22
22
|
`border-border`. No hex values, no `bg-zinc-800`, no `dark:` overrides that
|
|
23
23
|
swap one token for another.
|
|
24
|
+
5. **Paint a surface, hand down its ink.** Any element you give a background
|
|
25
|
+
needs `INK_ON_FILL` (a tone fill) or one of `INK_ON_CARD`, `INK_ON_POPOVER`,
|
|
26
|
+
`INK_ON_SIDEBAR` (a tinted one), or the type inside it keeps the page's ink
|
|
27
|
+
and fails contrast silently. Never build one of these class strings
|
|
28
|
+
yourself: Tailwind only generates a class it can read as text, so an
|
|
29
|
+
assembled one styles nothing. For a surface with no constant, spread
|
|
30
|
+
`inkOnSurfaceStyle(token)` into `style`.
|
|
31
|
+
6. **Write the words like a person would.** See Writing copy below. It applies
|
|
32
|
+
to every string a reader sees and to the comments you leave behind.
|
|
24
33
|
|
|
25
34
|
## Which component
|
|
26
35
|
|
|
@@ -40,6 +49,8 @@ reference: https://github.com/supertypeai/foundations
|
|
|
40
49
|
| a number or metric | `TypographyStat` | root |
|
|
41
50
|
| inline code | `TypographyInlineCode` | root |
|
|
42
51
|
| a link | `TypographyLink` | root |
|
|
52
|
+
| an anchor around something already drawn | `Anchor` | `/blocks` |
|
|
53
|
+
| where an href goes, without a component | `resolveLink` | root |
|
|
43
54
|
| a highlighted phrase | `TypographyHighlight` | root |
|
|
44
55
|
| a button, or a link that looks like one | `Button` | `/blocks` |
|
|
45
56
|
| a status label, count or chip | `Badge` | `/blocks` |
|
|
@@ -61,15 +72,15 @@ reference: https://github.com/supertypeai/foundations
|
|
|
61
72
|
|
|
62
73
|
| import | exports |
|
|
63
74
|
|---|---|
|
|
64
|
-
| `@supertype.ai/foundations` | `cn`, `TypographyH1`, `TypographyH2`, `TypographyH3`, `TypographyH4`, `TypographyEyebrow`, `TypographyP`, `TypographyMuted`, `TypographyProse`, `TypographyList`, `TypographyProseList`, `TypographyCaption`, `TypographySmall`, `TypographyLabel`, `TypographyStat`, `TypographyInlineCode`, `TypographyLink`, `TypographyHighlight`, `headingClass`, `headingFace`, `eyebrowClass`, `toneClass`, `impliedTone`. Types: `TypographyTag`, `ParagraphVariants`, `ListProps`, `CaptionVariants`, `LabelVariants`, `StatVariants`, `Tone`, `HighlightTone` |
|
|
65
|
-
| `@supertype.ai/foundations/blocks` | `Cards`, `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `Callout`, `Button`, `buttonVariants`, `Badge`, `badgeVariants`, `Steps`, `Step`, `Disclosure`, `DisclosureGroup`, `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`, `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `TabGroup`, `SEGMENT`. Types: `ButtonLook`, `BadgeLook`, `TabItem` |
|
|
75
|
+
| `@supertype.ai/foundations` | `cn`, `TypographyH1`, `TypographyH2`, `TypographyH3`, `TypographyH4`, `TypographyEyebrow`, `TypographyP`, `TypographyMuted`, `TypographyProse`, `TypographyList`, `TypographyProseList`, `TypographyCaption`, `TypographySmall`, `TypographyLabel`, `TypographyStat`, `TypographyInlineCode`, `TypographyLink`, `TypographyHighlight`, `headingClass`, `headingFace`, `eyebrowClass`, `toneClass`, `impliedTone`, `resolveLink`, `isExternalHref`. Types: `TypographyTag`, `ParagraphVariants`, `ListProps`, `CaptionVariants`, `LabelVariants`, `StatVariants`, `Tone`, `HighlightTone`, `LinkBehavior`, `ResolvedLink` |
|
|
76
|
+
| `@supertype.ai/foundations/blocks` | `Anchor`, `Cards`, `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `Callout`, `Button`, `buttonVariants`, `Badge`, `badgeVariants`, `Steps`, `Step`, `Disclosure`, `DisclosureGroup`, `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`, `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `TabGroup`, `SEGMENT`. Types: `ButtonLook`, `BadgeLook`, `TabItem` |
|
|
66
77
|
| `@supertype.ai/foundations/mdx` | `proseMdxComponents` |
|
|
67
78
|
| `@supertype.ai/foundations/essay` | `createEssay`, `EssayHeader`, `EssayLayout`, `EssaySection`, `EssayPullQuote`, `EssayFigure`, `EssayMovements`, `EssayDocument`, `EssayColumns`, `EssayAside`, `EssayBody`, `ReadingLayout`, `TableOfContents`, `ReadingRail`, `ReadingProgressBar`, `Rail`, `RailLink`, `PostMetaRow`, `PostDate`, `ReadTime`, `TagPills`, `MetaDot`, `formatPostDate`, `extractHeadings`, `readingTime`, `createSlugger`, `useReadingProgress`, `useScrollSpy`. Types: `TocHeading`, `EssayDecorations`, `EssayIndexEntry`, `EssayDocSection`, `EssayMovement`, `PostDateFormat` |
|
|
68
79
|
| `@supertype.ai/foundations/seo` | `createSeo`. Types: `SeoConfig`, `ArticleAuthor`, `ArticleOptions`, `PageMetadata` |
|
|
69
80
|
| `@supertype.ai/foundations/og` | `ogCard`, `OG_SIZE`. Types: `OgCardOptions` |
|
|
70
|
-
| `@supertype.ai/foundations/eslint` | `designRules` (every rule as one array
|
|
81
|
+
| `@supertype.ai/foundations/eslint` | `designRules` (every rule as one array, the one to spread), `designConfig` (the same set wrapped as a flat-config entry). The builders `colourRules`, `typographyRules`, `linkRules`, `themeOverrideRules`, `surfaceAsInkRules`, `renamedTokenRules` are exported too, though spreading them by hand is how a consumer ends up missing one. Types: `FlatConfigEntry`, `DesignRuleOptions`, `DesignConfigOptions`, `RestrictedSyntax`, `ColourOptions`, `TypographyOptions` |
|
|
71
82
|
| `@supertype.ai/foundations/rehype` | `rehypeProseCode`, `proseCodeOptions`, `PROSE_LANGS`, `PROSE_THEMES`. Build-time only, must not resolve React |
|
|
72
|
-
| `@supertype.ai/foundations/contrast` | `checkLegibility` (inks at 4.5:1), `checkSignals` (fills at 3:1, tinted inks at 4.5:1, labels against their own fill), `resolveTokens`, `formatFailures`, `specificity`, `parseColor`, `luminance`, `contrast
|
|
83
|
+
| `@supertype.ai/foundations/contrast` | `checkLegibility` (inks at 4.5:1), `checkSignals` (fills at 3:1 — status hues, the categorical earth hues and the six chart series alike — tinted inks at 4.5:1, `--subtle-foreground` at the 3:1 it is documented for, labels against their own fill: the tone rows are read off `TONE` and each cut is resolved along its `var()` fallback chain, so an app that declares `--brand` without `--brand-foreground` is measured on the label the cascade really reaches for rather than skipped), `checkHairlines` (`--border` and `--input` at 1.4:1 on `--background` and `--card`, `--sidebar-border` on `--sidebar`: a rule is exempt from the ink and mark bars, but it still has to read as the same weight in both themes), `resolveTokens`, `formatFailures`, `specificity`, `parseColor`, `luminance`, `contrast` (WCAG ratio), `lc` (APCA lightness contrast: polarity-aware, for checking that an ink ramp is perceptually ordered rather than merely ordered by ratio), `tokenCuts` (which cuts a token ships: fill, the label printed on it, the hue as words, the taxonomy `checkSignals` measures against). Types: `Rgb`, `Theme`, `LegibilityFailure`, `TokenCuts`. Build-time only |
|
|
73
84
|
|
|
74
85
|
## Props worth knowing
|
|
75
86
|
|
|
@@ -77,51 +88,104 @@ reference: https://github.com/supertypeai/foundations
|
|
|
77
88
|
- `TypographyH2`: `variant?`, plus `divider?: boolean` for a rule underneath.
|
|
78
89
|
- `TypographyP`: `variant?: "ui" | "prose"` (default `ui`), `tone?: "default" | "muted"`.
|
|
79
90
|
- `TypographyMuted`, `TypographyProse`, `TypographyProseList` are presets. The
|
|
80
|
-
prop each one pins is
|
|
91
|
+
prop each one pins is dropped from its type, so passing it fails to compile.
|
|
81
92
|
- `TypographyCaption`, `TypographyLabel`, `TypographySmall`: `size?: "sm" | "xs" | "2xs" | "inherit"`, `as?`.
|
|
82
93
|
- `TypographyEyebrow`: `tone?: "heading" | "label"`, `as?`.
|
|
83
94
|
- `TypographyStat`: `size?: "inherit" | "card" | "panel" | "page" | "display"`, `figures?: "tabular" | "proportional"`. Keep tabular where a value updates in place.
|
|
84
|
-
- `TypographyLink`: `href` (required), `tone?: Tone` (default `muted`), `addArrow?`, `newTab?`.
|
|
85
|
-
- `TypographyHighlight`: `tone?: HighlightTone
|
|
95
|
+
- `TypographyLink`: `href` (required), `tone?: Tone` (default `muted`), `addArrow?`, `newTab?`. The href decides internal versus external.
|
|
96
|
+
- `TypographyHighlight`: `tone?: HighlightTone`, one of `"primary" | "success" | "ochre" | "terracotta" | "sage" | "fig"`, plus `seed?: number`. A separate type from `Tone` on purpose: this axis is categorical (which one it is) where `Tone` is semantic (what it means), the same split theme.css draws between the earth swatches and the status tokens.
|
|
86
97
|
- `Card`: `href`, `title`, `description`, `icon`, `external`. An href makes the whole card a link.
|
|
87
|
-
- `
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
- `Anchor`: `href` (required), plus `external`/`newTab`. An unstyled anchor for a
|
|
99
|
+
link that is not typography and not a control — a thumbnail, a chip, a tooltip
|
|
100
|
+
trigger. It exists so `target`/`rel` are never written at a call site; `external`
|
|
101
|
+
is for a same-origin path that is not a route, which the router would prefetch.
|
|
102
|
+
- `Tone` is the one semantic colour vocabulary, shared by `Button`, `Badge`, `Callout`, `TypographyLink` and `TabsList`: `"muted" | "primary" | "secondary" | "brand" | "success" | "warn" | "destructive"`, defaulting to `muted` everywhere except a solid `Button`. Seven tones, seven tokens, one to one, which is the bar for adding one. Four names map onto others: `neutral` and `foreground` are `muted`, the word the rest of the package uses; `accent` is `--primary`'s hover tint, so a washed `primary` renders the same thing; `info` is covered by the `success | warn | destructive` triad. `brand` falls back to `--primary` in an app that defines no `--brand`.
|
|
103
|
+
- **Ink is handed down by whatever paints.** `toneClass(tone)` is a palette and sets no ink. A surface that fills adds `INK_ON_FILL`; a tinted one adds `INK_ON_CARD`, `INK_ON_POPOVER` or `INK_ON_SIDEBAR`, and one the package does not name spreads `inkOnSurfaceStyle(token)` into `style` rather than building a class. Both declare `--ink` and `--ink-muted`, which every type primitive reads, falling back to the page. Paint a background without them and a nested `TypographyLabel` prints `--foreground` on your fill, which measures 2.34:1 on `--primary`. On a hue fill `--ink-muted` equals `--ink`: a filled control has one ink, and wanting a second rung means wanting a tinted surface.
|
|
104
|
+
- `Button`: `variant?: "solid" | "soft" | "outline" | "ghost" | "link"` (default `solid`), `tone?: Tone` (defaults to `primary` on a solid button and `muted` on every other variant — filling a button in is how a page says this is the action), `size?: "xs" | "sm" | "md" | "lg" | "xl"` (default `md`), `icon?: boolean` for a square glyph box, `pill?: boolean` for full-round corners, `href` to make it a link, `render` for an element that is neither a button nor a link. Variant is how much ink it spends and tone is what the ink means, on separate axes, so a quiet delete is `variant="ghost" tone="destructive"`.
|
|
105
|
+
- `Badge`: `variant?: "solid" | "soft" | "outline" | "ghost"` (default `solid`), `tone?: Tone`, `size?: "xs" | "sm"` (default `sm`), `pill?: boolean`, `href` for a badge that leads somewhere. Same axes and same spellings as `Button`, minus `link`, which belongs to things you click. `warning` and `supertype` were `tone="warn"` and `tone="brand"` under invented names.
|
|
90
106
|
- `Callout`: `tone?: Tone`, `density?: "compact" | "editorial"`, `title`, `icon`, `action`.
|
|
91
107
|
- `DisclosureGroup`: `type?: "multiple" | "single"`, `defaultValue` (matches the title string).
|
|
92
|
-
- `TabsList`: `variant?: "default" | "line"`, `tone?: Tone` (default `primary`)
|
|
93
|
-
inks the marker
|
|
94
|
-
|
|
108
|
+
- `TabsList`: `variant?: "default" | "line"`, `tone?: Tone` (default `primary`). The tone
|
|
109
|
+
inks the marker alone, which on `line` means the underline and the active icon. The
|
|
110
|
+
boxed track keeps its marker flat, so a tone there paints nothing.
|
|
95
111
|
- `TabGroup`: `tabs: readonly TabItem[]` (`{ value, label, icon?, content }`), `defaultValue?`,
|
|
96
112
|
`value?`, `onValueChange?`, `variant?`, `tone?`, `iconPosition?: "inline-start" | "inline-end"`.
|
|
97
|
-
`icon` is an element (`<Icons.Mic />`)
|
|
98
|
-
whenever the tabs are data
|
|
113
|
+
`icon` is an element (`<Icons.Mic />`) that the trigger sizes and inks. Reach for it
|
|
114
|
+
whenever the tabs are data, and compose `Tabs`/`TabsTrigger` by hand only for a shape
|
|
115
|
+
it cannot express.
|
|
116
|
+
|
|
117
|
+
## Writing copy
|
|
118
|
+
|
|
119
|
+
Every string a reader sees goes through this: page copy, section notes, button
|
|
120
|
+
labels, callout titles, error messages, and the comments you leave in the file.
|
|
121
|
+
Write the way a person writes when they know the subject and respect the reader's
|
|
122
|
+
time.
|
|
123
|
+
|
|
124
|
+
- **Say the thing.** State what is true and move on. Skip the setup sentence, the
|
|
125
|
+
restatement, and the closing summary of what you just said.
|
|
126
|
+
- **Define forwards.** "A tone sets three variables and the component paints from
|
|
127
|
+
them" over "the component does not branch on the tone". Reach for a negative
|
|
128
|
+
only when the absence is the point.
|
|
129
|
+
- **One em dash per page, at most.** Prefer a full stop, a comma, or a colon. The
|
|
130
|
+
same goes for a parenthetical aside mid-sentence.
|
|
131
|
+
- **No arrow glyphs in prose.** Write "3.44:1 in light, 6.75:1 in dark" rather
|
|
132
|
+
than joining the two with an arrow. Where a UI genuinely points at something,
|
|
133
|
+
render a real icon.
|
|
134
|
+
- **Watch the tacked-on clause.** "…, and it is the shape to reach for", "…, and
|
|
135
|
+
it exists so that…". The second half is usually the point: lead with it, or
|
|
136
|
+
make it its own sentence.
|
|
137
|
+
- **Break the triples.** "X, Y, and Z" as a rhetorical flourish, three clauses
|
|
138
|
+
joined by "and", and the "not just A, but B" shape all read as machine prose.
|
|
139
|
+
Two items, or a list.
|
|
140
|
+
- **Cut the throat-clearing.** No "it is worth noting", "it is important to",
|
|
141
|
+
"simply", "just", "of course", "in other words". No "this is not X, it is Y".
|
|
142
|
+
- **Skip the rationale.** A note explains what the reader needs to use the thing.
|
|
143
|
+
Design history, near-misses, and the case for a decision go in the commit
|
|
144
|
+
message or the docs, not in the copy.
|
|
145
|
+
- **Concrete over abstract.** Name the class, the prop, the file. "Five
|
|
146
|
+
components take the prop" beats "several components".
|
|
147
|
+
- **Vary the sentences.** A paragraph of same-length clauses reads as generated
|
|
148
|
+
even when every sentence is true.
|
|
149
|
+
- **Headings are labels.** "How it stays current", not "Why it cannot go stale".
|
|
150
|
+
|
|
151
|
+
Code samples and commit messages stay conventional. This is about prose.
|
|
99
152
|
|
|
100
153
|
## Common mistakes
|
|
101
154
|
|
|
102
|
-
- `<p className="text-sm text-muted-foreground"
|
|
103
|
-
- `<h2 className="text-lg font-semibold"
|
|
104
|
-
`headingClass()`
|
|
155
|
+
- `<p className="text-sm text-muted-foreground">`: use `<TypographyMuted>`.
|
|
156
|
+
- `<h2 className="text-lg font-semibold">`: use `<TypographyH2>`, or
|
|
157
|
+
`headingClass()` to pass classes into someone else's component.
|
|
105
158
|
- Importing `Card`, `Callout` or `Button` from `@supertype.ai/foundations`. They
|
|
106
159
|
live in `@supertype.ai/foundations/blocks`.
|
|
107
|
-
- `<Button variant="destructive">` or `variant="secondary"
|
|
108
|
-
|
|
109
|
-
- `<Button size="icon-sm"
|
|
110
|
-
- `<Badge variant="warning">`
|
|
160
|
+
- `<Button variant="destructive">` or `variant="secondary"`: those are tones.
|
|
161
|
+
Write `variant="soft" tone="destructive"`, `variant="solid" tone="secondary"`.
|
|
162
|
+
- `<Button size="icon-sm">`: one size ladder. Write `size="sm" icon`.
|
|
163
|
+
- `<Badge variant="warning">` or `variant="supertype"`: tones, and misspelled ones.
|
|
111
164
|
Write `variant="outline" tone="warn"` and `variant="solid" tone="brand"`.
|
|
112
|
-
- `tone="neutral"`, `tone="foreground"` or `tone="accent"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- An `<a>` or `<Link>` styled by hand to look like a button
|
|
116
|
-
`render={<
|
|
117
|
-
|
|
165
|
+
- `tone="neutral"`, `tone="foreground"` or `tone="accent"`: all three went when the
|
|
166
|
+
tone lists merged. Write `tone="muted"` for the first two, `tone="primary"` for
|
|
167
|
+
the third.
|
|
168
|
+
- An `<a>` or `<Link>` styled by hand to look like a button, and equally
|
|
169
|
+
`render={<a href="/x" />}` or `render={<Link href="/x" />}` on anything that
|
|
170
|
+
takes an `href`. Write `<Button href="/x">`. `Button`, `Badge`, `Card` and
|
|
171
|
+
`TypographyLink` all take `href` and route it through one rule
|
|
172
|
+
(`resolveLink`): a scheme leaves the app and gets `target`/`rel`, a `#hash`
|
|
173
|
+
stays a plain anchor, everything else goes through the router's `Link` and
|
|
174
|
+
keeps the view transition. A hand-passed anchor skips all of that. `render` is
|
|
175
|
+
for an element that is genuinely not a link — and for `RailLink`, which takes a
|
|
176
|
+
router `Link` that way on purpose, since `essay/rail.tsx` has to import without
|
|
177
|
+
Next.
|
|
178
|
+
- Exporting a constant from a `"use client"` module and importing it into a server
|
|
179
|
+
component. It crosses the boundary as a stub, not a string, so an `href` built that
|
|
180
|
+
way arrives as a function. Keep shared constants in a plain module.
|
|
181
|
+
- `<TypographyMuted tone="default">`: a type error. Use `TypographyP`.
|
|
118
182
|
- Binding fonts with `font.className` instead of `font.variable`. The className
|
|
119
183
|
form sets `font-family` on the element and leaves the roles unresolved.
|
|
120
184
|
- Omitting `@source '../node_modules/@supertype.ai/foundations/dist/**/*.js'` from
|
|
121
185
|
the CSS entry. Tailwind then purges every class the package ships.
|
|
122
186
|
- Omitting `@import "@supertype.ai/foundations/theme.css"`. `tokens.css` names the
|
|
123
187
|
colour roles but holds no values, so the whole palette resolves to nothing.
|
|
124
|
-
- Using `Accordion` for a static FAQ. `Disclosure`
|
|
188
|
+
- Using `Accordion` for a static FAQ. `Disclosure` runs on the browser alone.
|
|
125
189
|
- Adding a second `@custom-variant dark`. `tokens.css` already binds it.
|
|
126
190
|
|
|
127
191
|
Run `npx foundations doctor` in the app to check the last four.
|
|
@@ -130,8 +194,8 @@ Run `npx foundations doctor` in the app to check the last four.
|
|
|
130
194
|
|
|
131
195
|
Two classes change how everything renders, and both go on `<html>` or a subtree:
|
|
132
196
|
|
|
133
|
-
- `.dark` re-points every colour token.
|
|
134
|
-
OS setting.
|
|
197
|
+
- `.dark` re-points every colour token. `tokens.css` binds it to the class, so
|
|
198
|
+
the OS setting leaves it alone.
|
|
135
199
|
- `.editorial` gives the heading role to the serif at weight 400 and retunes the
|
|
136
200
|
whole heading ladder against an 18px body, instead of the product's 13px.
|
|
137
201
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supertype.ai/foundations",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"./package.json": "./package.json"
|
|
83
83
|
},
|
|
84
84
|
"scripts": {
|
|
85
|
-
"build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/cjs-marker.mjs && node scripts/check-llms.mjs && node scripts/pins.mjs",
|
|
85
|
+
"build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/cjs-marker.mjs && node scripts/check-candidates.mjs && node scripts/check-llms.mjs && node scripts/pins.mjs",
|
|
86
86
|
"dev": "tsc -p tsconfig.json --watch",
|
|
87
87
|
"test": "yarn build && vitest run",
|
|
88
88
|
"test:watch": "vitest",
|
package/src/theme.css
CHANGED
|
@@ -91,18 +91,35 @@
|
|
|
91
91
|
both, so its label stays light in both. */
|
|
92
92
|
--tint-foreground: hsl(0, 0%, 100%);
|
|
93
93
|
|
|
94
|
+
/* Which way a control moves under the pointer: away from the page, so it
|
|
95
|
+
deepens on latte and lifts on espresso. How far is the state's own
|
|
96
|
+
business, and hover spends 18%.
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
The extreme rather than `--foreground`, because mixing toward an ink that
|
|
99
|
+
already sits near the fill gives a step the size of the gap between them:
|
|
100
|
+
`--primary` moved 4.9 ΔL* on latte against 6.2 on espresso from the same
|
|
101
|
+
declaration, and read as no hover at all. Against black and white every
|
|
102
|
+
tone clears 6 ΔL* in both themes. */
|
|
103
|
+
--hover-toward: hsl(0, 0%, 0%);
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
/* Status, on the same three-cut rule as every other tone: the fill is a mark
|
|
107
|
+
(3:1), the `-ink` is that hue used as words (4.5:1), and the `-foreground`
|
|
108
|
+
is the label printed on the fill (4.5:1 against it). A filled status
|
|
109
|
+
control is a real thing — `Button tone="warn" variant="solid"` — so the
|
|
110
|
+
pair is measured rather than assumed. checkSignals holds all three. */
|
|
111
|
+
--success: hsl(142 75% 29%);
|
|
99
112
|
--success-ink: hsl(142 68% 28%);
|
|
113
|
+
/* White clears 4.94:1 here. At the old 31% it measured 4.42:1, which passed
|
|
114
|
+
nothing and shipped anyway, because no component was checked against it. */
|
|
115
|
+
--success-foreground: var(--tint-foreground);
|
|
100
116
|
/* Was 52%, which measured 2.27:1 on latte — a dot you could not see. */
|
|
101
117
|
--warn: hsl(30 100% 43%);
|
|
102
118
|
--warn-ink: hsl(22 85% 36%);
|
|
103
|
-
/*
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
/* The label on the warn fill, and one value for both themes: amber is a mark
|
|
120
|
+
in each, so the ink that reads on it is deep in each. 4.84:1 on latte,
|
|
121
|
+
6.70:1 on espresso. White measured 3.37:1 and 2.44:1. */
|
|
122
|
+
--warn-foreground: hsl(30 25% 12%);
|
|
106
123
|
--info: hsl(211 80% 43%);
|
|
107
124
|
--info-ink: hsl(211 80% 40%);
|
|
108
125
|
/* Danger ships as an ink only: a vivid brick red harmonised toward terracotta. */
|
|
@@ -153,6 +170,12 @@
|
|
|
153
170
|
--popover-foreground: hsl(30 14% 12%);
|
|
154
171
|
--primary: hsl(133 11% 33%); /* #4A5D4E */
|
|
155
172
|
--primary-foreground: hsl(0 0% 100%);
|
|
173
|
+
/* The third cut, the one `--secondary` and every status hue already shipped.
|
|
174
|
+
A fill is a mark and words are read, so one value doing both jobs is tuned
|
|
175
|
+
for neither — and that is why the espresso CTA measured Lc 48.9 against
|
|
176
|
+
this theme's 89.3. On latte the two happen to coincide, so this is an
|
|
177
|
+
alias here and a value of its own under .dark. */
|
|
178
|
+
--primary-ink: var(--primary);
|
|
156
179
|
/* Three tokens, because the accent pulls opposite ways: fill, the label on it,
|
|
157
180
|
and the accent as text. Tuning any one for another sinks the third. */
|
|
158
181
|
--secondary: hsl(14, 67%, 72%);
|
|
@@ -167,13 +190,23 @@
|
|
|
167
190
|
--accent-foreground: hsl(133 11% 33%);
|
|
168
191
|
--destructive: hsl(0 50% 36%);
|
|
169
192
|
--destructive-foreground: hsl(0 0% 98%);
|
|
170
|
-
/* Soft beige-grey, to keep a rule un-intrusive
|
|
171
|
-
|
|
193
|
+
/* Soft beige-grey, to keep a rule un-intrusive — but a rule still has to be
|
|
194
|
+
seen. L88 measured 1.20:1 on --background and 1.29:1 on --card, below the
|
|
195
|
+
1.34:1 the dark twin at L22 was rejected for, so the light theme shipped the
|
|
196
|
+
fainter hairline of the two. L80 puts --card at 1.56:1, within a point of
|
|
197
|
+
the dark theme's 1.57:1, so the same border reads the same weight in both. */
|
|
198
|
+
--border: hsl(40 15% 80%); /* #CFC8BA */
|
|
172
199
|
--input: var(--border);
|
|
173
200
|
--ring: hsl(133 11% 33%); /* the brand green */
|
|
201
|
+
/* A series is a fill: docs/cli.md promises every one of them clears 3:1 on the
|
|
202
|
+
page and on a card, and until `checkSignals` measured them two did not. The
|
|
203
|
+
sand was the worst in the palette at 2.18:1 — a 43° hue on a 43° ground, the
|
|
204
|
+
same colour 36 points apart in lightness. Saturation rises as it darkens, or
|
|
205
|
+
it lands as mud rather than as sand. The six stay 17.1 ΔE76 apart at their
|
|
206
|
+
closest (chart-4 against chart-6), which is where the floor sat before. */
|
|
174
207
|
--chart-1: hsl(133 18% 45%);
|
|
175
|
-
--chart-2: hsl(14 47%
|
|
176
|
-
--chart-3: hsl(43
|
|
208
|
+
--chart-2: hsl(14 47% 56%); /* 2.98:1 at L59 */
|
|
209
|
+
--chart-3: hsl(43 45% 42%); /* 2.18:1 at 33% L60 */
|
|
177
210
|
--chart-4: hsl(200 20% 50%);
|
|
178
211
|
--chart-5: hsl(30 12% 40%);
|
|
179
212
|
/* A muted teal: the one cool hue the warm set leaves open, and far enough from
|
|
@@ -191,21 +224,27 @@
|
|
|
191
224
|
inset 0 1px 3px hsl(30 18% 12% / 0.07),
|
|
192
225
|
inset 0 0 0 1px hsl(30 18% 12% / 0.03);
|
|
193
226
|
--sidebar: hsl(40 25% 94%); /* #F5F2EC */
|
|
194
|
-
|
|
227
|
+
/* Warm-keyed like every other ink here. It shipped as hsl(0 0% 25%), the one
|
|
228
|
+
neutral grey in the light theme, on a surface hued at 40° — the same cold
|
|
229
|
+
read L146 rules out for --foreground. Same lightness step, 9.43:1. */
|
|
230
|
+
--sidebar-foreground: hsl(30 12% 24%);
|
|
195
231
|
--sidebar-primary: hsl(133 11% 33%);
|
|
196
232
|
--sidebar-primary-foreground: hsl(0 0% 100%);
|
|
197
233
|
--sidebar-accent: hsl(133 15% 88%);
|
|
198
234
|
--sidebar-accent-foreground: hsl(133 11% 25%);
|
|
199
|
-
--sidebar
|
|
235
|
+
/* A sidebar rule sits on --sidebar, not the page, and that surface is lighter
|
|
236
|
+
than --background — so it needs 2 points more than --border to read the same
|
|
237
|
+
(1.49:1, against the dark twin's 1.49:1). */
|
|
238
|
+
--sidebar-border: hsl(40 15% 77%);
|
|
200
239
|
--sidebar-ring: hsl(133 11% 33%);
|
|
201
240
|
}
|
|
202
241
|
|
|
203
242
|
.dark {
|
|
243
|
+
--hover-toward: hsl(0, 0%, 100%);
|
|
204
244
|
/* --success does not flip: the same green clears 3:1 on espresso as on latte. */
|
|
205
245
|
--success-ink: hsl(142 55% 58%);
|
|
206
246
|
--warn: hsl(30 90% 55%);
|
|
207
247
|
--warn-ink: hsl(33 60% 72%);
|
|
208
|
-
--warn-foreground: var(--warn-ink);
|
|
209
248
|
--info: hsl(211 75% 60%);
|
|
210
249
|
--info-ink: hsl(211 75% 64%);
|
|
211
250
|
/* Soft terracotta-red. The light cut measured ~2.9:1 on espresso and read muddy. */
|
|
@@ -248,8 +287,14 @@
|
|
|
248
287
|
--card-foreground: hsl(43 20% 92%);
|
|
249
288
|
--popover: hsl(30 8% 14%);
|
|
250
289
|
--popover-foreground: hsl(43 20% 92%);
|
|
251
|
-
|
|
252
|
-
|
|
290
|
+
/* Split in two, so each cut is tuned for its own job. The fill takes a white
|
|
291
|
+
label at Lc 83.0 against latte's 89.3, and still clears 3:1 as a mark on
|
|
292
|
+
espresso (3.36:1). The ink reads as words at Lc 73.8 against latte's 79.1.
|
|
293
|
+
Both sit inside the 15 Lc the themes are held to; the single token they
|
|
294
|
+
replace sat 30 Lc adrift on both counts. */
|
|
295
|
+
--primary: hsl(133 34% 34%);
|
|
296
|
+
--primary-foreground: var(--tint-foreground);
|
|
297
|
+
--primary-ink: hsl(133 26% 76%);
|
|
253
298
|
/* Espresso twin: the fill darkens under a white label, the ink lifts as text. */
|
|
254
299
|
--secondary: hsl(14, 64%, 37%);
|
|
255
300
|
--secondary-foreground: hsl(0 0% 100%);
|
|
@@ -264,8 +309,12 @@
|
|
|
264
309
|
--accent: hsl(133 12% 20%);
|
|
265
310
|
--accent-foreground: hsl(133 18% 78%);
|
|
266
311
|
/* Overwhelmingly an ink: sixty `text-destructive` sites, no fill carrying text.
|
|
267
|
-
The light value measured 2.08:1 here — a colour, not words.
|
|
268
|
-
|
|
312
|
+
The light value measured 2.08:1 here — a colour, not words.
|
|
313
|
+
L67 read 4.48:1 on --muted, which is AA to two decimal places and under it
|
|
314
|
+
to three, on a surface with several hundred call sites. L68 is the smallest
|
|
315
|
+
step that clears with room to spare (4.64:1) rather than landing back on the
|
|
316
|
+
line; --background and --card, already clear, rise with it. */
|
|
317
|
+
--destructive: hsl(0 65% 68%);
|
|
269
318
|
/* The ink is light here, so anything printed on it must be dark. Nothing does
|
|
270
319
|
today; white would arm a 1.3:1 trap for whoever tries first. */
|
|
271
320
|
--destructive-foreground: hsl(30 10% 10%);
|
|
@@ -278,7 +327,9 @@
|
|
|
278
327
|
--chart-2: hsl(14 45% 55%);
|
|
279
328
|
--chart-3: hsl(43 20% 70%);
|
|
280
329
|
--chart-4: hsl(200 15% 55%);
|
|
281
|
-
|
|
330
|
+
/* The espresso twin of the light sand: 2.26:1 on --card, the same failure the
|
|
331
|
+
light theme carried, in the theme that usually gets tuned first. */
|
|
332
|
+
--chart-5: hsl(30 8% 46%);
|
|
282
333
|
--chart-6: hsl(178 30% 52%);
|
|
283
334
|
/* A warm tint reads as haze on espresso: deep black, more spread. */
|
|
284
335
|
--elevation-raised:
|
|
@@ -295,7 +346,9 @@
|
|
|
295
346
|
--sidebar-primary-foreground: hsl(133 20% 10%);
|
|
296
347
|
--sidebar-accent: hsl(30 8% 19%);
|
|
297
348
|
--sidebar-accent-foreground: hsl(43 20% 85%);
|
|
298
|
-
--sidebar-
|
|
349
|
+
/* L20 measured 1.28:1 on --sidebar, the same too-faint rule the light theme
|
|
350
|
+
shipped. L24 is the twin of the light 1.49:1. */
|
|
351
|
+
--sidebar-border: hsl(30 8% 24%);
|
|
299
352
|
--sidebar-ring: hsl(133 18% 58%);
|
|
300
353
|
}
|
|
301
354
|
|
package/src/tokens.css
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
--color-popover-foreground: var(--popover-foreground);
|
|
16
16
|
--color-primary: var(--primary);
|
|
17
17
|
--color-primary-foreground: var(--primary-foreground);
|
|
18
|
+
--color-primary-ink: var(--primary-ink);
|
|
18
19
|
--color-secondary: var(--secondary);
|
|
19
20
|
--color-secondary-foreground: var(--secondary-foreground);
|
|
20
21
|
--color-muted: var(--muted);
|
|
@@ -25,18 +26,18 @@
|
|
|
25
26
|
--color-destructive-foreground: var(--destructive-foreground);
|
|
26
27
|
|
|
27
28
|
/* Named for meaning, not hue: a `success` a project renders blue still reads
|
|
28
|
-
right.
|
|
29
|
+
right. The fill is a mark, the ink is words, the foreground is the label
|
|
30
|
+
printed on the fill. */
|
|
29
31
|
--color-success: var(--success);
|
|
30
32
|
--color-success-ink: var(--success-ink);
|
|
33
|
+
--color-success-foreground: var(--success-foreground);
|
|
31
34
|
--color-warn: var(--warn);
|
|
32
35
|
--color-warn-ink: var(--warn-ink);
|
|
36
|
+
--color-warn-foreground: var(--warn-foreground);
|
|
33
37
|
--color-info: var(--info);
|
|
34
38
|
--color-info-ink: var(--info-ink);
|
|
35
39
|
--color-danger: var(--danger);
|
|
36
40
|
|
|
37
|
-
/* Deprecated: this was always an ink. Use `warn-ink`. */
|
|
38
|
-
--color-warn-foreground: var(--warn-foreground);
|
|
39
|
-
|
|
40
41
|
--color-border: var(--border);
|
|
41
42
|
--color-input: var(--input);
|
|
42
43
|
--color-ring: var(--ring);
|
package/src/type.css
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
|
|
40
40
|
@layer base {
|
|
41
41
|
:root {
|
|
42
|
-
/* 680, not 600: Ubuntu Sans steps 500
|
|
42
|
+
/* 680, not 600: Ubuntu Sans steps 500 to 600 by 9.3% where Geist stepped 11.9%,
|
|
43
43
|
and panel titles stopped separating from the labels inside them. */
|
|
44
44
|
--heading-weight: 680;
|
|
45
45
|
}
|