kempo-ui 0.4.8 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,91 +0,0 @@
1
- ---
2
- name: highlight-code
3
- description: Generates syntax-highlighted HTML for documentation code samples. USE THIS instead of hand-writing <pre><code class="hljs ..."> blocks or creating temporary scripts. Run via `npx kempo-highlightcode <lang>` with code piped on stdin.
4
- ---
5
-
6
- # Highlight Code
7
-
8
- ## When to Use
9
-
10
- Use this skill whenever you need syntax-highlighted HTML to embed in a documentation page — for example, when adding or updating a `<pre><code class="hljs ...">` block in a `docs-src/components/*.page.html` file. **Do not hand-write the highlighted markup, and do not create temporary scripts to do this.**
11
-
12
- > Source files live in `docs-src/` and are pre-rendered to `docs/` by the kempo-server templating system. Always edit the `*.page.html` source — never the generated `docs/*.html`.
13
-
14
- ## Usage
15
-
16
- Pipe code via stdin (supports multi-line):
17
-
18
- **bash / zsh:**
19
- ```bash
20
- cat <<'EOF' | npx kempo-highlightcode <lang>
21
- <div class='container'>
22
- <h1>Hello</h1>
23
- </div>
24
- EOF
25
- ```
26
-
27
- **PowerShell:**
28
- ```powershell
29
- @"
30
- <div class='container'>
31
- <h1>Hello</h1>
32
- </div>
33
- "@ | npx kempo-highlightcode <lang>
34
- ```
35
-
36
- Or pass minified code as an argument (works in any shell):
37
- ```bash
38
- npx kempo-highlightcode <lang> "<div class='container'><h1>Hello</h1></div>"
39
- ```
40
-
41
- **Supported languages:** `html`, `css`, `js` / `javascript`, `ts` / `typescript`, `json`, `md` / `markdown`, `sh` / `bash`, `xml`
42
-
43
- ## Output
44
-
45
- Prints a complete `<pre><code class="hljs {lang}">…</code></pre>` block to stdout, with `<br>` tags instead of newlines — a single line suitable for embedding directly in HTML.
46
-
47
- Input is automatically beautified before highlighting, so you can pass minified code.
48
-
49
- ## Workflow for Updating Doc Code Samples
50
-
51
- 1. Capture the highlighted block to a shell variable (or a temp file):
52
-
53
- **bash / zsh:**
54
- ```bash
55
- HL=$(cat <<'EOF' | npx kempo-highlightcode xml
56
- <k-table id=myExample></k-table>
57
- <script type=module>
58
- doSomething('foo');
59
- </script>
60
- EOF
61
- )
62
- ```
63
-
64
- **PowerShell:**
65
- ```powershell
66
- $hl = @"
67
- <k-table id=myExample></k-table>
68
- <script type=module>
69
- doSomething('foo');
70
- </script>
71
- "@ | npx kempo-highlightcode xml
72
- ```
73
-
74
- 2. Replace the existing `<pre><code class="hljs xml">…</code></pre>` block in `docs-src/components/<name>.page.html` with the new value:
75
- - **In an editor / Claude Edit tool / VS Code Copilot edit:** find the existing `<pre><code class="hljs xml">…</code></pre>` block and replace it. This handles escaping correctly.
76
- - **In PowerShell scripts** (legacy): use `[System.IO.File]::ReadAllText` + `.Replace()` (not `-replace`) to avoid regex interpretation:
77
- ```powershell
78
- $path = Resolve-Path 'docs-src/components/my-component.page.html'
79
- $html = [System.IO.File]::ReadAllText($path)
80
- $old = [regex]::Match($html, '(?s)<pre><code class="hljs xml">.*?</code></pre>').Value
81
- [System.IO.File]::WriteAllText($path, $html.Replace($old, $hl))
82
- ```
83
-
84
- ## Important Notes
85
-
86
- - Use **single-quotes** for JS string literals inside the code. This preserves all quoting correctly through to node.
87
- - HTML attribute values can be **unquoted** in the argument (`id=foo` not `id="foo"`) — the beautifier adds consistent formatting anyway.
88
- - When piping multi-line code in bash/zsh, use a **quoted heredoc** (`<<'EOF'`) so the shell does not interpolate `$`, backticks, or backslashes inside the code. PowerShell here-strings (`@"…"@`) handle this without extra quoting.
89
- - If a page has multiple `<pre><code>` blocks, include enough surrounding context in your replace target to make the match unique (e.g. include the nearby `<h3>` or `<k-card label="HTML">` wrapper).
90
- - The beautifier handles indentation and formatting automatically.
91
- - Output uses `<br>` instead of `\n`, keeping the block on one line in the HTML source.
@@ -1,363 +0,0 @@
1
- ---
2
- name: new-component
3
- description: Creates a new Kempo UI web component end-to-end — choosing the right base class, writing the source file, registering the custom element, adding the docs page, wiring up the nav/index/llms.txt, AND writing tests. Use any time you are asked to create a new component or add a new custom element.
4
- ---
5
-
6
- # New Component
7
-
8
- ## When to Use
9
-
10
- Use this skill any time you are asked to create a new component or add a new custom element to the project.
11
-
12
- ---
13
-
14
- ## Overview
15
-
16
- Creating a component involves six steps. Do not skip steps — especially the tests.
17
-
18
- 1. **Choose the base component** — pick the right rendering strategy
19
- 2. **Write the source file** in `src/components/` (also registers the custom element)
20
- 3. **Read the templating primer** so the docs page is structured correctly
21
- 4. **Add the documentation page** in `docs-src/components/` and wire up nav/index/llms.txt
22
- 5. **Write and run unit tests** in `tests/components/`
23
- 6. **Verify in the browser** at `http://localhost:8083`
24
-
25
- ---
26
-
27
- ## Step 1: Choose the Base Component
28
-
29
- Three base classes are available. Pick based on rendering needs:
30
-
31
- ### `ShadowComponent`
32
- Use when the component needs shadow DOM encapsulation. The base class automatically injects the kempo-css stylesheet into the shadow root. **This is the default for most components.**
33
-
34
- ```javascript
35
- import { html, css } from '../lit-all.min.js';
36
- import ShadowComponent from './ShadowComponent.js';
37
-
38
- export default class MyComponent extends ShadowComponent {
39
- render() {
40
- return html`<p>Shadow DOM content with scoped styles</p>`;
41
- }
42
- }
43
- ```
44
-
45
- ### `LightComponent`
46
- Use when the component renders to the light DOM (no encapsulation, inherits page styles). Override `renderLightDom()`.
47
-
48
- ### `HybridComponent`
49
- Use when the component needs both a shadow DOM portion and a light DOM portion (e.g. slotted children that also need managed light DOM output). Override both `render()` and `renderLightDom()`.
50
-
51
- **Important:** Always call `super.updated(...)` when overriding `updated()` in any base class.
52
-
53
- ---
54
-
55
- ## Step 2: Write the Source File
56
-
57
- Create `src/components/MyComponent.js`. Follow these conventions (also see [AGENTS.md](../../../AGENTS.md)):
58
-
59
- - Use multi-line comments to separate logical sections: `Lifecycle Callbacks`, `Event Handlers`, `Public Methods`, `Utility`, `Rendering`, `Styles`.
60
- - Declare reactive properties with `static properties = { ... }` and initialize defaults in the constructor.
61
- - Use `static styles = css\`...\`` for component-scoped CSS (shadow DOM only).
62
- - Use **arrow functions** for class methods to avoid `.bind(this)`.
63
- - For private fields use native JS private fields (`#field`) — never underscore-prefixed.
64
- - For form-associated components: set `static formAssociated = true`, call `this.attachInternals()` in the constructor, and use `internals.setFormValue(...)` / `internals.setValidity(...)`.
65
- - **Buttons inside the shadow DOM should have `class="no-btn"`** to opt out of kempo-css's default button styling. Add explicit `display: inline-flex; align-items: center; justify-content: center;` in the component CSS to keep content centered after stripping. The same applies to `class="no-style"` on `<select>` / `<input>` if you need to fully opt out, but most form controls render fine with kempo-css defaults.
66
-
67
- Example skeleton:
68
-
69
- ```javascript
70
- import { html, css } from '../lit-all.min.js';
71
- import ShadowComponent from './ShadowComponent.js';
72
-
73
- export default class MyComponent extends ShadowComponent {
74
- static properties = {
75
- value: { type: String, reflect: true },
76
- disabled: { type: Boolean, reflect: true }
77
- };
78
-
79
- /*
80
- Lifecycle Callbacks
81
- */
82
- constructor() {
83
- super();
84
- this.value = '';
85
- this.disabled = false;
86
- }
87
-
88
- /*
89
- Event Handlers
90
- */
91
- handleClick = () => {
92
- if(this.disabled) return;
93
- this.dispatchEvent(new CustomEvent('change', {
94
- detail: { value: this.value },
95
- bubbles: true
96
- }));
97
- };
98
-
99
- /*
100
- Rendering
101
- */
102
- render() {
103
- return html`
104
- <button class="no-btn btn" ?disabled=${this.disabled} @click=${this.handleClick}>
105
- ${this.value}
106
- </button>
107
- `;
108
- }
109
-
110
- /*
111
- Styles
112
- */
113
- static styles = css`
114
- :host { display: inline-block; }
115
- .btn {
116
- display: inline-flex;
117
- align-items: center;
118
- justify-content: center;
119
- padding: var(--spacer_h) var(--spacer);
120
- border: 1px solid var(--c_border);
121
- border-radius: var(--radius);
122
- background: var(--c_bg);
123
- color: var(--tc);
124
- cursor: pointer;
125
- }
126
- `;
127
- }
128
-
129
- customElements.define('k-my-component', MyComponent);
130
- ```
131
-
132
- ### Custom element naming
133
- - All elements use the `k-` prefix (e.g. `k-spinner`, `k-color-picker`).
134
- - Use kebab-case for multi-word names.
135
- - The `customElements.define(...)` call goes at the **bottom** of the file, after the class.
136
-
137
- ---
138
-
139
- ## Step 3: kempo-server Templating Primer
140
-
141
- The docs site is built with the **kempo-server v3 templating system**. Source files live in `docs-src/`; production pages are pre-rendered into `docs/` at build time. **Do not edit anything inside `docs/components/` directly — those files are generated.**
142
-
143
- ### File types
144
-
145
- | Suffix | Purpose | Example |
146
- |---|---|---|
147
- | `*.page.html` | An individual page. Wraps content in `<page>` and fills template slots with `<content>` blocks. | `docs-src/components/slider.page.html` |
148
- | `*.template.html` | Shared layout. Defines named slots with `<location>` and pulls in fragments with `<fragment name="..." />`. | `docs-src/default.template.html` |
149
- | `*.fragment.html` | Reusable HTML partial. Included via `<fragment name="..." />` from templates or pages. | `docs-src/nav.fragment.html` |
150
- | `*.global.html` | Site-wide content auto-injected into matching `<location>` tags across every page. | (none currently) |
151
-
152
- ### How a page renders
153
-
154
- 1. The `<page>` tag chooses a template (defaults to `default`, looked up upward from the page directory). For component docs that's `docs-src/default.template.html`.
155
- 2. Each `<content>` block in the page fills a `<location>` slot in the template:
156
- - `<content>` (no `location`) fills `<location />` (the unnamed default slot — body content).
157
- - `<content location="scripts">` fills `<location name="scripts" />` (`<script type="module">` tags at the end of `<body>`).
158
- - `<content location="header">` fills `<location name="header">` (overrides the default `<h1>` heading).
159
- 3. Page tag attributes become template variables: `<page pageName="Slider" title="...">` makes `{{pageName}}` and `{{title}}` available throughout the template.
160
- 4. The `<fragment name="nav" />` call in the template pulls in `docs-src/nav.fragment.html`, which renders the navbar and side menu.
161
- 5. Path variables: **`{{pathToRoot}}`** is the relative path back to `docs-src/` — use it for every asset reference. The renderer substitutes the correct number of `../` segments based on the page's depth. Other built-ins include `{{year}}`, `{{date}}`, `{{datetime}}`, `{{timestamp}}`, `{{version}}`, `{{env}}`.
162
- 6. Templates and fragments resolve **upward** from the referencing page directory (nearest match wins). Pages and globals scan **downward** (recursively).
163
-
164
- ### Conditionals and loops
165
-
166
- The templating engine supports:
167
- - `<if condition="..."> … </if>` with `===`, `!==`, `>`, `<`, `>=`, `<=`, `&&`, `||`, `!`
168
- - `<foreach in="arrayName" as="item"> {{item.name}} </foreach>` with dot-path access
169
-
170
- ### Dev server
171
-
172
- A dev server is already running on `http://localhost:8083` (started via `npm run dev`). It uses SSR for `docs-src/`, so your changes appear on refresh without a build. Static assets in `docs/` (CSS, media, manifest) are served via customRoutes. **Do not start another server.**
173
-
174
- For production, `npm run build` minifies the JS, copies icons, and pre-renders all pages from `docs-src/` into `docs/`.
175
-
176
- ---
177
-
178
- ## Step 4: Add the Documentation Page
179
-
180
- Create `docs-src/components/my-component.page.html`. Use an existing page (e.g. [`slider.page.html`](../../../docs-src/components/slider.page.html), [`time.page.html`](../../../docs-src/components/time.page.html)) as a structural reference. Recommended sections:
181
-
182
- - A Table of Contents accordion at the top
183
- - Examples (Basic Usage, Default Value, mode-specific examples, etc.)
184
- - A `<h2 id="jsRef">JavaScript Reference</h2>` section covering: Constructor, Requirements, Properties, Methods, CSS Variables, Events
185
- - Module script tags inside `<content location="scripts">`
186
-
187
- ```html
188
- <page pageName="My Component" title="My Component - Components - Kempo Docs - A Web Components Solution">
189
- <content>
190
- <k-accordion persistent-id="toc" class="b r mb">
191
- <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
192
- <k-accordion-panel name="toc-panel">
193
- <!-- TOC links -->
194
- </k-accordion-panel>
195
- </k-accordion>
196
-
197
- <h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
198
- <!-- examples -->
199
-
200
- <h2 id="jsRef"><a href="#jsRef" class="no-link">JavaScript Reference</a></h2>
201
- <!-- properties / methods / events -->
202
- </content>
203
- <content location="scripts">
204
- <script type="module" src="{{pathToRoot}}src/components/MyComponent.js"></script>
205
- <script type="module" src="{{pathToRoot}}src/components/Accordion.js"></script>
206
- <script type="module" src="{{pathToRoot}}src/components/Card.js"></script>
207
- </content>
208
- </page>
209
- ```
210
-
211
- Use `{{pathToRoot}}` for any relative path. **Do not** add `<!DOCTYPE html>`, `<html>`, `<head>`, `<body>`, or a `<k-import>` for the nav — those come from the template.
212
-
213
- ### Code Samples in the Docs
214
-
215
- For every `<pre><code class="hljs ...">` block, **use the [highlight-code skill](../highlight-code/SKILL.md)** to generate the markup. Do not hand-write the highlighted HTML — it is fragile and error-prone.
216
-
217
- ```bash
218
- cat <<'EOF' | npx kempo-highlightcode xml
219
- <k-my-component value="hello"></k-my-component>
220
- EOF
221
- ```
222
-
223
- Then paste the result into the page.
224
-
225
- ### Wire Up Nav, Index, and llms.txt
226
-
227
- After creating the page, add the component in **four** places, all in alphabetical order:
228
-
229
- #### 1. Search filter dropdown — [`docs-src/nav.fragment.html`](../../../docs-src/nav.fragment.html)
230
-
231
- Inside `<k-filter-list id="navSearchList">`, add a `<k-filter-item>`:
232
-
233
- ```html
234
- <k-filter-item filter-keywords="my component mycomponent keywords here components"><a
235
- href="{{pathToRoot}}components/my-component.html"
236
- >My Component<br><small>Component</small></a></k-filter-item>
237
- ```
238
-
239
- **WATCH OUT:** When inserting a new filter-item with a search-and-replace tool, do **not** truncate the `<a` of the surrounding filter-item. Always re-read the file after each edit to verify nothing was clipped.
240
-
241
- #### 2. Sidebar menu link — same `nav.fragment.html`
242
-
243
- Inside the `<menu>` block under `<h3>Components</h3>`, add an `<a>` tag in alphabetical order:
244
-
245
- ```html
246
- <a href="{{pathToRoot}}components/my-component.html">My Component</a>
247
- ```
248
-
249
- #### 3. Homepage card — [`docs-src/index.page.html`](../../../docs-src/index.page.html)
250
-
251
- Inside the `<div class="row -mx">` under `<h2>Components</h2>`, add a card in alphabetical order:
252
-
253
- ```html
254
- <div class="span-12 t-span-6 d-span-4 px">
255
- <a href="{{pathToRoot}}components/my-component.html" class="card mb no-link d-b">
256
- <h3 class="tc-primary">My Component</h3>
257
- <p class="tc-muted">One-sentence description of what the component does.</p>
258
- </a>
259
- </div>
260
- ```
261
-
262
- #### 4. LLM reference — [`llms.txt`](../../../llms.txt)
263
-
264
- Add a row to the **Components** table (alphabetical by element name):
265
-
266
- ```markdown
267
- | `<k-my-component>` | `MyComponent.js` | One-sentence description with key attributes and events | [my-component.html](https://dustinpoissant.github.io/kempo-ui/components/my-component.html) |
268
- ```
269
-
270
- If the component registers multiple elements (e.g. parent + child), list all element names in the first column separated by spaces.
271
-
272
- ---
273
-
274
- ## Step 5: Write and Run Unit Tests
275
-
276
- **This step is required.** Skipping tests is a common mistake — AGENTS.md says "ALL tests must pass — ZERO failures are acceptable."
277
-
278
- Create `tests/components/MyComponent.browser-test.js`. Use [`Toggle.browser-test.js`](../../../tests/components/Toggle.browser-test.js) or [`Slider.browser-test.js`](../../../tests/components/Slider.browser-test.js) as a reference.
279
-
280
- Conventions:
281
- - Import the component class at the top.
282
- - Define an async `createMyComponent(attrs = {})` helper that builds the DOM, appends to `document.body`, awaits `el.updateComplete`, and returns `{ container, el }`.
283
- - Define a `cleanup(container)` helper that removes the container from the DOM.
284
- - Export a default plain object where each key is a test description and each value is an `async ({pass, fail}) => {}` function.
285
- - Always call `cleanup(container)` before every `pass()` or `fail()` call.
286
- - Use multi-line comments to group related tests (`/* Element Creation */`, `/* Properties */`, etc.).
287
-
288
- Tests to include at minimum:
289
-
290
- - Element is created and is an instance of the component class
291
- - Element has a shadow root (when applicable)
292
- - Default property values are correct
293
- - Attribute reflection works (when `reflect: true`)
294
- - Public methods behave correctly
295
- - Events are dispatched correctly with the right `detail` shape
296
- - For form-associated components: form submission produces the expected value
297
-
298
- Run the tests after writing them:
299
-
300
- ```bash
301
- npm run test -- MyComponent
302
- ```
303
-
304
- The partial string `MyComponent` matches any test file path containing it. Fix any failures before considering the component complete. Zero failures.
305
-
306
- ---
307
-
308
- ## Step 6: Verify in the Browser
309
-
310
- The dev server is running on `http://localhost:8083` (don't start another).
311
-
312
- - Navigate to `http://localhost:8083/components/my-component.html`
313
- - Interact with the rendered output — golden path AND edge cases
314
- - Confirm form-associated behavior by submitting an actual `<form>`
315
- - Watch for console errors that aren't pre-existing
316
-
317
- If you cannot test the UI for some reason, say so explicitly rather than claiming success.
318
-
319
- ---
320
-
321
- ## Component Architecture and Communication
322
-
323
- - Use **methods** to trigger actions. Events notify that something already happened; they should not be used to trigger logic.
324
- - Prefer `el.closest('k-parent')?.doSomething()` over dispatching an event and listening for it.
325
- - Child components should locate their parent via `closest('k-parent-element')` and call its methods directly.
326
- - Avoid `window` globals and global custom events for coordination. Scope events to the relevant element; reserve `window` events for global, non-visual concerns (e.g. settings changes).
327
-
328
- ---
329
-
330
- ## Elevation (Z-Index)
331
-
332
- Any component using `position: fixed` must follow the kempo-css elevation system where `z-index = level × 10`.
333
-
334
- | Level | z-index | Kempo UI Components | Notes |
335
- |-------|---------|---------------------|-------|
336
- | 2 | 20 | (page default) | No z-index needed for flow-position components |
337
- | 3 | 30 | Aside (push) | Fixed panels that sit **below** a fixed navbar |
338
- | 5 | 50 | *(navbar — user-defined)* | Reserved buffer for user-defined navbars |
339
- | 6 | 60 | Aside (overlay) | Overlay drawers that sit **above** a fixed navbar |
340
- | 7 | 70 | Dropdown | Floating menus; above navbar and overlay |
341
- | 8 | 80 | Dialog, PhotoViewer | Full-screen modals and lightboxes |
342
- | 9 | 90 | Toast | Notification toasts; always topmost |
343
-
344
- Levels 1, 4 are intentional buffer zones for user customization.
345
-
346
- When deciding a new component's elevation:
347
- - If it is a panel or drawer in `push` mode (shifts page content), use level 3.
348
- - If it is a panel or drawer in `overlay` mode (floats over content), use level 6.
349
- - If it covers the entire viewport (modal/dialog), use level 8.
350
- - If it is a temporary notification, use level 9.
351
-
352
- ---
353
-
354
- ## Common Mistakes To Avoid
355
-
356
- - **Hand-writing the syntax-highlighted HTML** in code samples — use the [highlight-code skill](../highlight-code/SKILL.md) instead.
357
- - **Skipping tests** — every component needs a `*.browser-test.js` file with the minimum coverage above.
358
- - **Editing `docs/`** — that directory is generated by the build. Edit `docs-src/`.
359
- - **Adding `<!DOCTYPE>` / `<html>` / `<head>` / `<body>` / `<k-import>` to a page file** — the template provides the document shell. Pages contain only `<page>` and `<content>` blocks.
360
- - **Using a relative path like `../src/components/...`** in a page — use `{{pathToRoot}}src/components/...` so it resolves correctly at any depth.
361
- - **Forgetting `class="no-btn"` on shadow-DOM `<button>` elements** — kempo-css aggressively styles native buttons; opt out and re-center with flex.
362
- - **Updating only one of the four wiring locations** (search filter, sidebar menu, homepage card, llms.txt) — all four must be updated for a new component.
363
- - **Truncating adjacent elements when editing `nav.fragment.html`** — search-and-replace boundaries must include whole lines; always re-read the file after editing to verify nothing was clipped.
@@ -1,23 +0,0 @@
1
- name: Run Unit Tests
2
-
3
- on:
4
- pull_request:
5
- branches:
6
- - main
7
-
8
- jobs:
9
- test:
10
- runs-on: ubuntu-latest
11
- steps:
12
- - uses: actions/checkout@v4
13
- with:
14
- token: ${{ secrets.GITHUB_TOKEN }}
15
-
16
- - uses: actions/setup-node@v4
17
- with:
18
- node-version: '20.x'
19
-
20
- - run: npm ci
21
-
22
- - name: Run Unit Tests
23
- run: npm test