@designtools/docs 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +133 -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 +38 -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 +14 -0
- package/dist/imagery.d.ts +6 -0
- package/dist/imagery.js +17 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +33 -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/lookup.d.ts +35 -0
- package/dist/lib/lookup.js +41 -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 +7 -0
- package/dist/lib/status.js +17 -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 +85 -0
- package/dist/next/config.js +1 -0
- package/dist/next/index.d.ts +62 -0
- package/dist/next/index.js +63 -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 +122 -0
- package/dist/next/prose.d.ts +9 -0
- package/dist/next/prose.js +37 -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 +8 -0
- package/dist/pattern.js +19 -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 +12 -0
- package/dist/rule.js +32 -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 +89 -0
- package/dist/shell.js +199 -0
- package/dist/standards.d.ts +13 -0
- package/dist/standards.js +19 -0
- package/dist/styles.css +3519 -0
- package/dist/swatches.d.ts +28 -0
- package/dist/swatches.js +94 -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 +53 -0
- package/dist/voice-terms.d.ts +5 -0
- package/dist/voice-terms.js +13 -0
- package/dist/workbench.d.ts +33 -0
- package/dist/workbench.js +273 -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 +114 -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 +71 -0
- package/src/imagery.tsx +64 -0
- package/src/index.ts +34 -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/lookup.tsx +49 -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/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 +80 -0
- package/src/next/index.tsx +100 -0
- package/src/next/markdown.ts +119 -0
- package/src/next/pages.tsx +370 -0
- package/src/next/prose.tsx +87 -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 +67 -0
- package/src/playground.tsx +352 -0
- package/src/preview-frame.tsx +131 -0
- package/src/props-table.tsx +154 -0
- package/src/rule.tsx +116 -0
- package/src/scale.tsx +175 -0
- package/src/search.tsx +155 -0
- package/src/shell.tsx +555 -0
- package/src/standards.tsx +58 -0
- package/src/styles.css +155 -0
- package/src/swatches.tsx +287 -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 +195 -0
- package/src/voice-terms.tsx +46 -0
- package/src/workbench.tsx +584 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adherence report: what `designtools-adherence` writes with `--json`, and
|
|
3
|
+
* what the "Adherence summary" docs block renders.
|
|
4
|
+
*
|
|
5
|
+
* This file has no imports on purpose, so @designtools/docs can carry a copy
|
|
6
|
+
* and read the report through the same types the tool wrote it with.
|
|
7
|
+
*
|
|
8
|
+
* Every path is relative to the project root, with forward slashes. Lines and
|
|
9
|
+
* columns start at 1. Every array is sorted (files and routes by path, findings
|
|
10
|
+
* by line then column, components and elements by name), and there are no
|
|
11
|
+
* timestamps, so the same source gives the same bytes.
|
|
12
|
+
*/
|
|
13
|
+
export declare const ADHERENCE_SCHEMA = "designtools.adherence/1";
|
|
14
|
+
export interface AdherenceReport {
|
|
15
|
+
/** `@designtools/adherence@<version>`. */
|
|
16
|
+
generator: string;
|
|
17
|
+
schema: string;
|
|
18
|
+
/** The components.json the system was read from. */
|
|
19
|
+
manifest: string;
|
|
20
|
+
/** The system folder, which is never scanned as product. */
|
|
21
|
+
system: string;
|
|
22
|
+
/** The globs that chose the product files, as given or defaulted. */
|
|
23
|
+
include: string[];
|
|
24
|
+
exclude: string[];
|
|
25
|
+
summary: Summary;
|
|
26
|
+
/** One per Next app router page (`app/**\/page.tsx`), sorted by route. */
|
|
27
|
+
routes: RouteEntry[];
|
|
28
|
+
/** Every scanned file with at least one use, raw element or finding, sorted by path. */
|
|
29
|
+
files: FileEntry[];
|
|
30
|
+
/** Every system component, used or not, sorted by name. */
|
|
31
|
+
components: ComponentUsage[];
|
|
32
|
+
/** Every raw element some component `replaces`, sorted by selector. */
|
|
33
|
+
elements: ElementUsage[];
|
|
34
|
+
/** Files a scanner could not parse, sorted by path. Their numbers are missing from the report. */
|
|
35
|
+
skipped: SkippedFile[];
|
|
36
|
+
}
|
|
37
|
+
/** The numbers every level of the report shares: the whole product, a route, a file. */
|
|
38
|
+
export interface Counts {
|
|
39
|
+
/** JSX uses of system components, sub-components included. */
|
|
40
|
+
systemUses: number;
|
|
41
|
+
/** Raw elements that some system component `replaces`, such as `<button>` when Button replaces it. */
|
|
42
|
+
rawElements: number;
|
|
43
|
+
/**
|
|
44
|
+
* systemUses ÷ (systemUses + rawElements), from 0 to 1, to four decimal places.
|
|
45
|
+
* Null when both are 0: there was nothing to measure.
|
|
46
|
+
*/
|
|
47
|
+
share: number | null;
|
|
48
|
+
/** Classes that bypass the tokens: palette steps and arbitrary values. */
|
|
49
|
+
offSystemValues: number;
|
|
50
|
+
/** System components given a className that changes colour, spacing or radius. */
|
|
51
|
+
overrides: number;
|
|
52
|
+
}
|
|
53
|
+
export interface Summary extends Counts {
|
|
54
|
+
/** Product files scanned. */
|
|
55
|
+
files: number;
|
|
56
|
+
/** Files with at least one raw element, off-system value or override. */
|
|
57
|
+
filesWithFindings: number;
|
|
58
|
+
offSystem: Record<OffSystemKind, number>;
|
|
59
|
+
overrideKinds: Record<OverrideKind, number>;
|
|
60
|
+
/** System components used at least once. */
|
|
61
|
+
componentsUsed: number;
|
|
62
|
+
/** System components never used in the product, by name. */
|
|
63
|
+
componentsUnused: string[];
|
|
64
|
+
/**
|
|
65
|
+
* The raw elements counted, from every component's `replaces`. Empty means no
|
|
66
|
+
* component declares any, so `share` measures nothing yet.
|
|
67
|
+
*/
|
|
68
|
+
replaceable: string[];
|
|
69
|
+
}
|
|
70
|
+
export interface RouteEntry {
|
|
71
|
+
/** The URL path: route groups and parallel-route slots removed, dynamic segments kept. `/companies/[key]`. */
|
|
72
|
+
route: string;
|
|
73
|
+
/** The page file. */
|
|
74
|
+
page: string;
|
|
75
|
+
/**
|
|
76
|
+
* The files counted for the route: the page, files beside it, and files in
|
|
77
|
+
* folders under it that lead to no other page. Layouts shared by several
|
|
78
|
+
* routes are counted per file only.
|
|
79
|
+
*/
|
|
80
|
+
files: string[];
|
|
81
|
+
counts: Counts;
|
|
82
|
+
}
|
|
83
|
+
export interface FileEntry {
|
|
84
|
+
file: string;
|
|
85
|
+
/** The route the file is counted under, when it has one. */
|
|
86
|
+
route?: string;
|
|
87
|
+
counts: Counts;
|
|
88
|
+
uses: ComponentUse[];
|
|
89
|
+
raw: RawElement[];
|
|
90
|
+
offSystem: OffSystemValue[];
|
|
91
|
+
overrides: Override[];
|
|
92
|
+
}
|
|
93
|
+
/** A literal prop value, or the kind of expression it was, e.g. `(Identifier)`. */
|
|
94
|
+
export type PropValue = string | number | boolean | null;
|
|
95
|
+
export interface ComponentUse {
|
|
96
|
+
/** The component's name in the manifest. */
|
|
97
|
+
component: string;
|
|
98
|
+
/** The element as written, when it differs: `Select.Trigger`, `DS.Button`. */
|
|
99
|
+
as?: string;
|
|
100
|
+
line: number;
|
|
101
|
+
column: number;
|
|
102
|
+
/** Props as written, sorted. A className built from expressions keeps its literal classes only. */
|
|
103
|
+
props: Record<string, PropValue>;
|
|
104
|
+
/** True when it also takes `{...spread}` props, whose names are unknown. */
|
|
105
|
+
spread: boolean;
|
|
106
|
+
}
|
|
107
|
+
export interface RawElement {
|
|
108
|
+
/** The tag as written: `button`. */
|
|
109
|
+
element: string;
|
|
110
|
+
/** The `replaces` selector it matched: `button`, `input[type=checkbox]`. */
|
|
111
|
+
selector: string;
|
|
112
|
+
/** The components that replace it, most specific first. */
|
|
113
|
+
replacedBy: string[];
|
|
114
|
+
line: number;
|
|
115
|
+
column: number;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* `palette`: a primitive ramp step used directly, `bg-blue-500` or `text-primary-500`.
|
|
119
|
+
* `arbitrary`: a value in brackets, `p-[13px]` or `bg-[#fff]`.
|
|
120
|
+
* `status-text`: a status fill used as text, `text-destructive`: use `text-destructive-subdued-foreground`,
|
|
121
|
+
* which reads on every background, or neutral text with an icon for a warning.
|
|
122
|
+
*/
|
|
123
|
+
export type OffSystemKind = "palette" | "arbitrary" | "status-text";
|
|
124
|
+
export interface OffSystemValue {
|
|
125
|
+
/** The class as written, variants included: `hover:bg-blue-500`. */
|
|
126
|
+
class: string;
|
|
127
|
+
kind: OffSystemKind;
|
|
128
|
+
line: number;
|
|
129
|
+
column: number;
|
|
130
|
+
}
|
|
131
|
+
export type OverrideKind = "colour" | "spacing" | "radius";
|
|
132
|
+
export interface Override {
|
|
133
|
+
component: string;
|
|
134
|
+
/** Each class in the className that overrides the component, with what it changes. */
|
|
135
|
+
classes: {
|
|
136
|
+
class: string;
|
|
137
|
+
kind: OverrideKind;
|
|
138
|
+
}[];
|
|
139
|
+
line: number;
|
|
140
|
+
column: number;
|
|
141
|
+
}
|
|
142
|
+
export interface ComponentUsage {
|
|
143
|
+
name: string;
|
|
144
|
+
source: string;
|
|
145
|
+
uses: number;
|
|
146
|
+
/** Files it is used in. */
|
|
147
|
+
files: number;
|
|
148
|
+
/** How many uses pass each prop, by prop name. */
|
|
149
|
+
props: Record<string, number>;
|
|
150
|
+
/**
|
|
151
|
+
* Per variant axis, how many uses pick each option. A use that leaves the prop
|
|
152
|
+
* out counts under the axis's default, or `(unset)`; one that computes it
|
|
153
|
+
* counts under `(dynamic)`.
|
|
154
|
+
*/
|
|
155
|
+
variants?: Record<string, Record<string, number>>;
|
|
156
|
+
}
|
|
157
|
+
export interface ElementUsage {
|
|
158
|
+
/** The `replaces` selector. */
|
|
159
|
+
selector: string;
|
|
160
|
+
/** Raw uses in the product. */
|
|
161
|
+
uses: number;
|
|
162
|
+
files: number;
|
|
163
|
+
replacedBy: string[];
|
|
164
|
+
}
|
|
165
|
+
export interface SkippedFile {
|
|
166
|
+
file: string;
|
|
167
|
+
reason: string;
|
|
168
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adherence report: what `designtools-adherence` writes with `--json`, and
|
|
3
|
+
* what the "Adherence summary" docs block renders.
|
|
4
|
+
*
|
|
5
|
+
* This file has no imports on purpose, so @designtools/docs can carry a copy
|
|
6
|
+
* and read the report through the same types the tool wrote it with.
|
|
7
|
+
*
|
|
8
|
+
* Every path is relative to the project root, with forward slashes. Lines and
|
|
9
|
+
* columns start at 1. Every array is sorted (files and routes by path, findings
|
|
10
|
+
* by line then column, components and elements by name), and there are no
|
|
11
|
+
* timestamps, so the same source gives the same bytes.
|
|
12
|
+
*/
|
|
13
|
+
export const ADHERENCE_SCHEMA = "designtools.adherence/1";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component, type ReactNode } from "react";
|
|
2
|
+
/** Keeps one broken example from blanking the whole page: the error shows where the example would. */
|
|
3
|
+
export declare class Boundary extends Component<{
|
|
4
|
+
label: string;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}, {
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}> {
|
|
9
|
+
state: {
|
|
10
|
+
error: Error | null;
|
|
11
|
+
};
|
|
12
|
+
static getDerivedStateFromError(error: Error): {
|
|
13
|
+
error: Error;
|
|
14
|
+
};
|
|
15
|
+
render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Component } from "react";
|
|
4
|
+
/** Keeps one broken example from blanking the whole page: the error shows where the example would. */
|
|
5
|
+
export class Boundary extends Component {
|
|
6
|
+
state = { error: null };
|
|
7
|
+
static getDerivedStateFromError(error) {
|
|
8
|
+
return { error };
|
|
9
|
+
}
|
|
10
|
+
render() {
|
|
11
|
+
if (!this.state.error)
|
|
12
|
+
return this.props.children;
|
|
13
|
+
return (_jsxs("p", { "data-slot": "block-error", role: "alert", className: "rounded-md border border-dashed border-destructive p-3 text-xs", children: [_jsxs("span", { className: "font-medium", children: [this.props.label, " did not render:"] }), " ", this.state.error.message] }));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrast measured on what the browser paints, not on the values written in
|
|
3
|
+
* the stylesheet: a 1px canvas turns any computed CSS colour (oklch, color-mix,
|
|
4
|
+
* a var chain) into sRGB bytes. Browser only.
|
|
5
|
+
*/
|
|
6
|
+
/** WCAG 2 contrast ratio between two CSS colours, or null where it cannot be measured. */
|
|
7
|
+
export declare function contrastRatio(foreground: string, background: string): number | null;
|
|
8
|
+
export declare function wcagGrade(ratio: number): "AAA" | "AA" | "AA large" | "Fail";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrast measured on what the browser paints, not on the values written in
|
|
3
|
+
* the stylesheet: a 1px canvas turns any computed CSS colour (oklch, color-mix,
|
|
4
|
+
* a var chain) into sRGB bytes. Browser only.
|
|
5
|
+
*/
|
|
6
|
+
let context = null;
|
|
7
|
+
function rgb(css) {
|
|
8
|
+
if (typeof document === "undefined")
|
|
9
|
+
return null;
|
|
10
|
+
if (!context) {
|
|
11
|
+
const canvas = document.createElement("canvas");
|
|
12
|
+
canvas.width = canvas.height = 1;
|
|
13
|
+
context = canvas.getContext("2d", { willReadFrequently: true });
|
|
14
|
+
}
|
|
15
|
+
if (!context)
|
|
16
|
+
return null;
|
|
17
|
+
context.clearRect(0, 0, 1, 1);
|
|
18
|
+
context.fillStyle = "#000";
|
|
19
|
+
context.fillStyle = css;
|
|
20
|
+
context.fillRect(0, 0, 1, 1);
|
|
21
|
+
const [r, g, b] = context.getImageData(0, 0, 1, 1).data;
|
|
22
|
+
return [r, g, b];
|
|
23
|
+
}
|
|
24
|
+
function luminance([r, g, b]) {
|
|
25
|
+
const channel = (v) => {
|
|
26
|
+
const s = v / 255;
|
|
27
|
+
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
28
|
+
};
|
|
29
|
+
return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
|
|
30
|
+
}
|
|
31
|
+
/** WCAG 2 contrast ratio between two CSS colours, or null where it cannot be measured. */
|
|
32
|
+
export function contrastRatio(foreground, background) {
|
|
33
|
+
const a = rgb(foreground);
|
|
34
|
+
const b = rgb(background);
|
|
35
|
+
if (!a || !b)
|
|
36
|
+
return null;
|
|
37
|
+
const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
|
|
38
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
39
|
+
}
|
|
40
|
+
export function wcagGrade(ratio) {
|
|
41
|
+
return ratio >= 7 ? "AAA" : ratio >= 4.5 ? "AA" : ratio >= 3 ? "AA large" : "Fail";
|
|
42
|
+
}
|
package/dist/lib/cx.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anything pressable in the docs: at least 44px by default (WCAG 2.5.5), with a
|
|
3
|
+
* pointer. A client with its own rule sets `--docs-target` on the docs layout
|
|
4
|
+
* (`3rem` for 48px), so the site that states the rule also meets it. Links inside
|
|
5
|
+
* a sentence are exempt, as WCAG exempts them. The pointer is here, not left to the
|
|
6
|
+
* project's base CSS: Tailwind v4 puts buttons back to the arrow, and a project
|
|
7
|
+
* without the rule would show every block's button and tab as inert.
|
|
8
|
+
*/
|
|
9
|
+
export declare const target = "min-h-[var(--docs-target,2.75rem)] min-w-[var(--docs-target,2.75rem)] cursor-pointer disabled:cursor-not-allowed data-disabled:cursor-not-allowed";
|
|
10
|
+
/** Join class names, skipping the falsy ones. */
|
|
11
|
+
export declare function cx(...classes: (string | false | null | undefined)[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* Headings in the docs: regular weight, large, so size makes the hierarchy rather
|
|
14
|
+
* than boldness; the brand's display face when the project names one
|
|
15
|
+
* (`--font-display`), else its body face. Set `--docs-display` on the docs layout
|
|
16
|
+
* to give the docs a face of their own.
|
|
17
|
+
*/
|
|
18
|
+
export declare const display = "font-normal [font-family:var(--docs-display,var(--font-display,var(--font-sans)))]";
|
|
19
|
+
/**
|
|
20
|
+
* The docs' accent: the current page's marker in the navigation, the active tab. A
|
|
21
|
+
* fill or a bar, never text, so a pale brand colour (a yellow primary) cannot fail as
|
|
22
|
+
* text on the page. Defaults to the primary; set `--docs-accent` to change it.
|
|
23
|
+
*/
|
|
24
|
+
export declare const accent = "bg-[var(--docs-accent,var(--primary))]";
|
package/dist/lib/cx.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anything pressable in the docs: at least 44px by default (WCAG 2.5.5), with a
|
|
3
|
+
* pointer. A client with its own rule sets `--docs-target` on the docs layout
|
|
4
|
+
* (`3rem` for 48px), so the site that states the rule also meets it. Links inside
|
|
5
|
+
* a sentence are exempt, as WCAG exempts them. The pointer is here, not left to the
|
|
6
|
+
* project's base CSS: Tailwind v4 puts buttons back to the arrow, and a project
|
|
7
|
+
* without the rule would show every block's button and tab as inert.
|
|
8
|
+
*/
|
|
9
|
+
export const target = "min-h-[var(--docs-target,2.75rem)] min-w-[var(--docs-target,2.75rem)] cursor-pointer disabled:cursor-not-allowed data-disabled:cursor-not-allowed";
|
|
10
|
+
/** Join class names, skipping the falsy ones. */
|
|
11
|
+
export function cx(...classes) {
|
|
12
|
+
return classes.filter(Boolean).join(" ");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Headings in the docs: regular weight, large, so size makes the hierarchy rather
|
|
16
|
+
* than boldness; the brand's display face when the project names one
|
|
17
|
+
* (`--font-display`), else its body face. Set `--docs-display` on the docs layout
|
|
18
|
+
* to give the docs a face of their own.
|
|
19
|
+
*/
|
|
20
|
+
export const display = "font-normal [font-family:var(--docs-display,var(--font-display,var(--font-sans)))]";
|
|
21
|
+
/**
|
|
22
|
+
* The docs' accent: the current page's marker in the navigation, the active tab. A
|
|
23
|
+
* fill or a bar, never text, so a pale brand colour (a yellow primary) cannot fail as
|
|
24
|
+
* text on the page. Defaults to the primary; set `--docs-accent` to change it.
|
|
25
|
+
*/
|
|
26
|
+
export const accent = "bg-[var(--docs-accent,var(--primary))]";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props back to JSX, so the code shown beside a preview is the code that drew it.
|
|
3
|
+
* Defaults and undefined values are left out: the snippet is what a person would write.
|
|
4
|
+
*/
|
|
5
|
+
export type JsxProps = Record<string, unknown>;
|
|
6
|
+
export declare function toJSX(name: string, props: JsxProps, children?: string): string;
|
package/dist/lib/jsx.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props back to JSX, so the code shown beside a preview is the code that drew it.
|
|
3
|
+
* Defaults and undefined values are left out: the snippet is what a person would write.
|
|
4
|
+
*/
|
|
5
|
+
export function toJSX(name, props, children) {
|
|
6
|
+
const attrs = Object.entries(props)
|
|
7
|
+
.filter(([key, value]) => value !== undefined && key !== "children")
|
|
8
|
+
.map(([key, value]) => attribute(key, value));
|
|
9
|
+
// text with braces or angle brackets is not valid JSX as written; quote it as an expression
|
|
10
|
+
if (children && /[{}<>]/.test(children))
|
|
11
|
+
children = `{${JSON.stringify(children)}}`;
|
|
12
|
+
const open = attrs.length ? `<${name} ${attrs.join(" ")}` : `<${name}`;
|
|
13
|
+
const oneLine = children ? `${open}>${children}</${name}>` : `${open} />`;
|
|
14
|
+
if (oneLine.length <= 80)
|
|
15
|
+
return oneLine;
|
|
16
|
+
const lines = [`<${name}`, ...attrs.map((a) => ` ${a}`)];
|
|
17
|
+
return children ? `${lines.join("\n")}\n>\n ${children}\n</${name}>` : `${lines.join("\n")}\n/>`;
|
|
18
|
+
}
|
|
19
|
+
function attribute(key, value) {
|
|
20
|
+
if (value === true)
|
|
21
|
+
return key;
|
|
22
|
+
if (typeof value === "string")
|
|
23
|
+
return /["\n{}]/.test(value) ? `${key}={${JSON.stringify(value)}}` : `${key}="${value}"`;
|
|
24
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
25
|
+
return `${key}={${String(value)}}`;
|
|
26
|
+
if (typeof value === "function")
|
|
27
|
+
return `${key}={() => {}}`;
|
|
28
|
+
return `${key}={${JSON.stringify(value)}}`;
|
|
29
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
+
import type { AssetEntry, ComponentEntry, PatternEntry } from "./manifest-types.js";
|
|
3
|
+
import { type Registry } from "./registry.js";
|
|
4
|
+
/**
|
|
5
|
+
* The project's components, examples, patterns and assets, from the registry
|
|
6
|
+
* around the docs. Call it once at the top of a block, then look things up.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useLookup(): {
|
|
9
|
+
/** The real component a manifest entry describes. */
|
|
10
|
+
componentFor: (entry: ComponentEntry) => ComponentType<any> | undefined;
|
|
11
|
+
/** The examples module for a component: each named export is an example. */
|
|
12
|
+
examplesFor: (entry: ComponentEntry) => Record<string, unknown> | undefined;
|
|
13
|
+
/** The pattern module: each named export is a composition. */
|
|
14
|
+
compositionsFor: (pattern: PatternEntry) => Record<string, unknown> | undefined;
|
|
15
|
+
/** A brand asset's URL, from its static import in the registry. */
|
|
16
|
+
assetUrl: (asset: AssetEntry) => string | undefined;
|
|
17
|
+
};
|
|
18
|
+
export declare function lookupIn(registry: Registry): {
|
|
19
|
+
/** The real component a manifest entry describes. */
|
|
20
|
+
componentFor: (entry: ComponentEntry) => ComponentType<any> | undefined;
|
|
21
|
+
/** The examples module for a component: each named export is an example. */
|
|
22
|
+
examplesFor: (entry: ComponentEntry) => Record<string, unknown> | undefined;
|
|
23
|
+
/** The pattern module: each named export is a composition. */
|
|
24
|
+
compositionsFor: (pattern: PatternEntry) => Record<string, unknown> | undefined;
|
|
25
|
+
/** A brand asset's URL, from its static import in the registry. */
|
|
26
|
+
assetUrl: (asset: AssetEntry) => string | undefined;
|
|
27
|
+
};
|
|
28
|
+
/** Variant values are text in the manifest; boolean variants want booleans. */
|
|
29
|
+
export declare function coerce(values: Record<string, string>): Record<string, unknown>;
|
|
30
|
+
export declare function Missing({ name, what }: {
|
|
31
|
+
name: string;
|
|
32
|
+
what?: string;
|
|
33
|
+
}): import("react").JSX.Element;
|
|
34
|
+
/** An example export is a component that takes no props, or an element. */
|
|
35
|
+
export declare function renderExample(value: unknown, name: string): ReactNode;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createElement, isValidElement } from "react";
|
|
3
|
+
import { componentKey } from "./manifest.js";
|
|
4
|
+
import { useRegistry } from "./registry.js";
|
|
5
|
+
/**
|
|
6
|
+
* The project's components, examples, patterns and assets, from the registry
|
|
7
|
+
* around the docs. Call it once at the top of a block, then look things up.
|
|
8
|
+
*/
|
|
9
|
+
export function useLookup() {
|
|
10
|
+
return lookupIn(useRegistry());
|
|
11
|
+
}
|
|
12
|
+
export function lookupIn(registry) {
|
|
13
|
+
return {
|
|
14
|
+
/** The real component a manifest entry describes. */
|
|
15
|
+
componentFor: (entry) => registry.components[componentKey(entry)],
|
|
16
|
+
/** The examples module for a component: each named export is an example. */
|
|
17
|
+
examplesFor: (entry) => (entry.examples ? registry.examples[entry.examples.source] : undefined),
|
|
18
|
+
/** The pattern module: each named export is a composition. */
|
|
19
|
+
compositionsFor: (pattern) => registry.patterns[pattern.source],
|
|
20
|
+
/** A brand asset's URL, from its static import in the registry. */
|
|
21
|
+
assetUrl: (asset) => {
|
|
22
|
+
const imported = registry.assets[asset.file];
|
|
23
|
+
return typeof imported === "string" ? imported : imported?.src;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Variant values are text in the manifest; boolean variants want booleans. */
|
|
28
|
+
export function coerce(values) {
|
|
29
|
+
return Object.fromEntries(Object.entries(values).map(([k, v]) => [k, v === "true" ? true : v === "false" ? false : v]));
|
|
30
|
+
}
|
|
31
|
+
export function Missing({ name, what = "component" }) {
|
|
32
|
+
return (_jsxs("p", { "data-slot": "block-missing", className: "rounded-md border border-dashed border-border p-4 text-sm text-muted-foreground", children: [name, "'s ", what, " is not in the generated registry. Run ", _jsx("code", { className: "font-mono", children: "designtools-docs map" }), " ", "after rebuilding the manifest."] }));
|
|
33
|
+
}
|
|
34
|
+
/** An example export is a component that takes no props, or an element. */
|
|
35
|
+
export function renderExample(value, name) {
|
|
36
|
+
if (isValidElement(value))
|
|
37
|
+
return value;
|
|
38
|
+
if (typeof value === "function")
|
|
39
|
+
return createElement(value);
|
|
40
|
+
return _jsxs("span", { className: "text-xs text-muted-foreground", children: [name, " is not a component or an element."] });
|
|
41
|
+
}
|