pattern-dump 0.1.0-alpha.0 → 0.1.0-alpha.2
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 +60 -0
- package/README.md +14 -1
- package/dist/chunks/chunk-3WZHFYHZ.js +160 -0
- package/dist/dev-ui/main.css +38 -7
- package/dist/dev-ui/main.js +339 -80
- package/dist/index.js +3 -4
- package/dist/pd.js +588 -381
- package/dist/types/config/index.d.ts +19 -12
- package/dist/types/config/validate.d.ts +10 -0
- package/dist/types/contracts/dev-protocol.d.ts +26 -13
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0-alpha.2
|
|
4
|
+
|
|
5
|
+
Fixes found while moving a PatternLab styleguide to Pattern Dump, and the changes they needed.
|
|
6
|
+
|
|
7
|
+
### Check before upgrading
|
|
8
|
+
|
|
9
|
+
These can change how an existing project loads or renders:
|
|
10
|
+
|
|
11
|
+
- **The config is checked when it loads.** A missing required option, an unknown option or a value
|
|
12
|
+
of the wrong type now stops `pd` with a list of every problem, with a suggestion for likely typos.
|
|
13
|
+
`styles.strategy: "co-located"` and `assets.strategy: "component-relative"` were accepted but never
|
|
14
|
+
implemented; they are now rejected as not supported yet.
|
|
15
|
+
- **Numbered folders lose their number in handles.** `00-atoms/badge` is included as
|
|
16
|
+
`{{> atoms-badge }}`, as in PatternLab. Its id and address keep the number (`/00-atoms/badge`).
|
|
17
|
+
Includes written with the number (`{{> 00-atoms-badge }}`) need updating.
|
|
18
|
+
- **`documentBase` paths are authoritative.** A file or folder listed there always goes into the base
|
|
19
|
+
layer, even one that belongs to a component; `"."` makes the whole styles tree global. Rules that no
|
|
20
|
+
component owns still join the base layer, as before.
|
|
21
|
+
- **Previews have no wrapper element.** The markup sits directly in `<body>`; the `<main>` with inline
|
|
22
|
+
styles around it is gone. CSS or tests that target `main.layout-centered`, `main.layout-full` or
|
|
23
|
+
`main[data-component-id]` inside a preview need updating; `data-component-id` is now on `<body>`.
|
|
24
|
+
- **`/api/component/<id>` returns 404** for an id that no component has.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `assets.css` accepts full URLs, such as a web-font stylesheet.
|
|
29
|
+
- References that start with an asset folder's name are rewritten to the served `/assets/…` path
|
|
30
|
+
when written root-absolute (`/images/logo.svg`), as PatternLab projects write them, and in `url()`
|
|
31
|
+
in compiled CSS.
|
|
32
|
+
- A `centered` preview frame is as wide as its content and centred in the Stage. If a width media or
|
|
33
|
+
container query that styles the component would change at that width, the frame keeps the full
|
|
34
|
+
width instead. Gallery tiles fit and centre the same way.
|
|
35
|
+
- PatternLab-style links (`/#/atoms/button`) open the matching view. An address that names nothing
|
|
36
|
+
says so in the Stage and links the closest matches; a view that fails to load says so too.
|
|
37
|
+
- `pd dev` warns at startup about a `documentBase` entry that matches no file, and summarises the
|
|
38
|
+
unowned rules that are global without being listed.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- A `centered` preview whose height comes from the viewport (`height: 200vh` in the base layer, a
|
|
43
|
+
percentage chain) no longer grows without bound. Content-fitting such a height is circular — the
|
|
44
|
+
frame's height feeds the content's — and the frame used to double every tick to the browser's
|
|
45
|
+
layout ceiling, showing a size like `785 × 33554428`. The run of growth is now detected, the frame
|
|
46
|
+
keeps its last steady height and the content scrolls inside it, and the Console says why.
|
|
47
|
+
- SCSS edits reach the preview live when `styles.entry` is set, and edits to base-layer styles
|
|
48
|
+
update live too.
|
|
49
|
+
- `@import`, `@charset`, `@layer a, b` and `@namespace` kept their `;`: the next rule was being
|
|
50
|
+
swallowed and both were dropped, in `pd dev` and in `pd build`.
|
|
51
|
+
- Components in numbered pattern folders own their CSS, whatever the styles folders are called.
|
|
52
|
+
- Missing files return 404 instead of 200 with the workbench page, so broken asset paths show up.
|
|
53
|
+
- Every `href` and `src` written into a preview is escaped.
|
|
54
|
+
- The flattening and conflicts reports print their full path, and a bare wrapper element around
|
|
55
|
+
different includes is no longer reported as a flattened copy.
|
|
56
|
+
- `styles.strategy` is optional.
|
|
57
|
+
|
|
58
|
+
## 0.1.0-alpha.0
|
|
59
|
+
|
|
60
|
+
First public alpha.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A workbench for HTML and CSS design systems, and a successor to PatternLab. Writ
|
|
|
4
4
|
Handlebars templates with SCSS, data and Markdown docs; Pattern Dump shows them live, checks them, maps
|
|
5
5
|
how they relate, and publishes the result as a static site.
|
|
6
6
|
|
|
7
|
-
> **Alpha (0.1.0-alpha.
|
|
7
|
+
> **Alpha (0.1.0-alpha.2).** Published under the `alpha` tag. Options and file conventions can still change
|
|
8
8
|
> between releases.
|
|
9
9
|
|
|
10
10
|
## Requirements
|
|
@@ -32,6 +32,18 @@ npx pd init
|
|
|
32
32
|
few starter components, and adds `dev`, `audit`, `typecheck` and `build:scripts` scripts. It never
|
|
33
33
|
overwrites an existing file.
|
|
34
34
|
|
|
35
|
+
### Installing `pd` globally
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install --global pattern-dump@alpha
|
|
39
|
+
pd init my-design-system
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
A global `pd` is handy for creating projects, but each project still needs its own local
|
|
43
|
+
`pattern-dump` (which `pd init` installs): the config file imports `defineConfig` from it. A global `pd`
|
|
44
|
+
runs its own version, not the project's, so inside a project prefer `npm run dev`, `npm run audit`
|
|
45
|
+
and `npx pd build`, which always use the version the project depends on.
|
|
46
|
+
|
|
35
47
|
## Commands
|
|
36
48
|
|
|
37
49
|
| Command | What it does |
|
|
@@ -80,6 +92,7 @@ export default defineConfig({
|
|
|
80
92
|
- [Pattern packages](https://github.com/n8design/pattern-dump/blob/main/docs/guide/pattern-packages.md)
|
|
81
93
|
- [Static build](https://github.com/n8design/pattern-dump/blob/main/docs/guide/static-build.md)
|
|
82
94
|
- [Command line](https://github.com/n8design/pattern-dump/blob/main/docs/guide/cli.md)
|
|
95
|
+
- [Changelog](https://github.com/n8design/pattern-dump/blob/main/CHANGELOG.md): what changed in each release
|
|
83
96
|
|
|
84
97
|
## Support
|
|
85
98
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// packages/config/src/validate.ts
|
|
2
|
+
var SHAPE = {
|
|
3
|
+
$schema: "string",
|
|
4
|
+
sourceDir: "string",
|
|
5
|
+
patternsDir: "string",
|
|
6
|
+
outDir: "string",
|
|
7
|
+
styles: {
|
|
8
|
+
keys: {
|
|
9
|
+
strategy: { values: ["parallel"], unsupported: ["co-located"] },
|
|
10
|
+
dir: "string",
|
|
11
|
+
entry: "string-or-strings"
|
|
12
|
+
},
|
|
13
|
+
required: ["dir"]
|
|
14
|
+
},
|
|
15
|
+
themes: {
|
|
16
|
+
keys: {
|
|
17
|
+
dir: "string",
|
|
18
|
+
default: "string",
|
|
19
|
+
switch: { values: ["attribute", "stylesheet"] },
|
|
20
|
+
swatch: { keys: { slots: "strings" }, required: ["slots"] }
|
|
21
|
+
},
|
|
22
|
+
required: ["dir", "default"]
|
|
23
|
+
},
|
|
24
|
+
assets: {
|
|
25
|
+
keys: {
|
|
26
|
+
strategy: { values: ["central"], unsupported: ["component-relative"] },
|
|
27
|
+
dir: "string-or-strings",
|
|
28
|
+
css: "strings"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
scriptsDir: "string",
|
|
32
|
+
globalScripts: "strings",
|
|
33
|
+
dataDir: "string",
|
|
34
|
+
helpers: "string",
|
|
35
|
+
documentBase: "strings",
|
|
36
|
+
overviews: "boolean",
|
|
37
|
+
shell: {
|
|
38
|
+
keys: { brand: { keys: { title: "string", logo: "logo", logoAlt: "string", href: "string" } } }
|
|
39
|
+
},
|
|
40
|
+
packages: "packages",
|
|
41
|
+
exclude: "strings",
|
|
42
|
+
build: { keys: { outDir: "string", basePath: "string", audit: "boolean" } }
|
|
43
|
+
};
|
|
44
|
+
var REQUIRED = ["sourceDir", "patternsDir", "outDir", "styles"];
|
|
45
|
+
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
46
|
+
var isStrings = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
|
|
47
|
+
function distance(a, b) {
|
|
48
|
+
const row = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
49
|
+
for (let i = 1; i <= a.length; i++) {
|
|
50
|
+
let prev = row[0];
|
|
51
|
+
row[0] = i;
|
|
52
|
+
for (let j = 1; j <= b.length; j++) {
|
|
53
|
+
const cur = row[j];
|
|
54
|
+
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, prev + (a[i - 1].toLowerCase() === b[j - 1].toLowerCase() ? 0 : 1));
|
|
55
|
+
prev = cur;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return row[b.length];
|
|
59
|
+
}
|
|
60
|
+
function suggest(key, known) {
|
|
61
|
+
let best;
|
|
62
|
+
let bestD = Infinity;
|
|
63
|
+
for (const k of known) {
|
|
64
|
+
const d = distance(key, k);
|
|
65
|
+
if (d < bestD) {
|
|
66
|
+
best = k;
|
|
67
|
+
bestD = d;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (best === void 0) return void 0;
|
|
71
|
+
const sameStart = key.slice(0, 3).toLowerCase() === best.slice(0, 3).toLowerCase();
|
|
72
|
+
return bestD <= 2 || bestD <= 3 && sameStart ? best : void 0;
|
|
73
|
+
}
|
|
74
|
+
function checkObject(value, shape, required, at, problems) {
|
|
75
|
+
const known = Object.keys(shape);
|
|
76
|
+
const unknown = Object.keys(value).filter((k) => !(k in shape));
|
|
77
|
+
for (const key of required) {
|
|
78
|
+
if (value[key] !== void 0) continue;
|
|
79
|
+
const near = unknown.find((u) => suggest(u, [key]) === key);
|
|
80
|
+
problems.push(near ? `missing required "${at}${key}" (found "${at}${near}" \u2014 did you mean "${at}${key}"?)` : `missing required "${at}${key}"`);
|
|
81
|
+
}
|
|
82
|
+
for (const key of unknown) {
|
|
83
|
+
const near = suggest(key, known);
|
|
84
|
+
if (near && required.includes(near) && value[near] === void 0) continue;
|
|
85
|
+
problems.push(`unknown key "${at}${key}"${near ? ` \u2014 did you mean "${at}${near}"?` : ""}`);
|
|
86
|
+
}
|
|
87
|
+
for (const key of known) {
|
|
88
|
+
if (value[key] !== void 0) checkValue(value[key], shape[key], `${at}${key}`, problems);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function checkValue(value, rule, at, problems) {
|
|
92
|
+
const fail = (expected) => problems.push(`"${at}" must be ${expected}`);
|
|
93
|
+
if (rule === "string") {
|
|
94
|
+
if (typeof value !== "string") fail("a string");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (rule === "boolean") {
|
|
98
|
+
if (typeof value !== "boolean") fail("true or false");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (rule === "strings") {
|
|
102
|
+
if (!isStrings(value)) fail("a list of strings");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (rule === "string-or-strings") {
|
|
106
|
+
if (typeof value !== "string" && !isStrings(value)) fail("a string or a list of strings");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (rule === "packages") {
|
|
110
|
+
const ok = Array.isArray(value) && value.every((p) => typeof p === "string" || isObject(p) && typeof p.name === "string" && (p.exclude === void 0 || isStrings(p.exclude)));
|
|
111
|
+
if (!ok) fail(`a list of package names or { name, exclude } objects`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (rule === "logo") {
|
|
115
|
+
const ok = typeof value === "string" || isObject(value) && typeof value.light === "string" && typeof value.dark === "string";
|
|
116
|
+
if (!ok) fail(`a path or { light, dark }`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if ("values" in rule) {
|
|
120
|
+
if (typeof value === "string" && rule.unsupported?.includes(value)) {
|
|
121
|
+
problems.push(`"${at}": "${value}" is not supported yet \u2014 use ${rule.values.map((v) => `"${v}"`).join(" or ")}, or leave it out`);
|
|
122
|
+
} else if (typeof value !== "string" || !rule.values.includes(value)) {
|
|
123
|
+
fail(rule.values.map((v) => `"${v}"`).join(" or "));
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!isObject(value)) {
|
|
128
|
+
fail("an object");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
checkObject(value, rule.keys, rule.required ?? [], `${at}.`, problems);
|
|
132
|
+
}
|
|
133
|
+
var ConfigError = class extends Error {
|
|
134
|
+
name = "ConfigError";
|
|
135
|
+
};
|
|
136
|
+
function configProblems(raw) {
|
|
137
|
+
if (!isObject(raw)) return ["the config must be an object (a .ts config must `export default defineConfig({ \u2026 })`)"];
|
|
138
|
+
const problems = [];
|
|
139
|
+
checkObject(raw, SHAPE, REQUIRED, "", problems);
|
|
140
|
+
return problems;
|
|
141
|
+
}
|
|
142
|
+
function validateConfig(raw, source) {
|
|
143
|
+
const problems = configProblems(raw);
|
|
144
|
+
if (problems.length > 0) {
|
|
145
|
+
throw new ConfigError(`${source}: invalid config
|
|
146
|
+
${problems.map((p) => ` - ${p}`).join("\n")}`);
|
|
147
|
+
}
|
|
148
|
+
return raw;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// packages/config/src/index.ts
|
|
152
|
+
function defineConfig(config) {
|
|
153
|
+
return config;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
ConfigError,
|
|
158
|
+
validateConfig,
|
|
159
|
+
defineConfig
|
|
160
|
+
};
|
package/dist/dev-ui/main.css
CHANGED
|
@@ -914,6 +914,9 @@ figure.preview {
|
|
|
914
914
|
margin-inline: auto;
|
|
915
915
|
transition: width 2s ease;
|
|
916
916
|
}
|
|
917
|
+
.single-preview iframe.vp-measuring {
|
|
918
|
+
transition: none;
|
|
919
|
+
}
|
|
917
920
|
|
|
918
921
|
#preview-frame {
|
|
919
922
|
background: Canvas;
|
|
@@ -986,7 +989,9 @@ figure.preview {
|
|
|
986
989
|
padding-top: 0.5rem;
|
|
987
990
|
}
|
|
988
991
|
.gallery-item iframe {
|
|
989
|
-
width: 100
|
|
992
|
+
width: var(--vp-w, 100%);
|
|
993
|
+
max-width: 100%;
|
|
994
|
+
margin-inline: auto;
|
|
990
995
|
height: var(--vp-h, auto); /* pd-height sets --vp-h; auto = UA 150px until first fire */
|
|
991
996
|
border: none;
|
|
992
997
|
display: block;
|
|
@@ -1773,16 +1778,42 @@ dialog.fullpage.fp-chrome-visible .fullpage-close {
|
|
|
1773
1778
|
cursor: pointer;
|
|
1774
1779
|
}
|
|
1775
1780
|
|
|
1776
|
-
.audit-scope-
|
|
1777
|
-
margin: 0.
|
|
1778
|
-
|
|
1779
|
-
font-
|
|
1780
|
-
|
|
1781
|
+
.audit-scope-label {
|
|
1782
|
+
margin: 0.5rem 0 0.25rem;
|
|
1783
|
+
font-size: 0.75rem;
|
|
1784
|
+
font-weight: 600;
|
|
1785
|
+
color: var(--pd-ink-muted);
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
.audit-scope-list {
|
|
1789
|
+
margin: 0;
|
|
1790
|
+
padding-inline-start: 1rem;
|
|
1791
|
+
font-size: 0.75rem;
|
|
1781
1792
|
line-height: 1.5;
|
|
1782
|
-
white-space: pre-wrap;
|
|
1783
1793
|
color: var(--pd-ink-muted);
|
|
1784
1794
|
}
|
|
1785
1795
|
|
|
1796
|
+
.audit-scope-item + .audit-scope-item {
|
|
1797
|
+
margin-top: 0.2rem;
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
.audit-scope-name {
|
|
1801
|
+
color: var(--pd-ink);
|
|
1802
|
+
font-weight: 600;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
.audit-scope-code {
|
|
1806
|
+
font-family: ui-monospace, Menlo, Consolas, monospace;
|
|
1807
|
+
font-size: 0.95em;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
.audit-scope-note {
|
|
1811
|
+
margin: 0.5rem 0 0;
|
|
1812
|
+
font-size: 0.75rem;
|
|
1813
|
+
font-weight: 600;
|
|
1814
|
+
color: var(--pd-ink);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1786
1817
|
[data-resize] {
|
|
1787
1818
|
position: absolute;
|
|
1788
1819
|
z-index: 5;
|