kempo-ui 0.4.2 → 0.4.4

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 (104) hide show
  1. package/.claude/skills/get-icon/SKILL.md +144 -0
  2. package/.claude/skills/highlight-code/SKILL.md +62 -0
  3. package/.claude/skills/new-component/SKILL.md +362 -0
  4. package/.github/skills/get-icon/SKILL.md +4 -4
  5. package/.github/skills/highlight-code/SKILL.md +51 -20
  6. package/.github/skills/new-component/SKILL.md +183 -152
  7. package/AGENTS.md +2 -2
  8. package/dist/components/Calendar.js +170 -0
  9. package/dist/components/SpeechToText.js +60 -0
  10. package/dist/components/TextToSpeech.js +56 -0
  11. package/dist/components/Time.js +37 -0
  12. package/docs/components/accordion.html +16 -0
  13. package/docs/components/aside.html +16 -0
  14. package/docs/components/calendar.html +720 -0
  15. package/docs/components/card.html +16 -0
  16. package/docs/components/code-editor.html +16 -0
  17. package/docs/components/color-picker.html +16 -0
  18. package/docs/components/combobox.html +16 -0
  19. package/docs/components/content-slider.html +16 -0
  20. package/docs/components/context.html +16 -0
  21. package/docs/components/dialog.html +16 -0
  22. package/docs/components/dropdown.html +16 -0
  23. package/docs/components/filter-list.html +16 -0
  24. package/docs/components/focus-capture.html +16 -0
  25. package/docs/components/html-editor.html +16 -0
  26. package/docs/components/hybrid-component.html +16 -0
  27. package/docs/components/icon.html +16 -0
  28. package/docs/components/import.html +16 -0
  29. package/docs/components/light-component.html +16 -0
  30. package/docs/components/nav-spacer.html +16 -0
  31. package/docs/components/nav.html +16 -0
  32. package/docs/components/photo-viewer.html +16 -0
  33. package/docs/components/progress.html +16 -0
  34. package/docs/components/resize.html +16 -0
  35. package/docs/components/shadow-component.html +16 -0
  36. package/docs/components/show-more.html +16 -0
  37. package/docs/components/slider.html +16 -0
  38. package/docs/components/sortable.html +16 -0
  39. package/docs/components/speech-to-text.html +717 -0
  40. package/docs/components/spinner.html +16 -0
  41. package/docs/components/split.html +16 -0
  42. package/docs/components/table.html +16 -0
  43. package/docs/components/tableControls.html +16 -0
  44. package/docs/components/tableCustomFields.html +16 -0
  45. package/docs/components/tableFetchRecords.html +16 -0
  46. package/docs/components/tableFieldSortHide.html +16 -0
  47. package/docs/components/tablePagination.html +16 -0
  48. package/docs/components/tablePlaceholder.html +16 -0
  49. package/docs/components/tableRecordEditing.html +16 -0
  50. package/docs/components/tableRecordFiltering.html +16 -0
  51. package/docs/components/tableRecordHiding.html +16 -0
  52. package/docs/components/tableRecordSearching.html +16 -0
  53. package/docs/components/tableRecordSelection.html +16 -0
  54. package/docs/components/tableRowControls.html +16 -0
  55. package/docs/components/tableServerSync.html +16 -0
  56. package/docs/components/tableSorting.html +16 -0
  57. package/docs/components/tabs.html +16 -0
  58. package/docs/components/tags.html +16 -0
  59. package/docs/components/text-to-speech.html +668 -0
  60. package/docs/components/theme-select.html +16 -0
  61. package/docs/components/theme-switcher.html +16 -0
  62. package/docs/components/time.html +670 -0
  63. package/docs/components/timestamp.html +16 -0
  64. package/docs/components/toast.html +16 -0
  65. package/docs/components/toggle.html +16 -0
  66. package/docs/components/tree.html +16 -0
  67. package/docs/icons/mic.svg +1 -0
  68. package/docs/icons/record_voice_over.svg +1 -0
  69. package/docs/icons/stop.svg +1 -0
  70. package/docs/index.html +40 -0
  71. package/docs/src/components/Calendar.js +170 -0
  72. package/docs/src/components/SpeechToText.js +60 -0
  73. package/docs/src/components/TextToSpeech.js +56 -0
  74. package/docs/src/components/Time.js +37 -0
  75. package/docs/utils/context.html +16 -0
  76. package/docs/utils/cookie.html +16 -0
  77. package/docs/utils/debounce.html +16 -0
  78. package/docs/utils/drag.html +16 -0
  79. package/docs/utils/elevation.html +16 -0
  80. package/docs/utils/formatTimestamp.html +16 -0
  81. package/docs/utils/object.html +16 -0
  82. package/docs/utils/propConverters.html +16 -0
  83. package/docs/utils/string.html +16 -0
  84. package/docs/utils/theme.html +16 -0
  85. package/docs/utils/toTitleCase.html +16 -0
  86. package/docs/utils/type.html +16 -0
  87. package/docs/utils/wait.html +16 -0
  88. package/docs-src/components/calendar.page.html +254 -0
  89. package/docs-src/components/speech-to-text.page.html +251 -0
  90. package/docs-src/components/text-to-speech.page.html +202 -0
  91. package/docs-src/components/time.page.html +204 -0
  92. package/docs-src/index.page.html +24 -0
  93. package/docs-src/nav.fragment.html +16 -0
  94. package/icons/mic.svg +1 -0
  95. package/icons/record_voice_over.svg +1 -0
  96. package/icons/stop.svg +1 -0
  97. package/llms.txt +4 -0
  98. package/package.json +1 -1
  99. package/src/components/Calendar.js +473 -0
  100. package/src/components/SpeechToText.js +252 -0
  101. package/src/components/TextToSpeech.js +194 -0
  102. package/src/components/Time.js +137 -0
  103. package/tests/components/SpeechToText.browser-test.js +530 -0
  104. package/tests/components/TextToSpeech.browser-test.js +432 -0
