@pantoken/scaffold 1.2.0 → 1.2.1

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/dist/cli.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as scaffoldProject, i as resolveScaffoldPlatform, o as ThemeMode, r as isScaffoldPlatform, s as ThemeVariant, t as SCAFFOLD_PLATFORMS } from "./index-D2-Dhvt8.mjs";
1
+ import { a as resolveScaffoldPlatform, c as ThemeVariant, i as isScaffoldPlatform, n as ScaffoldPackageManager, o as scaffoldProject, s as ThemeMode, t as SCAFFOLD_PLATFORMS } from "./index-BloHpRKt.mjs";
2
2
  import { Command } from "commander";
3
3
  //#region src/locale.d.ts
4
4
  /** Every locale tag pantoken supports, as `--lang` accepts them. */
@@ -116,6 +116,7 @@ export declare function scaffoldWithSpinner(platform: string, dir: string, t: Lo
116
116
  mode?: ThemeMode;
117
117
  cdn?: string;
118
118
  locale?: string;
119
+ packageManager?: ScaffoldPackageManager;
119
120
  }): Promise<string[]>;
120
121
  /** Package managers `detectPackageManager` can identify. */
121
122
  export type PackageManager = "npm" | "pnpm" | "yarn" | "bun" | "deno" | "vp";
