@pure-ds/core 0.5.24 → 0.5.26

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.
@@ -1 +1 @@
1
- {"version":3,"file":"pds-registry.d.ts","sourceRoot":"","sources":["../../../../../src/js/pds-core/pds-registry.js"],"names":[],"mappings":"AA8EA,mCAA0C;AAzE1C;IAEI,cAAqB;IACrB;;;;;;MAMC;IAGH;;OAEG;IACH,oBAEC;IAED;;;OAGG;IACH,gCAKC;IAED;;;OAGG;IACH,wCAqBC;IAED;;OAEG;IACH,mBAEC;IAED;;OAEG;IACH,sBAEC;CACF"}
1
+ {"version":3,"file":"pds-registry.d.ts","sourceRoot":"","sources":["../../../../../src/js/pds-core/pds-registry.js"],"names":[],"mappings":"AA4EA,mCAA0C;AAvE1C;IAEI,cAAqB;IACrB;;;;;;MAMC;IAGH;;OAEG;IACH,oBAEC;IAED;;;OAGG;IACH,gCAGC;IAED;;;OAGG;IACH,wCAqBC;IAED;;OAEG;IACH,mBAEC;IAED;;OAEG;IACH,sBAEC;CACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pure-ds/core",
3
3
  "shortname": "pds",
4
- "version": "0.5.24",
4
+ "version": "0.5.26",
5
5
  "description": "Pure Design System - Why develop a Design System when you can generate one?",
6
6
  "repository": {
7
7
  "type": "git",
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readFile, writeFile, mkdir, access, rename, rm } from 'fs/promises';
3
+ import { readFile, writeFile, mkdir, access, rename, rm, copyFile, readdir } from 'fs/promises';
4
4
  import { existsSync } from 'fs';
5
5
  import path from 'path';
6
6
  import { spawn } from 'child_process';
7
- import { buildStarterPdsConfig } from './templates/starter-templates.js';
7
+ import { fileURLToPath } from 'url';
8
8
 
9
9
  const projectRoot = process.cwd();
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ const templateRoot = path.join(__dirname, 'templates', 'bootstrap');
10
12
 
11
13
  function log(message) {
12
14
  console.log(message);
@@ -29,6 +31,19 @@ async function writeFileIfMissing(filePath, content) {
29
31
  }
30
32
  }
31
33
 
34
+ async function copyFileIfMissing(sourcePath, targetPath) {
35
+ try {
36
+ await access(targetPath);
37
+ log(`↪️ Skipping existing ${path.relative(projectRoot, targetPath)}`);
38
+ return false;
39
+ } catch {
40
+ await ensureDir(path.dirname(targetPath));
41
+ await copyFile(sourcePath, targetPath);
42
+ log(`✅ Created ${path.relative(projectRoot, targetPath)}`);
43
+ return true;
44
+ }
45
+ }
46
+
32
47
  function getNpmCommand() {
33
48
  return process.platform === 'win32' ? 'npm.cmd' : 'npm';
34
49
  }
@@ -54,423 +69,48 @@ async function writePackageJson(pkgPath, pkg) {
54
69
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
55
70
  }
56
71
 
57
- function buildIndexHtml({ version, generatedAt }) {
58
- return `<!doctype html>
59
- <html lang="en">
60
- <head>
61
- <meta charset="UTF-8" />
62
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
63
- <title>Pure Design System</title>
64
-
65
- <!-- PDS Styles -->
66
- <link rel="stylesheet" href="/assets/css/app.css" />
67
-
68
- <!-- Import Map for Lit components -->
69
- <script type="importmap">
70
- {
71
- "imports": {
72
- "#pds/lit": "/assets/js/lit.js"
73
- }
74
- }
75
- </script>
76
-
77
- <!-- Dev live-reload (safe in production, no-op without server) -->
78
- <script type="module" src="/assets/js/dev-reload.js" defer></script>
79
-
80
- <!-- App Script -->
81
- <script type="module" src="/assets/js/app.js" defer></script>
82
- </head>
83
-
84
- <body class="container">
85
- <header class="stack-sm">
86
- <p class="auto-gen">Auto-generated by PDS ${version} at ${generatedAt}</p>
87
- </header>
88
-
89
- <main></main>
90
-
91
- <footer class="text-sm text-muted">
92
- <small>&copy; 2026 Pure Design System</small>
93
- </footer>
94
- </body>
95
- </html>
96
- `;
97
- }
98
-
99
- function buildDevReloadJs() {
100
- return `const shouldConnect =
101
- location.hostname === 'localhost' || location.hostname === '127.0.0.1';
102
-
103
- if (shouldConnect) {
104
- const reloadPort = 4174;
105
- const endpoint = 'http://localhost:' + reloadPort + '/events';
106
- const source = new EventSource(endpoint);
107
-
108
- source.onmessage = (event) => {
109
- if (event.data === 'reload') {
110
- location.reload();
111
- }
112
- };
113
-
114
- source.onerror = () => {
115
- source.close();
116
- };
117
- }
118
- `;
119
- }
120
-
121
- function buildAppCss() {
122
- return `html:not(.pds-ready) {
123
- opacity: 0;
124
- }
125
-
126
- main {
127
- margin: auto;
128
- }
129
-
130
- h1 {
131
- background: linear-gradient(var(--gradient-angle, 135deg),
132
- var(--color-primary-400),
133
- var(--color-accent-400)
134
- );
135
- background-clip: text;
136
- -webkit-background-clip: text;
137
- color: transparent;
138
- }
139
-
140
- .container {
141
- display: grid;
142
- grid-template-rows: auto 1fr auto;
143
- height: 100dvh;
144
- padding: 0;
145
- }
146
-
147
- header, footer {
148
- padding: var(--spacing-4);
149
- }
150
-
151
- footer {
152
- text-align: center;
72
+ async function writeIndexFromTemplate(sourcePath, targetPath, { version, generatedAt }) {
73
+ const raw = await readFile(sourcePath, 'utf8');
74
+ const content = raw
75
+ .replaceAll('{{PDS_VERSION}}', version)
76
+ .replaceAll('{{PDS_GENERATED_AT}}', generatedAt);
77
+ await writeFileIfMissing(targetPath, content);
153
78
  }
154
79
 
155
- .auto-gen {
156
- color: var(--color-text-muted);
157
- font-size: var(--font-size-xs);
158
- }
80
+ async function copyTemplateDirectory(sourceDir, targetDir, options) {
81
+ const entries = await readdir(sourceDir, { withFileTypes: true });
159
82
 
160
- #settings-btn {
161
- position: fixed;
162
- top: var(--spacing-4);
163
- right: var(--spacing-4);
164
- }
165
-
166
- .hero {
167
- padding: var(--spacing-8);
168
- zoom: 1.15;
169
- text-align: center;
170
- border: var(--border-width-medium) solid transparent;
171
- background: linear-gradient(var(--color-surface-base), var(--color-surface-base)) padding-box,
172
- linear-gradient(var(--gradient-angle, 135deg), var(--color-primary-400), var(--color-accent-400)) border-box;
173
- max-width: var(--max-w-lg);
174
- border-radius: var(--radius-lg);
175
- border-width: 3px;
176
- }
83
+ for (const entry of entries) {
84
+ const sourcePath = path.join(sourceDir, entry.name);
85
+ const targetPath = path.join(targetDir, entry.name);
86
+ const relativePath = path.relative(templateRoot, sourcePath);
177
87
 
178
- .hero > div {
179
- margin: var(--spacing-10) 0;
180
- }
181
- `;
182
- }
183
-
184
- function buildMyHome() {
185
- return `/**
186
- * @file my-home.js
187
- * @description A simple home component for the app.
188
- */
189
- customElements.define(
190
- "my-home",
191
- class extends HTMLElement {
192
- connectedCallback() {
193
- this.innerHTML = /*html*/ \`
194
- <article class="hero">
195
- <h1>Welcome to your new App</h1>
196
- <div>
197
- <p>
198
- This <code>&lt;my-home&gt;</code> Web Component is lazy-loaded and styled with Pure Design System.
199
- </p>
200
- <p>
201
- You can start building your app by editing the files in <code>public/assets/my/</code> and <code>src/js/</code>.
202
- </p>
203
- </div>
204
- <nav>
205
- <a target="_blank" href="https://github.com/Pure-Web-Foundation/pure-ds/blob/main/getting-started.md" class="btn btn-primary btn-lg">
206
- <pds-icon icon="rocket"></pds-icon> Get Started
207
- </a>
208
- <a target="_blank" href="https://puredesignsystem.z6.web.core.windows.net/storybook/" class="btn btn-secondary btn-lg">
209
- <pds-icon icon="book-open"></pds-icon> Storybook
210
- </a>
211
- </nav>
212
- </article>
213
- \`;
88
+ if (entry.isDirectory()) {
89
+ await ensureDir(targetPath);
90
+ await copyTemplateDirectory(sourcePath, targetPath, options);
91
+ continue;
214
92
  }
215
- },
216
- );
217
- `;
218
- }
219
93
 
220
- function buildMyTheme() {
221
- return `/**
222
- * my-theme Web Component - allows users to select the app theme (light, dark, system)
223
- *
224
- * Uses Pure Design System (PDS) for styling and theming.
225
- */
226
- customElements.define(
227
- "my-theme",
228
- class extends HTMLElement {
229
- constructor() {
230
- super();
231
- this.attachShadow({ mode: "open" });
94
+ if (relativePath === path.join('public', 'index.html')) {
95
+ await writeIndexFromTemplate(sourcePath, targetPath, options);
96
+ continue;
232
97
  }
233
98
 
234
- async connectedCallback() {
235
- const componentStyles = PDS.createStylesheet(
236
- "\n :host {\n display: block;\n }\n "
237
- );
238
-
239
- await PDS.adoptLayers(
240
- this.shadowRoot,
241
- ["tokens", "primitives", "components", "utilities"],
242
- [componentStyles],
243
- );
244
-
245
- this.shadowRoot.innerHTML +=
246
- "\n <form>\n <fieldset role=\"radiogroup\" aria-label=\"Theme\" class=\"buttons\">\n <legend>Theme</legend>\n <label>\n <input type=\"radio\" name=\"theme\" value=\"system\">\n <span>\n <pds-icon icon=\"moon-stars\"></pds-icon>\n System\n </span>\n </label>\n <label>\n <input type=\"radio\" name=\"theme\" value=\"light\">\n <span>\n <pds-icon icon=\"sun\"></pds-icon>\n Light\n </span>\n </label>\n <label>\n <input type=\"radio\" name=\"theme\" value=\"dark\">\n <span>\n <pds-icon icon=\"moon\"></pds-icon>\n Dark\n </span>\n </label>\n </fieldset>\n </form>";
247
-
248
- this.#updateCheckedState();
249
-
250
- this.shadowRoot.addEventListener("change", (e) => {
251
- if (e.target.type === "radio" && e.target.name === "theme") {
252
- PDS.theme = e.target.value;
253
- PDS.toast("Theme changed to " + e.target.value, { duration: 2000 });
254
- }
255
- });
256
-
257
- const observer = new MutationObserver(() => {
258
- this.#updateCheckedState();
259
- });
260
-
261
- observer.observe(document.documentElement, {
262
- attributes: true,
263
- attributeFilter: ["data-theme"],
264
- });
99
+ if (relativePath === 'esbuild-dev.cjs' || relativePath === 'esbuild-dev.mjs') {
100
+ continue;
265
101
  }
266
102
 
267
- #updateCheckedState() {
268
- const currentTheme = PDS.theme || "system";
269
- const radios = this.shadowRoot.querySelectorAll('input[type="radio"]');
270
- radios.forEach((radio) => {
271
- radio.checked = radio.value === currentTheme;
272
- });
273
- }
274
- },
275
- );
276
- `;
277
- }
278
-
279
- function buildAppJs() {
280
- return `import { PDS } from "@pure-ds/core";
281
- import { config } from "../../pds.config.js";
282
-
283
- await PDS.start(config);
284
-
285
- const main = document.querySelector("main");
286
- if (main && !main.querySelector("my-home")) {
287
- main.innerHTML = "<my-home></my-home>";
288
- }
289
-
290
- /**
291
- * Generates an HTML NodeList by parsing the given HTML string
292
- * @param {String} html
293
- * @returns {NodeListOf<ChildNode>} DOM element
294
- */
295
- const parseHTML = (html) => {
296
- return new DOMParser().parseFromString(html, "text/html").body.childNodes;
297
- };
298
-
299
- const settingsBtn = parseHTML(
300
- \`<button id="settings-btn" class="icon-only btn-xs btn-outline" aria-label="Settings">
301
- <pds-icon icon="gear"></pds-icon>
302
- </button>\`,
303
- )[0];
304
-
305
- document.body.appendChild(settingsBtn);
306
-
307
- const drawer = document.createElement("pds-drawer");
308
- drawer.setAttribute("position", "right");
309
-
310
- drawer.innerHTML = /*html*/ \`<div slot="drawer-header">Settings</div>\n <div slot="drawer-content"><my-theme></my-theme></div>\`;
311
- document.body.appendChild(drawer);
312
-
313
- settingsBtn.addEventListener("click", () => {
314
- drawer.open = true;
315
- });
316
- `;
317
- }
318
-
319
- function buildPdsConfig() {
320
- return buildStarterPdsConfig();
321
- }
322
-
323
- function buildEsbuildDevCjs() {
324
- return `const esbuild = require('esbuild');
325
- const http = require('http');
326
-
327
- const reloadPort = 4174;
328
- const reloadClients = new Set();
329
-
330
- function startReloadServer() {
331
- const server = http.createServer((req, res) => {
332
- if (req.url !== '/events') {
333
- res.writeHead(404);
334
- res.end();
335
- return;
336
- }
337
-
338
- res.writeHead(200, {
339
- 'Content-Type': 'text/event-stream',
340
- 'Cache-Control': 'no-cache',
341
- Connection: 'keep-alive',
342
- 'Access-Control-Allow-Origin': '*'
343
- });
344
-
345
- res.write('retry: 1000\\n\\n');
346
- reloadClients.add(res);
347
-
348
- req.on('close', () => {
349
- reloadClients.delete(res);
350
- });
351
- });
352
-
353
- server.listen(reloadPort, () => {
354
- console.log('Live reload listening on http://localhost:' + reloadPort + '/events');
355
- });
356
- }
357
-
358
- function notifyReload() {
359
- for (const client of reloadClients) {
360
- client.write('data: reload\\n\\n');
103
+ await copyFileIfMissing(sourcePath, targetPath);
361
104
  }
362
105
  }
363
106
 
364
- function liveReloadPlugin() {
365
- return {
366
- name: 'live-reload',
367
- setup(build) {
368
- build.onEnd((result) => {
369
- if (!result.errors.length) {
370
- notifyReload();
371
- }
372
- });
373
- }
374
- };
375
- }
376
-
377
- async function start() {
378
- startReloadServer();
379
- const ctx = await esbuild.context({
380
- entryPoints: ['src/js/app.js'],
381
- outdir: 'public/assets/js',
382
- bundle: true,
383
- format: 'esm',
384
- sourcemap: true,
385
- publicPath: '/assets/js',
386
- external: ['/assets/my/*'],
387
- logLevel: 'info',
388
- plugins: [liveReloadPlugin()]
389
- });
390
-
391
- await ctx.watch();
392
- const { host, port } = await ctx.serve({ servedir: 'public', port: 4173 });
393
- console.log('Dev server running at http://' + host + ':' + port);
394
- }
395
-
396
- start().catch((err) => {
397
- console.error(err);
398
- process.exit(1);
399
- });
400
- `;
401
- }
402
-
403
- function buildEsbuildDevEsm() {
404
- return `import esbuild from 'esbuild';
405
- import http from 'http';
406
-
407
- const reloadPort = 4174;
408
- const reloadClients = new Set();
409
-
410
- function startReloadServer() {
411
- const server = http.createServer((req, res) => {
412
- if (req.url !== '/events') {
413
- res.writeHead(404);
414
- res.end();
415
- return;
416
- }
417
-
418
- res.writeHead(200, {
419
- 'Content-Type': 'text/event-stream',
420
- 'Cache-Control': 'no-cache',
421
- Connection: 'keep-alive',
422
- 'Access-Control-Allow-Origin': '*'
423
- });
424
-
425
- res.write('retry: 1000\\n\\n');
426
- reloadClients.add(res);
427
-
428
- req.on('close', () => {
429
- reloadClients.delete(res);
430
- });
431
- });
432
-
433
- server.listen(reloadPort, () => {
434
- console.log('Live reload listening on http://localhost:' + reloadPort + '/events');
435
- });
436
- }
437
-
438
- function notifyReload() {
439
- for (const client of reloadClients) {
440
- client.write('data: reload\\n\\n');
441
- }
442
- }
443
-
444
- function liveReloadPlugin() {
445
- return {
446
- name: 'live-reload',
447
- setup(build) {
448
- build.onEnd((result) => {
449
- if (!result.errors.length) {
450
- notifyReload();
451
- }
452
- });
453
- }
454
- };
455
- }
456
-
457
- startReloadServer();
458
-
459
- const ctx = await esbuild.context({
460
- entryPoints: ['src/js/app.js'],
461
- outdir: 'public/assets/js',
462
- bundle: true,
463
- format: 'esm',
464
- sourcemap: true,
465
- publicPath: '/assets/js',
466
- external: ['/assets/my/*'],
467
- logLevel: 'info',
468
- plugins: [liveReloadPlugin()]
469
- });
107
+ async function copyBootstrapTemplate({ version, generatedAt, isModule }) {
108
+ await copyTemplateDirectory(templateRoot, projectRoot, { version, generatedAt });
470
109
 
471
- await ctx.watch();
472
- const { host, port } = await ctx.serve({ servedir: 'public', port: 4173 });
473
- `;
110
+ const esbuildTemplate = isModule ? 'esbuild-dev.mjs' : 'esbuild-dev.cjs';
111
+ const esbuildSource = path.join(templateRoot, esbuildTemplate);
112
+ const esbuildTarget = path.join(projectRoot, 'esbuild-dev.js');
113
+ await copyFileIfMissing(esbuildSource, esbuildTarget);
474
114
  }
475
115
 
476
116
  async function ensurePackageScripts(pkg, pkgPath) {
@@ -630,29 +270,7 @@ async function main() {
630
270
  const version = await getPdsCoreVersion();
631
271
  const generatedAt = new Date().toLocaleString();
632
272
 
633
- await writeFileIfMissing(
634
- path.join(projectRoot, 'public', 'index.html'),
635
- buildIndexHtml({ version, generatedAt })
636
- );
637
- await writeFileIfMissing(path.join(projectRoot, 'public', 'assets', 'css', 'app.css'), buildAppCss());
638
- await writeFileIfMissing(path.join(projectRoot, 'src', 'js', 'app.js'), buildAppJs());
639
- await writeFileIfMissing(path.join(projectRoot, 'pds.config.js'), buildPdsConfig());
640
- await writeFileIfMissing(
641
- path.join(projectRoot, 'public', 'assets', 'js', 'dev-reload.js'),
642
- buildDevReloadJs()
643
- );
644
- await writeFileIfMissing(
645
- path.join(projectRoot, 'public', 'assets', 'my', 'my-home.js'),
646
- buildMyHome()
647
- );
648
- await writeFileIfMissing(
649
- path.join(projectRoot, 'public', 'assets', 'my', 'my-theme.js'),
650
- buildMyTheme()
651
- );
652
-
653
- const esbuildDevPath = path.join(projectRoot, 'esbuild-dev.js');
654
- const esbuildDevContent = isModule ? buildEsbuildDevEsm() : buildEsbuildDevCjs();
655
- await writeFileIfMissing(esbuildDevPath, esbuildDevContent);
273
+ await copyBootstrapTemplate({ version, generatedAt, isModule });
656
274
 
657
275
  await ensurePdsAssets();
658
276
 
@@ -0,0 +1,76 @@
1
+ const esbuild = require("esbuild");
2
+ const http = require("http");
3
+
4
+ const reloadPort = 4174;
5
+ const reloadClients = new Set();
6
+
7
+ function startReloadServer() {
8
+ const server = http.createServer((req, res) => {
9
+ if (req.url !== "/events") {
10
+ res.writeHead(404);
11
+ res.end();
12
+ return;
13
+ }
14
+
15
+ res.writeHead(200, {
16
+ "Content-Type": "text/event-stream",
17
+ "Cache-Control": "no-cache",
18
+ Connection: "keep-alive",
19
+ "Access-Control-Allow-Origin": "*",
20
+ });
21
+
22
+ res.write("retry: 1000\n\n");
23
+ reloadClients.add(res);
24
+
25
+ req.on("close", () => {
26
+ reloadClients.delete(res);
27
+ });
28
+ });
29
+
30
+ server.listen(reloadPort, () => {
31
+ console.log("Live reload listening on http://localhost:" + reloadPort + "/events");
32
+ });
33
+ }
34
+
35
+ function notifyReload() {
36
+ for (const client of reloadClients) {
37
+ client.write("data: reload\n\n");
38
+ }
39
+ }
40
+
41
+ function liveReloadPlugin() {
42
+ return {
43
+ name: "live-reload",
44
+ setup(build) {
45
+ build.onEnd((result) => {
46
+ if (!result.errors.length) {
47
+ notifyReload();
48
+ }
49
+ });
50
+ },
51
+ };
52
+ }
53
+
54
+ async function start() {
55
+ startReloadServer();
56
+ const ctx = await esbuild.context({
57
+ entryPoints: ["src/js/app.js"],
58
+ outdir: "public/assets/js",
59
+ bundle: true,
60
+ format: "esm",
61
+ sourcemap: true,
62
+ publicPath: "/assets/js",
63
+ external: ["/assets/my/*"],
64
+ logLevel: "info",
65
+ plugins: [liveReloadPlugin()],
66
+ });
67
+
68
+ await ctx.watch();
69
+ const { host, port } = await ctx.serve({ servedir: "public", port: 4173 });
70
+ console.log("Dev server running at http://" + host + ":" + port);
71
+ }
72
+
73
+ start().catch((err) => {
74
+ console.error(err);
75
+ process.exit(1);
76
+ });
@@ -0,0 +1,69 @@
1
+ import esbuild from "esbuild";
2
+ import http from "http";
3
+
4
+ const reloadPort = 4174;
5
+ const reloadClients = new Set();
6
+
7
+ function startReloadServer() {
8
+ const server = http.createServer((req, res) => {
9
+ if (req.url !== "/events") {
10
+ res.writeHead(404);
11
+ res.end();
12
+ return;
13
+ }
14
+
15
+ res.writeHead(200, {
16
+ "Content-Type": "text/event-stream",
17
+ "Cache-Control": "no-cache",
18
+ Connection: "keep-alive",
19
+ "Access-Control-Allow-Origin": "*",
20
+ });
21
+
22
+ res.write("retry: 1000\n\n");
23
+ reloadClients.add(res);
24
+
25
+ req.on("close", () => {
26
+ reloadClients.delete(res);
27
+ });
28
+ });
29
+
30
+ server.listen(reloadPort, () => {
31
+ console.log("Live reload listening on http://localhost:" + reloadPort + "/events");
32
+ });
33
+ }
34
+
35
+ function notifyReload() {
36
+ for (const client of reloadClients) {
37
+ client.write("data: reload\n\n");
38
+ }
39
+ }
40
+
41
+ function liveReloadPlugin() {
42
+ return {
43
+ name: "live-reload",
44
+ setup(build) {
45
+ build.onEnd((result) => {
46
+ if (!result.errors.length) {
47
+ notifyReload();
48
+ }
49
+ });
50
+ },
51
+ };
52
+ }
53
+
54
+ startReloadServer();
55
+
56
+ const ctx = await esbuild.context({
57
+ entryPoints: ["src/js/app.js"],
58
+ outdir: "public/assets/js",
59
+ bundle: true,
60
+ format: "esm",
61
+ sourcemap: true,
62
+ publicPath: "/assets/js",
63
+ external: ["/assets/my/*"],
64
+ logLevel: "info",
65
+ plugins: [liveReloadPlugin()],
66
+ });
67
+
68
+ await ctx.watch();
69
+ const { host, port } = await ctx.serve({ servedir: "public", port: 4173 });