@@ -1,17 +1,30 @@
1
1
  ---
2
2
  name: highlight-code
3
- description: Generates syntax-highlighted HTML for use in documentation code examples. USE THIS instead of creating temporary scripts.
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
4
  ---
5
5
 
6
6
  # Highlight Code
7
7
 
8
8
  ## When to Use
9
9
 
10
- Use this skill whenever you need syntax-highlighted HTML to embed in a documentation page — for example, when updating a `<pre><code class="hljs ...">` block in a `docs/components/*.html` file. **Do not create temporary `.mjs` scripts to do this.**
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`.
11
13
 
12
14
  ## Usage
13
15
 
14
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:**
15
28
  ```powershell
16
29
  @"
17
30
  <div class='container'>
@@ -20,8 +33,8 @@ Pipe code via stdin (supports multi-line):
20
33
  "@ | npx kempo-highlightcode <lang>
21
34
  ```
22
35
 
23
- Or pass minified code as an argument:
24
- ```powershell
36
+ Or pass minified code as an argument (works in any shell):
37
+ ```bash
25
38
  npx kempo-highlightcode <lang> "<div class='container'><h1>Hello</h1></div>"
26
39
  ```
27
40
 
@@ -35,26 +48,44 @@ Input is automatically beautified before highlighting, so you can pass minified
35
48
 
36
49
  ## Workflow for Updating Doc Code Samples
37
50
 
38
- Pipe the code into the script, capture to `$hl`, then use PowerShell's `.Replace()` to patch the HTML file:
51
+ 1. Capture the highlighted block to a shell variable (or a temp file):
39
52
 
40
- ```powershell
41
- $hl = @"
42
- <k-table id=myExample></k-table>
43
- <script type=module>
44
- doSomething('foo');
45
- </script>
46
- "@ | npx kempo-highlightcode xml
47
- $html = [System.IO.File]::ReadAllText((Resolve-Path 'docs/components/my-component.html'))
48
- $old = [regex]::Match($html, '(?s)<pre><code class="hljs xml">.*?</code></pre>').Value
49
- [System.IO.File]::WriteAllText((Resolve-Path 'docs/components/my-component.html'), $html.Replace($old, $hl))
50
- ```
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
+ ```
51
83
 
52
84
  ## Important Notes
53
85
 
54
- - Use PowerShell **here-strings** (`@"…"@`) for multi-line code input via stdin.
55
86
  - Use **single-quotes** for JS string literals inside the code. This preserves all quoting correctly through to node.
56
- - HTML attribute values should be **unquoted** in the argument (`id=foo` not `id="foo"`) — the beautifier adds consistent formatting anyway.
57
- - Use `[System.IO.File]::ReadAllText` / `WriteAllText` + `.Replace()` (not `-replace`) to avoid regex interpretation of the replacement string.
58
- - If a page has multiple `<pre><code>` blocks, adjust the regex to match the specific one (e.g. match by a nearby unique string, or loop with an index).
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).
59
90
  - The beautifier handles indentation and formatting automatically.
60
91
  - Output uses `<br>` instead of `\n`, keeping the block on one line in the HTML source.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: new-component
3
- description: Creates a new Kempo UI web component — choosing the right base class, writing the source file, registering the custom element, and adding documentation.
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
4
  ---
5
5
 
6
6
  # New Component
@@ -13,14 +13,14 @@ Use this skill any time you are asked to create a new component or add a new cus
13
13
 
14
14
  ## Overview
15
15
 
16
- Creating a component involves six steps:
16
+ Creating a component involves six steps. Do not skip steps — especially the tests.
17
17
 
18
18
  1. **Choose the base component** — pick the right rendering strategy
19
- 2. **Write the source file** in `src/components/`
20
- 3. **Register the custom element** at the bottom of the source file
21
- 4. **Add documentation** in `docs/components/`
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
22
  5. **Write and run unit tests** in `tests/components/`
23
- 6. **Update `llm.txt.md`** add a row to the Components table
23
+ 6. **Verify in the browser** at `http://localhost:8083`
24
24
 
