kempo-ui 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/get-icon/SKILL.md +144 -0
- package/.claude/skills/highlight-code/SKILL.md +62 -0
- package/.claude/skills/new-component/SKILL.md +362 -0
- package/.github/skills/get-icon/SKILL.md +4 -4
- package/.github/skills/highlight-code/SKILL.md +51 -20
- package/.github/skills/new-component/SKILL.md +183 -152
- package/AGENTS.md +2 -2
- package/dist/components/SpeechToText.js +60 -0
- package/dist/components/TextToSpeech.js +56 -0
- package/dist/components/VoiceSelector.js +49 -0
- package/dist/utils/voice.js +1 -0
- package/docs/components/accordion.html +15 -0
- package/docs/components/aside.html +15 -0
- package/docs/components/calendar.html +15 -0
- package/docs/components/card.html +15 -0
- package/docs/components/code-editor.html +15 -0
- package/docs/components/color-picker.html +15 -0
- package/docs/components/combobox.html +15 -0
- package/docs/components/content-slider.html +15 -0
- package/docs/components/context.html +15 -0
- package/docs/components/dialog.html +15 -0
- package/docs/components/dropdown.html +15 -0
- package/docs/components/filter-list.html +15 -0
- package/docs/components/focus-capture.html +15 -0
- package/docs/components/html-editor.html +15 -0
- package/docs/components/hybrid-component.html +15 -0
- package/docs/components/icon.html +15 -0
- package/docs/components/import.html +15 -0
- package/docs/components/light-component.html +15 -0
- package/docs/components/nav-spacer.html +15 -0
- package/docs/components/nav.html +15 -0
- package/docs/components/photo-viewer.html +15 -0
- package/docs/components/progress.html +15 -0
- package/docs/components/resize.html +15 -0
- package/docs/components/shadow-component.html +15 -0
- package/docs/components/show-more.html +15 -0
- package/docs/components/slider.html +15 -0
- package/docs/components/sortable.html +15 -0
- package/docs/components/speech-to-text.html +724 -0
- package/docs/components/spinner.html +15 -0
- package/docs/components/split.html +15 -0
- package/docs/components/table.html +15 -0
- package/docs/components/tableControls.html +15 -0
- package/docs/components/tableCustomFields.html +15 -0
- package/docs/components/tableFetchRecords.html +15 -0
- package/docs/components/tableFieldSortHide.html +15 -0
- package/docs/components/tablePagination.html +15 -0
- package/docs/components/tablePlaceholder.html +15 -0
- package/docs/components/tableRecordEditing.html +15 -0
- package/docs/components/tableRecordFiltering.html +15 -0
- package/docs/components/tableRecordHiding.html +15 -0
- package/docs/components/tableRecordSearching.html +15 -0
- package/docs/components/tableRecordSelection.html +15 -0
- package/docs/components/tableRowControls.html +15 -0
- package/docs/components/tableServerSync.html +15 -0
- package/docs/components/tableSorting.html +15 -0
- package/docs/components/tabs.html +15 -0
- package/docs/components/tags.html +15 -0
- package/docs/components/text-to-speech.html +718 -0
- package/docs/components/theme-select.html +15 -0
- package/docs/components/theme-switcher.html +15 -0
- package/docs/components/time.html +15 -0
- package/docs/components/timestamp.html +15 -0
- package/docs/components/toast.html +15 -0
- package/docs/components/toggle.html +15 -0
- package/docs/components/tree.html +15 -0
- package/docs/components/voice-selector.html +598 -0
- package/docs/icons/mic.svg +1 -0
- package/docs/icons/record_voice_over.svg +1 -0
- package/docs/icons/stop.svg +1 -0
- package/docs/index.html +39 -0
- package/docs/src/components/SpeechToText.js +60 -0
- package/docs/src/components/TextToSpeech.js +56 -0
- package/docs/src/components/VoiceSelector.js +49 -0
- package/docs/src/utils/voice.js +1 -0
- package/docs/utils/context.html +15 -0
- package/docs/utils/cookie.html +15 -0
- package/docs/utils/debounce.html +15 -0
- package/docs/utils/drag.html +15 -0
- package/docs/utils/elevation.html +15 -0
- package/docs/utils/formatTimestamp.html +15 -0
- package/docs/utils/object.html +15 -0
- package/docs/utils/propConverters.html +15 -0
- package/docs/utils/string.html +15 -0
- package/docs/utils/theme.html +15 -0
- package/docs/utils/toTitleCase.html +15 -0
- package/docs/utils/type.html +15 -0
- package/docs/utils/voice.html +536 -0
- package/docs/utils/wait.html +15 -0
- package/docs-src/components/speech-to-text.page.html +251 -0
- package/docs-src/components/text-to-speech.page.html +245 -0
- package/docs-src/components/voice-selector.page.html +125 -0
- package/docs-src/index.page.html +24 -0
- package/docs-src/nav.fragment.html +15 -0
- package/docs-src/utils/voice.page.html +66 -0
- package/icons/mic.svg +1 -0
- package/icons/record_voice_over.svg +1 -0
- package/icons/stop.svg +1 -0
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/src/components/SpeechToText.js +252 -0
- package/src/components/TextToSpeech.js +205 -0
- package/src/components/VoiceSelector.js +271 -0
- package/src/utils/voice.js +103 -0
- package/tests/components/SpeechToText.browser-test.js +530 -0
- package/tests/components/TextToSpeech.browser-test.js +581 -0
- package/tests/components/VoiceSelector.browser-test.js +374 -0
- package/tests/utils/voice.browser-test.js +128 -0
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: highlight-code
|
|
3
|
-
description: Generates syntax-highlighted HTML for
|
|
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
|
|
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
|
-
```
|
|
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
|
-
|
|
51
|
+
1. Capture the highlighted block to a shell variable (or a temp file):
|
|
39
52
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
57
|
-
-
|
|
58
|
-
- If a page has multiple `<pre><code>` blocks,
|
|
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,
|
|
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. **
|
|
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. **
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
80
|
+
Lifecycle Callbacks
|
|
104
81
|
*/
|
|
105
|
-
constructor(){
|
|
82
|
+
constructor() {
|
|
106
83
|
super();
|
|
107
|
-
this.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.
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
164
|
+
### Conditionals and loops
|
|
159
165
|
|
|
160
|
-
|
|
161
|
-
-
|
|
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
|
-
|
|
170
|
+
### Dev server
|
|
164
171
|
|
|
165
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
<
|
|
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
|
-
|
|
174
|
-
|
|
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
|
-
|
|
223
|
+
Then paste the result into the page.
|
|
178
224
|
|
|
179
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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
|
-
|
|
186
|
-
|
|
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
|
-
|
|
249
|
+
#### 3. Homepage card — [`docs-src/index.page.html`](../../../docs-src/index.page.html)
|
|
190
250
|
|
|
191
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
```
|
|
217
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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 (
|
|
293
|
+
- Attribute reflection works (when `reflect: true`)
|
|
242
294
|
- Public methods behave correctly
|
|
243
|
-
- Events are dispatched correctly
|
|
295
|
+
- Events are dispatched correctly with the right `detail` shape
|
|
296
|
+
- For form-associated components: form submission produces the expected value
|
|
244
297
|
|
|
245
|
-
|
|
298
|
+
Run the tests after writing them:
|
|
246
299
|
|
|
247
|
-
```
|
|
248
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
- `
|
|
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
|