@designtools/docs 0.0.0-stage → 0.2.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/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.md +155 -2
- package/dist/a11y-panel.d.ts +58 -0
- package/dist/a11y-panel.js +75 -0
- package/dist/adherence-summary.d.ts +9 -0
- package/dist/adherence-summary.js +27 -0
- package/dist/agent-view.d.ts +19 -0
- package/dist/agent-view.js +23 -0
- package/dist/anatomy.d.ts +12 -0
- package/dist/anatomy.js +39 -0
- package/dist/ask-claude.d.ts +14 -0
- package/dist/ask-claude.js +40 -0
- package/dist/cli.js +322 -0
- package/dist/code-view.d.ts +17 -0
- package/dist/code-view.js +42 -0
- package/dist/examples.d.ts +25 -0
- package/dist/examples.js +48 -0
- package/dist/glossary.d.ts +5 -0
- package/dist/glossary.js +21 -0
- package/dist/imagery.d.ts +6 -0
- package/dist/imagery.js +17 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +34 -0
- package/dist/lib/adherence-types.d.ts +168 -0
- package/dist/lib/adherence-types.js +13 -0
- package/dist/lib/boundary.d.ts +16 -0
- package/dist/lib/boundary.js +15 -0
- package/dist/lib/contrast.d.ts +8 -0
- package/dist/lib/contrast.js +42 -0
- package/dist/lib/cx.d.ts +24 -0
- package/dist/lib/cx.js +26 -0
- package/dist/lib/jsx.d.ts +6 -0
- package/dist/lib/jsx.js +29 -0
- package/dist/lib/live.d.ts +10 -0
- package/dist/lib/live.js +10 -0
- package/dist/lib/lookup.d.ts +35 -0
- package/dist/lib/lookup.js +42 -0
- package/dist/lib/manifest-types.d.ts +253 -0
- package/dist/lib/manifest-types.js +14 -0
- package/dist/lib/manifest.d.ts +98 -0
- package/dist/lib/manifest.js +173 -0
- package/dist/lib/markdown.d.ts +50 -0
- package/dist/lib/markdown.js +286 -0
- package/dist/lib/measure.d.ts +12 -0
- package/dist/lib/measure.js +62 -0
- package/dist/lib/pseudo.d.ts +11 -0
- package/dist/lib/pseudo.js +71 -0
- package/dist/lib/registry.d.ts +21 -0
- package/dist/lib/registry.js +11 -0
- package/dist/lib/search.d.ts +44 -0
- package/dist/lib/search.js +62 -0
- package/dist/lib/standards.d.ts +17 -0
- package/dist/lib/standards.js +81 -0
- package/dist/lib/status.d.ts +6 -0
- package/dist/lib/status.js +17 -0
- package/dist/lib/terms.d.ts +15 -0
- package/dist/lib/terms.js +20 -0
- package/dist/lib/text.d.ts +8 -0
- package/dist/lib/text.js +9 -0
- package/dist/lib/ui.d.ts +100 -0
- package/dist/lib/ui.js +89 -0
- package/dist/lib/vision.d.ts +18 -0
- package/dist/lib/vision.js +27 -0
- package/dist/logo-usage.d.ts +14 -0
- package/dist/logo-usage.js +45 -0
- package/dist/next/config.d.ts +105 -0
- package/dist/next/config.js +1 -0
- package/dist/next/index.d.ts +65 -0
- package/dist/next/index.js +66 -0
- package/dist/next/markdown.d.ts +20 -0
- package/dist/next/markdown.js +95 -0
- package/dist/next/pages.d.ts +6 -0
- package/dist/next/pages.js +188 -0
- package/dist/next/prose.d.ts +9 -0
- package/dist/next/prose.js +39 -0
- package/dist/next/proxy.d.ts +19 -0
- package/dist/next/proxy.js +56 -0
- package/dist/next/site.d.ts +53 -0
- package/dist/next/site.js +136 -0
- package/dist/page-actions.d.ts +9 -0
- package/dist/page-actions.js +32 -0
- package/dist/pattern.d.ts +11 -0
- package/dist/pattern.js +22 -0
- package/dist/playground.d.ts +62 -0
- package/dist/playground.js +111 -0
- package/dist/preview-frame.d.ts +31 -0
- package/dist/preview-frame.js +63 -0
- package/dist/props-table.d.ts +10 -0
- package/dist/props-table.js +45 -0
- package/dist/rule.d.ts +16 -0
- package/dist/rule.js +37 -0
- package/dist/scale.d.ts +9 -0
- package/dist/scale.js +58 -0
- package/dist/search.d.ts +16 -0
- package/dist/search.js +46 -0
- package/dist/shell.d.ts +92 -0
- package/dist/shell.js +201 -0
- package/dist/standards.d.ts +13 -0
- package/dist/standards.js +19 -0
- package/dist/styles.css +3708 -0
- package/dist/swatches.d.ts +28 -0
- package/dist/swatches.js +100 -0
- package/dist/theme-switch.d.ts +20 -0
- package/dist/theme-switch.js +68 -0
- package/dist/type-ramp.d.ts +10 -0
- package/dist/type-ramp.js +31 -0
- package/dist/usage.d.ts +13 -0
- package/dist/usage.js +55 -0
- package/dist/variant-matrix.d.ts +15 -0
- package/dist/variant-matrix.js +58 -0
- package/dist/voice-terms.d.ts +5 -0
- package/dist/voice-terms.js +14 -0
- package/dist/workbench.d.ts +33 -0
- package/dist/workbench.js +274 -0
- package/package.json +107 -3
- package/src/a11y-panel.tsx +297 -0
- package/src/adherence-summary.tsx +134 -0
- package/src/agent-view.tsx +54 -0
- package/src/anatomy.tsx +119 -0
- package/src/ask-claude.tsx +90 -0
- package/src/code-view.tsx +112 -0
- package/src/css.d.ts +1 -0
- package/src/examples.tsx +141 -0
- package/src/glossary.tsx +70 -0
- package/src/imagery.tsx +64 -0
- package/src/index.ts +35 -0
- package/src/lib/adherence-types.ts +181 -0
- package/src/lib/boundary.tsx +21 -0
- package/src/lib/contrast.ts +44 -0
- package/src/lib/cx.ts +30 -0
- package/src/lib/jsx.ts +29 -0
- package/src/lib/live.tsx +15 -0
- package/src/lib/lookup.tsx +50 -0
- package/src/lib/manifest-types.ts +284 -0
- package/src/lib/manifest.ts +228 -0
- package/src/lib/markdown.ts +288 -0
- package/src/lib/measure.tsx +101 -0
- package/src/lib/pseudo.ts +74 -0
- package/src/lib/registry.tsx +29 -0
- package/src/lib/search.ts +99 -0
- package/src/lib/standards.ts +82 -0
- package/src/lib/status.tsx +32 -0
- package/src/lib/terms.tsx +53 -0
- package/src/lib/text.tsx +27 -0
- package/src/lib/ui.tsx +291 -0
- package/src/lib/vision.tsx +44 -0
- package/src/logo-usage.tsx +140 -0
- package/src/next/config.ts +101 -0
- package/src/next/index.tsx +103 -0
- package/src/next/markdown.ts +119 -0
- package/src/next/pages.tsx +483 -0
- package/src/next/prose.tsx +97 -0
- package/src/next/proxy.ts +55 -0
- package/src/next/site.ts +173 -0
- package/src/page-actions.tsx +92 -0
- package/src/pattern.tsx +72 -0
- package/src/playground.tsx +357 -0
- package/src/preview-frame.tsx +131 -0
- package/src/props-table.tsx +154 -0
- package/src/rule.tsx +165 -0
- package/src/scale.tsx +175 -0
- package/src/search.tsx +155 -0
- package/src/shell.tsx +569 -0
- package/src/standards.tsx +58 -0
- package/src/styles.css +157 -0
- package/src/swatches.tsx +298 -0
- package/src/theme-switch.tsx +90 -0
- package/src/type-ramp.tsx +150 -0
- package/src/usage.tsx +148 -0
- package/src/variant-matrix.tsx +178 -0
- package/src/voice-terms.tsx +37 -0
- package/src/workbench.tsx +587 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// cli/cli.ts
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
|
|
5
|
+
import { basename, dirname as dirname2, join as join2, relative, resolve, sep } from "path";
|
|
6
|
+
import { parseArgs } from "util";
|
|
7
|
+
|
|
8
|
+
// cli/blocks.ts
|
|
9
|
+
import { dirname, join } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
var SOURCE_DIR = join(dirname(fileURLToPath(import.meta.url)), "../src");
|
|
12
|
+
var BLOCKS = [
|
|
13
|
+
{ name: "shell", file: "shell.tsx", exports: [], description: "The frame: navigation, search, the mode switch, page header, sections and footer. Restyle it with the theme variables." },
|
|
14
|
+
{ name: "workbench", file: "workbench.tsx", exports: ["Workbench"], description: "A component's main area: the stage, its properties, code, props, actions, agent view and accessibility" },
|
|
15
|
+
{ name: "usage", file: "usage.tsx", exports: ["Usage"], description: "When to use a component, when not, what instead, and its facts" },
|
|
16
|
+
{ name: "examples", file: "examples.tsx", exports: ["Examples"], description: "The canonical example, then each do beside its don't" },
|
|
17
|
+
{ name: "variant-matrix", file: "variant-matrix.tsx", exports: ["VariantMatrix"], description: "Every variant combination, then each state" },
|
|
18
|
+
{ name: "anatomy", file: "anatomy.tsx", exports: ["Anatomy"], description: "The component's parts, found on hover" },
|
|
19
|
+
{ name: "props-table", file: "props-table.tsx", exports: ["PropsTable"], description: "Props as an API reference" },
|
|
20
|
+
{ name: "preview-frame", file: "preview-frame.tsx", exports: ["PreviewFrame"], description: "An example at device widths, in a browser window" },
|
|
21
|
+
{ name: "pattern", file: "pattern.tsx", exports: ["Pattern"], description: "A screen composition, live, with what it is made of" },
|
|
22
|
+
{ name: "rule", file: "rule.tsx", exports: ["Rule", "RuleIndex"], description: "A rule for people and as an agent reads it, with its check, and the index of every rule" },
|
|
23
|
+
{ name: "swatches", file: "swatches.tsx", exports: ["SemanticSwatches", "PageContrast", "RampSwatches"], description: "Colour: each pair measured, each colour on each background, the ramps" },
|
|
24
|
+
{ name: "type-ramp", file: "type-ramp.tsx", exports: ["TypeRamp"], description: "Type: families, the scale, weights, leading and tracking" },
|
|
25
|
+
{ name: "scale", file: "scale.tsx", exports: ["Scale"], description: "Space, size, radius, elevation and motion" },
|
|
26
|
+
{ name: "logo-usage", file: "logo-usage.tsx", exports: ["LogoUsage"], description: "Each logo on its surfaces, with its clear space and rules" },
|
|
27
|
+
{ name: "imagery", file: "imagery.tsx", exports: ["Imagery"], description: "The approved icons and imagery" },
|
|
28
|
+
{ name: "voice-terms", file: "voice-terms.tsx", exports: ["VoiceTerms"], description: "The words to use beside the ones not to" },
|
|
29
|
+
{ name: "glossary", file: "glossary.tsx", exports: ["Glossary"], description: "Every name in the system, found by its wrong forms too" },
|
|
30
|
+
{ name: "standards", file: "standards.tsx", exports: ["Standards"], description: "Budgets and targets from .mxa/stack.json" },
|
|
31
|
+
{ name: "adherence-summary", file: "adherence-summary.tsx", exports: ["AdherenceSummary"], description: "How closely the product follows the system" }
|
|
32
|
+
];
|
|
33
|
+
function ejected(source, file) {
|
|
34
|
+
const dir = dirname(file);
|
|
35
|
+
return source.replace(/(from\s+|import\s*\(\s*)(["'])(\.{1,2}\/[^"']+)\2/g, (_, lead, quote, spec) => {
|
|
36
|
+
const target = join(dir, spec).replace(/^\.\//, "").replace(/\\/g, "/");
|
|
37
|
+
return `${lead}${quote}@designtools/docs/${target}${quote}`;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// cli/map.ts
|
|
42
|
+
function generateMap(manifest, toRoot, manifestPath2) {
|
|
43
|
+
const spec = (source, keepExtension = false) => {
|
|
44
|
+
const path = `${toRoot || "."}/${keepExtension ? source : source.replace(/\.tsx?$/, "")}`;
|
|
45
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
46
|
+
};
|
|
47
|
+
const lines = [
|
|
48
|
+
`"use client";`,
|
|
49
|
+
`// Generated by designtools-docs map from ${manifestPath2}. Do not edit: run designtools-docs map again.`,
|
|
50
|
+
`import { type Registry as Entries, RegistryProvider } from "@designtools/docs/registry";`,
|
|
51
|
+
`import type { ReactNode } from "react";`
|
|
52
|
+
];
|
|
53
|
+
const components = [];
|
|
54
|
+
const examples = [];
|
|
55
|
+
const patterns = [];
|
|
56
|
+
const assets = [];
|
|
57
|
+
const seen = /* @__PURE__ */ new Set();
|
|
58
|
+
manifest.components.components.forEach((c, i) => {
|
|
59
|
+
lines.push(`import { ${c.export} as C${i} } from ${JSON.stringify(spec(c.source))};`);
|
|
60
|
+
components.push(` ${JSON.stringify(`${c.source}#${c.export}`)}: C${i},`);
|
|
61
|
+
if (c.examples && !seen.has(c.examples.source)) {
|
|
62
|
+
seen.add(c.examples.source);
|
|
63
|
+
const name = `E${examples.length}`;
|
|
64
|
+
lines.push(`import * as ${name} from ${JSON.stringify(spec(c.examples.source))};`);
|
|
65
|
+
examples.push(` ${JSON.stringify(c.examples.source)}: ${name},`);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
(manifest.patterns?.patterns ?? []).forEach((p, i) => {
|
|
69
|
+
lines.push(`import * as P${i} from ${JSON.stringify(spec(p.source))};`);
|
|
70
|
+
patterns.push(` ${JSON.stringify(p.source)}: P${i},`);
|
|
71
|
+
});
|
|
72
|
+
(manifest.assets?.assets ?? []).forEach((a, i) => {
|
|
73
|
+
lines.push(`import A${i} from ${JSON.stringify(spec(a.file, true))};`);
|
|
74
|
+
assets.push(` ${JSON.stringify(a.file)}: A${i},`);
|
|
75
|
+
});
|
|
76
|
+
const group = (name, rows) => [` ${name}: {`, ...rows, " },"];
|
|
77
|
+
return [
|
|
78
|
+
...lines,
|
|
79
|
+
"",
|
|
80
|
+
"const entries: Entries = {",
|
|
81
|
+
...group("components", components),
|
|
82
|
+
...group("examples", examples),
|
|
83
|
+
...group("patterns", patterns),
|
|
84
|
+
...group("assets", assets),
|
|
85
|
+
"};",
|
|
86
|
+
"",
|
|
87
|
+
"/** The project's components, examples, patterns and assets, for the docs: `registry` in the docs config. */",
|
|
88
|
+
"export default function Registry({ children }: { children: ReactNode }) {",
|
|
89
|
+
" return <RegistryProvider value={entries}>{children}</RegistryProvider>;",
|
|
90
|
+
"}",
|
|
91
|
+
""
|
|
92
|
+
].join("\n");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// cli/cli.ts
|
|
96
|
+
var VERSION = JSON.parse(readFileSync(join2(SOURCE_DIR, "../package.json"), "utf8")).version;
|
|
97
|
+
var CONFIG_FILE = "designtools.json";
|
|
98
|
+
var HEADER = /^\/\/ @designtools\/docs (\S+) · ejected (\S+)\r?\n/;
|
|
99
|
+
var HELP = `designtools-docs ${VERSION}
|
|
100
|
+
|
|
101
|
+
Design system docs as a package: pages, navigation, search, a workbench per
|
|
102
|
+
component and markdown for agents, themed by the project's tokens. This CLI
|
|
103
|
+
writes the registry that reaches the project's components, and copies a block
|
|
104
|
+
into the project when it needs to change more than the theme allows.
|
|
105
|
+
|
|
106
|
+
Usage
|
|
107
|
+
designtools-docs map Write the registry from the manifest
|
|
108
|
+
designtools-docs map --check Exit 1 if the registry is out of date
|
|
109
|
+
designtools-docs eject <block\u2026> Copy blocks' source into the project, to own and change
|
|
110
|
+
designtools-docs status Compare ejected blocks with this version
|
|
111
|
+
designtools-docs list List the blocks
|
|
112
|
+
designtools-docs show <block> Print this version of a block
|
|
113
|
+
|
|
114
|
+
Options
|
|
115
|
+
--registry <file> Where the registry goes (default: docs.registry in designtools.json,
|
|
116
|
+
else app/(design)/design/system/_registry.tsx, or src/app/\u2026 when src/app exists)
|
|
117
|
+
--dir <dir> Where ejected blocks go (default: docs.blocks in designtools.json,
|
|
118
|
+
else beside the registry, in _blocks)
|
|
119
|
+
--manifest <file> components.json (default: from manifest.system in designtools.json)
|
|
120
|
+
--root <dir> Project root (default: the current directory)
|
|
121
|
+
--force eject: overwrite a block already ejected
|
|
122
|
+
-h, --help Show this help
|
|
123
|
+
-v, --version Show the version
|
|
124
|
+
`;
|
|
125
|
+
function fail(message, code = 2) {
|
|
126
|
+
process.stderr.write(`designtools-docs: ${message}
|
|
127
|
+
`);
|
|
128
|
+
process.exit(code);
|
|
129
|
+
}
|
|
130
|
+
var parsed;
|
|
131
|
+
function parse() {
|
|
132
|
+
return parseArgs({
|
|
133
|
+
allowPositionals: true,
|
|
134
|
+
options: {
|
|
135
|
+
registry: { type: "string" },
|
|
136
|
+
dir: { type: "string" },
|
|
137
|
+
manifest: { type: "string" },
|
|
138
|
+
root: { type: "string" },
|
|
139
|
+
force: { type: "boolean" },
|
|
140
|
+
check: { type: "boolean" },
|
|
141
|
+
help: { type: "boolean", short: "h" },
|
|
142
|
+
version: { type: "boolean", short: "v" }
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
parsed = parse();
|
|
148
|
+
} catch (e) {
|
|
149
|
+
fail(`${e.message}
|
|
150
|
+
|
|
151
|
+
${HELP}`);
|
|
152
|
+
}
|
|
153
|
+
var { values, positionals } = parsed;
|
|
154
|
+
if (values.help) {
|
|
155
|
+
process.stdout.write(HELP);
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
if (values.version) {
|
|
159
|
+
process.stdout.write(`${VERSION}
|
|
160
|
+
`);
|
|
161
|
+
process.exit(0);
|
|
162
|
+
}
|
|
163
|
+
function real(path) {
|
|
164
|
+
if (existsSync(path)) return realpathSync(path);
|
|
165
|
+
const parent = dirname2(path);
|
|
166
|
+
return parent === path ? path : join2(real(parent), basename(path));
|
|
167
|
+
}
|
|
168
|
+
var root = real(resolve(values.root ?? "."));
|
|
169
|
+
var posix = (p) => p.split(sep).join("/");
|
|
170
|
+
var abs = (p) => real(resolve(root, p));
|
|
171
|
+
var shown = (p) => posix(relative(root, abs(p))) || ".";
|
|
172
|
+
var lf = (text) => text.replace(/\r\n/g, "\n");
|
|
173
|
+
function readConfig() {
|
|
174
|
+
const path = join2(root, CONFIG_FILE);
|
|
175
|
+
if (!existsSync(path)) return {};
|
|
176
|
+
try {
|
|
177
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
178
|
+
} catch (e) {
|
|
179
|
+
fail(`${CONFIG_FILE} is not valid JSON: ${e.message}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function registryPath(config) {
|
|
183
|
+
if (values.registry) return values.registry;
|
|
184
|
+
if (config.docs?.registry) return config.docs.registry;
|
|
185
|
+
const app = existsSync(join2(root, "src/app")) ? "src/app" : "app";
|
|
186
|
+
return `${app}/(design)/design/system/_registry.tsx`;
|
|
187
|
+
}
|
|
188
|
+
function blocksDir(config) {
|
|
189
|
+
if (values.dir) return values.dir;
|
|
190
|
+
if (config.docs?.blocks) return config.docs.blocks;
|
|
191
|
+
return `${posix(dirname2(registryPath(config)))}/_blocks`;
|
|
192
|
+
}
|
|
193
|
+
function manifestPath(config) {
|
|
194
|
+
if (values.manifest) return values.manifest;
|
|
195
|
+
const m = config.manifest;
|
|
196
|
+
if (!m?.system && !m?.out) fail(`no manifest. Pass --manifest <components.json>, or set manifest.system in ${CONFIG_FILE}.`);
|
|
197
|
+
return `${(m.out ?? `${m.system.replace(/\/+$/, "")}/manifest`).replace(/\/+$/, "")}/components.json`;
|
|
198
|
+
}
|
|
199
|
+
var [command, ...rest] = positionals;
|
|
200
|
+
switch (command) {
|
|
201
|
+
case "map":
|
|
202
|
+
map();
|
|
203
|
+
break;
|
|
204
|
+
case "eject":
|
|
205
|
+
eject();
|
|
206
|
+
break;
|
|
207
|
+
case "status":
|
|
208
|
+
status();
|
|
209
|
+
break;
|
|
210
|
+
case "list":
|
|
211
|
+
list();
|
|
212
|
+
break;
|
|
213
|
+
case "show":
|
|
214
|
+
show();
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
fail(command ? `unknown command "${command}"
|
|
218
|
+
|
|
219
|
+
${HELP}` : `a command is required
|
|
220
|
+
|
|
221
|
+
${HELP}`);
|
|
222
|
+
}
|
|
223
|
+
function list() {
|
|
224
|
+
const width = Math.max(...BLOCKS.map((b) => b.name.length));
|
|
225
|
+
for (const b of BLOCKS) process.stdout.write(`${b.name.padEnd(width)} ${b.description}
|
|
226
|
+
`);
|
|
227
|
+
}
|
|
228
|
+
function blockOf(name) {
|
|
229
|
+
const block = BLOCKS.find((b) => b.name === name || b.file === name);
|
|
230
|
+
if (!block) fail(`no block called "${name}". Run designtools-docs list to see them.`);
|
|
231
|
+
return block;
|
|
232
|
+
}
|
|
233
|
+
function map() {
|
|
234
|
+
const config = readConfig();
|
|
235
|
+
const target = registryPath(config);
|
|
236
|
+
const manifest = manifestPath(config);
|
|
237
|
+
if (!existsSync(abs(manifest))) fail(`${manifest} not found. Run designtools-manifest build first.`);
|
|
238
|
+
const expected = generate(target, manifest);
|
|
239
|
+
if (values.check) {
|
|
240
|
+
const ok = existsSync(abs(target)) && lf(readFileSync(abs(target), "utf8")) === expected;
|
|
241
|
+
process.stderr.write(ok ? `map: ${shown(target)} up to date
|
|
242
|
+
` : `map: ${shown(target)} is out of date. Run designtools-docs map.
|
|
243
|
+
`);
|
|
244
|
+
process.exit(ok ? 0 : 1);
|
|
245
|
+
}
|
|
246
|
+
mkdirSync(dirname2(abs(target)), { recursive: true });
|
|
247
|
+
writeFileSync(abs(target), expected);
|
|
248
|
+
process.stderr.write(`wrote ${shown(target)} from ${shown(manifest)}
|
|
249
|
+
`);
|
|
250
|
+
}
|
|
251
|
+
function generate(target, manifest) {
|
|
252
|
+
const json = JSON.parse(readFileSync(abs(manifest), "utf8"));
|
|
253
|
+
const sibling = (name) => {
|
|
254
|
+
const path = join2(dirname2(abs(manifest)), name);
|
|
255
|
+
return existsSync(path) ? JSON.parse(readFileSync(path, "utf8")) : void 0;
|
|
256
|
+
};
|
|
257
|
+
return generateMap(
|
|
258
|
+
{ components: json, patterns: sibling("patterns.json"), assets: sibling("assets.json") },
|
|
259
|
+
posix(relative(dirname2(abs(target)), sourceRoot(abs(manifest), json.system))),
|
|
260
|
+
shown(manifest)
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
function sourceRoot(manifest, system) {
|
|
264
|
+
const path = posix(manifest);
|
|
265
|
+
const tail = system ? `/${system.replace(/^\.?\/+|\/+$/g, "")}/manifest/components.json` : void 0;
|
|
266
|
+
return tail && path.endsWith(tail) ? path.slice(0, -tail.length) || "/" : root;
|
|
267
|
+
}
|
|
268
|
+
function eject() {
|
|
269
|
+
if (rest.length === 0) fail("name the blocks to eject. Run designtools-docs list to see them.");
|
|
270
|
+
const config = readConfig();
|
|
271
|
+
const dir = blocksDir(config);
|
|
272
|
+
const lines = [];
|
|
273
|
+
for (const name of rest) {
|
|
274
|
+
const block = blockOf(name);
|
|
275
|
+
const target = join2(abs(dir), block.file);
|
|
276
|
+
if (existsSync(target) && !values.force) {
|
|
277
|
+
process.stderr.write(`kept ${shown(target)} (already ejected; --force to replace, designtools-docs status to compare)
|
|
278
|
+
`);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
mkdirSync(dirname2(target), { recursive: true });
|
|
282
|
+
const source = readFileSync(join2(SOURCE_DIR, block.file), "utf8");
|
|
283
|
+
writeFileSync(target, `// @designtools/docs ${VERSION} \xB7 ejected ${block.name}
|
|
284
|
+
${ejected(source, block.file)}`);
|
|
285
|
+
process.stderr.write(`ejected ${shown(target)}
|
|
286
|
+
`);
|
|
287
|
+
for (const e of block.exports) lines.push(` ${e}: ${e}, // from "./${posix(relative(dirname2(abs(registryPath(config))), target)).replace(/\.tsx$/, "")}"`);
|
|
288
|
+
}
|
|
289
|
+
if (lines.length)
|
|
290
|
+
process.stderr.write(`
|
|
291
|
+
Use it in the docs config:
|
|
292
|
+
blocks: {
|
|
293
|
+
${lines.join("\n")}
|
|
294
|
+
},
|
|
295
|
+
Everything else keeps upgrading with the package.
|
|
296
|
+
`);
|
|
297
|
+
}
|
|
298
|
+
function status() {
|
|
299
|
+
const dir = blocksDir(readConfig());
|
|
300
|
+
let found = 0;
|
|
301
|
+
for (const block of BLOCKS) {
|
|
302
|
+
const target = join2(abs(dir), block.file);
|
|
303
|
+
if (!existsSync(target)) continue;
|
|
304
|
+
found++;
|
|
305
|
+
const copy = readFileSync(target, "utf8");
|
|
306
|
+
const header = HEADER.exec(copy);
|
|
307
|
+
const body = lf(header ? copy.slice(header[0].length) : copy);
|
|
308
|
+
const current = ejected(readFileSync(join2(SOURCE_DIR, block.file), "utf8"), block.file);
|
|
309
|
+
const from = header?.[1] ?? "unknown";
|
|
310
|
+
const state = body === current ? "same as the package" : from === VERSION ? "edited here" : `differs: ejected from ${from}, the package is ${VERSION} (designtools-docs show ${block.name} for the new one)`;
|
|
311
|
+
process.stdout.write(`${block.file.padEnd(22)} ${state}
|
|
312
|
+
`);
|
|
313
|
+
}
|
|
314
|
+
if (!found) process.stdout.write(`no ejected blocks in ${shown(dir)}: everything comes from the package
|
|
315
|
+
`);
|
|
316
|
+
}
|
|
317
|
+
function show() {
|
|
318
|
+
const [name] = rest;
|
|
319
|
+
if (!name) fail("name a block. Run designtools-docs list to see them.");
|
|
320
|
+
const block = blockOf(name);
|
|
321
|
+
process.stdout.write(ejected(readFileSync(join2(SOURCE_DIR, block.file), "utf8"), block.file));
|
|
322
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code, highlighted once Shiki has loaded (it loads on first use, so pages
|
|
3
|
+
* without code never pay for it) and readable as plain text before then. A file
|
|
4
|
+
* header with a copy button, numbered lines, and long code folded behind "Show
|
|
5
|
+
* all". `bare` drops the frame, for code inside another frame.
|
|
6
|
+
*/
|
|
7
|
+
export declare function CodeView({ code, lang, label, wrap, bare, numbered, }: {
|
|
8
|
+
code: string;
|
|
9
|
+
lang?: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Wrap long lines, for prose such as markdown, instead of scrolling them. */
|
|
12
|
+
wrap?: boolean;
|
|
13
|
+
/** No border or header of its own: for code inside an example or playground frame. */
|
|
14
|
+
bare?: boolean;
|
|
15
|
+
/** Line numbers. On by default for more than one line of code, off for prose. */
|
|
16
|
+
numbered?: boolean;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ChevronDown, FileCode } from "lucide-react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { cx } from "./lib/cx.js";
|
|
6
|
+
import { CopyButton } from "./lib/ui.js";
|
|
7
|
+
/* Shiki writes both themes as CSS variables; these pick the one for the page's mode, and number the lines. */
|
|
8
|
+
const THEME_CSS = `
|
|
9
|
+
[data-slot="code-view"] .shiki { background: transparent !important; counter-reset: line; }
|
|
10
|
+
[data-slot="code-view"][data-numbered] .shiki .line::before { counter-increment: line; content: counter(line); display: inline-block; width: 2ch; margin-right: 1.25rem; text-align: right; color: var(--muted-foreground); opacity: .6; }
|
|
11
|
+
[data-theme="dark"] [data-slot="code-view"] .shiki, [data-theme="dark"] [data-slot="code-view"] .shiki span { color: var(--shiki-dark) !important; }
|
|
12
|
+
@media (prefers-color-scheme: dark) {
|
|
13
|
+
:root:not([data-theme="light"]) [data-slot="code-view"] .shiki, :root:not([data-theme="light"]) [data-slot="code-view"] .shiki span { color: var(--shiki-dark) !important; }
|
|
14
|
+
}`;
|
|
15
|
+
/** Lines past which the code folds, with a fade and a "Show all". */
|
|
16
|
+
const FOLD = 14;
|
|
17
|
+
/**
|
|
18
|
+
* Code, highlighted once Shiki has loaded (it loads on first use, so pages
|
|
19
|
+
* without code never pay for it) and readable as plain text before then. A file
|
|
20
|
+
* header with a copy button, numbered lines, and long code folded behind "Show
|
|
21
|
+
* all". `bare` drops the frame, for code inside another frame.
|
|
22
|
+
*/
|
|
23
|
+
export function CodeView({ code, lang = "tsx", label = "Code", wrap = false, bare = false, numbered, }) {
|
|
24
|
+
const [html, setHtml] = useState(null);
|
|
25
|
+
const lines = code.split("\n").length;
|
|
26
|
+
const [open, setOpen] = useState(lines <= FOLD);
|
|
27
|
+
const numbers = numbered ?? (!wrap && lines > 1);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
let live = true;
|
|
30
|
+
import("shiki")
|
|
31
|
+
.then(({ codeToHtml }) => codeToHtml(code, { lang, themes: { light: "github-light", dark: "github-dark" } }))
|
|
32
|
+
.then((out) => live && setHtml(out))
|
|
33
|
+
.catch(() => live && setHtml(null));
|
|
34
|
+
return () => {
|
|
35
|
+
live = false;
|
|
36
|
+
};
|
|
37
|
+
}, [code, lang]);
|
|
38
|
+
const body = cx("overflow-x-auto px-4 py-3.5 font-mono text-sm leading-relaxed", wrap && "[&_pre]:break-words [&_pre]:whitespace-pre-wrap",
|
|
39
|
+
// room for the copy button floating at the top right
|
|
40
|
+
bare && "pr-12", !open && "max-h-96 overflow-y-hidden");
|
|
41
|
+
return (_jsxs("figure", { "data-slot": "code-view", "data-numbered": numbers || undefined, className: cx("relative min-w-0", !bare && "overflow-hidden rounded-xl border border-border bg-surface text-surface-foreground"), children: [_jsx("style", { children: THEME_CSS }), !bare && (_jsxs("figcaption", { className: "flex min-h-11 items-center justify-between gap-3 border-b border-border bg-muted/40 py-1 pr-1.5 pl-4 text-xs text-muted-foreground", children: [_jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [_jsx(FileCode, { "aria-hidden": true, className: "size-(--dt-size-xs) shrink-0" }), _jsx("span", { className: "truncate font-medium text-canvas-foreground", children: label })] }), _jsx(CopyButton, { text: code, label: "Copy code" })] })), _jsxs("div", { className: "relative", children: [bare && (_jsx("span", { className: "absolute top-1.5 right-1.5 z-10", children: _jsx(CopyButton, { text: code, label: "Copy code" }) })), html ? (_jsx("div", { className: body, tabIndex: 0, role: "region", "aria-label": label, dangerouslySetInnerHTML: { __html: html } })) : (_jsx("pre", { tabIndex: 0, "aria-label": label, className: cx(body, wrap && "break-words whitespace-pre-wrap"), children: _jsx("code", { children: code }) })), !open && (_jsx("div", { className: "absolute inset-x-0 bottom-0 flex h-24 items-end justify-center bg-linear-to-t from-surface via-surface/80 to-transparent pb-3", children: _jsxs("button", { type: "button", onClick: () => setOpen(true), className: "inline-flex min-h-(--docs-target,2.75rem) cursor-pointer items-center gap-1.5 rounded-full border border-border bg-surface px-4 text-xs font-medium text-surface-foreground shadow-sm hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring", children: ["Show all ", lines, " lines ", _jsx(ChevronDown, { "aria-hidden": true, className: "size-(--dt-size-xs)" })] }) }))] })] }));
|
|
42
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ComponentEntry } from "./lib/manifest-types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The canonical example first, the one to copy, then each do beside its don't.
|
|
5
|
+
* Every example is the real component; the code behind it is the code that drew it.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Examples({ entry, previewHref }: {
|
|
8
|
+
entry: ComponentEntry;
|
|
9
|
+
previewHref?: string;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
type Kind = "canonical" | "do" | "dont" | "other";
|
|
12
|
+
/**
|
|
13
|
+
* One example in its frame: Preview and Code on a switch, the stage in either mode
|
|
14
|
+
* or at a phone's width, a copy button, and a link to it alone. The caption says
|
|
15
|
+
* what kind of example it is and why. Patterns use it for their compositions too.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ExampleFrame({ name, kind, description, code, href, children, }: {
|
|
18
|
+
name: string;
|
|
19
|
+
kind?: Kind;
|
|
20
|
+
description?: string;
|
|
21
|
+
code?: string;
|
|
22
|
+
href?: string;
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}): import("react").JSX.Element;
|
|
25
|
+
export {};
|
package/dist/examples.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CircleCheck, CircleX, Code, Eye, Maximize2, Moon, Smartphone, Sun } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { CodeView } from "./code-view.js";
|
|
6
|
+
import { Boundary } from "./lib/boundary.js";
|
|
7
|
+
import { cx } from "./lib/cx.js";
|
|
8
|
+
import { Missing, renderExample, useLookup } from "./lib/lookup.js";
|
|
9
|
+
import { inline } from "./lib/text.js";
|
|
10
|
+
import { CopyButton, IconButton, IconLink, Segmented, SegmentedList, SegmentedPanel, Stage, Toolbar } from "./lib/ui.js";
|
|
11
|
+
/**
|
|
12
|
+
* The canonical example first, the one to copy, then each do beside its don't.
|
|
13
|
+
* Every example is the real component; the code behind it is the code that drew it.
|
|
14
|
+
*/
|
|
15
|
+
export function Examples({ entry, previewHref }) {
|
|
16
|
+
const lookup = useLookup();
|
|
17
|
+
const ex = entry.examples;
|
|
18
|
+
if (!ex) {
|
|
19
|
+
return (_jsxs("p", { "data-slot": "examples-empty", className: "rounded-xl border border-dashed border-border p-6 text-sm text-muted-foreground", children: ["No examples yet. Add ", _jsx("code", { className: "font-mono text-xs", children: entry.source.replace(/\.tsx$/, ".examples.tsx") }), " with a", " ", _jsx("code", { className: "font-mono text-xs", children: "canonical" }), " export and do and don't pairs."] }));
|
|
20
|
+
}
|
|
21
|
+
const module = lookup.examplesFor(entry);
|
|
22
|
+
if (!module)
|
|
23
|
+
return _jsx(Missing, { name: entry.name, what: "examples" });
|
|
24
|
+
const pairs = Array.from({ length: Math.max(ex.do.length, ex.dont.length) }, (_, i) => [ex.do[i], ex.dont[i]]);
|
|
25
|
+
const frame = (ref, kind) => (_jsx(ExampleFrame, { name: ref.name, kind: kind, description: ref.description, code: ref.code, href: previewHref && `${previewHref}/${encodeURIComponent(ref.name)}`, children: renderExample(module[ref.name], ref.name) }, ref.name));
|
|
26
|
+
return (_jsxs("div", { "data-slot": "examples", className: "flex flex-col gap-10", children: [ex.canonical && frame(ex.canonical, "canonical"), pairs.length > 0 && (_jsx("div", { className: "flex flex-col gap-6", children: pairs.map(([d, n], i) => (_jsxs("div", { "data-slot": "examples-pair", className: "grid grid-cols-1 gap-4 lg:grid-cols-2", children: [d ? frame(d, "do") : _jsx("span", {}), n ? frame(n, "dont") : _jsx("span", {})] }, d?.name ?? n?.name ?? i))) })), ex.other.length > 0 && _jsx("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-2", children: ex.other.map((o) => frame(o, "other")) })] }));
|
|
27
|
+
}
|
|
28
|
+
const MARK = {
|
|
29
|
+
// the canonical example is simply first, the usual use; it needs no badge to say so
|
|
30
|
+
canonical: { label: "", tone: "" },
|
|
31
|
+
// a measured pairing, never a fill colour used as text (text-success read 3.9:1 on the canvas)
|
|
32
|
+
do: { label: "Do", icon: CircleCheck, tone: "bg-success-subdued text-success-subdued-foreground" },
|
|
33
|
+
dont: { label: "Don't", icon: CircleX, tone: "bg-destructive-subdued text-destructive-subdued-foreground" },
|
|
34
|
+
other: { label: "", tone: "" },
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* One example in its frame: Preview and Code on a switch, the stage in either mode
|
|
38
|
+
* or at a phone's width, a copy button, and a link to it alone. The caption says
|
|
39
|
+
* what kind of example it is and why. Patterns use it for their compositions too.
|
|
40
|
+
*/
|
|
41
|
+
export function ExampleFrame({ name, kind = "other", description, code, href, children, }) {
|
|
42
|
+
const [theme, setTheme] = useState();
|
|
43
|
+
const [narrow, setNarrow] = useState(false);
|
|
44
|
+
const mark = MARK[kind];
|
|
45
|
+
const Icon = mark.icon;
|
|
46
|
+
const views = [{ value: "preview", label: "Preview", icon: Eye }, ...(code ? [{ value: "code", label: "Code", icon: Code }] : [])];
|
|
47
|
+
return (_jsxs("figure", { "data-slot": "example", "data-kind": kind, className: "flex min-w-0 flex-col gap-3", children: [_jsxs(Segmented, { defaultValue: "preview", className: "overflow-hidden rounded-xl border border-border bg-surface text-surface-foreground shadow-xs", children: [_jsxs(Toolbar, { children: [_jsx(SegmentedList, { items: views, label: `${name}: preview or code` }), _jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx(IconButton, { icon: Smartphone, label: "Phone width", pressed: narrow, onClick: () => setNarrow(!narrow) }), _jsx(IconButton, { icon: theme === "dark" ? Sun : Moon, label: theme === "dark" ? "Show in light mode" : "Show in dark mode", pressed: theme !== undefined, onClick: () => setTheme(theme === "dark" ? "light" : "dark") }), code && _jsx(CopyButton, { text: code, label: "Copy code" }), href && _jsx(IconLink, { icon: Maximize2, label: "Open on its own", href: href })] })] }), _jsx(SegmentedPanel, { value: "preview", children: _jsx(Stage, { theme: theme, width: narrow ? 375 : undefined, className: kind === "canonical" ? "min-h-64" : "min-h-48", children: _jsx(Boundary, { label: name, children: children }) }) }), code && (_jsx(SegmentedPanel, { value: "code", children: _jsx(CodeView, { code: code, label: name, bare: true }) }))] }), (mark.label || description) && (_jsxs("figcaption", { className: "flex items-start gap-2 px-1", children: [mark.label && (_jsxs("span", { className: cx("inline-flex h-6 shrink-0 items-center gap-1.5 rounded-full pr-2.5 pl-2 text-xs font-medium", mark.tone), children: [Icon && _jsx(Icon, { "aria-hidden": true, className: "size-3.5" }), mark.label] })), description && _jsx("span", { className: "pt-0.5 text-sm", children: inline(description) })] }))] }));
|
|
48
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TermEntry } from "./lib/manifest-types.js";
|
|
2
|
+
/** Every name in the system, searchable by its wrong forms too, so a wrong name finds the right one. A to Z. */
|
|
3
|
+
export declare function Glossary({ terms }: {
|
|
4
|
+
terms: TermEntry[];
|
|
5
|
+
}): import("react").JSX.Element;
|
package/dist/glossary.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ArrowRight, Search } from "lucide-react";
|
|
4
|
+
import { useId, useState } from "react";
|
|
5
|
+
import { TermRow } from "./lib/terms.js";
|
|
6
|
+
/** Every name in the system, searchable by its wrong forms too, so a wrong name finds the right one. A to Z. */
|
|
7
|
+
export function Glossary({ terms }) {
|
|
8
|
+
const id = useId();
|
|
9
|
+
const [query, setQuery] = useState("");
|
|
10
|
+
const q = query.trim().toLowerCase();
|
|
11
|
+
const matches = (q ? terms.filter((t) => t.name.toLowerCase().includes(q) || t.wrong?.some((w) => w.toLowerCase().includes(q))) : terms)
|
|
12
|
+
.slice()
|
|
13
|
+
.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
|
|
14
|
+
const corrected = q ? terms.find((t) => t.wrong?.some((w) => w.toLowerCase() === q)) : undefined;
|
|
15
|
+
const letters = new Map();
|
|
16
|
+
for (const t of matches) {
|
|
17
|
+
const l = /[a-z]/i.test(t.name[0]) ? t.name[0].toUpperCase() : "#";
|
|
18
|
+
letters.set(l, [...(letters.get(l) ?? []), t]);
|
|
19
|
+
}
|
|
20
|
+
return (_jsxs("div", { "data-slot": "glossary", className: "flex flex-col gap-10", children: [_jsxs("div", { className: "flex max-w-3xl flex-col gap-4", children: [_jsx("label", { htmlFor: id, className: "sr-only", children: "Find a term" }), _jsxs("div", { className: "relative", children: [_jsx(Search, { "aria-hidden": true, className: "pointer-events-none absolute top-1/2 left-0 size-(--dt-size-md) -translate-y-1/2 text-muted-foreground" }), _jsx("input", { id: id, type: "search", value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Find a term, or a name you half remember", className: "h-16 w-full border-0 border-b border-border bg-transparent pr-2 pl-10 text-2xl tracking-tight placeholder:text-muted-foreground/70 hover:border-input focus-visible:border-b-2 focus-visible:border-canvas-foreground focus-visible:outline-none" })] }), _jsx("div", { "aria-live": "polite", children: corrected ? (_jsxs("p", { "data-slot": "glossary-correction", className: "flex flex-wrap items-center gap-2 rounded-xl bg-muted/60 px-5 py-4 text-lg", children: ["Say ", _jsx("strong", { className: "font-semibold", children: corrected.name }), _jsx(ArrowRight, { "aria-hidden": true, className: "size-4 text-muted-foreground" }), _jsxs("span", { className: "text-muted-foreground", children: ["not \u201C", query.trim(), "\u201D"] })] })) : (_jsx("p", { className: "text-sm text-muted-foreground", children: q ? `${matches.length} ${matches.length === 1 ? "term" : "terms"}` : `${terms.length} terms, A to Z. Search by the right name or a wrong one.` })) })] }), _jsx("div", { "data-slot": "glossary-list", className: "flex flex-col gap-8", children: [...letters].map(([letter, list]) => (_jsxs("section", { "aria-label": letter, className: "grid gap-x-8 lg:grid-cols-[3rem_minmax(0,1fr)]", children: [_jsx("h3", { className: "pt-5 text-2xl tracking-tight text-muted-foreground lg:sticky lg:top-24 lg:self-start", children: letter }), _jsx("div", { children: _jsx("dl", { children: list.map((t) => (_jsx(TermRow, { term: t, kind: true }, `${t.kind}:${t.name}`))) }) })] }, letter))) })] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AssetEntry } from "./lib/manifest-types.js";
|
|
2
|
+
/** The approved icons and imagery, each on a stage with how to use it; an icon is shown at its three sizes too. */
|
|
3
|
+
export declare function Imagery({ assets, kinds }: {
|
|
4
|
+
assets: AssetEntry[];
|
|
5
|
+
kinds?: AssetEntry["kind"][];
|
|
6
|
+
}): import("react").JSX.Element;
|
package/dist/imagery.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useLookup } from "./lib/lookup.js";
|
|
4
|
+
import { inline } from "./lib/text.js";
|
|
5
|
+
import { Stage } from "./lib/ui.js";
|
|
6
|
+
/** The approved icons and imagery, each on a stage with how to use it; an icon is shown at its three sizes too. */
|
|
7
|
+
export function Imagery({ assets, kinds = ["icon", "image", "other"] }) {
|
|
8
|
+
const lookup = useLookup();
|
|
9
|
+
const shown = assets.filter((a) => kinds.includes(a.kind));
|
|
10
|
+
if (shown.length === 0)
|
|
11
|
+
return _jsx("p", { className: "text-sm text-muted-foreground", children: "No icons or imagery in the brand folder yet." });
|
|
12
|
+
return (_jsx("ul", { "data-slot": "imagery", className: "grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3", children: shown.map((a) => {
|
|
13
|
+
const src = lookup.assetUrl(a);
|
|
14
|
+
const icon = a.kind === "icon";
|
|
15
|
+
return (_jsx("li", { className: "min-w-0", children: _jsxs("figure", { "data-slot": "asset", className: "flex h-full flex-col overflow-hidden rounded-2xl border border-border bg-surface text-surface-foreground shadow-xs", children: [_jsx(Stage, { className: "h-44 p-6", children: src ? (icon ? (_jsx("span", { "aria-hidden": !a.alt, role: a.alt ? "img" : undefined, "aria-label": a.alt || undefined, className: "block size-14 bg-current", style: { mask: `url(${src}) center / contain no-repeat`, WebkitMask: `url(${src}) center / contain no-repeat` } })) : (_jsx("img", { src: src, alt: a.alt ?? "", className: "max-h-full max-w-full rounded-md object-contain" }))) : (_jsx("span", { className: "font-mono text-xs text-muted-foreground", children: a.file })) }), _jsxs("figcaption", { className: "flex flex-1 flex-col gap-2 border-t border-border p-4 text-sm", children: [_jsxs("span", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-lg", children: a.name }), icon && src ? (_jsx("span", { "aria-hidden": true, className: "flex items-end gap-2 text-muted-foreground", children: [16, 20, 24].map((size) => (_jsx("span", { className: "block bg-current", style: { width: size, height: size, mask: `url(${src}) center / contain no-repeat`, WebkitMask: `url(${src}) center / contain no-repeat` } }, size))) })) : (_jsx("span", { className: "rounded-full bg-muted px-2 py-0.5 font-mono text-xs text-muted-foreground", children: a.kind }))] }), _jsx("span", { className: "text-muted-foreground", children: a.usage ? inline(a.usage) : "No usage notes yet." }), _jsxs("span", { className: "mt-auto pt-1 font-mono text-xs text-muted-foreground", children: [a.file, a.width && a.height ? ` · ${a.width} × ${a.height}` : ""] })] })] }) }, a.file));
|
|
16
|
+
}) }));
|
|
17
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @designtools/docs: every block, for a project composing its own pages. Most
|
|
3
|
+
* projects use `@designtools/docs/next` instead, which composes them.
|
|
4
|
+
*/
|
|
5
|
+
export { A11yPanel, AxeReport, useAxe } from "./a11y-panel.js";
|
|
6
|
+
export { AdherenceSummary } from "./adherence-summary.js";
|
|
7
|
+
export { AgentInstructions, AgentView } from "./agent-view.js";
|
|
8
|
+
export { Anatomy } from "./anatomy.js";
|
|
9
|
+
export { AskClaude } from "./ask-claude.js";
|
|
10
|
+
export { CodeView } from "./code-view.js";
|
|
11
|
+
export { ExampleFrame, Examples } from "./examples.js";
|
|
12
|
+
export { Glossary } from "./glossary.js";
|
|
13
|
+
export { Imagery } from "./imagery.js";
|
|
14
|
+
export { LogoUsage } from "./logo-usage.js";
|
|
15
|
+
export { PageActions } from "./page-actions.js";
|
|
16
|
+
export { Pattern } from "./pattern.js";
|
|
17
|
+
export { Playground } from "./playground.js";
|
|
18
|
+
export { PreviewComposition, PreviewExample, PreviewFrame, PreviewSurface } from "./preview-frame.js";
|
|
19
|
+
export { PropsTable } from "./props-table.js";
|
|
20
|
+
export { Rule, RuleIndex } from "./rule.js";
|
|
21
|
+
export { Scale } from "./scale.js";
|
|
22
|
+
export { DocsSearch } from "./search.js";
|
|
23
|
+
export { type DocsLink, DocsFooter, DocsHeader, DocsSection, DocsShell } from "./shell.js";
|
|
24
|
+
export { Standards } from "./standards.js";
|
|
25
|
+
export { PageContrast, RampSwatches, SemanticSwatches } from "./swatches.js";
|
|
26
|
+
export { ThemeSwitch, themeScript, useThemeScript } from "./theme-switch.js";
|
|
27
|
+
export { TypeRamp } from "./type-ramp.js";
|
|
28
|
+
export { Usage } from "./usage.js";
|
|
29
|
+
export { VariantMatrix } from "./variant-matrix.js";
|
|
30
|
+
export { VoiceTerms } from "./voice-terms.js";
|
|
31
|
+
export { Workbench } from "./workbench.js";
|
|
32
|
+
export { Live } from "./lib/live.js";
|
|
33
|
+
export { type Registry, RegistryProvider, useRegistry } from "./lib/registry.js";
|
|
34
|
+
export * from "./lib/manifest-types.js";
|
|
35
|
+
export type { AdherenceReport } from "./lib/adherence-types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @designtools/docs: every block, for a project composing its own pages. Most
|
|
3
|
+
* projects use `@designtools/docs/next` instead, which composes them.
|
|
4
|
+
*/
|
|
5
|
+
export { A11yPanel, AxeReport, useAxe } from "./a11y-panel.js";
|
|
6
|
+
export { AdherenceSummary } from "./adherence-summary.js";
|
|
7
|
+
export { AgentInstructions, AgentView } from "./agent-view.js";
|
|
8
|
+
export { Anatomy } from "./anatomy.js";
|
|
9
|
+
export { AskClaude } from "./ask-claude.js";
|
|
10
|
+
export { CodeView } from "./code-view.js";
|
|
11
|
+
export { ExampleFrame, Examples } from "./examples.js";
|
|
12
|
+
export { Glossary } from "./glossary.js";
|
|
13
|
+
export { Imagery } from "./imagery.js";
|
|
14
|
+
export { LogoUsage } from "./logo-usage.js";
|
|
15
|
+
export { PageActions } from "./page-actions.js";
|
|
16
|
+
export { Pattern } from "./pattern.js";
|
|
17
|
+
export { Playground } from "./playground.js";
|
|
18
|
+
export { PreviewComposition, PreviewExample, PreviewFrame, PreviewSurface } from "./preview-frame.js";
|
|
19
|
+
export { PropsTable } from "./props-table.js";
|
|
20
|
+
export { Rule, RuleIndex } from "./rule.js";
|
|
21
|
+
export { Scale } from "./scale.js";
|
|
22
|
+
export { DocsSearch } from "./search.js";
|
|
23
|
+
export { DocsFooter, DocsHeader, DocsSection, DocsShell } from "./shell.js";
|
|
24
|
+
export { Standards } from "./standards.js";
|
|
25
|
+
export { PageContrast, RampSwatches, SemanticSwatches } from "./swatches.js";
|
|
26
|
+
export { ThemeSwitch, themeScript, useThemeScript } from "./theme-switch.js";
|
|
27
|
+
export { TypeRamp } from "./type-ramp.js";
|
|
28
|
+
export { Usage } from "./usage.js";
|
|
29
|
+
export { VariantMatrix } from "./variant-matrix.js";
|
|
30
|
+
export { VoiceTerms } from "./voice-terms.js";
|
|
31
|
+
export { Workbench } from "./workbench.js";
|
|
32
|
+
export { Live } from "./lib/live.js";
|
|
33
|
+
export { RegistryProvider, useRegistry } from "./lib/registry.js";
|
|
34
|
+
export * from "./lib/manifest-types.js";
|