25
25
  ---
26
26
 
@@ -29,10 +29,10 @@ Creating a component involves six steps:
29
29
  Three base classes are available. Pick based on rendering needs:
30
30
 
31
31
  ### `ShadowComponent`
32
- Use when the component needs shadow DOM encapsulation. The base class automatically injects the `/kempo.css` stylesheet into the shadow root.
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
33
 
34
34
  ```javascript
35
- import { html } from '../lit-all.min.js';
35
+ import { html, css } from '../lit-all.min.js';
36
36
  import ShadowComponent from './ShadowComponent.js';
37
37
 
38
38
  export default class MyComponent extends ShadowComponent {
@@ -43,50 +43,26 @@ export default class MyComponent extends ShadowComponent {
43
43
  ```
44
44
 
45
45
  ### `LightComponent`
46
- Use when the component renders to the light DOM (no encapsulation, inherits page styles).
47
-
48
- ```javascript
49
- import { html } from '../lit-all.min.js';
50
- import LightComponent from './LightComponent.js';
51
-
52
- export default class MyComponent extends LightComponent {
53
- renderLightDom() {
54
- return html`<p>Light DOM content</p>`;
55
- }
56
- }
57
- ```
46
+ Use when the component renders to the light DOM (no encapsulation, inherits page styles). Override `renderLightDom()`.
58
47
 
59
48
  ### `HybridComponent`
60
- 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).
61
-
62
- ```javascript
63
- import { html } from '../lit-all.min.js';
64
- import HybridComponent from './HybridComponent.js';
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()`.
65
50
 
66
- export default class MyComponent extends HybridComponent {
67
- render() {
68
- return html`<p>Shadow DOM content</p>`;
69
- }
70
-
71
- renderLightDom() {
72
- return html`<p>Light DOM content alongside natural children</p>`;
73
- }
74
- }
75
- ```
76
-
77
- **Important:** Always call `super.updated()` when overriding the `updated()` method in `LightComponent` or `HybridComponent`.
51
+ **Important:** Always call `super.updated(...)` when overriding `updated()` in any base class.
78
52
 
79
53
  ---
80
54
 
81
55
  ## Step 2: Write the Source File
82
56
 
83
- Create `src/components/MyComponent.js`. Follow these conventions:
57
+ Create `src/components/MyComponent.js`. Follow these conventions (also see [AGENTS.md](../../../AGENTS.md)):
84
58
 
85
- - Use multi-line comments to separate logical sections: `Lifecycle Callbacks`, `Event Handlers`, `Public Methods`, `Utility Functions`, `Rendering`, `Styles`.
59
+ - Use multi-line comments to separate logical sections: `Lifecycle Callbacks`, `Event Handlers`, `Public Methods`, `Utility`, `Rendering`, `Styles`.
86
60
  - Declare reactive properties with `static properties = { ... }` and initialize defaults in the constructor.
87
61
  - Use `static styles = css\`...\`` for component-scoped CSS (shadow DOM only).
88
- - Use arrow functions for class methods to avoid `.bind(this)`.
89
- - Do not prefix private fields with underscores — use native JS private fields (`#field`) when true privacy is needed.
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.
90
66
 
91
67
  Example skeleton:
92
68
 
@@ -96,26 +72,28 @@ import ShadowComponent from './ShadowComponent.js';
96
72
 
