@keenmate/web-components-devkit 0.0.0-stage → 1.0.0-rc01

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.
Files changed (109) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/LICENSE +21 -0
  3. package/README.md +417 -2
  4. package/components.json +189 -0
  5. package/package.json +75 -4
  6. package/src/cli/args.js +16 -0
  7. package/src/cli/commands/check-release.js +66 -0
  8. package/src/cli/commands/check-vars.js +116 -0
  9. package/src/cli/commands/doctor.js +289 -0
  10. package/src/cli/commands/new.js +302 -0
  11. package/src/cli/commands/readme.js +111 -0
  12. package/src/cli/commands/sync.js +48 -0
  13. package/src/cli/kmwc.js +72 -0
  14. package/src/cli/sync-plan.js +163 -0
  15. package/src/config.d.ts +147 -0
  16. package/src/config.js +257 -0
  17. package/src/examples/auto.js +20 -0
  18. package/src/examples/chapter-nav.js +246 -0
  19. package/src/examples/constants.js +80 -0
  20. package/src/examples/controls-persistence.js +97 -0
  21. package/src/examples/copy-link.js +89 -0
  22. package/src/examples/css/base.css +215 -0
  23. package/src/examples/css/chapter-nav.css +179 -0
  24. package/src/examples/css/content.css +251 -0
  25. package/src/examples/css/controls.css +205 -0
  26. package/src/examples/css/copy-link.css +82 -0
  27. package/src/examples/css/demo.css +50 -0
  28. package/src/examples/css/index-page.css +118 -0
  29. package/src/examples/css/style.css +30 -0
  30. package/src/examples/css/theme-switch.css +38 -0
  31. package/src/examples/css/tokens.css +110 -0
  32. package/src/examples/css/widgets.css +133 -0
  33. package/src/examples/demo-code.js +30 -0
  34. package/src/examples/index-page.js +78 -0
  35. package/src/examples/index.d.ts +107 -0
  36. package/src/examples/index.js +18 -0
  37. package/src/examples/kit.js +22 -0
  38. package/src/examples/page-config.js +30 -0
  39. package/src/examples/sections.js +53 -0
  40. package/src/examples/theme-switch.js +72 -0
  41. package/src/examples/version-badge.js +23 -0
  42. package/src/playwright/index.d.ts +15 -0
  43. package/src/playwright/index.js +66 -0
  44. package/src/template.js +11 -0
  45. package/src/vite/index.d.ts +28 -0
  46. package/src/vite/index.js +243 -0
  47. package/src/vite/page-composer.js +209 -0
  48. package/templates/Dockerfile.tmpl +39 -0
  49. package/templates/Makefile.tmpl +136 -0
  50. package/templates/claude-block.md +40 -0
  51. package/templates/dockerignore.tmpl +10 -0
  52. package/templates/examples-layout.html +13 -0
  53. package/templates/new/.claude/commands/publish.md +226 -0
  54. package/templates/new/CHANGELOG.md +13 -0
  55. package/templates/new/LICENSE +21 -0
  56. package/templates/new/README.md +71 -0
  57. package/templates/new/_gitignore +7 -0
  58. package/templates/new/component-variables.manifest.json +32 -0
  59. package/templates/new/custom-elements-manifest.config.mjs +23 -0
  60. package/templates/new/docs/accessibility.md +24 -0
  61. package/templates/new/docs/examples.md +33 -0
  62. package/templates/new/docs/theming.md +54 -0
  63. package/templates/new/docs/usage.md +51 -0
  64. package/templates/new/e2e/dark-mode.spec.ts +30 -0
  65. package/templates/new/e2e/smoke.spec.ts +26 -0
  66. package/templates/new/examples-basic.html +57 -0
  67. package/templates/new/examples-theming.html +28 -0
  68. package/templates/new/index.html +16 -0
  69. package/templates/new/partials/note.html +5 -0
  70. package/templates/new/playwright.config.ts +4 -0
  71. package/templates/new/src/__FEATURE__.ts +55 -0
  72. package/templates/new/src/css/animations.css +1 -0
  73. package/templates/new/src/css/base.css +43 -0
  74. package/templates/new/src/css/controls.css +20 -0
  75. package/templates/new/src/css/dark-mode.css +36 -0
  76. package/templates/new/src/css/floating.css +1 -0
  77. package/templates/new/src/css/main.css +27 -0
  78. package/templates/new/src/css/states.css +22 -0
  79. package/templates/new/src/css/variables.css +40 -0
  80. package/templates/new/src/env.d.ts +7 -0
  81. package/templates/new/src/index.ts +17 -0
  82. package/templates/new/src/logger.ts +11 -0
  83. package/templates/new/src/types.ts +25 -0
  84. package/templates/new/src/web-component.ts +73 -0
  85. package/templates/new/test/dark-mode.html +18 -0
  86. package/templates/new/test/fixture.html +11 -0
  87. package/templates/new/tsconfig.json +15 -0
  88. package/templates/new/vite.config.ts +5 -0
  89. package/templates/new-minimal/CHANGELOG.md +13 -0
  90. package/templates/new-minimal/README.md +71 -0
  91. package/templates/new-minimal/component-variables.manifest.json +24 -0
  92. package/templates/new-minimal/docs/accessibility.md +20 -0
  93. package/templates/new-minimal/docs/examples.md +17 -0
  94. package/templates/new-minimal/docs/theming.md +53 -0
  95. package/templates/new-minimal/docs/usage.md +43 -0
  96. package/templates/new-minimal/e2e/smoke.spec.ts +10 -0
  97. package/templates/new-minimal/examples-basic.html +23 -0
  98. package/templates/new-minimal/examples-theming.html +28 -0
  99. package/templates/new-minimal/src/__FEATURE__.ts +37 -0
  100. package/templates/new-minimal/src/css/base.css +48 -0
  101. package/templates/new-minimal/src/css/controls.css +1 -0
  102. package/templates/new-minimal/src/css/states.css +1 -0
  103. package/templates/new-minimal/src/css/variables.css +26 -0
  104. package/templates/new-minimal/src/index.ts +17 -0
  105. package/templates/new-minimal/src/types.ts +10 -0
  106. package/templates/new-minimal/src/web-component.ts +48 -0
  107. package/templates/new-minimal/test/dark-mode.html +18 -0
  108. package/templates/new-minimal/test/fixture.html +11 -0
  109. package/templates/nginx.conf.tmpl +43 -0