@@ -156,7 +157,8 @@ export declare function installWithSpinner(dir: string, pm: PackageManager | und
156
157
  * needed — regardless of platform. Otherwise, when `platform` has a `scaffold.json`-derived entry in
157
158
  * `SCAFFOLD_METADATA`, next steps/notes/caveats are rendered from its (localized, `{{var}}`-
158
159
  * substituted) authored strings; failing that, a generic cd/install/run-script fallback is used,
159
- * with the run script itself detected from the scaffolded `package.json` (`dev`, else `preview`).
160
+ * with the run script itself detected from the scaffolded `package.json` (`dev`, else `preview`)
161
+ * or defaulted to `dev` for scaffolded app templates.
160
162
  *
161
163
  * @param dir - The scaffold directory
162
164
  * @param written - The paths written by scaffoldProject
package/dist/cli.mjs CHANGED
@@ -1,7 +1,6 @@
1
- import { c as SUPPORTED_LOCALES, d as validateLocaleTag, i as scaffoldProject, l as createLocaleLookup, n as isScaffoldPlatform, o as validateThemeMode, r as resolveScaffoldPlatform, s as validateThemeVariant, t as SCAFFOLD_PLATFORMS, u as detectLocale } from "./src-DxBSPAO9.mjs";
1
+ import { c as SUPPORTED_LOCALES, d as validateLocaleTag, i as scaffoldProject, l as createLocaleLookup, n as isScaffoldPlatform, o as validateThemeMode, r as resolveScaffoldPlatform, s as validateThemeVariant, t as SCAFFOLD_PLATFORMS, u as detectLocale } from "./src-BTDVd_Xe.mjs";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { basename, join } from "node:path";
4
- import { CDN_PROVIDERS } from "@pantoken/canvas-theme-editor";
5
4
  import { Argument, Command, CommanderError, InvalidArgumentError } from "commander";
6
5
  import { cancel, isCancel, select, spinner, text } from "@clack/prompts";
7
6
  import tab from "@bomb.sh/tab/commander";
@@ -2760,6 +2759,7 @@ function detectPackageManager(env, execPath) {
2760
2759
  if (userAgent.includes("bun")) return "bun";
2761
2760
  if (userAgent.includes("deno")) return "deno";
2762
2761
  if (userAgent.includes("npm")) return "npm";
2762
+ if ("Deno" in globalThis) return "deno";
2763
2763
  if ((execPath ?? process.execPath).includes("vite-plus")) return "vp";
2764
2764
  }
2765
2765
  /** Fully-composed command fragments per package manager, so callers never hand-compose them. */
@@ -2827,7 +2827,12 @@ function buildCreateUsageCommand(pm) {
2827
2827
  * @returns Whether the install command exited successfully
2828
2828
  */
2829
2829
  function installWithSpinner(dir, pm, t) {
2830
- const [command, ...args] = pmCommands(pm).install.split(" ");
2830
+ const npmExecPath = pm === "npm" ? process.env.npm_execpath : void 0;
2831
+ const [command, ...args] = npmExecPath ? [
2832
+ process.execPath,
2833
+ npmExecPath,
2834
+ "install"
2835
+ ] : pmCommands(pm).install.split(" ");
2831
2836
  const s = spinner();
2832
2837
  s.start(t("installSpinnerStart"));
2833
2838
  try {
@@ -2874,7 +2879,8 @@ function buildDevStep(dir, dev) {
2874
2879
  * needed — regardless of platform. Otherwise, when `platform` has a `scaffold.json`-derived entry in
2875
2880
  * `SCAFFOLD_METADATA`, next steps/notes/caveats are rendered from its (localized, `{{var}}`-
2876
2881
  * substituted) authored strings; failing that, a generic cd/install/run-script fallback is used,
2877
- * with the run script itself detected from the scaffolded `package.json` (`dev`, else `preview`).
2882
+ * with the run script itself detected from the scaffolded `package.json` (`dev`, else `preview`)
2883
+ * or defaulted to `dev` for scaffolded app templates.
2878
2884
  *
2879
2885
  * @param dir - The scaffold directory
2880
2886
  * @param written - The paths written by scaffoldProject
@@ -2885,8 +2891,7 @@ function buildDevStep(dir, dev) {
2885
2891
  function printNextSteps(dir, written, t, platform, installed) {
2886
2892
  const pm = detectPackageManager();
2887
2893
  const { install, run } = pmCommands(pm);
2888
- const script = detectRunScript(written);
2889
- const dev = script ? `${run} ${script}` : t("nextStepsDevServer");
2894
+ const dev = `${run} ${detectRunScript(written) ?? "dev"}`;
2890
2895
  const vars = {
2891
2896
  dir,
2892
2897
  pm: pm ?? "npm",
@@ -2926,8 +2931,13 @@ function validateScaffoldPlatform(value) {
2926
2931
  * @throws InvalidArgumentError if the value isn't a known CDN provider id
2927
2932
  */
2928
2933
  function validateCdnProviderId(value) {
2929
- if (value in CDN_PROVIDERS) return value;
2930
- throw new InvalidArgumentError(`CDN provider "${value}" is not valid. Expected one of: ${Object.keys(CDN_PROVIDERS).join(", ")}.`);
2934
+ const providers = [
2935
+ "jsdelivr",
2936
+ "unpkg",
2937
+ "esmsh"
2938
+ ];
2939
+ if (providers.includes(value)) return value;
2940
+ throw new InvalidArgumentError(`CDN provider "${value}" is not valid. Expected one of: ${providers.join(", ")}.`);
2931
2941
  }
2932
2942
  /**
2933
2943
  * Builds the full, ready-to-parse commander Command for pantoken-scaffold/create-pantoken-app.
@@ -2953,19 +2963,21 @@ function createScaffoldCommand(options) {
2953
2963
  t
2954
2964
  });
2955
2965
  const expandedDir = expandHome(dir);
2966
+ const packageManager = detectPackageManager();
2956
2967
  const written = await scaffoldWithSpinner(platform, expandedDir, t, {
2957
2968
  theme: opts.theme,
2958
2969
  mode: opts.themeMode,
2959
2970
  cdn: opts.cdn,
2960
- locale
2971
+ locale,
2972
+ packageManager
2961
2973
  });
2962
2974
  for (const path of written) console.log(t("wroteFile", { path }));
2975
+ const installed = opts.install !== false && installWithSpinner(expandedDir, packageManager, t);
2963
2976
  let printDir = expandedDir;
2964
- if (expandedDir !== ".") try {
2977
+ if (installed && expandedDir !== ".") try {
2965
2978
  process.chdir(expandedDir);
2966
2979
  printDir = ".";
2967
2980
  } catch {}
2968
- const installed = opts.install !== false && installWithSpinner(expandedDir, detectPackageManager(), t);
2969
2981
  printNextSteps(printDir, written, t, resolveScaffoldPlatform(platform), installed);
2970
2982
  } catch (err) {
2971
2983
  if (err instanceof ScaffoldCliError) throw err;
@@ -1,9 +1,5 @@
1
- import { Preset } from "@pantoken/scaffold-base";
2
- //#region generated/preset-ledger.d.ts
3
- /**
4
- * Registry of all available pantoken scaffold presets, keyed by platform name.
5
- */
6
- declare const PRESET_LEDGER: Record<string, Preset>;
1
+ //#region generated/scaffolds.d.ts
2
+ declare const SCAFFOLDS: Record<string, Record<string, string>>;
7
3
  //#endregion
8
4
  //#region src/theme.d.ts
9
5
  /** A pantoken token theme variant. */
@@ -26,11 +22,19 @@ declare function validateThemeVariant(value: string): ThemeVariant;
26
22
  declare function validateThemeMode(value: string): ThemeMode;
27
23
  //#endregion
28
24
  //#region src/index.d.ts
25
+ /** Package managers whose commands can be reflected in scaffolded project files. */
26
+ type ScaffoldPackageManager = "npm" | "pnpm" | "yarn" | "bun" | "deno" | "vp";
27
+ interface ScaffoldProjectOptions {
28
+ theme?: ThemeVariant;
29
+ mode?: ThemeMode;
30
+ cdn?: string;
31
+ locale?: string;
32
+ packageManager?: ScaffoldPackageManager;
33
+ }
29
34
  /**
30
- * A platform pantoken can scaffold a starter project for — either preset-ledger-backed (Bingo)
31
- * or a legacy template-only entry (e.g. `canvas-theme-editor`) with no preset yet.
35
+ * A platform pantoken can scaffold a starter project for.
32
36
  */
33
- type ScaffoldPlatform = keyof typeof PRESET_LEDGER;
37
+ type ScaffoldPlatform = keyof typeof SCAFFOLDS;
34
38
  /**
35
39
  * Every scaffoldable platform key (discovered from available presets, plus any legacy
36
40
  * template-only platforms not yet backed by a preset).
@@ -74,11 +78,6 @@ declare function resolveScaffoldPlatform(platform: string): ScaffoldPlatform;
74
78
  * scaffoldProject("vue", "./my-vue-app", { theme: "canvas", locale: "hu" });
75
79
  * ```
76
80
  */
77
- declare function scaffoldProject(platform: string, dir?: string, options?: {
78
- theme?: ThemeVariant;
79
- mode?: ThemeMode;
80
- cdn?: string;
81
- locale?: string;
82
- }): Promise<string[]>;
81
+ declare function scaffoldProject(platform: string, dir?: string, options?: ScaffoldProjectOptions): Promise<string[]>;
83
82
  //#endregion
84
- export { scaffoldProject as a, themeStylesheetImport as c, resolveScaffoldPlatform as i, validateThemeMode as l, ScaffoldPlatform as n, ThemeMode as o, isScaffoldPlatform as r, ThemeVariant as s, SCAFFOLD_PLATFORMS as t, validateThemeVariant as u };
83
+ export { resolveScaffoldPlatform as a, ThemeVariant as c, validateThemeVariant as d, isScaffoldPlatform as i, themeStylesheetImport as l, ScaffoldPackageManager as n, scaffoldProject as o, ScaffoldPlatform as r, ThemeMode as s, SCAFFOLD_PLATFORMS as t, validateThemeMode as u };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as scaffoldProject, c as themeStylesheetImport, i as resolveScaffoldPlatform, l as validateThemeMode, n as ScaffoldPlatform, o as ThemeMode, r as isScaffoldPlatform, s as ThemeVariant, t as SCAFFOLD_PLATFORMS, u as validateThemeVariant } from "./index-D2-Dhvt8.mjs";
2
- export { SCAFFOLD_PLATFORMS, ScaffoldPlatform, type ThemeMode, type ThemeVariant, isScaffoldPlatform, resolveScaffoldPlatform, scaffoldProject, themeStylesheetImport, validateThemeMode, validateThemeVariant };
1
+ import { a as resolveScaffoldPlatform, c as ThemeVariant, d as validateThemeVariant, i as isScaffoldPlatform, l as themeStylesheetImport, n as ScaffoldPackageManager, o as scaffoldProject, r as ScaffoldPlatform, s as ThemeMode, t as SCAFFOLD_PLATFORMS, u as validateThemeMode } from "./index-BloHpRKt.mjs";
2
+ export { SCAFFOLD_PLATFORMS, ScaffoldPackageManager, ScaffoldPlatform, type ThemeMode, type ThemeVariant, isScaffoldPlatform, resolveScaffoldPlatform, scaffoldProject, themeStylesheetImport, validateThemeMode, validateThemeVariant };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as themeStylesheetImport, i as scaffoldProject, n as isScaffoldPlatform, o as validateThemeMode, r as resolveScaffoldPlatform, s as validateThemeVariant, t as SCAFFOLD_PLATFORMS } from "./src-DxBSPAO9.mjs";
1
+ import { a as themeStylesheetImport, i as scaffoldProject, n as isScaffoldPlatform, o as validateThemeMode, r as resolveScaffoldPlatform, s as validateThemeVariant, t as SCAFFOLD_PLATFORMS } from "./src-BTDVd_Xe.mjs";
2
2
  export { SCAFFOLD_PLATFORMS, isScaffoldPlatform, resolveScaffoldPlatform, scaffoldProject, themeStylesheetImport, validateThemeMode, validateThemeVariant };
@@ -1,13 +1,5 @@
1
1
  import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
- import { producePreset } from "bingo-stratum";
4
- import { buildTheme } from "@pantoken/canvas-theme-editor";
5
- import { presetComponents } from "@pantoken/components/scaffold-preset";
6
- import { presetReact } from "@pantoken/react/scaffold-preset";
7
- import { presetVue } from "@pantoken/vue/scaffold-preset";
8
- import { presetWebComponents } from "@pantoken/web-components/scaffold-preset";
9
- import { presetAngular } from "@pantoken/angular/scaffold-preset";
10
- import { presetSvelte } from "@pantoken/svelte/scaffold-preset";
11
3
  import { InvalidArgumentError } from "commander";
12
4
  //#region generated/scaffolds.ts
13
5
  const SCAFFOLDS = {
@@ -15,8 +7,8 @@ const SCAFFOLDS = {
15
7
  ".gitignore": "node_modules\ndist\n",
16
8
  "README.md": "# {{projectName}}\n\nA standalone Angular app (via Vite + `@analogjs/vite-plugin-angular`, no Angular CLI) styled with\n[`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components) and\n[`@pantoken/angular`](https://www.npmjs.com/package/@pantoken/angular) (pantoken custom elements\nfor Angular).\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.ts` calls `registerPantokenElements()` (from `@pantoken/angular`) once at bootstrap so\n elements like `<instui-icon>` work in templates, and imports the token/component CSS plus\n `@pantoken/interactions` (wires up modal, tooltip, and other component behaviors out of the\n box).\n- `src/app.component.ts` is a standalone component (`CUSTOM_ELEMENTS_SCHEMA` lets the template\n compiler accept pantoken's custom element tags) whose template is styled with `instui-*`\n classes; optional insertion points (header, filters, content, trailing) are marked with\n `<div data-slot=\"...\">`.\n- Apply classes like `class=\"instui-button\"` to markup; see the\n [component reference](https://pantoken.app/api/css) for the full class list.\n\n## Learn more\n\nSee the [getting started guide](https://pantoken.app/guide/getting-started) to learn more.\n",
17
9
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body class=\"instui-display-flex\">\n <app-root></app-root>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
18
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@angular/common\": \"^22.1.3\",\n \"@angular/compiler\": \"^22.1.3\",\n \"@angular/core\": \"^22.1.3\",\n \"@angular/platform-browser\": \"^22.1.3\",\n \"@pantoken/angular\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"rxjs\": \"^7.8.2\",\n \"zone.js\": \"^0.16.2\"\n },\n \"devDependencies\": {\n \"@analogjs/vite-plugin-angular\": \"^2.7.0\",\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
19
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
10
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@angular/common\": \"^22.1.3\",\n \"@angular/compiler\": \"^22.1.3\",\n \"@angular/core\": \"^22.1.3\",\n \"@angular/platform-browser\": \"^22.1.3\",\n \"@pantoken/angular\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"rxjs\": \"^7.8.2\",\n \"zone.js\": \"^0.16.2\"\n },\n \"devDependencies\": {\n \"@analogjs/vite-plugin-angular\": \"^2.7.0\",\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
11
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
20
12
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"experimentalDecorators\": true,\n \"useDefineForClassFields\": false,\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
21
13
  "vite.config.ts": "import angular from \"@analogjs/vite-plugin-angular\";\nimport { defineConfig } from \"vite\";\n\nexport default defineConfig({\n plugins: [angular()],\n});\n",
22
14
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\", \"angular.ng-template\"]\n}\n",
@@ -29,8 +21,8 @@ const SCAFFOLDS = {
29
21
  ".gitignore": "node_modules\ndist\n",
30
22
  "README.md": "# {{projectName}}\n\nUpload-ready assets for Canvas LMS's **Theme Editor**, plus a local preview for authoring Rich\nContent Editor (RCE) page templates styled with\n[`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components).\n\n## What's here\n\n- `theme.css` / `theme.js` — upload these two files under **Theme Editor → Advanced** in Canvas.\n They're built for the CDN provider/theme/mode you chose when scaffolding (`--cdn`/`--theme`/\n `--theme-mode`; jsDelivr/rebrand/light by default) and include a loader for\n `@pantoken/interactions` (wires up component behaviors like modal, tooltip, and drilldown).\n- `index.html` / `src/main.ts` — a local, TinyMCE-based editor (`npm run dev`) that mirrors Canvas's\n RCE so you can author page templates against pantoken's classes before copying them into Canvas.\n The page itself is built with pantoken's `wrapper` layout: click **Edit theme** to open a tray\n with **Config** / **CSS** / **JS** tabs (CDN provider/theme/mode selects, and syntax-highlighted,\n hand-editable copies of `theme.css`/`theme.js` that feed the live preview), and the **?** button\n for full instructions. Use the **Layouts** toolbar button to start from one of pantoken's bundled\n starter page layouts (hero, callout, two-column, rubric note, testimonial), sourced from\n [`@pantoken/plugin-layouts`](https://www.npmjs.com/package/@pantoken/plugin-layouts).\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\nThis opens a Vite dev server with:\n\n- An **editor** pane (TinyMCE, matching the version/config\n [instructure/canvas-lms](https://github.com/instructure/canvas-lms) itself uses — see below).\n Use the **Layouts** button to load one of the bundled starter layouts (this replaces the whole\n document, after a confirm, rather than inserting at the cursor), and the **Source code** toggle\n to hand-edit the raw HTML in a syntax-highlighted (CodeMirror) view alongside the editor, with\n the preview pane updating live as you type — unlike TinyMCE's stock `code` plugin, which edits in\n a one-shot modal dialog with no live preview.\n- A **preview** pane showing the editor's content with the current CSS/JS tab's stylesheet/script\n applied (not just the resolved CDN URLs), wrapped to match Canvas's own content-area background\n and max width — a faithful \"what this will look like once uploaded to Canvas\" check, updated\n live as you type or edit the theme.\n- The editor and preview panes sit in a split view you can resize by dragging the divider, stack\n vertically instead of side by side, and swap the order of (drag a pane's toolbar onto the other,\n or use the **Swap panes** button). Each pane has its own fullscreen button.\n- The **Edit theme** tray's **Config** tab holds the CDN provider/theme/mode selects and\n **Download theme.css** / **Download theme.js** links; its **CSS**/**JS** tabs are editable copies\n of the generated files — hand-edit them and the preview picks up your changes directly. Changing\n a Config select re-generates the CSS/JS tabs unless you've already edited them, in which case a\n **Regenerate from config** button appears instead of silently overwriting your edit.\n\n## Workflow\n\n1. Upload `theme.css` and `theme.js` to Canvas's Theme Editor (**Advanced → CSS / JavaScript**) so\n pantoken's classes are available on every page.\n2. Run `npm run dev`, use **Layouts** to start from a bundled starter, and edit it like you\n would in Canvas's own RCE.\n3. Click **Copy HTML** and paste the result into a Canvas page's RCE (switch to the HTML editor\n view first). Canvas sanitizes pasted HTML server-side — this scaffold doesn't attempt to\n replicate that, so always verify the pasted result in Canvas (see \"Notes on Canvas's RCE\"\n below).\n\n## Notes on Canvas's RCE\n\nThe Canvas Rich Content Editor runs TinyMCE and sanitizes submitted HTML on the server against an\nallowlist (`gems/canvas_sanitize` in canvas-lms, kept in sync with TinyMCE's own\n`valid_elements`/`extended_valid_elements`). What that allowlist means for templates built here:\n\n- `class`, `id`, `style`, `title`, `role`, and `aria-*` attributes are allowed on every element —\n pantoken's `class=\"instui-*\"` styling hooks (and inline `style`, e.g. for CSS anchor positioning)\n **do** survive being pasted and saved, contrary to older guidance in this file. `<script>` tags\n are always stripped.\n- **RCE-safe pantoken components**: static/display components — alert, view, heading, text, table,\n a button-as-`<a>` (not a real `<button>`), blockquote. Stick to semantic HTML pantoken already\n supports (`div`, `p`, `span`, `a`, `img`, headings, lists, tables).\n- **RCE-unsafe**: anything from `@pantoken/interactions`'s behavior set — modal, tooltip,\n drilldown, close-button, or any other component driven by the native `popover`/`popovertarget`/\n `command`/`commandfor` attributes. Those attributes aren't in Canvas's sanitizer allowlist, so\n the markup survives but the interactive behavior silently breaks the first time the page is\n saved in Canvas, even with `theme.js`'s `@pantoken/interactions` loader present. Real form\n elements (`input`, `form`, `button`, `select`, `textarea`, `label`) and inline `<svg>` are\n stripped outright — none of the bundled starter templates use them.\n\n`theme.js` loads `@pantoken/interactions` from the CDN, which runs in Canvas's global page scope —\nuseful for interactions on pages you build directly in Canvas's RCE with raw HTML edits, but (per\nabove) any `popover`/`command`-attribute-driven markup pasted from the RCE preview here won't stay\ninteractive once saved.\n",
31
23
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}} — RCE template authoring</title>\n </head>\n <body class=\"instui-display-flex\">\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
32
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/canvas-theme-editor\": \"latest\",\n \"@pantoken/cdn\": \"latest\",\n \"@pantoken/components\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/plugin-layouts\": \"latest\",\n \"@pantoken/tinymce\": \"latest\"\n },\n \"devDependencies\": {\n \"@codemirror/lang-css\": \"catalog:\",\n \"@codemirror/lang-html\": \"catalog:\",\n \"@codemirror/lang-javascript\": \"catalog:\",\n \"codemirror\": \"catalog:\",\n \"tinymce\": \"catalog:\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
33
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
24
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/canvas-theme-editor\": \"latest\",\n \"@pantoken/cdn\": \"latest\",\n \"@pantoken/components\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/plugin-layouts\": \"latest\",\n \"@pantoken/tinymce\": \"latest\"\n },\n \"devDependencies\": {\n \"@codemirror/lang-css\": \"catalog:\",\n \"@codemirror/lang-html\": \"catalog:\",\n \"@codemirror/lang-javascript\": \"catalog:\",\n \"codemirror\": \"catalog:\",\n \"tinymce\": \"catalog:\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
25
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
34
26
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true,\n \"noEmit\": true\n },\n \"include\": [\"src\"]\n}\n",
35
27
  "vite.config.ts": "import { defineConfig } from \"vite\";\n\nexport default defineConfig({});\n",
36
28
  "src/app.css": "/* Layout for this scaffold's own authoring UI (not part of any Canvas-pasted RCE content). */\n\n.instui-tray .list {\n display: flex;\n gap: 0.5rem;\n}\n\n.instui-tray .panel[hidden] {\n display: none;\n}\n\n.code-editor {\n border: var(--instui-component-tray-border-width, 1px) solid\n var(--instui-component-tray-border-color, #ccc);\n min-height: 20rem;\n}\n\n.split-pane {\n display: flex;\n flex-direction: row;\n gap: 0;\n min-height: 30rem;\n}\n\n.split-pane.-orientation-column {\n flex-direction: column;\n}\n\n.pane {\n flex: 1 1 50%;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pane:fullscreen {\n padding: 1rem;\n background: var(--instui-background-color-page, #fff);\n}\n\n.pane-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n /* Also the drag handle for reordering panes (not resizing — see .split-handle for that). */\n cursor: grab;\n}\n\n.pane-toolbar.-dragging {\n cursor: grabbing;\n opacity: 0.6;\n}\n\n.pane.-drop-target {\n outline: 2px dashed var(--instui-color-stroke-brand, #0374b5);\n}\n\n#editor,\n#css-editor,\n#js-editor,\n#preview {\n flex: 1 1 auto;\n min-height: 0;\n width: 100%;\n}\n\n#preview {\n border: 1px solid #ccc;\n}\n\n.split-handle {\n flex: 0 0 0.375rem;\n cursor: col-resize;\n background: var(--instui-color-stroke-base, #d3d3d3);\n}\n\n.split-pane.-orientation-column > .split-handle {\n cursor: row-resize;\n}\n\n.split-handle:hover,\n.split-handle.-dragging {\n background: var(--instui-color-stroke-brand, #0374b5);\n}\n",
@@ -43,8 +35,8 @@ const SCAFFOLDS = {
43
35
  ".gitignore": "node_modules\ndist\n",
44
36
  "README.md": "# {{projectName}}\n\nA plain TypeScript app (via Vite) styled with\n[`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components), Instructure's\ndesign tokens and icons.\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `index.html` holds the actual page markup — a `wrapper`-layout shell from\n [`@pantoken/plugin-layouts`](https://www.npmjs.com/package/@pantoken/plugin-layouts). View source\n and edit it directly; nothing is injected by JavaScript.\n- `src/main.ts` imports `@pantoken/css` (defines every `--instui-*` custom property),\n `@pantoken/components/base.css` (document defaults + focus ring), `components.css`\n (`.instui-*` classes), `@pantoken/interactions` (wires up modal, tooltip, and other component\n behaviors out of the box), and your own `src/style.css` — add interactive behavior here.\n- Optional insertion points (header, filters, content, trailing) are marked with\n `<div data-slot=\"...\">` in `index.html` — replace their contents with your own markup.\n- Apply classes like `class=\"instui-button\"` to markup; see the\n [component reference](https://pantoken.app/api/css) for the full class list.\n\n## Learn more\n\nSee the [HTML guide](https://pantoken.app/guide/components) to learn more.\n",
45
37
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body class=\"instui-display-flex\">\n <div class=\"container\">\n <div class=\"header\">\n <div class=\"top\">\n <!-- breadcrumb -->\n <div class=\"utilities\"> <!-- optional -->\n <button class=\"instui-button\"></button>\n </div>\n </div>\n <div class=\"info\">\n <div class=\"title\">\n {{projectName}}\n </div>\n <div class=\"description\"> <!-- optional -->\n Styled with <code>@pantoken/components</code>.\n </div>\n </div>\n <div data-slot=\"header\"></div> <!-- optional -->\n <div class=\"actions\"> <!-- optional -->\n <button class=\"instui-button\"></button>\n </div>\n <div class=\"tabs\"> <!-- optional -->\n <!-- tabs -->\n </div>\n <div class=\"filters\"> <!-- optional -->\n <div data-slot=\"filters\"></div>\n </div>\n </div>\n <div class=\"content\">\n <div class=\"list\"></div> <!-- optional -->\n <div class=\"main\" data-slot=\"content\">\n <p>Get started building with pantoken.</p>\n <button class=\"instui-button -color-primary\" type=\"button\">Get started</button>\n </div>\n <div class=\"trailing\" data-slot=\"trailing\"></div> <!-- optional -->\n </div>\n </div>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
46
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/components\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
47
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
38
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/components\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
39
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
48
40
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
49
41
  "vite.config.ts": "import { defineConfig } from \"vite\";\n\nexport default defineConfig({});\n",
50
42
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\"]\n}\n",
@@ -57,8 +49,8 @@ const SCAFFOLDS = {
57
49
  ".gitignore": "node_modules\n.next\n",
58
50
  "README.md": "# {{projectName}}\n\nA Next.js (App Router) app styled with [`@pantoken/next`](https://www.npmjs.com/package/@pantoken/next),\nInstructure's design tokens and icons.\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `next.config.mjs` wraps the config with `withPantoken(...)` (adds pantoken to\n `transpilePackages`).\n- `app/layout.tsx` imports `@pantoken/css`, which defines every `--instui-*` custom\n property, at the root so it's available on every page, plus the `wrapper` layout's root class on\n `<body>` and `PantokenInteractions` (a client component that loads `@pantoken/interactions` —\n wires up modal, tooltip, and other component behaviors out of the box).\n- `app/page.tsx` renders markup styled with `instui-*` classes; optional insertion points (header,\n filters, content, trailing) are marked with `<div data-slot=\"...\">`.\n\n## Learn more\n\nSee the [getting started guide](https://pantoken.app/guide/getting-started) to learn more.\n",
59
51
  "next.config.mjs": "import { withPantoken } from \"@pantoken/next\";\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default withPantoken(nextConfig);\n",
60
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/next\": \"latest\",\n \"next\": \"^16.2.11\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
61
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
52
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/next\": \"latest\",\n \"next\": \"^16.2.11\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
53
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
62
54
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"jsx\": \"preserve\",\n \"strict\": true,\n \"skipLibCheck\": true,\n \"plugins\": [{ \"name\": \"next\" }]\n },\n \"include\": [\"app\", \"next-env.d.ts\"]\n}\n",
63
55
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\"]\n}\n",
64
56
  ".vscode/settings.json": "{\n \"html.customData\": [\"./node_modules/@pantoken/pantoken/dist/html-custom-data.json\"],\n \"css.customData\": [\"./node_modules/@pantoken/pantoken/dist/css-custom-data.json\"]\n}\n",
@@ -71,8 +63,8 @@ const SCAFFOLDS = {
71
63
  ".gitignore": "node_modules\ndist\n",
72
64
  "README.md": "# {{projectName}}\n\nA Vite + React app styled with [`@pantoken/react`](https://www.npmjs.com/package/@pantoken/react)\nand [`@pantoken/css`](https://www.npmjs.com/package/@pantoken/css), Instructure's design tokens and\nicons.\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.tsx` imports `@pantoken/css` (defines every `--instui-*` custom property) and\n `@pantoken/interactions` (wires up modal, tooltip, and other component behaviors out of the\n box).\n- `src/App.tsx` renders markup styled with `instui-*` classes; optional insertion points (header,\n filters, content, trailing) are marked with `<div data-slot=\"...\">`.\n- For InstUI's full React component library (buttons, modals, etc. — including `@pantoken/react`'s\n `<Icon>`), add the specific `@instructure/ui-*` packages you need — see <https://instructure.design>.\n\n## Learn more\n\nSee the [getting started guide](https://pantoken.app/guide/getting-started) to learn more.\n",
73
65
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"><\/script>\n </body>\n</html>\n",
74
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/react\": \"latest\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"@types/react\": \"^19.2.18\",\n \"@types/react-dom\": \"^19.2.5\",\n \"@vitejs/plugin-react\": \"^6.1.0\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
75
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
66
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/react\": \"latest\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"@types/react\": \"^19.2.18\",\n \"@types/react-dom\": \"^19.2.5\",\n \"@vitejs/plugin-react\": \"^6.1.0\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
67
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
76
68
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"jsx\": \"react-jsx\",\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
77
69
  "vite.config.ts": "import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\nexport default defineConfig({\n plugins: [react()],\n});\n",
78
70
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\"]\n}\n",
@@ -85,8 +77,8 @@ const SCAFFOLDS = {
85
77
  ".gitignore": "node_modules\ndist\n",
86
78
  "README.md": "# {{projectName}}\n\nA Vite + Svelte app styled with [`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components)\nand [`@pantoken/svelte`](https://www.npmjs.com/package/@pantoken/svelte) (icon action + token reads).\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.ts` calls `register()` (from `@pantoken/svelte`) once at bootstrap so elements like\n `<instui-icon>` work in templates, and imports the token CSS plus `@pantoken/interactions`\n (wires up modal, tooltip, and other component behaviors out of the box).\n- `src/App.svelte`'s markup is styled with `instui-*` classes; optional insertion points (header,\n filters, content, trailing) are marked with `<div data-slot=\"...\">`.\n- Apply classes like `class=\"instui-button\"` to markup; see the\n [component reference](https://pantoken.app/api/css) for the full class list.\n\n## Learn more\n\nSee the [getting started guide](https://pantoken.app/guide/getting-started) to learn more.\n",
87
79
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
88
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/svelte\": \"latest\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"@sveltejs/vite-plugin-svelte\": \"^7.3.0\",\n \"svelte\": \"^5.56.10\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
89
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
80
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/svelte\": \"latest\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"@sveltejs/vite-plugin-svelte\": \"^7.3.0\",\n \"svelte\": \"^5.56.10\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
81
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
90
82
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
91
83
  "vite.config.ts": "import { defineConfig } from \"vite\";\nimport { svelte } from \"@sveltejs/vite-plugin-svelte\";\n\nexport default defineConfig({\n plugins: [svelte()],\n});\n",
92
84
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\", \"svelte.svelte-vscode\"]\n}\n",
@@ -99,8 +91,8 @@ const SCAFFOLDS = {
99
91
  ".gitignore": "node_modules\ndist\n",
100
92
  "README.md": "# {{projectName}}\n\nA Vite + Vue 3 app styled with [`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components)\nand [`@pantoken/vue`](https://www.npmjs.com/package/@pantoken/vue) (the pantoken Vue plugin).\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.ts` calls `app.use(PantokenVue)` (from `@pantoken/vue`) so elements like\n `<instui-icon>` work in templates, and imports the token CSS plus `@pantoken/interactions`\n (wires up modal, tooltip, and other component behaviors out of the box).\n- `src/App.vue`'s template is styled with `instui-*` classes; optional insertion points (header,\n filters, content, trailing) are marked with `<div data-slot=\"...\">`.\n- Apply classes like `class=\"instui-button\"` to markup; see the\n [component reference](https://pantoken.app/api/css) for the full class list.\n\n## Learn more\n\nSee the [getting started guide](https://pantoken.app/guide/getting-started) to learn more.\n",
101
93
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
102
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/vue\": \"latest\",\n \"vue\": \"^3.5.41\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"@vitejs/plugin-vue\": \"^6.0.8\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\",\n \"vue-tsc\": \"^3.3.11\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
103
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
94
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/vue\": \"latest\",\n \"vue\": \"^3.5.41\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"@vitejs/plugin-vue\": \"^6.0.8\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\",\n \"vue-tsc\": \"^3.3.11\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
95
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
104
96
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
105
97
  "vite.config.ts": "import { defineConfig } from \"vite\";\nimport vue from \"@vitejs/plugin-vue\";\n\nexport default defineConfig({\n plugins: [vue()],\n});\n",
106
98
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\", \"Vue.volar\"]\n}\n",
@@ -113,8 +105,8 @@ const SCAFFOLDS = {
113
105
  ".gitignore": "node_modules\ndist\n",
114
106
  "README.md": "# {{projectName}}\n\nA plain TypeScript app (via Vite) styled with\n[`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components) and using\nframework-agnostic custom elements from\n[`@pantoken/web-components`](https://www.npmjs.com/package/@pantoken/web-components).\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.ts` imports `@pantoken/css` (defines every `--instui-*` custom property),\n `@pantoken/components/base.css` + `components.css` (`.instui-*` classes),\n `@pantoken/interactions` (wires up modal, tooltip, and other component behaviors out of the\n box), and `@pantoken/web-components` (auto-registers elements like `<instui-icon>`), then\n renders markup into `#app`.\n- Optional insertion points (header, filters, content, trailing) are marked with\n `<div data-slot=\"...\">` — replace their contents with your own markup.\n- Use custom elements directly in markup, e.g. `<instui-button>`, `<instui-alert variant=\"success\">` —\n see the [`@pantoken/web-components` README](https://www.npmjs.com/package/@pantoken/web-components)\n for the full element list.\n\n## Learn more\n\nSee the [HTML guide](https://pantoken.app/guide/components) to learn more.\n",
115
107
  "index.html": "<!doctype html>\n<html lang=\"{{locale}}\" dir=\"{{dir}}\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body class=\"instui-display-flex\">\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
116
- "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/components\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/web-components\": \"latest\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"ttf2woff2\"\n ]\n}\n",
117
- "pnpm-workspace.yaml": "# core-js/ttf2woff2 arrive transitively via @pantoken/pantoken; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
108
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/components\": \"latest\",\n \"@pantoken/css\": \"latest\",\n \"@pantoken/interactions\": \"latest\",\n \"@pantoken/web-components\": \"latest\"\n },\n \"devDependencies\": {\n \"@pantoken/pantoken\": \"latest\",\n \"typescript\": \"^7.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"allowScripts\": {\n \"core-js\": true,\n \"fsevents\": true,\n \"ttf2woff2\": true\n },\n \"trustedDependencies\": [\n \"core-js\",\n \"fsevents\",\n \"ttf2woff2\"\n ]\n}\n",
109
+ "pnpm-workspace.yaml": "# core-js/fsevents/ttf2woff2 arrive transitively; pre-approve their install scripts\n# so `pnpm install` doesn't fail/warn under pnpm's default strictDepBuilds gate.\nallowBuilds:\n core-js: true\n fsevents: true\n ttf2woff2: true\n# @pantoken/tokens pulls in a git-resolved upstream dependency several levels deep; pnpm's default\n# blockExoticSubdeps gate otherwise fails the install with ERR_PNPM_EXOTIC_SUBDEP.\nblockExoticSubdeps: false\n",
118
110
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"types\": [\"vite/client\"],\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
119
111
  "vite.config.ts": "import { defineConfig } from \"vite\";\n\nexport default defineConfig({});\n",
120
112
  ".vscode/extensions.json": "{\n \"recommendations\": [\"cssdoc.cssdoc-vscode\"]\n}\n",
@@ -567,19 +559,6 @@ const SCAFFOLD_OVERLAYS = {
567
559
  }
568
560
  };
569
561
  //#endregion
570
- //#region generated/preset-ledger.ts
571
- /**
572
- * Registry of all available pantoken scaffold presets, keyed by platform name.
573
- */
574
- const PRESET_LEDGER = {
575
- "components": presetComponents,
576
- "react": presetReact,
577
- "vue": presetVue,
578
- "web-components": presetWebComponents,
579
- "angular": presetAngular,
580
- "svelte": presetSvelte
581
- };
582
- //#endregion
583
562
  //#region generated/locale-registry.ts
584
563
  /** Text direction per supported BCP47 tag; its keys are the tags `--lang` accepts. */
585
564
  const LOCALE_DIRS = {
@@ -768,11 +747,50 @@ function validateThemeMode(value) {
768
747
  * installed and wired in. Standalone; usable via `npx @pantoken/scaffold <platform>` without
769
748
  * `@pantoken/ai`.
770
749
  *
771
- * Powered by Bingo presets: each platform exports a preset that defines its scaffold structure.
750
+ * Powered by generated template strings so the published CLI stays lean and package-manager-safe.
772
751
  *
773
752
  * @module
774
753
  * @alpha
775
754
  */
755
+ const SCAFFOLD_PM_COMMANDS = {
756
+ npm: {
757
+ install: "npm install",
758
+ dev: "npm run dev"
759
+ },
760
+ pnpm: {
761
+ install: "pnpm install",
762
+ dev: "pnpm run dev"
763
+ },
764
+ yarn: {
765
+ install: "yarn install",
766
+ dev: "yarn run dev"
767
+ },
768
+ bun: {
769
+ install: "bun install",
770
+ dev: "bun run dev"
771
+ },
772
+ deno: {
773
+ install: "deno install",
774
+ dev: "deno task dev"
775
+ },
776
+ vp: {
777
+ install: "vp install",
778
+ dev: "vp run dev"
779
+ }
780
+ };
781
+ const CDN_PROVIDER_IDS = [
782
+ "jsdelivr",
783
+ "unpkg",
784
+ "esmsh"
785
+ ];
786
+ const THEME_FONT_ASSETS = [{
787
+ package: "@pantoken/components",
788
+ path: "dist/fonts.css"
789
+ }];
790
+ const THEME_JS_ASSETS = [{
791
+ package: "@pantoken/interactions",
792
+ path: "dist/interactions.iife.js"
793
+ }];
776
794
  /**
777
795
  * Every scaffoldable platform key (discovered from available presets, plus any legacy
778
796
  * template-only platforms not yet backed by a preset).
@@ -784,7 +802,7 @@ function validateThemeMode(value) {
784
802
  * console.log(SCAFFOLD_PLATFORMS); // → ["components", "react", "vue", "web-components"]
785
803
  * ```
786
804
  */
787
- const SCAFFOLD_PLATFORMS = Array.from(/* @__PURE__ */ new Set([...Object.keys(PRESET_LEDGER), ...Object.keys(SCAFFOLDS)]));
805
+ const SCAFFOLD_PLATFORMS = Array.from(new Set(Object.keys(SCAFFOLDS))).sort();
788
806
  const SCAFFOLD_PLATFORM_SET = new Set(SCAFFOLD_PLATFORMS);
789
807
  /** Alternate platform names accepted alongside the canonical preset key (e.g. the pre-Bingo `html`). */
790
808
  const PLATFORM_ALIASES = {
@@ -812,39 +830,104 @@ function writeScaffoldFile(path, content) {
812
830
  mkdirSync(dirname(path), { recursive: true });
813
831
  writeFileSync(path, content);
814
832
  }
815
- /** Renders `resolvedPlatform`'s Bingo preset (if any) into `dir`; `[]` if there's no preset or it throws. */
816
- function writePresetFiles(resolvedPlatform, dir, projectName) {
817
- const preset = PRESET_LEDGER[resolvedPlatform];
818
- if (!preset) return [];
819
- try {
820
- const creation = producePreset(preset, {
821
- offline: true,
822
- options: { name: projectName }
823
- });
824
- return Object.entries(creation.files ?? {}).map(([file, rawContent]) => {
825
- const path = join(dir, file);
826
- writeScaffoldFile(path, rawContent instanceof ArrayBuffer ? Buffer.from(rawContent) : rawContent);
827
- return path;
828
- });
829
- } catch {
830
- return [];
831
- }
833
+ function shouldWriteScaffoldFile(file, packageManager) {
834
+ return file !== "pnpm-workspace.yaml" || !packageManager || packageManager === "pnpm" || packageManager === "vp";
835
+ }
836
+ function applyPackageManagerCommands(file, content, packageManager) {
837
+ if (!packageManager || file !== "README.md" || typeof content !== "string") return content;
838
+ const commands = SCAFFOLD_PM_COMMANDS[packageManager];
839
+ return content.replaceAll("npm install", commands.install).replaceAll("npm run dev", commands.dev);
832
840
  }
833
841
  /** Writes `resolvedPlatform`'s legacy `SCAFFOLDS` templates (for platforms with no preset yet). */
834
- function writeLegacyTemplateFiles(resolvedPlatform, dir, locale, substitutions) {
842
+ function writeLegacyTemplateFiles(resolvedPlatform, dir, locale, substitutions, packageManager) {
835
843
  const templates = SCAFFOLDS[resolvedPlatform];
836
844
  if (!templates) return [];
837
845
  const localized = {
838
846
  ...templates,
839
847
  ...SCAFFOLD_OVERLAYS[locale]?.[resolvedPlatform]
840
848
  };
841
- return Object.entries(localized).map(([file, content]) => {
842
- const substituted = Object.entries(substitutions).reduce((text, [token, value]) => text.replaceAll(`{{${token}}}`, value), content);
849
+ return Object.entries(localized).flatMap(([file, content]) => {
850
+ if (!shouldWriteScaffoldFile(file, packageManager)) return [];
851
+ const resolved = applyPackageManagerCommands(file, Object.entries(substitutions).reduce((text, [token, value]) => text.replaceAll(`{{${token}}}`, value), content), packageManager);
843
852
  const path = join(dir, file);
844
- writeScaffoldFile(path, substituted);
845
- return path;
853
+ writeScaffoldFile(path, resolved);
854
+ return [path];
846
855
  });
847
856
  }
857
+ function themeCssAssets(theme = "rebrand", mode = "light") {
858
+ return [
859
+ {
860
+ package: "@pantoken/css",
861
+ path: `dist/${theme === "canvas" ? "style.canvas.lean.css" : theme === "canvasHighContrast" ? "style.canvas-high-contrast.lean.css" : mode === "light" ? "style.rebrand.light.lean.css" : "style.lean.css"}`
862
+ },
863
+ {
864
+ package: "@pantoken/components",
865
+ path: "dist/base.css"
866
+ },
867
+ {
868
+ package: "@pantoken/components",
869
+ path: "dist/component-icons.css"
870
+ },
871
+ {
872
+ package: "@pantoken/components",
873
+ path: "dist/components.css"
874
+ },
875
+ {
876
+ package: "@pantoken/components",
877
+ path: "dist/utilities.css"
878
+ }
879
+ ];
880
+ }
881
+ function fileSpecifier(file) {
882
+ return `${file.package}/${file.path}`;
883
+ }
884
+ function cdnUrl(file, provider) {
885
+ const specifier = fileSpecifier(file);
886
+ if (provider === "unpkg") return `https://unpkg.com/${specifier}`;
887
+ if (provider === "esmsh") return `https://esm.sh/${specifier}?raw`;
888
+ return `https://cdn.jsdelivr.net/npm/${specifier}`;
889
+ }
890
+ function cdnImportLines(files, provider) {
891
+ if (provider === "jsdelivr" && files.length > 1) return `@import url("https://cdn.jsdelivr.net/combine/${files.map((file) => `npm/${fileSpecifier(file)}`).join(",")}");`;
892
+ return files.map((file) => `@import url("${cdnUrl(file, provider)}");`).join("\n");
893
+ }
894
+ function cdnScriptTags(files, provider) {
895
+ return files.map((file) => ` var script = document.createElement("script");\n script.src = "${cdnUrl(file, provider)}";\n document.head.appendChild(script);`).join("\n");
896
+ }
897
+ function resolveCdnProviderId(id) {
898
+ if (!id) return "jsdelivr";
899
+ if (CDN_PROVIDER_IDS.includes(id)) return id;
900
+ throw new Error(`Unknown CDN provider id "${id}". Valid ids: ${CDN_PROVIDER_IDS.join(", ")}.`);
901
+ }
902
+ function buildTheme(options = {}) {
903
+ const provider = resolveCdnProviderId(options.cdn);
904
+ return {
905
+ css: `/**
906
+ * Pantoken Canvas Theme Editor CSS.
907
+ * Upload this file in Canvas Theme Editor > Advanced > CSS.
908
+ */
909
+
910
+ /* Component styles */
911
+ ${cdnImportLines(themeCssAssets(options.theme, options.mode), provider)}
912
+ /* Fonts */
913
+ ${cdnImportLines(THEME_FONT_ASSETS, provider)}
914
+
915
+ /* Add custom CSS overrides below. */
916
+ `,
917
+ js: `/**
918
+ * Pantoken Canvas Theme Editor JavaScript.
919
+ * Upload this file in Canvas Theme Editor > Advanced > JavaScript.
920
+ */
921
+ (function pantokenTheme() {
922
+ "use strict";
923
+
924
+ ${cdnScriptTags(THEME_JS_ASSETS, provider)}
925
+ })();
926
+
927
+ /* Add custom JavaScript overrides below. */
928
+ `
929
+ };
930
+ }
848
931
  /**
849
932
  * Builds canvas-theme-editor's `theme.css`/`theme.js` for the chosen CDN provider/theme/mode at
850
933
  * scaffold time (rather than shipping a pre-baked jsDelivr/rebrand default); `[]` for every other
@@ -853,7 +936,7 @@ function writeLegacyTemplateFiles(resolvedPlatform, dir, locale, substitutions)
853
936
  function writeCanvasThemeEditorAssets(resolvedPlatform, dir, options) {
854
937
  if (resolvedPlatform !== "canvas-theme-editor") return [];
855
938
  const { css, js } = buildTheme({
856
- provider: options?.cdn,
939
+ cdn: options?.cdn,
857
940
  theme: options?.theme,
858
941
  mode: options?.mode
859
942
  });
@@ -888,14 +971,12 @@ async function scaffoldProject(platform, dir = ".", options) {
888
971
  const resolvedPlatform = resolveScaffoldPlatform(platform);
889
972
  const projectName = dir === "." ? "pantoken-app" : dir.split("/").pop() ?? "pantoken-app";
890
973
  const locale = options?.locale ?? "en";
891
- const substitutions = {
974
+ const written = writeLegacyTemplateFiles(resolvedPlatform, dir, locale, {
892
975
  projectName,
893
976
  pantokenCssImport: themeStylesheetImport(options?.theme, options?.mode),
894
977
  locale,
895
978
  dir: localeDirection(locale)
896
- };
897
- const written = writePresetFiles(resolvedPlatform, dir, projectName);
898
- if (written.length === 0) written.push(...writeLegacyTemplateFiles(resolvedPlatform, dir, locale, substitutions));
979
+ }, options?.packageManager);
899
980
  written.push(...writeCanvasThemeEditorAssets(resolvedPlatform, dir, options));
900
981
  return written;
901
982
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pantoken/scaffold",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "npx @pantoken/scaffold <platform> — scaffold a starter project (html, react, next, angular, web-components, ...) with pantoken already installed and wired in.",
5
5
  "homepage": "https://pantoken.app",
6
6
  "bugs": "https://github.com/thedannywahl/pantoken/issues",
@@ -31,21 +31,21 @@
31
31
  "dependencies": {
32
32
  "@bomb.sh/tab": "^0.0.22",
33
33
  "@clack/prompts": "^1.8.0",
34
+ "commander": "^15.0.0"
35
+ },
36
+ "devDependencies": {
34
37
  "@pantoken/angular": "0.1.30",
35
38
  "@pantoken/canvas-theme-editor": "0.2.0",
36
39
  "@pantoken/components": "1.1.2",
40
+ "@pantoken/i18n-engine": "0.3.0",
41
+ "@pantoken/plugin-layouts": "0.3.0",
37
42
  "@pantoken/react": "0.1.31",
38
43
  "@pantoken/scaffold-base": "0.3.0",
39
44
  "@pantoken/svelte": "0.1.31",
40
45
  "@pantoken/vue": "0.1.31",
41
46
  "@pantoken/web-components": "0.6.2",
42
- "bingo-stratum": "^0.5.13",
43
- "commander": "^15.0.0"
44
- },
45
- "devDependencies": {
46
- "@pantoken/i18n-engine": "0.3.0",
47
- "@pantoken/plugin-layouts": "0.3.0",
48
47
  "@types/node": "^26.5.0",
48
+ "bingo-stratum": "^0.5.13",
49
49
  "typescript": "^7.0.2",
50
50
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.1",
51
51
  "vite-plus": "0.3.1"