97
73
  export default class MyComponent extends ShadowComponent {
98
74
  static properties = {
99
- value: { type: String, reflect: true }
75
+ value: { type: String, reflect: true },
76
+ disabled: { type: Boolean, reflect: true }
100
77
  };
101
-
78
+
102
79
  /*
103
- Lifecycle Calblacks
80
+ Lifecycle Callbacks
104
81
  */
105
- constructor(){
82
+ constructor() {
106
83
  super();
107
- this.value = 'default value';
108
- }
109
- connectedCallback(){
110
- super.connectedCallback();
111
- // Do things
84
+ this.value = '';
85
+ this.disabled = false;
112
86
  }
113
87
 
114
88
  /*
115
89
  Event Handlers
116
90
  */
117
91
  handleClick = () => {
118
- this.dispatchEvent(new CustomEvent('my-event', { bubbles: true, composed: true }));
92
+ if(this.disabled) return;
93
+ this.dispatchEvent(new CustomEvent('change', {
94
+ detail: { value: this.value },
95
+ bubbles: true
96
+ }));
119
97
  };
120
98
 
121
99
  /*
@@ -123,24 +101,29 @@ export default class MyComponent extends ShadowComponent {
123
101
  */
124
102
  render() {
125
103
  return html`
126
- <button @click=${this.handleClick}>${this.value}</button>
104
+ <button class="no-btn btn" ?disabled=${this.disabled} @click=${this.handleClick}>
105
+ ${this.value}
106
+ </button>
127
107
  `;
128
108
  }
109
+
129
110
  /*
130
111
  Styles
131
112
  */
132
113
  static styles = css`
133
- :host {
134
- display: block;
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;
135
125
  }
136
126
  `;
137
-
138
- /*
139
- Static Methods
140
- */
141
- static staticMethod(){
142
- // Do things
143
- }
144
127
  }
145
128
 
146
129
  customElements.define('k-my-component', MyComponent);
@@ -153,138 +136,185 @@ customElements.define('k-my-component', MyComponent);
153
136
 
154
137
  ---
155
138
 
156
- ## Step 3: Register in the Nav, Search, and Index (if it should appear in docs)
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).
157
163
 
158
- There are **two** nav include files that must both be updated:
164
+ ### Conditionals and loops
159
165
 
160
- - `docs/nav.inc.html` used on the homepage (paths start with `./`)
161
- - `docs/nav-1.inc.html` used on sub-pages (paths start with `../`)
166
+ The templating engine supports:
167
+ - `<if condition="..."> </if>` with `===`, `!==`, `>`, `<`, `>=`, `<=`, `&&`, `||`, `!`
168
+ - `<foreach in="arrayName" as="item"> {{item.name}} </foreach>` with dot-path access
162
169
 
163
- In **each** file, add the component in **three** places, all in alphabetical order:
170
+ ### Dev server
164
171
 
165
- ### 1. Search dropdown filter item
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.**
166
173
 
167
- Inside the `<k-filter-list id="navSearchList">`, add a `<k-filter-item>` in alphabetical order among the other component entries:
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">`
168
186
 
169
187
  ```html
170
- <!-- nav.inc.html (homepage) -->
171
- <k-filter-item filter-keywords="my component mycomponent components"><a href="./components/my-component.html">My Component<br><small>Component</small></a></k-filter-item>
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.
172
216
 
173
- <!-- nav-1.inc.html (sub-pages) -->
174
- <k-filter-item filter-keywords="my component mycomponent components"><a href="../components/my-component.html">My Component<br><small>Component</small></a></k-filter-item>
217
+ ```bash
218
+ cat <<'EOF' | npx kempo-highlightcode xml
219
+ <k-my-component value="hello"></k-my-component>
220
+ EOF
175
221
  ```
176
222
 
177
- ### 2. Sidebar menu link
223
+ Then paste the result into the page.
178
224
 
179
- Inside the `<menu>` under the `Components` `<div>`, add an `<a>` tag in alphabetical order:
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>`:
180
232
 
181
233
  ```html
182
- <!-- nav.inc.html -->
183
- <a href="./components/my-component.html">My Component</a>
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.
184
240
 
185
- <!-- nav-1.inc.html -->
186
- <a href="../components/my-component.html">My Component</a>
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>
187
247
  ```
188
248
 
189
- ### 3. Homepage card
249
+ #### 3. Homepage card — [`docs-src/index.page.html`](../../../docs-src/index.page.html)
190
250
 