@@ -0,0 +1,39 @@
1
+ # syntax=docker/dockerfile:1
2
+ {{HEADER}}
3
+ #
4
+ # Examples site for {{PACKAGE_NAME}}: Vite multi-page build → static nginx.
5
+
6
+ # ─────────────────────────────────────────────────────────────────────────────
7
+ # Stage 1 — build: `npm run build:examples` (= vite build --mode examples)
8
+ # ─────────────────────────────────────────────────────────────────────────────
9
+ FROM node:{{NODE_IMAGE}} AS build
10
+ WORKDIR /app
11
+
12
+ # Latest npm first — the bundled one can lag by weeks; newer npm ships registry
13
+ # hardening that reduces supply-chain exposure. Own layer, cached per base image.
14
+ RUN npm install -g npm@latest
15
+
16
+ # NOT `npm ci`: local lockfiles may resolve sibling packages (core, devkit) to
17
+ # file: links that don't exist in this build context. A plain install
18
+ # re-resolves them from the registry. Manifests first so this layer stays
19
+ # cached until dependencies change.
20
+ {{COPY_PACKAGE_JSONS}}
21
+ RUN {{INSTALL_COMMAND}}
22
+
23
+ # Source + build. The kmwc Vite plugin bundles each example page, injects the
24
+ # shared kit, stamps the version badge (BUILD_TIME, default: now) and adds the
25
+ # analytics snippet — no post-build sed.
26
+ COPY . .
27
+ ARG BUILD_TIME
28
+ ENV BUILD_TIME=${BUILD_TIME}
29
+ RUN npm run build:examples
30
+
31
+ # ─────────────────────────────────────────────────────────────────────────────
32
+ # Stage 2 — serve
33
+ # ─────────────────────────────────────────────────────────────────────────────
34
+ FROM nginx:alpine AS serve
35
+ COPY nginx.conf /etc/nginx/conf.d/default.conf
36
+ COPY --from=build /app/{{OUT_DIR}} /usr/share/nginx/html
37
+
38
+ EXPOSE 80
39
+ CMD ["nginx", "-g", "daemon off;"]
@@ -0,0 +1,136 @@
1
+ {{HEADER}}
2
+ #
3
+ # Repo-specific targets go in Makefile.local (included at the end; a target
4
+ # redefined there wins, with a make "overriding recipe" warning). Per-developer
5
+ # overrides (container runner, image name, port) go in .makefile.env.
6
+
7
+ .PHONY: help setup dev kill-port build build-examples preview-examples package publish-dry publish publish-rc clean check-version check-vars doctor sync test test-e2e test-e2e-ui test-e2e-headed test-e2e-install image-build image-run image-stop image-clean
8
+
9
+ -include .makefile.env
10
+ DOCKER_RUNNER ?= {{RUNNER}}
11
+ IMAGE_NAME ?= {{IMAGE_NAME}}
12
+ CONTAINER_NAME ?= {{CONTAINER_NAME}}
13
+ IMAGE_PORT ?= {{IMAGE_PORT}}
14
+ DEV_PORT := {{DEV_PORT}}
15
+ PREVIEW_PORT := {{PREVIEW_PORT}}
16
+
17
+ help: ## Show this help message
18
+ @echo "Available targets:"
19
+ @grep -hE '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-18s %s\n", $$1, $$2}'
20
+
21
+ setup: ## Install dependencies
22
+ npm install
23
+
24
+ dev: ## Start the dev server (examples on http://localhost:{{DEV_PORT}})
25
+ @rm -rf node_modules/.vite
26
+ npm run dev
27
+
28
+ # Free the dev + preview ports. Vite runs with strictPort, so a stale server is
29
+ # the only thing that can hold them. On Windows a PowerShell one-liner covers
30
+ # IPv4 + IPv6 listeners; `$$_` escapes make's `$` and the single quotes stop sh
31
+ # from expanding `$_` before PowerShell sees it.
32
+ kill-port: ## Free the dev/preview ports ({{DEV_PORT}}, {{PREVIEW_PORT}})
33
+ ifeq ($(OS),Windows_NT)
34
+ -@powershell -NoProfile -Command '$(DEV_PORT),$(PREVIEW_PORT) | ForEach-Object { Get-NetTCPConnection -LocalPort $$_ -State Listen -ErrorAction SilentlyContinue } | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object { Stop-Process -Id $$_ -Force -ErrorAction SilentlyContinue }'
35
+ else
36
+ -@for p in $(DEV_PORT) $(PREVIEW_PORT); do lsof -ti tcp:$$p | xargs -r kill -9; done
37
+ endif
38
+ @echo "Ports $(DEV_PORT), $(PREVIEW_PORT) are free"
39
+
40
+ build: ## Build the library (dist/)
41
+ npm run build
42
+
43
+ build-examples: ## Build the static examples site ({{OUT_DIR}}/)
44
+ npm run build:examples
45
+
46
+ preview-examples: build-examples ## Serve the built examples site (http://localhost:{{PREVIEW_PORT}})
47
+ npm run preview:examples
48
+
49
+ package: build ## Create an npm tarball
50
+ npm pack
51
+
52
+ publish-dry: ## Publish dry run (clean build first)
53
+ npm run clean:dist
54
+ npm run build
55
+ npm publish --dry-run
56
+
57
+ # Release gates (publish-command.md): the version must fit the dist-tag
58
+ # (latest = no pre-release suffix, rc = -rcN), must not be on npm yet, and the
59
+ # e2e suite must pass. `kmwc check-release` does the first two.
60
+ publish: ## Publish to npm as 'latest' (release versions only)
61
+ npx kmwc check-release --tag latest
62
+ @echo "WARNING: publishing to npm under the 'latest' dist-tag. Use 'make publish-rc' for pre-releases."
63
+ @$(CONFIRM)
64
+ npm run clean:dist
65
+ npm run build
66
+ ifneq ($(wildcard playwright.config.*),)
67
+ npm run test:e2e
68
+ endif
69
+ npm publish
70
+
71
+ publish-rc: ## Publish to npm under the 'rc' dist-tag (does NOT touch 'latest')
72
+ npx kmwc check-release --tag rc
73
+ @echo "WARNING: publishing to npm under the 'rc' dist-tag."
74
+ @$(CONFIRM)
75
+ npm run clean:dist
76
+ npm run build
77
+ ifneq ($(wildcard playwright.config.*),)
78
+ npm run test:e2e
79
+ endif
80
+ npm publish --tag rc
81
+
82
+ clean: ## Clean build artifacts
83
+ npm run clean
84
+
85
+ check-version: ## Show the current package version
86
+ @node -p "require('./package.json').version"
87
+
88
+ check-vars: ## Validate component-variables.manifest.json against the CSS
89
+ npx kmwc check-vars
90
+
91
+ doctor: ## Check this repo against the Keenmate component standard
92
+ npx kmwc doctor
93
+
94
+ sync: ## Regenerate devkit-owned files (Dockerfile, nginx.conf, Makefile, …)
95
+ npx kmwc sync
96
+
97
+ test: ## Run unit tests
98
+ npm test
99
+
100
+ test-e2e: ## Run Playwright e2e tests (headless)
101
+ npm run test:e2e
102
+
103
+ test-e2e-ui: ## Run Playwright e2e tests in UI mode
104
+ npm run test:e2e:ui
105
+
106
+ test-e2e-headed: ## Run Playwright e2e tests headed
107
+ npm run test:e2e:headed
108
+
109
+ test-e2e-install: ## Install the chromium browser binary (one-time)
110
+ npm run test:e2e:install
111
+
112
+ # ── Container image (examples site) ──────────────────────────────────────────
113
+
114
+ image-build: ## Build the examples container image
115
+ $(DOCKER_RUNNER) build --build-arg BUILD_TIME=$$(date -u +%Y-%m-%dT%H:%MZ) -t $(IMAGE_NAME) .
116
+
117
+ image-run: ## Run the examples image on IMAGE_PORT (default {{IMAGE_PORT}})
118
+ -@$(DOCKER_RUNNER) rm -f $(CONTAINER_NAME) >/dev/null 2>&1
119
+ $(DOCKER_RUNNER) run -d --name $(CONTAINER_NAME) -p $(IMAGE_PORT):80 $(IMAGE_NAME)
120
+ @echo "Serving examples at http://localhost:$(IMAGE_PORT)"
121
+
122
+ image-stop: ## Stop and remove the examples container
123
+ -@$(DOCKER_RUNNER) rm -f $(CONTAINER_NAME) >/dev/null 2>&1
124
+
125
+ image-clean: image-stop ## Remove the examples container and image
126
+ -@$(DOCKER_RUNNER) rmi $(IMAGE_NAME) >/dev/null 2>&1
127
+
128
+ ifeq ($(OS),Windows_NT)
129
+ CONFIRM = powershell -NoProfile -Command "Write-Host 'Press Enter to continue, Ctrl+C to cancel...'; Read-Host | Out-Null"
130
+ else
131
+ CONFIRM = read -p "Press Enter to continue, Ctrl+C to cancel... " _
132
+ endif
133
+
134
+ -include Makefile.local
135
+
136
+ .DEFAULT_GOAL := help
@@ -0,0 +1,40 @@
1
+ ## Shared infrastructure — `@keenmate/web-components-devkit` (read before touching examples/build files)
2
+
3
+ This repo follows the Keenmate component standard: the BlissFramework rulebook
4
+ (`C:\Git\BlissFramework\guidelines\web-components\` — structure, naming, CSS,
5
+ theming, README, CEM, publish) plus the devkit (`../web-components`, published
6
+ as `@keenmate/web-components-devkit`), which owns the example-site kit, the
7
+ Vite/Playwright configs and the deploy files. Do not re-create or patch those
8
+ locally — every local fork is how they drifted apart.
9
+
10
+ - **Never add** `examples-chapter-nav.js`, `examples-copy-link.js`,
11
+ `examples-controls-store.js`, `examples-shared.css`, `plausible-snippet.html`
12
+ or `scripts/check-variable-manifest.mjs`. The chapter nav, copy-link buttons,
13
+ shared styles, theme switch, version badge and analytics are injected into
14
+ every root `*.html` page by the Vite plugin automatically.
15
+ - **Generated — do not edit:** `Dockerfile`, `nginx.conf`, `Makefile`,
16
+ `.dockerignore` (they start with a `GENERATED by kmwc sync` header). Change
17
+ `package.json#kmwc` and run `npx kmwc sync`, or fix the template in the devkit.
18
+ Repo-specific make targets go in `Makefile.local`.
19
+ - **Per-component settings** (title, tagline, CSS prefix, ports, accent colours,
20
+ analytics id, image name, canonical origin) live **only** in `package.json#kmwc`.
21
+ - **Example page styles:** shared rules are in `@layer kmwc` and read
22
+ `--base-*` tokens (pages support light / dark / auto via the theme switch), so
23
+ any unlayered rule wins. Put component-only rules in `examples-local.css`.
24
+ Re-theme with `kmwc.theme.accentColor`, never by copying CSS. If a second
25
+ component needs a pattern, it belongs in the devkit.
26
+ - **Example pages are fragments:** no `<html>`/`<head>`/`<header>` — start with
27
+ `<meta name="kmwc:title" content="…">`, the devkit layout adds the rest. Shared text
28
+ goes in `partials/` via `<kmwc-include>`; show code with `<kmwc-demo>` (the live
29
+ markup IS the snippet) — never hand-copy a demo into a `.code-block`.
30
+ - **Controls persistence:**
31
+ `import { attachControlsPersistence } from '@keenmate/web-components-devkit/examples'`.
32
+ **Landing page:** `renderExamplesIndex({ pages })` from the same module.
33
+ - **Found a bug in a shared helper?** Fix it in `../web-components` (so every
34
+ component gets it), not here. Say so in your summary if you can't.
35
+ - **Never ship AI-assistant files:** `package.json` `files` must keep
36
+ `"!**/CLAUDE.md"` and `"!**/.claude"` (a `CLAUDE.md` you add under `src/` is
37
+ otherwise published with it).
38
+ - Before finishing: `npx kmwc doctor` must pass — it runs the devkit checks,
39
+ checks the `npm pack` file list for dev-only files, and runs the rulebook's
40
+ `*.checks.sh` suites.
@@ -0,0 +1,10 @@
1
+ {{HEADER}}
2
+ node_modules
3
+ **/node_modules
4
+ dist
5
+ {{OUT_DIR}}
6
+ test-results
7
+ playwright-report
8
+ .git
9
+ *.tgz
10
+ .makefile.env
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{DOCUMENT_TITLE}}</title>
7
+ {{ENTRY_SCRIPT_HTML}}
8
+ {{HEAD_HTML}}
9
+ </head>
10
+ <body{{BODY_ATTRIBUTES}}>
11
+ {{BODY_HTML}}
12
+ </body>
13
+ </html>
@@ -0,0 +1,226 @@
1
+ ---
2
+ description: Prepare {{PACKAGE_NAME}} for npm publish — bump version, finalize CHANGELOG/README, build, test, commit
3
+ argument-hint: rc|release|patch|minor|major
4
+ ---
5
+
6
+ # /publish — prepare an npm release of {{PACKAGE_NAME}}
7
+
8
+ You are preparing this package for `npm publish`. **Do not run `npm publish`** — the user logs in and publishes manually.
9
+
10
+ This command follows the canonical `/publish` structure defined in the BlissFramework component guidelines at
11
+ `web-components/publish-command.md`. Sections marked **[canonical]** are byte-identical across every
12
+ component's `/publish`; sections marked **[per-repo]** are customized for this repo's layout, build, and tests.
13
+
14
+ ## Argument [canonical]
15
+
16
+ The release type: **$ARGUMENTS**
17
+
18
+ Must be one of:
19
+
20
+ - `rc` — ship the WIP rc as-is. The topmost CHANGELOG heading (e.g. `## [1.10.0-rc02] - 2026-06-18`) gets ` [PUBLISHED]` appended.
21
+ - `release` — promote a WIP rc to a final release. `X.Y.Z-rcN` → `X.Y.Z`. CHANGELOG heading is renamed to match the new version.
22
+ - `patch` — SemVer patch bump. Drops any `-rc` suffix.
23
+ - `minor` — SemVer minor bump. Drops `-rc`. Resets patch.
24
+ - `major` — SemVer major bump. Drops `-rc`. Resets minor and patch.
25
+
26
+ If missing or invalid, stop and ask the user which one to use (don't guess).
27
+
28
+ ## Repo layout [per-repo]
29
+
30
+ Single-package repo, everything at root:
31
+
32
+ - **`./package.json`** — `version` field is the source of truth.
33
+ - **`./CHANGELOG.md`** — at the root. Topmost `## [X.Y.Z] - YYYY-MM-DD` heading **without** the `[PUBLISHED]` marker is the WIP section.
34
+ - **`./README.md`** — at the root. Carries `## What's New in vX.Y.Z` sections near the top (one per release, the **two most recent** retained).
35
+ - **`./dist/`** — gitignored. Produced by `npm run build` (custom-elements-manifest analyze + Vite). Never staged.
36
+ - **`./custom-elements.json`, `./web-types.json`, `./vscode.html-custom-data.json`, `./vscode.css-custom-data.json`** — generated by `npm run analyze` (part of the build) and **committed** (custom-elements-manifest D-CEM-2 = A).
37
+ - **`./component-variables.manifest.json`** — published with the package. Edit if the variable surface changes; `npm run check:vars` validates it.
38
+ - **`./docs/`** — usage / theming / examples / accessibility, published with the package.
39
+
40
+ ## CHANGELOG convention in this repo [canonical]
41
+
42
+ There is **no `## [Unreleased]` section**. The WIP section is the topmost `## [X.Y.Z] - YYYY-MM-DD` heading without a `[PUBLISHED]` tag. Already-released sections carry `[PUBLISHED]` at the end of their heading:
43
+
44
+ ```
45
+ ## [1.10.0-rc02] - 2026-06-18 ← WIP, the one you're shipping
46
+ ### Added
47
+ - ...
48
+
49
+ ## [1.9.0] - 2026-06-09 [PUBLISHED]
50
+ ### Added
51
+ - ...
52
+ ```
53
+
54
+ Publishing the WIP section means **appending ` [PUBLISHED]`** to its heading — exact format: `## [X.Y.Z] - YYYY-MM-DD [PUBLISHED]`. The next development cycle creates a fresh `## [next-version] - <date>` heading on its first CHANGELOG edit.
55
+
56
+ ## Resolve versions [canonical]
57
+
58
+ Read `./package.json` `version` as `CURRENT_VERSION`.
59
+ Read the topmost `## [X.Y.Z...]` heading from `./CHANGELOG.md` as `WIP_VERSION` (the version the latest WIP section is tagged for).
60
+
61
+ Compute `NEW_VERSION`:
62
+
63
+ | Argument | Logic |
64
+ |---|---|
65
+ | `rc` | If `CURRENT_VERSION` matches `X.Y.Z-rcN`, `NEW_VERSION = CURRENT_VERSION` (no bump — we're shipping what's already in package.json). If `CURRENT_VERSION` is not an rc, stop and ask the user (they probably wanted `release`/`patch`/etc.). |
66
+ | `release` | If `CURRENT_VERSION` matches `X.Y.Z-rcN`, `NEW_VERSION = X.Y.Z`. Otherwise stop. |
67
+ | `patch` | Strip any `-rcN`, then bump patch. |
68
+ | `minor` | Strip any `-rcN`, then bump minor, reset patch. |
69
+ | `major` | Strip any `-rcN`, then bump major, reset minor and patch. |
70
+
71
+ If `WIP_VERSION` ≠ `NEW_VERSION` (e.g. the WIP is `X.Y.Z-rcN` but the user asked for `release`), the CHANGELOG heading rename in step 3 also re-tags the section to `NEW_VERSION` — call this out in the report so the user notices.
72
+
73
+ ## Steps (in order)
74
+
75
+ ### 1. Sanity checks [canonical]
76
+
77
+ - Run `git status`. The repo intentionally keeps `.claude/`, `test-results/`, `playwright-report/` and `dist-examples/` untracked — those are fine. If there are **other** uncommitted changes that aren't `CHANGELOG.md`, `README.md`, or `package.json`, list them and ask the user before continuing. (Typical case: substantive source changes belonging in this release that haven't been committed yet — confirm they're intended for this version before bumping.)
78
+ - **Verify the new version isn't already on npm.** Run `npm view {{PACKAGE_NAME}}@<NEW_VERSION> version 2>/dev/null` — if it returns the version string, that version is already published and **stop**: bumping over it would fail at publish time and pollute the commit.
79
+ - **Verify the registry hasn't drifted past you.** Run `npm view {{PACKAGE_NAME}} version` to fetch the latest published version on the `latest` tag; if it's higher than `NEW_VERSION` (e.g. someone shipped from another machine, or there's a registry-vs-local mismatch from before the [PUBLISHED] convention landed), warn the user and ask before continuing.
80
+ - Confirm the WIP CHANGELOG section has at least one bullet of substantive content under `### Added`, `### Changed`, `### Removed`, `### Fixed`, or `### Internal`. If empty, stop — there's nothing meaningful to release.
81
+ - Confirm `./README.md` has a `## What's New in vWIP_VERSION` section. If it's missing, draft one from the CHANGELOG and present it to the user for approval before continuing:
82
+ - Read the WIP CHANGELOG section, distill it to 5–8 scannable bullets covering the Added/Changed themes (paraphrase, don't copy CHANGELOG bullets verbatim — those are exhaustive; What's New is the highlight reel). Pure internal refactors and Fixed-only entries don't need coverage, though headline bug fixes worth advertising are worth a bullet.
83
+ - **Follow the canonical "What's New" format** defined in the BlissFramework component guidelines (`web-components/readme-structure.md` → "`## What's New in vX.Y.Z` — canonical format"). Auto-check **C-RS-16** in `readme-structure.checks.sh` enforces it. Concretely:
84
+ - **Heading:** `## What's New in vNEW_VERSION` — lowercase `v`, no backticks around the version, no date.
85
+ - **Each bullet:** `- **<area or component> — <one-line headline>** — <engineer-level prose, 3–8 sentences>`. Bold-wrapped lead phrase, then a true em-dash (` — `, U+2014 with surrounding spaces), then a prose body explaining *what changed*, *why* (regression history / motivation), *what surface is affected* (concrete component / prop / file names listed inline), and *the mechanism* (the technique used). Plain hyphens or en-dashes fail the check.
86
+ - **No `### ` sub-headings** inside a What's New section — no `### Added` / `### Fixed` lifted from the CHANGELOG. It's a flat bullet list.
87
+ - **Reference implementation:** the `## What's New in v1.3.3` / `v1.3.2` sections at the top of `svelte-fluentui/README.md` are the canonical shape — mirror that voice and structure.
88
+ - Show the user the proposed draft as plain markdown in your reply. Ask whether to (a) insert as-is, (b) edit, or (c) abort so they can write it themselves.
89
+ - Only proceed past step 1 once the user approves the draft (or supplies their own). On approval, insert the section directly above the current top `## What's New in vX.Y.Z` heading in `./README.md`, then continue.
90
+ - Do not silently insert the draft without confirmation — release highlights are a writing call and the user owns the voice.
91
+
92
+ ### 2. Bump version (if needed) [canonical]
93
+
94
+ If `NEW_VERSION` ≠ `CURRENT_VERSION`, edit `./package.json` and change `"version": "CURRENT_VERSION"` to `"version": "NEW_VERSION"`.
95
+
96
+ For `rc` arg this is normally a no-op — version was bumped earlier in the development cycle.
97
+
98
+ ### 3. Finalize CHANGELOG [canonical]
99
+
100
+ In `./CHANGELOG.md`:
101
+
102
+ - If `WIP_VERSION` ≠ `NEW_VERSION` (e.g. promoting `X.Y.Z-rcN` → `X.Y.Z`), rename the WIP heading from `## [WIP_VERSION] - <date>` to `## [NEW_VERSION] - <today>` (today's date from system context).
103
+ - If `WIP_VERSION` == `NEW_VERSION`, leave the bracketed version alone but update the date to today **if** the existing date is stale (more than a few days old). The WIP date is usually whatever day the section was opened; refresh it so the changelog reflects the actual ship date.
104
+ - In either case, **append ` [PUBLISHED]`** to the heading so it reads exactly: `## [NEW_VERSION] - YYYY-MM-DD [PUBLISHED]`.
105
+ - Leave all bullet content untouched.
106
+ - **Do not** create an empty new WIP section — the next dev cycle's first CHANGELOG edit will create one.
107
+
108
+ ### 4. Update README "What's New" — only if version changed [canonical]
109
+
110
+ In `./README.md`:
111
+
112
+ - If the existing `## What's New in vWIP_VERSION` section's version differs from `NEW_VERSION` (e.g. promoting `X.Y.Z-rcN` → `X.Y.Z`), rename its heading to `## What's New in vNEW_VERSION`. (No content rewrites — the text was already curated for this release.)
113
+ - Then count the `## What's New in vX.Y.Z` headings. If there are more than **two**, delete the oldest ones so only the **two most recent** remain (the just-finalized one plus the one before it).
114
+
115
+ For `rc` arg this is normally a no-op on the heading itself — only trims if someone left an extra-old section behind.
116
+
117
+ ### 5. Validate README reflects the release [canonical]
118
+
119
+ Read both the finalized CHANGELOG section and the matching `What's New in vNEW_VERSION` section. Every **Added** or **Changed** bullet in the CHANGELOG that represents a user-facing feature or behavior change should have a corresponding hit in the What's New section (paraphrased, not verbatim). Pure internal refactors and `Fixed`-only entries don't need coverage, though headline bug fixes worth advertising (e.g. "X used to silently fail; now works") are worth a bullet.
120
+
121
+ If you find a significant CHANGELOG entry that isn't reflected in What's New, add a bullet for it. If the section ends up with more than ~8 bullets after this pass, condense — What's New should be scannable, not exhaustive.
122
+
123
+ ### 6. Validate CHANGELOG entries match recent work [canonical]
124
+
125
+ Find the previous `[PUBLISHED]` tag in CHANGELOG (the version just before NEW_VERSION) and locate the commit that bumped to it — usually a commit whose subject starts with `v<previous-version>` or `- v<previous-version>`. Run `git log --oneline <previous-publish-commit>..HEAD` to list commits since.
126
+
127
+ Also check `git diff` (or `git status`) for any uncommitted source/test work outside the files you're editing in this command.
128
+
129
+ For every substantive commit or uncommitted change, verify the WIP CHANGELOG section mentions it. If something significant is missing, **stop and ask the user** before finalizing — don't invent entries on their behalf. Pure example/doc tweaks and trivial typo fixes don't need entries.
130
+
131
+ ### 7. Run tests [per-repo]
132
+
133
+ Run `npm run test:e2e` (or equivalently `make test-e2e`). e2e tests via Playwright. All specs must pass.
134
+
135
+ If anything fails, **stop and report**. Do not proceed to build/commit. The user fixes the regression (or decides to fixme the spec) before the publish flow can continue.
136
+
137
+ If Playwright complains that chromium isn't installed, suggest `make test-e2e-install` and stop.
138
+
139
+ ### 8. Build the package [per-repo]
140
+
141
+ Run `npm run build` (or `make build`). This:
142
+ - Runs `npm run analyze` — regenerates `custom-elements.json`, `web-types.json` and the VS Code custom-data files.
143
+ - Runs Vite to emit `dist/{{FILE_NAME}}.js`, `dist/{{FILE_NAME}}.umd.js`, `dist/style.css`, and the type declarations.
144
+
145
+ If the build errors, stop and report.
146
+
147
+ After build, do a quick smoke check on the emitted artifacts:
148
+ - `dist/{{FILE_NAME}}.js` and `dist/{{FILE_NAME}}.umd.js` both exist and are non-empty.
149
+ - `dist/style.css` exists.
150
+ - `dist/index.d.ts` (or whatever the `types` field points to) exists.
151
+ - `git status` shows the regenerated CEM files only if the element API changed — stage them in step 10 if so.
152
+
153
+ ### 9. Verify the package contents [per-repo]
154
+
155
+ Run `npm pack --dry-run` and confirm the file list includes:
156
+
157
+ - `dist/` (built JS + d.ts files + style.css)
158
+ - `custom-elements.json`, `web-types.json`, `vscode.html-custom-data.json`, `vscode.css-custom-data.json`
159
+ - `component-variables.manifest.json`
160
+ - `docs/`
161
+ - `README.md`
162
+ - `LICENSE`
163
+ - `package.json`
164
+
165
+ If anything user-facing is missing or anything private leaked in (e.g. `test/`, `e2e/`, `examples-*.html`, `*.spec.ts`, `tsconfig.json`, `vite.config.ts`), stop and report — the `files` field in `package.json` controls this and the leak needs fixing before publish.
166
+
167
+ ### 10. Commit [canonical]
168
+
169
+ Stage:
170
+
171
+ - `./CHANGELOG.md`
172
+ - `./README.md`
173
+ - `./package.json`
174
+ - `./custom-elements.json`, `./web-types.json`, `./vscode.html-custom-data.json`, `./vscode.css-custom-data.json` (if the build regenerated them)
175
+
176
+ Do **not** stage `dist/` — it's gitignored.
177
+
178
+ Commit message format:
179
+
180
+ ```
181
+ vNEW_VERSION - <one-line summary of the headline change>
182
+
183
+ <grouped bullets paraphrased from the CHANGELOG section — split into the same
184
+ groups the CHANGELOG used: Added, Fixed, Changed, Internal, etc. Keep bullets
185
+ terse; full prose lives in the CHANGELOG.>
186
+
187
+ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
188
+ ```
189
+
190
+ ### 11. Report [canonical]
191
+
192
+ Report back with:
193
+
194
+ - The new version number
195
+ - The commit SHA
196
+ - The exact commands to publish. **Pick the right one for the arg type:**
197
+ - For `rc` (publishing a pre-release):
198
+ ```
199
+ npm login # if not already logged in
200
+ npm publish --tag rc
201
+ ```
202
+ The `--tag rc` is critical — without it npm assigns the `latest` dist-tag, which would make the pre-release the default install for everyone running `npm install {{PACKAGE_NAME}}`. With `--tag rc`, the `latest` tag stays put and consumers opt in via `@rc` or pinning the exact version.
203
+ - For `release` / `patch` / `minor` / `major` (publishing a stable release):
204
+ ```
205
+ npm login # if not already logged in
206
+ npm publish
207
+ ```
208
+ Or `make publish`. No `--tag` needed — it correctly lands as `latest`.
209
+ - A reminder that the CHANGELOG `[PUBLISHED]` tag is now in place — if `npm publish` fails, the user should revert both the tag (CHANGELOG heading) and the version bump (`package.json`) before retrying, since the registry will refuse to re-publish the same version.
210
+
211
+ ## Things not to do [canonical]
212
+
213
+ - **Do not run `npm publish`.** The user publishes manually after `npm login`.
214
+ - **Do not push to git remote.** The commit stays local until the user pushes.
215
+ - **Do not create an empty `[Unreleased]` or new WIP heading** in CHANGELOG after finalizing — the next dev cycle's first edit creates the next heading.
216
+ - **Do not retro-fix older CHANGELOG sections** that are missing the `[PUBLISHED]` tag or carry legacy markers — only finalize the section you're shipping.
217
+ - **Do not silently insert a drafted What's New section.** If you draft one in Step 1 because it's missing, you must present it and wait for explicit approval (or edits) before inserting — the writing voice is the user's call, even when you're handing them a starting point.
218
+ - **Do not keep more than two `## What's New in vX.Y.Z` sections in the README.** Step 4 trims older ones; if you see three or more after Step 4, you missed one.
219
+ - **Do not skip the build step** — without it `dist/` is stale and the publish would ship outdated artifacts (or fail entirely if `dist/` was wiped by `make clean`).
220
+ - **Do not skip the test gate** if the repo has one — the gate is what catches regressions before they ship.
221
+ - **Do not invent CHANGELOG entries** to cover commits you find; ask the user if something's missing.
222
+ - **Do not bump if there's nothing meaningful in the WIP section** — stop and explain.
223
+
224
+ ### Repo-specific don'ts
225
+
226
+ - **Do not stage `test/`, `e2e/`, `test-results/`, `playwright-report/` or `dist-examples/`** — they're either ignored or test artifacts.
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## [{{VERSION}}] - {{TODAY}}
4
+
5
+ ### Added
6
+
7
+ - Initial scaffold (`kmwc new`, `@keenmate/web-components-devkit`): `<{{TAG}}>` element (`{{ELEMENT_CLASS}}`) over the `{{LOGIC_CLASS}}` logic class, `label` / `active` inputs, `change` event with the `onChange` property twin.
8
+ - Canonical CSS set (`src/css/`, prefix `{{PREFIX}}`) with `@layer variables, component, overrides`, `--base-*` fallback chains and Strategy-B dark mode.
9
+ - Custom Elements Manifest (`custom-elements.json`, `web-types.json`, VS Code custom data) and `component-variables.manifest.json`.
10
+
11
+ ### Internal
12
+
13
+ - Intake: technology web-component · package `{{PACKAGE_NAME}}` · tag `<{{TAG}}>` · CSS prefix `{{PREFIX}}` (reserve it in BlissFramework `guidelines/web-components/base-variables.md`) · dev port {{DEV_PORT}}.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) {{YEAR}} Keenmate s.r.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,71 @@
1
+ # {{PACKAGE_NAME}}
2
+
3
+ > {{TAGLINE}}
4
+
5
+ ## What is it
6
+
7
+ `{{PACKAGE_NAME}}` is a custom element (`<{{TAG}}>`) built on
8
+ [`@keenmate/web-components-core`](https://www.npmjs.com/package/@keenmate/web-components-core).
9
+ It works in any HTML page or framework that can render a custom element —
10
+ React, Vue, Svelte, Blazor, plain HTML.
11
+
12
+ It reads `--base-*` variables from the page when `@keenmate/theme-designer`
13
+ is present, falls back to sensible light/dark defaults otherwise, and supports
14
+ per-instance dark mode via `data-theme`.
15
+
16
+ ## What's New in v{{VERSION}}
17
+
18
+ - **`<{{TAG}}>` — initial release** — First version, scaffolded with `kmwc new` from `@keenmate/web-components-devkit`. Ships the Element / Logic / Side-layer split, the canonical eight-file CSS set with `@layer variables, component, overrides`, light/dark defaults through `light-dark()` fallbacks, a Custom Elements Manifest for editor tooling, and a `change` event with an `onChange` property twin. See [CHANGELOG.md](./CHANGELOG.md).
19
+
20
+ ## Demos & docs
21
+
22
+ - 🚀 [Live demo](https://demos.keenmate.com/{{ID}})
23
+ - 📘 [Usage / API reference](./docs/usage.md)
24
+ - 🎨 [Theming contract](./docs/theming.md)
25
+ - 📚 [Examples / cookbook](./docs/examples.md)
26
+ - ♿ [Accessibility](./docs/accessibility.md)
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ npm install {{PACKAGE_NAME}}
32
+ ```
33
+
34
+ ## Quick start
35
+
36
+ ```html
37
+ <script type="module">
38
+ import '{{PACKAGE_NAME}}';
39
+ </script>
40
+
41
+ <{{TAG}} label="Hello"></{{TAG}}>
42
+ ```
43
+
44
+ Clicking toggles the `active` state and dispatches a `change` event
45
+ (`event.detail.isActive`). See [usage.md](./docs/usage.md) for the full API.
46
+
47
+ ## Browser support
48
+
49
+ Modern evergreen browsers (Chrome, Edge, Firefox, Safari) — anything with
50
+ native `customElements`, CSS `@layer` and `light-dark()` support. No polyfills
51
+ shipped.
52
+
53
+ ## About
54
+
55
+ Authored and maintained by [Keenmate s.r.o.](https://keenmate.com/).
56
+ The component ships standalone with sensible light/dark defaults;
57
+ when mounted inside [Pure Admin](https://pureadmin.io/) — or any
58
+ host that publishes the `--base-*` taxonomy via
59
+ [`@keenmate/theme-designer`](https://www.npmjs.com/package/@keenmate/theme-designer) — it adopts the host's colors,
60
+ typography, and sizing automatically. There is no runtime
61
+ dependency on Pure Admin; the integration is opt-in via CSS
62
+ variables.
63
+
64
+ ## Built with BlissFramework
65
+
66
+ Follows the [BlissFramework component guidelines](https://blissframework.dev/)
67
+ for structure, theming, color-scheme, and accessibility.
68
+
69
+ ## License
70
+
71
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,7 @@
1
+ node_modules/
2
+ dist/
3
+ dist-examples/
4
+ test-results/
5
+ playwright-report/
6
+ *.tgz
7
+ .makefile.env
@@ -0,0 +1,32 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/keenmate/schemas/main/component-variables.schema.json",
3
+ "component": "{{PACKAGE_NAME}}",
4
+ "prefix": "{{PREFIX}}",
5
+ "baseVariables": [
6
+ { "name": "base-main-bg", "required": false, "usage": "Component surface" },
7
+ { "name": "base-text-color-1", "required": false, "usage": "Label text" },
8
+ { "name": "base-border-color", "required": false, "usage": "Button border" },
9
+ { "name": "base-accent-color", "required": false, "usage": "Active state fill, focus outline" },
10
+ { "name": "base-text-color-on-accent", "required": false, "usage": "Label text in the active state" },
11
+ { "name": "base-hover-bg", "required": false, "usage": "Hover background (falls back to a text/surface color-mix)" },
12
+ { "name": "base-font-family", "required": false, "usage": "Font family" },
13
+ { "name": "base-font-size-base", "required": false, "usage": "Font size (multiplier × --{{PREFIX}}-rem)" },
14
+ { "name": "base-border-radius-md", "required": false, "usage": "Corner radius (multiplier × --{{PREFIX}}-rem)" },
15
+ { "name": "base-input-size-md-height", "required": false, "usage": "Minimum height (multiplier × --{{PREFIX}}-rem)" }
16
+ ],
17
+ "componentVariables": [
18
+ { "name": "{{PREFIX}}-rem", "category": "spacing", "usage": "Base unit for every size (default 10px; 1rem follows the page font size)" },
19
+ { "name": "{{PREFIX}}-bg", "category": "surface", "usage": "Component surface" },
20
+ { "name": "{{PREFIX}}-text-color-1", "category": "text", "usage": "Label text" },
21
+ { "name": "{{PREFIX}}-border-color", "category": "border", "usage": "Button border" },
22
+ { "name": "{{PREFIX}}-accent-color", "category": "accent", "usage": "Active state fill, focus outline" },
23
+ { "name": "{{PREFIX}}-text-color-on-accent", "category": "text", "usage": "Label text in the active state" },
24
+ { "name": "{{PREFIX}}-hover-bg", "category": "state", "usage": "Hover background" },
25
+ { "name": "{{PREFIX}}-font-family", "category": "typography", "usage": "Font family" },
26
+ { "name": "{{PREFIX}}-font-size-base", "category": "typography", "usage": "Font size" },
27
+ { "name": "{{PREFIX}}-root-border-radius", "category": "radius", "usage": "Corner radius" },
28
+ { "name": "{{PREFIX}}-root-min-height", "category": "spacing", "usage": "Minimum height" },
29
+ { "name": "{{PREFIX}}-root-padding-block", "category": "spacing", "usage": "Vertical padding" },
30
+ { "name": "{{PREFIX}}-root-padding-inline", "category": "spacing", "usage": "Horizontal padding" }
31
+ ]
32
+ }
@@ -0,0 +1,23 @@
1
+ import { blissAnalyzerConfig, cssVariablesFromManifestPlugin } from '@keenmate/web-components-core/cem';
2
+ import { customElementVsCodePlugin } from 'custom-element-vs-code-integration';
3
+ import { customElementJetBrainsPlugin } from 'custom-element-jet-brains-integration';
4
+
5
+ /**
6
+ * Custom Elements Manifest (custom-elements-manifest.md). Core's
7
+ * blissAnalyzerConfig() reads the `static inputs` / `static events` tables
8
+ * (ATTRIBUTE_TABLE) straight from the AST, so attributes, properties and events
9
+ * in custom-elements.json come from the same table the runtime uses.
10
+ * cssVariablesFromManifestPlugin() adds the --{{PREFIX}}-* surface from
11
+ * component-variables.manifest.json; the editor plugins then emit
12
+ * vscode.html-custom-data.json / vscode.css-custom-data.json / web-types.json.
13
+ */
14
+ export default blissAnalyzerConfig({
15
+ globs: ['src/**/*.ts'],
16
+ exclude: ['src/**/*.spec.ts', 'src/**/*.test.ts', 'src/**/*.d.ts', 'src/index.ts'],
17
+ outdir: '.',
18
+ plugins: [
19
+ cssVariablesFromManifestPlugin(),
20
+ customElementVsCodePlugin({ outdir: '.' }),
21
+ customElementJetBrainsPlugin({ outdir: '.', packageJson: false }),
22
+ ],
23
+ });