@supertype.ai/foundations 0.1.24

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +369 -0
  3. package/bin/foundations.mjs +713 -0
  4. package/dist/blocks/accordion.d.ts +23 -0
  5. package/dist/blocks/accordion.js +59 -0
  6. package/dist/blocks/callout.d.ts +57 -0
  7. package/dist/blocks/callout.js +61 -0
  8. package/dist/blocks/card.d.ts +34 -0
  9. package/dist/blocks/card.js +56 -0
  10. package/dist/blocks/index.d.ts +7 -0
  11. package/dist/blocks/index.js +7 -0
  12. package/dist/blocks/interactive-accordion.d.ts +13 -0
  13. package/dist/blocks/interactive-accordion.js +27 -0
  14. package/dist/blocks/segment.d.ts +37 -0
  15. package/dist/blocks/segment.js +37 -0
  16. package/dist/blocks/steps.d.ts +10 -0
  17. package/dist/blocks/steps.js +13 -0
  18. package/dist/blocks/tabs.d.ts +32 -0
  19. package/dist/blocks/tabs.js +69 -0
  20. package/dist/cjs/eslint.js +146 -0
  21. package/dist/cjs/package.json +3 -0
  22. package/dist/cn.d.ts +2 -0
  23. package/dist/cn.js +5 -0
  24. package/dist/contrast.d.ts +47 -0
  25. package/dist/contrast.js +255 -0
  26. package/dist/eslint.d.ts +74 -0
  27. package/dist/eslint.js +138 -0
  28. package/dist/essay/contents.d.ts +10 -0
  29. package/dist/essay/contents.js +17 -0
  30. package/dist/essay/essay.d.ts +125 -0
  31. package/dist/essay/essay.js +92 -0
  32. package/dist/essay/index.d.ts +7 -0
  33. package/dist/essay/index.js +9 -0
  34. package/dist/essay/layout.d.ts +72 -0
  35. package/dist/essay/layout.js +77 -0
  36. package/dist/essay/rail.d.ts +15 -0
  37. package/dist/essay/rail.js +26 -0
  38. package/dist/essay/reading.d.ts +17 -0
  39. package/dist/essay/reading.js +31 -0
  40. package/dist/essay/scroll.d.ts +8 -0
  41. package/dist/essay/scroll.js +78 -0
  42. package/dist/essay/toc.d.ts +23 -0
  43. package/dist/essay/toc.js +50 -0
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.js +33 -0
  46. package/dist/injection.d.ts +8 -0
  47. package/dist/injection.js +1 -0
  48. package/dist/mdx.d.ts +47 -0
  49. package/dist/mdx.js +68 -0
  50. package/dist/og.d.ts +18 -0
  51. package/dist/og.js +50 -0
  52. package/dist/rehype.d.ts +18 -0
  53. package/dist/rehype.js +41 -0
  54. package/dist/seo.d.ts +174 -0
  55. package/dist/seo.js +152 -0
  56. package/dist/typography/as.d.ts +15 -0
  57. package/dist/typography/as.js +8 -0
  58. package/dist/typography/header.d.ts +44 -0
  59. package/dist/typography/header.js +119 -0
  60. package/dist/typography/highlight.d.ts +33 -0
  61. package/dist/typography/highlight.js +98 -0
  62. package/dist/typography/index.d.ts +4 -0
  63. package/dist/typography/index.js +3 -0
  64. package/dist/typography/paragraph.d.ts +157 -0
  65. package/dist/typography/paragraph.js +229 -0
  66. package/llms.txt +125 -0
  67. package/package.json +140 -0
  68. package/src/prose.css +12 -0
  69. package/src/shiki.css +23 -0
  70. package/src/theme.css +272 -0
  71. package/src/tokens.css +43 -0
  72. package/src/type.css +73 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Supertype
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,369 @@
1
+ # @supertype.ai/foundations
2
+
3
+ The shared design layer behind the Supertype projects: typography primitives,
4
+ content blocks, the long-form essay shell, the token and theme CSS, and the
5
+ build-time tooling that checks it all (SEO, OG cards, lint rules, contrast
6
+ checks).
7
+
8
+ ```sh
9
+ yarn add @supertype.ai/foundations
10
+ ```
11
+
12
+ **Start here:** [Install](#install) → [Your first page](#your-first-page).
13
+
14
+ **Reference:** [Typography](docs/typography.md) · [Blocks](docs/blocks.md) ·
15
+ [The essay shell](docs/essay.md) · [Build-time tooling](docs/tooling.md) ·
16
+ [The CLI](docs/cli.md)
17
+
18
+ **Working on the package itself:** [Contributing](docs/contributing.md), for
19
+ local iteration against a consumer and for releasing.
20
+
21
+ ## See it running
22
+
23
+ ```sh
24
+ yarn example:install # once, to install Next, the peers and the package
25
+ yarn example # then open http://localhost:3000
26
+ ```
27
+
28
+ [`examples/site`](examples/site) renders every component next to the source that
29
+ produced it, carries whole-page [recipes](examples/site/app/_recipes) to copy,
30
+ and puts the `dark` and `.editorial` surfaces on a switch. It is also where
31
+ documentation changes get checked, so start here if you are improving the docs.
32
+
33
+ ---
34
+
35
+ ## Install
36
+
37
+ Get step 2 or 3 wrong and nothing throws an error; the components just render
38
+ unstyled, or in the wrong typeface. So the package ships a CLI that writes the
39
+ CSS for you and checks the rest:
40
+
41
+ ```sh
42
+ npx @supertype.ai/foundations init # edits your CSS entry, prints the rest
43
+ npx @supertype.ai/foundations doctor # checks this app against everything below
44
+ ```
45
+
46
+ `init` edits one file: the CSS entry that imports Tailwind. It adds the imports
47
+ you are missing and reorders the ones you already have, since the imports are a
48
+ cascade. Run it with `--dry-run` first to see the patch. Everything else it
49
+ prints for you to paste — the font binding, and the `llms.txt` line for a coding
50
+ agent — because those belong in files the CLI has no business rewriting.
51
+
52
+ The steps are written out below anyway. `init` is a shortcut through them, not
53
+ a replacement for knowing what it changed. See [the CLI](docs/cli.md).
54
+
55
+ ### 1. Add the package
56
+
57
+ ```sh
58
+ yarn add @supertype.ai/foundations
59
+ # or: npm install @supertype.ai/foundations
60
+ ```
61
+
62
+ The package ships built, so there is no install-time build step. Peers are
63
+ React 19+, Next 15+, `next-view-transitions` 0.3+ and `@base-ui/react` 1.4+.
64
+
65
+ <details>
66
+ <summary>Installing from a git tag instead</summary>
67
+
68
+ Every release is tagged as well as published, so a commit can be installed
69
+ directly — useful for trying an unreleased fix. Pin a tag, never `#main`: an
70
+ untagged git dependency re-resolves to a different commit on any fresh install.
71
+
72
+ ```jsonc
73
+ // package.json
74
+ "@supertype.ai/foundations": "https://github.com/supertypeai/foundations.git#v0.1.24"
75
+ ```
76
+
77
+ </details>
78
+
79
+ ### 2. Import the CSS, in this order
80
+
81
+ ```css
82
+ /* app/global.css */
83
+ @import "tailwindcss";
84
+ @import "@supertype.ai/foundations/tokens.css"; /* structural tokens + dark variant */
85
+ @import "@supertype.ai/foundations/theme.css"; /* the house palette */
86
+ @import "@supertype.ai/foundations/type.css"; /* the type ramp + font roles */
87
+ @import "@supertype.ai/foundations/prose.css"; /* inline-code rule */
88
+ @import "@supertype.ai/foundations/shiki.css"; /* only if you render code fences */
89
+
90
+ @source '../node_modules/@supertype.ai/foundations/dist/**/*.js';
91
+ ```
92
+
93
+ **The `@source` line is required.** Tailwind does not scan `node_modules` by
94
+ default, so without it every class the package ships is purged and the components
95
+ render with no styles at all.
96
+
97
+ **`theme.css` is required.** `tokens.css` names the colour roles; `theme.css` is
98
+ what gives them values. Without it every colour utility still generates and
99
+ resolves to nothing, so the page renders unpainted with no error. It also carries
100
+ `--secondary-ink`, `--subtle-foreground`, the four earth tones the marker
101
+ highlight uses, and the `accordion-down` and `accordion-up` keyframes. Skip it
102
+ only if you declare every role yourself; `foundations doctor` fails when neither
103
+ is true, and names the roles you left unpainted.
104
+
105
+ ### 3. Bind the fonts
106
+
107
+ The package cannot load the typefaces for you. `next/font` runs in your app and
108
+ generates hashed variable names at build time, so each app loads the three fonts
109
+ and binds them to the roles `type.css` expects:
110
+
111
+ ```tsx
112
+ // app/layout.tsx
113
+ import { Ubuntu_Sans, Ubuntu_Sans_Mono, Average } from "next/font/google";
114
+
115
+ const sans = Ubuntu_Sans({ variable: "--font-ubuntu-sans", subsets: ["latin"] });
116
+ const mono = Ubuntu_Sans_Mono({ variable: "--font-ubuntu-sans-mono", subsets: ["latin"] });
117
+ const serif = Average({ variable: "--font-average", weight: "400", subsets: ["latin"] });
118
+
119
+ <html className={`${sans.variable} ${mono.variable} ${serif.variable} font-sans`}>
120
+ ```
121
+
122
+ **Bind with `.variable`, never `.className`.** A className sets `font-family` on
123
+ the element itself and leaves the roles unresolved, so the page renders one
124
+ typeface while every `font-sans` and `font-heading` utility on it renders
125
+ another.
126
+
127
+ ### 4. Check the wiring
128
+
129
+ ```sh
130
+ npx foundations doctor
131
+ ```
132
+
133
+ It reads your CSS entry, your root layout and the installed tree, then reports
134
+ on import order, the `@source` path, the font bindings and the peer versions. It
135
+ exits non-zero on a real problem, so it works as a CI step too. Every check and
136
+ what it catches is listed in [the CLI](docs/cli.md).
137
+
138
+ ---
139
+
140
+ ## Your first page
141
+
142
+ ```tsx
143
+ import {
144
+ TypographyH1,
145
+ TypographyH2,
146
+ TypographyProse,
147
+ TypographyEyebrow,
148
+ TypographyLink,
149
+ TypographyCaption,
150
+ } from "@supertype.ai/foundations";
151
+ import { Card, Cards, Callout } from "@supertype.ai/foundations/blocks";
152
+
153
+ export default function Page() {
154
+ return (
155
+ <main className="mx-auto max-w-3xl px-6 py-16">
156
+ <TypographyEyebrow>Guides</TypographyEyebrow>
157
+ <TypographyH1 variant="display" className="mt-2 text-balance">
158
+ Getting data out of Postgres
159
+ </TypographyH1>
160
+ <TypographyProse className="mt-4">
161
+ Three approaches, ordered by how much of your schema they need to know.
162
+ </TypographyProse>
163
+
164
+ <TypographyH2 divider className="mt-12">
165
+ Approaches
166
+ </TypographyH2>
167
+
168
+ <Cards>
169
+ <Card
170
+ href="/notes/logical-replication"
171
+ title="Logical replication"
172
+ description="Row-level changes, no schema coupling."
173
+ />
174
+ <Card
175
+ href="https://www.postgresql.org/docs/current/sql-copy.html"
176
+ title="COPY"
177
+ description="Fastest bulk path. Leaves the app."
178
+ />
179
+ </Cards>
180
+
181
+ <Callout tone="warn" title="Before you start" className="mt-8">
182
+ Replication slots hold WAL until they are consumed. An abandoned slot
183
+ fills the disk — see{" "}
184
+ <TypographyLink href="/ops/slots" addArrow>
185
+ slot hygiene
186
+ </TypographyLink>
187
+ .
188
+ </Callout>
189
+
190
+ <TypographyCaption as="p" className="mt-8">
191
+ Last reviewed March 2026
192
+ </TypographyCaption>
193
+ </main>
194
+ );
195
+ }
196
+ ```
197
+
198
+ Two rules cover most of the API:
199
+
200
+ - **Do not write type styles by hand.** A paragraph carrying
201
+ `text-sm text-muted-foreground` is `<TypographyMuted>`. Using the primitives
202
+ keeps a size and a colour from drifting apart across a few hundred call sites.
203
+ - **Retune with CSS variables, not classes.** The package owns its own
204
+ classnames. Change a `--text-*` rung, `--heading-weight` or a colour token and
205
+ everything moves together.
206
+
207
+ ---
208
+
209
+ ## The example site
210
+
211
+ `yarn example` (above) builds the package, syncs it in and starts the dev
212
+ server. `yarn example:build` is what CI would run.
213
+
214
+ It installs the package from a git tag rather than from the registry — the
215
+ install path that has no lockfile-independent proof anywhere else — and updates
216
+ it with `yarn sync`, with no workspace and no symlink. Its `global.css`
217
+ and `layout.tsx` are the blocks above, unchanged, so an install instruction that
218
+ stops being true breaks the site.
219
+
220
+ `/recipes` holds whole pages rather than single components: a marketing hero, a
221
+ metrics panel, pricing tiers, a docs page, an article index, and the three files
222
+ that wire up MDX. Each one lives in
223
+ [`app/_recipes/`](examples/site/app/_recipes) as a complete file that imports
224
+ only from this package, so you can paste it into your app and it compiles.
225
+ `yarn example:build` fails if a recipe reaches for a local helper.
226
+
227
+ ---
228
+
229
+ ## For coding agents
230
+
231
+ The package ships an `llms.txt` with the public API, the rules, and the mistakes
232
+ that do not produce an error. Point your agent at it once and it stops
233
+ hand-writing `text-sm text-muted-foreground` where a primitive exists:
234
+
235
+ ```md
236
+ <!-- CLAUDE.md, AGENTS.md, or your agent's equivalent -->
237
+
238
+ @node_modules/@supertype.ai/foundations/llms.txt
239
+ ```
240
+
241
+ `yarn build` fails if an export is missing from it, so it cannot fall behind the
242
+ package.
243
+
244
+ ---
245
+
246
+ ## Entry points
247
+
248
+ | import | contains | docs |
249
+ | --------------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------- |
250
+ | `@supertype.ai/foundations` | all typography primitives, `cn` | [Typography](docs/typography.md) |
251
+ | `@supertype.ai/foundations/blocks` | `Card`, `Callout`, `Steps`, `Tabs`, `Accordion`, `Disclosure`, `SEGMENT` | [Blocks](docs/blocks.md) |
252
+ | `@supertype.ai/foundations/mdx` | `proseMdxComponents` — the MDX element map | [In MDX](docs/blocks.md#in-mdx) |
253
+ | `@supertype.ai/foundations/essay` | the long-form shell, TOC, reading rail, post meta | [Essay](docs/essay.md) |
254
+ | `@supertype.ai/foundations/seo` | `createSeo(...)` — metadata + JSON-LD | [Tooling](docs/tooling.md#seo-and-og-images) |
255
+ | `@supertype.ai/foundations/og` | `ogCard`, `OG_SIZE` — an element for `next/og` | [Tooling](docs/tooling.md#seo-and-og-images) |
256
+ | `@supertype.ai/foundations/eslint` | the design rules as ESLint selectors | [Tooling](docs/tooling.md#lint-rules) |
257
+ | `@supertype.ai/foundations/rehype` | `rehypeProseCode` — **build-time only** | [In MDX](docs/blocks.md#in-mdx) |
258
+ | `@supertype.ai/foundations/contrast` | token resolution + legibility checks, build-time only | [Tooling](docs/tooling.md#contrast-checks) |
259
+ | `./tokens.css` `./theme.css` `./type.css` `./prose.css` `./shiki.css` | the style layer | [Tokens and theming](#tokens-and-theming) |
260
+ | `foundations` (bin) | `init` and `doctor` | [The CLI](docs/cli.md) |
261
+
262
+ The entries are split by what they pull in. Blocks and the MDX map stay out of
263
+ the root barrel so that importing a heading does not resolve `@base-ui/react` or
264
+ `next/image`, and `/rehype` and `/contrast` stay out of both so they can run in
265
+ bare Node, where React cannot be resolved.
266
+
267
+ None of the entry points can be imported from plain Node, though: typography
268
+ reaches `next/link` through `next-view-transitions`. Import them from a Next app,
269
+ or from a test runner that resolves Next — both consumers' vitest suites do.
270
+
271
+ ---
272
+
273
+ ## Tokens and theming
274
+
275
+ `tokens.css` names the structural roles and nothing else: `--background`,
276
+ `--foreground`, `--card`, `--muted`, `--primary`, `--border` and `--ring`, plus
277
+ the status set. They are named for meaning rather than hue, so a project that
278
+ renders `success` in blue still reads correctly. It holds no values, so there is
279
+ only ever one palette in play.
280
+
281
+ Each status hue ships twice, on the same rule as the categorical tints:
282
+ `--success`, `--warn` and `--info` are **fills**, held to 3:1 against the page
283
+ and a card because a dot or a bar is a mark rather than words; `--success-ink`,
284
+ `--warn-ink` and `--info-ink` are the same hues as **text**, held to 4.5:1.
285
+ `--danger` ships as an ink only. `--destructive` keeps shadcn's shape, where
286
+ `--destructive-foreground` is the label printed on the fill — that is what
287
+ `-foreground` means throughout, and `-ink` means the hue used as words.
288
+ `checkSignals` in `@supertype.ai/foundations/contrast` measures all three bars.
289
+
290
+ `tokens.css` also binds the `dark:` variant to the `.dark` class. Do not skip
291
+ that import: Tailwind v4 otherwise follows the OS setting and quietly ignores
292
+ your toggle.
293
+
294
+ `theme.css` gives those roles the house latte and espresso palette, and adds the
295
+ editorial inks (`--secondary-ink`, `--subtle-foreground`, and the ochre,
296
+ terracotta, sage and fig pairs) along with the elevation shadows.
297
+
298
+ **No brand colours in the package.** Structural tokens only, with brand colours
299
+ left to the app. To repaint, override the raw variables after the imports rather
300
+ than patching the utilities:
301
+
302
+ ```css
303
+ :root {
304
+ --primary: hsl(24 60% 42%);
305
+ }
306
+ .dark {
307
+ --primary: hsl(24 70% 62%);
308
+ }
309
+ ```
310
+
311
+ ### `.editorial`
312
+
313
+ `type.css` names three font roles (`--font-sans`, `--font-mono` and
314
+ `--font-heading`) and the weight that goes with the heading face. `.editorial`
315
+ gives the heading role to the serif and drops the weight to 400, since Average
316
+ only has one:
317
+
318
+ ```tsx
319
+ <div className="editorial">…</div> {/* or on <html> for an editorial site */}
320
+ ```
321
+
322
+ It also retunes the whole heading ladder, which is the larger part of what it
323
+ does. Heading sizes are a _ratio_ to the body text under them, and the two
324
+ surfaces set body at different sizes: 13px in the product, 18px on `.editorial`. Scope the
325
+ class to whichever surfaces should be editorial, whether that is a marketing and
326
+ docs section or the whole site.
327
+
328
+ ---
329
+
330
+ ## Design rules
331
+
332
+ 1. **The package owns its final classnames.** Retune with CSS custom properties
333
+ (the `--text-*` ramp, `--heading-weight`, the colour tokens) rather than by
334
+ patching classes. A property the package declares is read by the package —
335
+ `test/tokens-live.test.ts` fails on one that is not, because a knob that
336
+ turns nothing is worse than no knob at all.
337
+ 2. **No variant props on the MDX map.** Elements that MDX renders automatically
338
+ take no options, because there is no call site to make the choice. Components
339
+ you invoke by hand can have variants.
340
+ 3. **Use the platform first, and a library only where it falls short.**
341
+ `Disclosure` is a `<details>`/`<summary>` pair: no JavaScript, correct before
342
+ hydration, and available to an MDX author. `Accordion` and `Tabs` use Base UI,
343
+ since animation and managed selection are beyond what the platform gives you.
344
+ 4. **No brand colours.** Structural tokens only, with brand colours left to the
345
+ app.
346
+ 5. **Put structure in CSS rather than the component map.** A host framework can
347
+ substitute its own element and strip the classes off it, but it cannot strip a
348
+ child combinator. Both the Shiki theming and the inline-code rule rely on
349
+ this.
350
+
351
+ ---
352
+
353
+ ## In production
354
+
355
+ Sites running the package:
356
+
357
+ - [supertype.ai](https://supertype.ai) — Supertype, a regional-leading analytics engineering and data science consulting firm.
358
+ - [viably.app](https://viably.app) — Viably, an observability-first business operating system and CRM for automation-obsessed teams.
359
+
360
+ ---
361
+
362
+ ## License
363
+
364
+ MIT. Copyright © 2026 Supertype. See [LICENSE](LICENSE).
365
+
366
+ Published to npm as
367
+ [`@supertype.ai/foundations`](https://www.npmjs.com/package/@supertype.ai/foundations),
368
+ and installable from this repository by tag. The MIT grant covers using,
369
+ modifying and redistributing it either way.