191
- Add a card in `docs/index.html` inside the `<div class="row -mx">` under the `<h2>Components</h2>` section, in alphabetical order:
251
+ Inside the `<div class="row -mx">` under `<h2>Components</h2>`, add a card in alphabetical order:
192
252
 
193
253
  ```html
194
254
  <div class="span-12 t-span-6 d-span-4 px">
195
- <a href="./components/my-component.html" class="card mb no-link d-b">
255
+ <a href="{{pathToRoot}}components/my-component.html" class="card mb no-link d-b">
196
256
  <h3 class="tc-primary">My Component</h3>
197
257
  <p class="tc-muted">One-sentence description of what the component does.</p>
198
258
  </a>
199
259
  </div>
200
260
  ```
201
261
 
202
- ---
203
-
204
- ## Step 4: Add Documentation
205
-
206
- Create `docs/components/my-component.html`. Use an existing docs page (e.g. `docs/components/spinner.html`) as a reference for structure and conventions.
262
+ #### 4. LLM reference — [`llms.txt`](../../../llms.txt)
207
263
 
208
- Key requirements:
209
- - Consistent `<head>` with title, stylesheets, and `window.litDisableBundleWarning = true`.
210
- - `<k-import src="../nav-1.inc.html"></k-import>` at the top of `<body>`.
211
- - A Table of Contents accordion.
212
- - Sections for: examples/usage, and a JavaScript Reference covering constructor, attributes/properties, CSS variables, events, and public methods (as applicable).
213
- - Use the `highlight-code` skill for all code examples that need syntax highlighting.
214
- - At the bottom of the file, load the component and its dependencies as `<script type="module">` tags:
264
+ Add a row to the **Components** table (alphabetical by element name):
215
265
 
216
- ```html
217
- <script type="module" src="../src/components/MyComponent.js"></script>
218
- <script type="module" src="../src/components/Import.js"></script>
219
- <script type="module" src="../src/components/Accordion.js"></script>
220
- <script type="module" src="../src/components/Card.js"></script>
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) |
221
268
  ```
222
269
 
270
+ If the component registers multiple elements (e.g. parent + child), list all element names in the first column separated by spaces.
271
+
223
272
  ---
224
273
 
225
274
  ## Step 5: Write and Run Unit Tests
226
275
 
227
- Create `tests/components/MyComponent.browser-test.js`. Use an existing test file (e.g. `tests/components/Toggle.browser-test.js`) as a reference.
276
+ **This step is required.** Skipping tests is a common mistake AGENTS.md says "ALL tests must pass — ZERO failures are acceptable."
228
277
 
229
- Key conventions:
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:
230
281
  - Import the component class at the top.
231
- - Define an async `createMyComponent()` helper that builds the DOM, appends it to `document.body`, awaits `el.updateComplete`, and returns `{ container, el }`.
282
+ - Define an async `createMyComponent(attrs = {})` helper that builds the DOM, appends to `document.body`, awaits `el.updateComplete`, and returns `{ container, el }`.
232
283
  - Define a `cleanup(container)` helper that removes the container from the DOM.
233
284
  - Export a default plain object where each key is a test description and each value is an `async ({pass, fail}) => {}` function.
234
285
  - Always call `cleanup(container)` before every `pass()` or `fail()` call.
235
- - Use multi-line comments to group related tests (e.g. `/* Element Creation */`, `/* Properties */`).
286
+ - Use multi-line comments to group related tests (`/* Element Creation */`, `/* Properties */`, etc.).
236
287
 
237
288
  Tests to include at minimum:
289
+
238
290
  - Element is created and is an instance of the component class
239
- - Element has a shadow root
291
+ - Element has a shadow root (when applicable)
240
292
  - Default property values are correct
241
- - Attribute reflection works (if applicable)
293
+ - Attribute reflection works (when `reflect: true`)
242
294
  - Public methods behave correctly
243
- - Events are dispatched correctly (if applicable)
295
+ - Events are dispatched correctly with the right `detail` shape
296
+ - For form-associated components: form submission produces the expected value
244
297
 
245
- Example skeleton:
298
+ Run the tests after writing them:
246
299
 
247
- ```javascript
248
- import MyComponent from '../../src/components/MyComponent.js';
249
-
250
- const createMyComponent = async () => {
251
- const container = document.createElement('div');
252
- container.innerHTML = `<k-my-component></k-my-component>`;
253
- document.body.appendChild(container);
254
- const el = container.querySelector('k-my-component');
255
- await el.updateComplete;
256
- return { container, el };
257
- };
258
-
259
- const cleanup = (container) => {
260
- if(container && container.parentNode){
261
- container.parentNode.removeChild(container);
262
- }
263
- };
264
-
265
- export default {
266
- /*
267
- Element Creation
268
- */
269
- 'should create my-component element': async ({pass, fail}) => {
270
- const { container, el } = await createMyComponent();
271
- if(!(el instanceof MyComponent)){
272
- cleanup(container);
273
- return fail('Element should be instance of MyComponent');
274
- }
275
- cleanup(container);
276
- pass('MyComponent element created correctly');
277
- },
278
- };
300
+ ```bash
301
+ npm run test -- MyComponent
279
302
  ```
280
303
 
281
- After writing the tests, run them to confirm they all pass:
304
+ The partial string `MyComponent` matches any test file path containing it. Fix any failures before considering the component complete. Zero failures.
282
305
 
283
- ```
284
- npm run test -- MyComponent
285
- ```
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
286
316
 
287
- The partial string `MyComponent` will match any test file whose path contains that string. Fix any failures before considering the component complete.
317
+ If you cannot test the UI for some reason, say so explicitly rather than claiming success.
288
318
 
289
319
  ---
290
320
 
@@ -307,7 +337,7 @@ Any component using `position: fixed` must follow the kempo-css elevation system
307
337
  | 3 | 30 | Aside (push) | Fixed panels that sit **below** a fixed navbar |
308
338
  | 5 | 50 | *(navbar — user-defined)* | Reserved buffer for user-defined navbars |
309
339
  | 6 | 60 | Aside (overlay) | Overlay drawers that sit **above** a fixed navbar |
310
- | 7 | 70 | Dropdown | Floating menus; above navbar and overlay|
340
+ | 7 | 70 | Dropdown | Floating menus; above navbar and overlay |
311
341
  | 8 | 80 | Dialog, PhotoViewer | Full-screen modals and lightboxes |
312
342
  | 9 | 90 | Toast | Notification toasts; always topmost |
313
343
 
@@ -321,12 +351,13 @@ When deciding a new component's elevation:
321
351
 
322
352
  ---
323
353
 
324
- ## Step 6: Update `llm.txt.md`
325
-
326
- Add a row for the new component to the **Components** table in `llm.txt.md` at the root of the repository. Keep the table in alphabetical order by element name.
327
-
328
- ```markdown
329
- | `<k-my-component>` | `MyComponent.js` | One-sentence description | [my-component.html](https://dustinpoissant.github.io/kempo-ui/components/my-component.html) |
330
- ```
354
+ ## Common Mistakes To Avoid
331
355
 
332
- If the component registers multiple elements (e.g. a parent + child pair), list all element names in the first column separated by spaces.
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.
package/AGENTS.md CHANGED
@@ -7,7 +7,7 @@
7
7
  - All utility function module files should be in the `src/utils/` directory.
8
8
  - All documnentation should be in the `docs/` directory. This directory is used by GitHub as the "GitHub Pages", so all links need to be relative, and there will be a build script which copies all code to the `docs/` directory.
9
9
  - Documentation source files (templates, fragments, page files) are in the `docs-src/` directory. These use the kempo-server v3 templating system and are pre-rendered to `docs/` during build.
10
- - `llm.txt.md` in the root is the consumer-facing LLM reference for this library. **Keep it up to date**: when adding a new component or utility, add a row to the relevant table in `llm.txt.md`.
10
+ - `llms.txt` in the root is the consumer-facing LLM reference for this library. **Keep it up to date**: when adding a new component or utility, add a row to the relevant table in `llms.txt`.
11
11
 
12
12
  ## Dependencies
13
13
 
@@ -102,7 +102,7 @@ Do not prefix identifiers with underscores.
102
102
  - **DO NOT** start a development server - one is already running
103
103
  - Default port: **8083**
104
104
  - Base URL: `http://localhost:8083`
105
- - Documentation URLs follow the directory/file structure in `docs/` (e.g., `docs/components/color-picker.html` → `http://localhost:8083/components/color-picker.html`)
105
+ - Documentation URLs follow the directory/file structure in `docs-src/` (e.g., source `docs-src/components/color-picker.page.html` → URL `http://localhost:8083/components/color-picker.html`). Edit the `*.page.html` source — never the generated `docs/` output.
106
106
  - Use this server for all testing and verification
107
107
 
108
108
  ### Testing and Verification