@mhmo91/schmancy 0.10.9 → 0.10.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/handover/agent-runtime-followups.md +1 -1
- package/dist/handover/agent-runtime-v1.md +3 -3
- package/dist/handover/claude-design-brief.md +86 -46
- package/dist/handover/claude-design-setup.md +11 -7
- package/dist/handover/schmancy-token-reference.md +12 -6
- package/dist/skills/INDEX.md +1 -1
- package/dist/skills/SKILL.md +7 -6
- package/dist/skills/audio.md +1 -1
- package/dist/skills/discovery.md +3 -3
- package/dist/skills/menu.md +1 -1
- package/dist/skills/overlay.md +1 -1
- package/dist/skills/schmancy/INDEX.md +1 -1
- package/dist/skills/schmancy/SKILL.md +7 -6
- package/dist/skills/schmancy/audio.md +1 -1
- package/dist/skills/schmancy/discovery.md +3 -3
- package/dist/skills/schmancy/menu.md +1 -1
- package/dist/skills/schmancy/overlay.md +1 -1
- package/dist/skills/schmancy/state.md +42 -22
- package/dist/skills/state.md +42 -22
- package/dist/state-BusMG6sM.js.map +1 -1
- package/dist/state-DNdCPITt.cjs.map +1 -1
- package/package.json +1 -1
- package/skills/schmancy/INDEX.md +1 -1
- package/skills/schmancy/SKILL.md +7 -6
- package/skills/schmancy/audio.md +1 -1
- package/skills/schmancy/discovery.md +3 -3
- package/skills/schmancy/menu.md +1 -1
- package/skills/schmancy/overlay.md +1 -1
- package/skills/schmancy/state.md +42 -22
- package/src/CLAUDE.md +112 -354
- package/src/state/CLAUDE.md +26 -18
- package/src/state/SCOPING.md +23 -9
|
@@ -203,7 +203,7 @@ The manifest already has everything needed; the package is just the JSON-RPC wra
|
|
|
203
203
|
|
|
204
204
|
**Problem.** `handover/agent-runtime-v1.md` had `<PENDING>` placeholders that we manually replaced with `0.9.13` after the first publish. Future handover docs will have the same issue.
|
|
205
205
|
|
|
206
|
-
**Fix.** A build step that substitutes `0.10.
|
|
206
|
+
**Fix.** A build step that substitutes `0.10.11` in `handover/**/*.md` against `package.json`'s `version` field on every build. `dist/handover/**/*.md` gets the rendered version; the source stays templated.
|
|
207
207
|
|
|
208
208
|
**Effort:** ~30 min (one sed step or a tiny script).
|
|
209
209
|
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
## The URLs you asked for
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
https://esm.sh/@mhmo91/schmancy/agent@0.10.
|
|
11
|
-
https://esm.sh/@mhmo91/schmancy/agent/manifest@0.10.
|
|
10
|
+
https://esm.sh/@mhmo91/schmancy/agent@0.10.11
|
|
11
|
+
https://esm.sh/@mhmo91/schmancy/agent/manifest@0.10.11
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
`0.9.13` is the first release containing `/agent`; every subsequent publish serves the same subpath. `npm view @mhmo91/schmancy version` always returns the current pin if you want to float forward.
|
|
@@ -20,7 +20,7 @@ One script tag. No bundler, no bare specifiers, no npm install.
|
|
|
20
20
|
```html
|
|
21
21
|
<!doctype html>
|
|
22
22
|
<script type="module">
|
|
23
|
-
import { $dialog, theme } from 'https://esm.sh/@mhmo91/schmancy/agent@0.10.
|
|
23
|
+
import { $dialog, theme } from 'https://esm.sh/@mhmo91/schmancy/agent@0.10.11';
|
|
24
24
|
</script>
|
|
25
25
|
<schmancy-theme root scheme="dark">
|
|
26
26
|
<schmancy-surface type="solid" fill="all">
|
|
@@ -1,88 +1,124 @@
|
|
|
1
1
|
# Claude Design brief: building with schmancy
|
|
2
2
|
|
|
3
|
-
You're designing or redesigning a web page. Use the `@mhmo91/schmancy`
|
|
3
|
+
You're designing or redesigning a web page. Use the `@mhmo91/schmancy`
|
|
4
|
+
component library for every interactive tag, every surface, every
|
|
5
|
+
color. This file is the operating manual — paste it in alongside the
|
|
6
|
+
design ask.
|
|
4
7
|
|
|
5
8
|
## Pin URL
|
|
6
9
|
|
|
7
10
|
```
|
|
8
|
-
https://
|
|
11
|
+
https://esm.sh/@mhmo91/schmancy/agent
|
|
9
12
|
```
|
|
10
13
|
|
|
11
|
-
One
|
|
14
|
+
One module import installs every `<schmancy-*>` custom element. No
|
|
15
|
+
bundler, no npm install, no bare specifiers. The same URL also
|
|
16
|
+
re-exports the full library surface (`theme`, `area`, `state`, `show`,
|
|
17
|
+
`lazy`, every directive, every service, `SchmancyElement`) for in-page
|
|
18
|
+
script code.
|
|
19
|
+
|
|
20
|
+
For introspection — every tag's attributes, events, slots, CSS parts,
|
|
21
|
+
plus the `values` array on every typed attribute — read the static
|
|
22
|
+
manifest at `https://esm.sh/@mhmo91/schmancy/agent/manifest` (JSON,
|
|
23
|
+
shape follows Custom Elements Manifest v1).
|
|
12
24
|
|
|
13
25
|
## App shell (always this shape)
|
|
14
26
|
|
|
15
27
|
```html
|
|
16
28
|
<!doctype html>
|
|
17
29
|
<script type="module">
|
|
18
|
-
import 'https://
|
|
30
|
+
import 'https://esm.sh/@mhmo91/schmancy/agent';
|
|
19
31
|
</script>
|
|
20
32
|
|
|
21
33
|
<schmancy-theme root scheme="dark">
|
|
22
34
|
<schmancy-surface type="solid" fill="all">
|
|
23
35
|
<!-- your page content -->
|
|
24
|
-
<schmancy-skill></schmancy-skill>
|
|
25
36
|
</schmancy-surface>
|
|
26
37
|
</schmancy-theme>
|
|
27
38
|
```
|
|
28
39
|
|
|
29
|
-
- `<schmancy-theme>` generates a Material 3 palette from a seed color +
|
|
30
|
-
|
|
31
|
-
- `<schmancy-
|
|
40
|
+
- `<schmancy-theme>` generates a Material 3 palette from a seed color +
|
|
41
|
+
scheme. Attribute `root` publishes tokens onto `document.body`.
|
|
42
|
+
- `<schmancy-surface>` picks up theme tokens for background / on-color
|
|
43
|
+
/ elevation. Nest surfaces for hierarchical color stacking.
|
|
32
44
|
|
|
33
|
-
## Discovery —
|
|
45
|
+
## Discovery — read the static manifest
|
|
34
46
|
|
|
35
47
|
```js
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
window.schmancy.capabilities()
|
|
47
|
-
// → { popover, declarativeShadowDom, scopedRegistries, trustedTypes,
|
|
48
|
-
// cssRegisteredProperties, elementInternalsAria, formAssociated,
|
|
49
|
-
// adoptedStyleSheets }
|
|
48
|
+
const manifest = await fetch('https://esm.sh/@mhmo91/schmancy/agent/manifest')
|
|
49
|
+
.then(r => r.json())
|
|
50
|
+
|
|
51
|
+
// Every tag, attribute, event, slot, CSS part, CSS property.
|
|
52
|
+
// Typed-attribute enums surface as `values: ['filled', 'tonal', ...]`
|
|
53
|
+
// so you don't parse `"'filled' | 'tonal' | ..."` strings.
|
|
54
|
+
manifest.modules
|
|
55
|
+
.flatMap(m => m.declarations)
|
|
56
|
+
.filter(d => d.kind === 'class' && d.tagName?.startsWith('schmancy-'))
|
|
50
57
|
```
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
The manifest is the authoritative source. Pull a tag's declaration
|
|
60
|
+
once at page-build time and use the `attributes`, `events`, `slots`,
|
|
61
|
+
and `cssProperties` arrays to drive the rest of the page.
|
|
53
62
|
|
|
54
63
|
## Rules
|
|
55
64
|
|
|
56
|
-
1. **Every UI tag is `<schmancy-*>`.** Use `<schmancy-button>`, not
|
|
57
|
-
|
|
65
|
+
1. **Every UI tag is `<schmancy-*>`.** Use `<schmancy-button>`, not
|
|
66
|
+
`<button>`. `<schmancy-input>`, not `<input>`. `<schmancy-list-item>`,
|
|
67
|
+
not `<li>`. Look up the exact tag in the manifest.
|
|
68
|
+
2. **Colors: Tailwind utility classes against schmancy tokens.** Every
|
|
69
|
+
`--schmancy-sys-color-*` token is exposed as a Tailwind color
|
|
70
|
+
utility.
|
|
58
71
|
- `bg-primary-default`, `bg-primary-container`, `text-primary-on`
|
|
59
72
|
- `bg-surface-default`, `bg-surface-low`, `bg-surface-high`, `text-surface-on`
|
|
60
73
|
- `border-outline`, `border-outline-variant`
|
|
61
74
|
- `bg-secondary-container`, `bg-error-default`, `bg-success-default`, `bg-warning-default`
|
|
62
|
-
- **Never hex (`#6200ee`), never arbitrary values (`bg-[#ff0000]`).**
|
|
63
|
-
|
|
75
|
+
- **Never hex (`#6200ee`), never arbitrary values (`bg-[#ff0000]`).**
|
|
76
|
+
Both defeat theming.
|
|
77
|
+
3. **Forms:** wrap form controls in `<schmancy-form>`. Its `submit`
|
|
78
|
+
event fires with a `FormData` payload — no manual walking of inputs.
|
|
79
|
+
Every form control (`<schmancy-input>`, `<schmancy-select>`,
|
|
80
|
+
`<schmancy-checkbox>`, etc.) is form-associated via
|
|
81
|
+
`ElementInternals`, so `new FormData(form)` just works.
|
|
64
82
|
4. **Layout:**
|
|
65
|
-
- `<schmancy-page rows="auto_1fr_auto">` for app shell — fills
|
|
66
|
-
|
|
67
|
-
- `<schmancy-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
- `<schmancy-page rows="auto_1fr_auto">` for app shell — fills
|
|
84
|
+
viewport, suppresses double-tap zoom and pull-to-refresh.
|
|
85
|
+
- `<schmancy-nav-drawer>` for responsive sidebar + app-bar +
|
|
86
|
+
content (persistent on desktop, modal on mobile).
|
|
87
|
+
- `<schmancy-scroll>` when you need debounced scroll events or
|
|
88
|
+
hidden scrollbars.
|
|
89
|
+
- `<schmancy-grid>` and `<schmancy-flex>` for layout primitives
|
|
90
|
+
with design intent; raw Tailwind `grid` / `flex` utilities for
|
|
91
|
+
incidental layout math.
|
|
92
|
+
5. **Overlays use the imperative service, not element APIs:**
|
|
70
93
|
```js
|
|
71
|
-
import {
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
import { show, confirm, prompt } from 'https://esm.sh/@mhmo91/schmancy/agent';
|
|
95
|
+
import { $notify } from 'https://esm.sh/@mhmo91/schmancy/agent';
|
|
96
|
+
|
|
97
|
+
show(new MyEditor()); // centered fallback
|
|
98
|
+
show(new QuickPicker(), { anchor: ev }); // anchored at click
|
|
99
|
+
show(new SheetForm()); // narrow viewport → sheet (auto)
|
|
100
|
+
await confirm({ title: 'Delete?', message: 'Cannot be undone.', confirmText: 'Delete' });
|
|
74
101
|
$notify.success('Saved');
|
|
75
102
|
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
103
|
+
`show()` is the single overlay primitive — layout (centered /
|
|
104
|
+
anchored / sheet) is chosen automatically by viewport + anchor
|
|
105
|
+
presence. There is no `$dialog` and no `sheet` service.
|
|
106
|
+
6. **Accessibility is built in.** Components handle ARIA roles, focus
|
|
107
|
+
management, keyboard navigation, form validation messages. Don't
|
|
108
|
+
re-implement. Do provide `aria-label` on icon-only buttons
|
|
109
|
+
(`<schmancy-icon-button aria-label="Close">`).
|
|
110
|
+
7. **Typography:** use `<schmancy-typography type="..." token="...">`
|
|
111
|
+
for text. Type = `display` / `headline` / `title` / `body` / `label`.
|
|
112
|
+
Token = `lg` / `md` / `sm`.
|
|
113
|
+
8. **Icons:** `<schmancy-icon>close</schmancy-icon>` renders a Material
|
|
114
|
+
Symbols glyph. Pass the icon name as text content.
|
|
79
115
|
|
|
80
116
|
## Minimum working page (copy, paste, it runs)
|
|
81
117
|
|
|
82
118
|
```html
|
|
83
119
|
<!doctype html>
|
|
84
120
|
<script type="module">
|
|
85
|
-
import 'https://
|
|
121
|
+
import 'https://esm.sh/@mhmo91/schmancy/agent';
|
|
86
122
|
</script>
|
|
87
123
|
|
|
88
124
|
<schmancy-theme root scheme="auto" color="#6200ee">
|
|
@@ -114,18 +150,22 @@ window.schmancy.capabilities()
|
|
|
114
150
|
<schmancy-navigation-bar-item icon="search" label="Search"></schmancy-navigation-bar-item>
|
|
115
151
|
<schmancy-navigation-bar-item icon="settings" label="Settings"></schmancy-navigation-bar-item>
|
|
116
152
|
</schmancy-navigation-bar>
|
|
117
|
-
|
|
118
|
-
<schmancy-skill></schmancy-skill>
|
|
119
153
|
</schmancy-page>
|
|
120
154
|
</schmancy-theme>
|
|
121
155
|
```
|
|
122
156
|
|
|
123
157
|
## When the design asks for something you don't recognize
|
|
124
158
|
|
|
125
|
-
1.
|
|
126
|
-
|
|
127
|
-
|
|
159
|
+
1. Fetch the manifest and filter `declarations` by `tagName` to find a
|
|
160
|
+
tag that fits the role.
|
|
161
|
+
2. Read the matching declaration's `attributes`, `slots`, `events`,
|
|
162
|
+
and `cssProperties` arrays — they're the contract.
|
|
163
|
+
3. If no tag fits, compose from primitives (`<schmancy-surface>` +
|
|
164
|
+
`<schmancy-button>` + `<schmancy-grid>` / `<schmancy-flex>` for
|
|
165
|
+
layout) before reaching for a one-off custom element.
|
|
128
166
|
|
|
129
167
|
## Report bugs
|
|
130
168
|
|
|
131
|
-
github.com/mhmo91/schmancy — include
|
|
169
|
+
`github.com/mhmo91/schmancy` — include the schmancy version
|
|
170
|
+
(`https://esm.sh/@mhmo91/schmancy/package.json`), the minimum failing
|
|
171
|
+
HTML, and the manifest's `schemaVersion`.
|
|
@@ -13,9 +13,11 @@ Claude Design (Anthropic Labs) extracts a design system from a codebase at org-o
|
|
|
13
13
|
|
|
14
14
|
```
|
|
15
15
|
schmancy — Material 3 web-component library (100+ <schmancy-*> Lit elements,
|
|
16
|
-
Tailwind 4 theme tokens, RxJS). Single-URL ESM runtime
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
Tailwind 4 theme tokens, RxJS). Single-URL ESM runtime registers every tag
|
|
17
|
+
from one import. Component contracts are introspectable via the static
|
|
18
|
+
Custom Elements Manifest at @mhmo91/schmancy/agent/manifest. Designs look
|
|
19
|
+
like Material You: tonal surfaces, rounded corners, dynamic color palette
|
|
20
|
+
generated from a seed color.
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
**Link code on GitHub:**
|
|
@@ -37,10 +39,12 @@ Use <schmancy-*> custom elements for every UI tag — never raw <button>, <input
|
|
|
37
39
|
Colors: Tailwind utility classes against schmancy theme tokens (bg-primary-default,
|
|
38
40
|
text-surface-on, border-outline-variant). Never hex. Never arbitrary values like bg-[#xxx].
|
|
39
41
|
App shell: wrap in <schmancy-theme root scheme="auto" color="#seed"> then
|
|
40
|
-
<schmancy-surface type="solid" fill="all">.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
in the
|
|
42
|
+
<schmancy-surface type="solid" fill="all">. Overlays use the imperative service
|
|
43
|
+
`show()` / `confirm()` / `prompt()` from @mhmo91/schmancy/overlay — there is no
|
|
44
|
+
$dialog or sheet service. Component contracts (attributes, events, slots, CSS
|
|
45
|
+
parts, typed-attribute enums) live in the static manifest at
|
|
46
|
+
@mhmo91/schmancy/agent/manifest. Full operating manual + copy-pastable minimum
|
|
47
|
+
page: handover/claude-design-brief.md in the repo.
|
|
44
48
|
```
|
|
45
49
|
|
|
46
50
|
## After onboarding
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Every token your design can lean on, grouped by what it's for. Use the **Tailwind class** column when styling — every system token is exposed as a Tailwind utility, so reach for `bg-primary-default` or `text-surface-on` before the raw CSS variable. The CSS variable column is the fallback for properties Tailwind doesn't cover (e.g. `box-shadow`, `transition-duration`).
|
|
4
4
|
|
|
5
|
-
Source of truth: `src/theme/theme.interface.ts` in this repo.
|
|
5
|
+
Source of truth: `src/theme/theme.interface.ts` in this repo. The same flat list of CSS custom property names is enumerated in the static manifest at `@mhmo91/schmancy/agent/manifest` under each tag's `cssProperties` array.
|
|
6
6
|
|
|
7
7
|
> **Never use raw hex** (`#6200ee`) **or arbitrary values** (`bg-[#ff0000]`). Both defeat theming — the whole palette is regenerated from `<schmancy-theme color="…">` and your hardcoded color won't follow scheme switches.
|
|
8
8
|
|
|
@@ -188,11 +188,17 @@ Opacity multipliers for interactive states.
|
|
|
188
188
|
|
|
189
189
|
Both bypass theming and break when `<schmancy-theme color="…" scheme="…">` regenerates the palette.
|
|
190
190
|
|
|
191
|
-
##
|
|
191
|
+
## Introspection at build time
|
|
192
192
|
|
|
193
193
|
```js
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
const manifest = await fetch('https://esm.sh/@mhmo91/schmancy/agent/manifest')
|
|
195
|
+
.then(r => r.json())
|
|
196
|
+
|
|
197
|
+
const tokens = new Set(
|
|
198
|
+
manifest.modules
|
|
199
|
+
.flatMap(m => m.declarations)
|
|
200
|
+
.flatMap(d => (d.cssProperties ?? []).map(p => p.name))
|
|
201
|
+
)
|
|
202
|
+
// → Set<string> — every --schmancy-sys-* property name surfaced by any tag.
|
|
203
|
+
// Use this to verify a token exists before referencing it in CSS.
|
|
198
204
|
```
|
package/dist/skills/INDEX.md
CHANGED
|
@@ -8,7 +8,7 @@ The framework pieces — touch before components.
|
|
|
8
8
|
|
|
9
9
|
- [Area](./area.md) — `<schmancy-area>`, `<schmancy-route>`, `area.push()`, `lazy()` for routing.
|
|
10
10
|
- [State](./state.md) — `state()` factory (memory / session / local / idb), variant write APIs (`Object` / `Map` / `Set` / `Array` / `Scalar`), `bindState`, `computed`, `stateFromObservable`.
|
|
11
|
-
- [Mixins](./mixins.md) —
|
|
11
|
+
- [Mixins](./mixins.md) — `SchmancyElement` base class.
|
|
12
12
|
- [Theme](./theme.md) — `<schmancy-theme>`, color scheme, CSS variables.
|
|
13
13
|
- [Directives](./directives.md) — Lit directives for physics, effects, text, visibility, interaction.
|
|
14
14
|
- [Animation](./animation.md) — Spring presets (`SPRING_SMOOTH`, etc.), `createAnimation`.
|
package/dist/skills/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: schmancy
|
|
3
|
-
description: UI patterns, component APIs, and conventions for the @mhmo91/schmancy web-component library (Lit + RxJS + Tailwind) — the exclusive UI stack in this repo's `web/` workspace. Fire this skill on ANY web-UI work, even when the user doesn't name schmancy explicitly — including adding or editing a component, building a form, showing a dialog / toast / side drawer / bottom sheet, wiring routing, reading or writing a
|
|
3
|
+
description: UI patterns, component APIs, and conventions for the @mhmo91/schmancy web-component library (Lit + RxJS + Tailwind) — the exclusive UI stack in this repo's `web/` workspace. Fire this skill on ANY web-UI work, even when the user doesn't name schmancy explicitly — including adding or editing a component, building a form, showing a dialog / toast / side drawer / bottom sheet, wiring routing, reading or writing a state, styling with theme tokens, adding a drop zone / file input / date picker / autocomplete, working with `SchmancyElement`, or touching any `<schmancy-*>` tag. Also fire on prompts like "build a page", "add a modal", "wire a route", "save user prefs in storage", "animate this", "style with our theme", "make a notification", "how do I do X in Lit", "my drag-and-drop", "dark mode toggle".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Schmancy
|
|
@@ -56,19 +56,20 @@ Use component tags (`<schmancy-menu>`, `<schmancy-dropdown>`, `<schmancy-tooltip
|
|
|
56
56
|
Remediation: before reporting any file compliant, run a grep against each forbidden pattern named by the rule under audit (e.g. `grep -nE '\[(?:[^]]+)\]' <file>` for `TOKEN_FIRST_NO_ARBITRARY`; `grep -nE 'class="[^"]*\b(text-|bg-|border-|rounded-|shadow-|tracking-|leading-|p[xy]?-)' <file>` plus a manual scan for raw `<div>`/`<span>` carrying those classes for `PRIMITIVE_FIRST`). The compliance report's body is the concatenation of those grep outputs annotated with their rule name; an empty body across every pattern under every rule is the only form of "compliant". A claim of compliance unaccompanied by the grep evidence is not a compliance report and is treated as an unverified assertion that the audit loop rejects.
|
|
57
57
|
- **Schmancy primitive first** (`PRIMITIVE_FIRST`). Within `web/**`, every visible UI element is a custom element exported from `packages/schmancy/src/**`, and an element absent from that export set is added there before being imported into `web/**`. The rule sits above the styling rules: a `<div class="text-xs text-surface-on-variant">…</div>` whose role is typography is a violation even when every utility resolves to a registered token, because `<schmancy-typography>` already covers that role; the styling rules apply only to whatever class strings remain after the right primitive has been selected.
|
|
58
58
|
Sources: [packages/schmancy/skills/schmancy/INDEX.md](../INDEX.md) catalogues the export set by job (foundations / atoms / forms / navigation / overlays / interaction / feedback / display); each role's reference file (`typography.md`, `surface.md`, `button.md`, `overlay.md`, …) names the props, slots, and events that displace the equivalent `<div>` + utility-class pattern. The export set is the single source — a primitive that is not exported from `packages/schmancy/src/**` does not satisfy this rule even if it lives in a private file inside the schmancy tree.
|
|
59
|
-
Remediation: walk every `.ts` and `.html` file under `web/**` and list every raw HTML element whose class string carries design-system styling (typography, color, spacing-as-design-decision, surface, layout-as-design-decision, motion, overlay) — those are the violations. For each, look up the matching schmancy primitive in `INDEX.md` and rewrite the element through that primitive (`<schmancy-typography type=… token=…>` for type-scale text, `<schmancy-surface type=… fill=…>` for elevated/bounded surfaces, `<schmancy-grid>`/`<schmancy-flex>` for layout primitives with design intent, the imperative `show`/`$notify`/`schmancyContentDrawer.push` services for overlays, `<schmancy-scroll>` for scroll containers). When a needed primitive is absent from the export set, design and implement it as a new component under `packages/schmancy/src/<role>/` — extending
|
|
59
|
+
Remediation: walk every `.ts` and `.html` file under `web/**` and list every raw HTML element whose class string carries design-system styling (typography, color, spacing-as-design-decision, surface, layout-as-design-decision, motion, overlay) — those are the violations. For each, look up the matching schmancy primitive in `INDEX.md` and rewrite the element through that primitive (`<schmancy-typography type=… token=…>` for type-scale text, `<schmancy-surface type=… fill=…>` for elevated/bounded surfaces, `<schmancy-grid>`/`<schmancy-flex>` for layout primitives with design intent, the imperative `show`/`$notify`/`schmancyContentDrawer.push` services for overlays, `<schmancy-scroll>` for scroll containers). When a needed primitive is absent from the export set, design and implement it as a new component under `packages/schmancy/src/<role>/` — extending `SchmancyElement` with `static styles = [css\`...\`]`, registered in `HTMLElementTagNameMap`, exported through the package barrel, and documented with a sibling `.md` in the skill's reference set — and only then introduce the first call site in `web/**`. The audit subagent iterates the whole `web/**` tree, surfaces the violation list, applies the rewrites, runs `yarn workspace @momo/web tsc --noEmit` plus the colocated `*-view.test.ts` suites, and reports pre-existing violations that require a new schmancy primitive as a separate punch list for designer/architect approval before the implementation lands. The loop exits when every `web/**` file's visible UI elements are schmancy primitives and the typecheck plus the test suites pass.
|
|
60
60
|
|
|
61
61
|
## Non-negotiable conventions
|
|
62
62
|
|
|
63
63
|
**Component authoring**
|
|
64
|
-
- Every component extends `SchmancyElement` and declares its component-local CSS via `static styles = [css\`...\`]`. Never raw `LitElement`. Never wrap with `SignalWatcher` — the base already includes it; double-wrapping creates two nested Computeds and panics with "Detected cycle in computations" at runtime.
|
|
64
|
+
- Every component extends `SchmancyElement` and declares its component-local CSS via `static styles = [css\`...\`]`. Never raw `LitElement`. Never wrap with `SignalWatcher` — the base already includes it; double-wrapping creates two nested Computeds and panics with "Detected cycle in computations" at runtime.
|
|
65
65
|
- Every RxJS subscription ends with `.pipe(takeUntil(this.disconnecting))`.
|
|
66
66
|
- Register the tag in `HTMLElementTagNameMap` for TypeScript.
|
|
67
67
|
|
|
68
68
|
**State**
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
69
|
+
- States live at module scope. Many small states beat one monolith. Use `state('feature/name').{memory,session,local,idb}(initial)` from `@mhmo91/schmancy/state`.
|
|
70
|
+
- Reading `state.value` inside `render()` auto-tracks via the base class's `SignalWatcher` — no decorator or binding needed for the default case.
|
|
71
|
+
- `await state.ready` (or `if (state.loaded)`) before reading persisted-backend values that hydrate asynchronously.
|
|
72
|
+
- Storage tiers: `.memory()` (regenerable) · `.session()` (per-tab) · `.local()` (user prefs) · `.idb()` (>100-entry collections).
|
|
72
73
|
|
|
73
74
|
**Routing**
|
|
74
75
|
- Route guards are `Observable<boolean>`, never cached booleans.
|
package/dist/skills/audio.md
CHANGED
|
@@ -36,7 +36,7 @@ sound.muted$.subscribe(m => {})
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
## Settings Persistence
|
|
39
|
-
Volume, mute, and custom theme persist to `localStorage` under key `schmancy-sound-settings` (via `
|
|
39
|
+
Volume, mute, and custom theme persist to `localStorage` under key `schmancy-sound-settings` (via `state(...).local(...)` from `@mhmo91/schmancy/state`).
|
|
40
40
|
|
|
41
41
|
## AI-Generated Themes
|
|
42
42
|
```typescript
|
package/dist/skills/discovery.md
CHANGED
|
@@ -38,7 +38,7 @@ discoverAnyComponent('schmancy-navigation-rail', 'schmancy-navigation-bar')
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
### `discoverElement(selector, timeout = 150)`
|
|
41
|
-
Finds any element by CSS selector across shadow DOM. Uses a request ID + universal `schmancy-discover` event. Every
|
|
41
|
+
Finds any element by CSS selector across shadow DOM. Uses a request ID + universal `schmancy-discover` event. Every `SchmancyElement` responds if it finds a match in its shadow root.
|
|
42
42
|
```typescript
|
|
43
43
|
discoverElement('[data-section="pricing"]').subscribe(section => section?.scrollIntoView())
|
|
44
44
|
```
|
|
@@ -51,12 +51,12 @@ discoverAllElements('.flagged').subscribe(all => console.log(all.length))
|
|
|
51
51
|
|
|
52
52
|
## How the Handshake Works
|
|
53
53
|
1. Caller creates a unique `requestId` and broadcasts `schmancy-discover` on `window` with `{ selector, requestId }`.
|
|
54
|
-
2. Every
|
|
54
|
+
2. Every `SchmancyElement` listens for this event (wired up in the base class).
|
|
55
55
|
3. Any matching element dispatches `schmancy-discover-response` with `{ requestId, element }`.
|
|
56
56
|
4. Caller collects responses for the timeout window and emits via RxJS.
|
|
57
57
|
|
|
58
58
|
## Pattern in Base Class
|
|
59
|
-
Every
|
|
59
|
+
Every `SchmancyElement` inherits auto-response: `discover<T>(tag)` (method on the component) and `{tagName}-where-are-you`/`{tagName}-here-i-am` events. See [mixins.md](./mixins.md).
|
|
60
60
|
|
|
61
61
|
## When to Use
|
|
62
62
|
- Cross-shadow coordination between unrelated components.
|
package/dist/skills/menu.md
CHANGED
|
@@ -36,4 +36,4 @@ Auto-dismisses the dialog when clicked. Renders as a `schmancy-list-item` intern
|
|
|
36
36
|
</schmancy-menu>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Uses
|
|
39
|
+
Uses `show(overlay, { anchor })` from `@mhmo91/schmancy/overlay` internally. `<schmancy-menu-item>` auto-closes the menu by dispatching a `'close'` event on click. Custom components in the default slot dismiss the menu the same way: `this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))`.
|
package/dist/skills/overlay.md
CHANGED
|
@@ -40,7 +40,7 @@ Centered is the fallback (no anchor given). Sheet is the responsive adaptation (
|
|
|
40
40
|
|
|
41
41
|
## Subscription IS the overlay lifecycle
|
|
42
42
|
|
|
43
|
-
Inside any
|
|
43
|
+
Inside any `SchmancyElement`, pipe `takeUntil(this.disconnecting)`. When the caller unmounts, the overlay auto-dismisses — no handles to track, no leaks.
|
|
44
44
|
|
|
45
45
|
```ts
|
|
46
46
|
show(MyForm, { props: { id }, anchor: ev })
|
|
@@ -8,7 +8,7 @@ The framework pieces — touch before components.
|
|
|
8
8
|
|
|
9
9
|
- [Area](./area.md) — `<schmancy-area>`, `<schmancy-route>`, `area.push()`, `lazy()` for routing.
|
|
10
10
|
- [State](./state.md) — `state()` factory (memory / session / local / idb), variant write APIs (`Object` / `Map` / `Set` / `Array` / `Scalar`), `bindState`, `computed`, `stateFromObservable`.
|
|
11
|
-
- [Mixins](./mixins.md) —
|
|
11
|
+
- [Mixins](./mixins.md) — `SchmancyElement` base class.
|
|
12
12
|
- [Theme](./theme.md) — `<schmancy-theme>`, color scheme, CSS variables.
|
|
13
13
|
- [Directives](./directives.md) — Lit directives for physics, effects, text, visibility, interaction.
|
|
14
14
|
- [Animation](./animation.md) — Spring presets (`SPRING_SMOOTH`, etc.), `createAnimation`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: schmancy
|
|
3
|
-
description: UI patterns, component APIs, and conventions for the @mhmo91/schmancy web-component library (Lit + RxJS + Tailwind) — the exclusive UI stack in this repo's `web/` workspace. Fire this skill on ANY web-UI work, even when the user doesn't name schmancy explicitly — including adding or editing a component, building a form, showing a dialog / toast / side drawer / bottom sheet, wiring routing, reading or writing a
|
|
3
|
+
description: UI patterns, component APIs, and conventions for the @mhmo91/schmancy web-component library (Lit + RxJS + Tailwind) — the exclusive UI stack in this repo's `web/` workspace. Fire this skill on ANY web-UI work, even when the user doesn't name schmancy explicitly — including adding or editing a component, building a form, showing a dialog / toast / side drawer / bottom sheet, wiring routing, reading or writing a state, styling with theme tokens, adding a drop zone / file input / date picker / autocomplete, working with `SchmancyElement`, or touching any `<schmancy-*>` tag. Also fire on prompts like "build a page", "add a modal", "wire a route", "save user prefs in storage", "animate this", "style with our theme", "make a notification", "how do I do X in Lit", "my drag-and-drop", "dark mode toggle".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Schmancy
|
|
@@ -56,19 +56,20 @@ Use component tags (`<schmancy-menu>`, `<schmancy-dropdown>`, `<schmancy-tooltip
|
|
|
56
56
|
Remediation: before reporting any file compliant, run a grep against each forbidden pattern named by the rule under audit (e.g. `grep -nE '\[(?:[^]]+)\]' <file>` for `TOKEN_FIRST_NO_ARBITRARY`; `grep -nE 'class="[^"]*\b(text-|bg-|border-|rounded-|shadow-|tracking-|leading-|p[xy]?-)' <file>` plus a manual scan for raw `<div>`/`<span>` carrying those classes for `PRIMITIVE_FIRST`). The compliance report's body is the concatenation of those grep outputs annotated with their rule name; an empty body across every pattern under every rule is the only form of "compliant". A claim of compliance unaccompanied by the grep evidence is not a compliance report and is treated as an unverified assertion that the audit loop rejects.
|
|
57
57
|
- **Schmancy primitive first** (`PRIMITIVE_FIRST`). Within `web/**`, every visible UI element is a custom element exported from `packages/schmancy/src/**`, and an element absent from that export set is added there before being imported into `web/**`. The rule sits above the styling rules: a `<div class="text-xs text-surface-on-variant">…</div>` whose role is typography is a violation even when every utility resolves to a registered token, because `<schmancy-typography>` already covers that role; the styling rules apply only to whatever class strings remain after the right primitive has been selected.
|
|
58
58
|
Sources: [packages/schmancy/skills/schmancy/INDEX.md](../INDEX.md) catalogues the export set by job (foundations / atoms / forms / navigation / overlays / interaction / feedback / display); each role's reference file (`typography.md`, `surface.md`, `button.md`, `overlay.md`, …) names the props, slots, and events that displace the equivalent `<div>` + utility-class pattern. The export set is the single source — a primitive that is not exported from `packages/schmancy/src/**` does not satisfy this rule even if it lives in a private file inside the schmancy tree.
|
|
59
|
-
Remediation: walk every `.ts` and `.html` file under `web/**` and list every raw HTML element whose class string carries design-system styling (typography, color, spacing-as-design-decision, surface, layout-as-design-decision, motion, overlay) — those are the violations. For each, look up the matching schmancy primitive in `INDEX.md` and rewrite the element through that primitive (`<schmancy-typography type=… token=…>` for type-scale text, `<schmancy-surface type=… fill=…>` for elevated/bounded surfaces, `<schmancy-grid>`/`<schmancy-flex>` for layout primitives with design intent, the imperative `show`/`$notify`/`schmancyContentDrawer.push` services for overlays, `<schmancy-scroll>` for scroll containers). When a needed primitive is absent from the export set, design and implement it as a new component under `packages/schmancy/src/<role>/` — extending
|
|
59
|
+
Remediation: walk every `.ts` and `.html` file under `web/**` and list every raw HTML element whose class string carries design-system styling (typography, color, spacing-as-design-decision, surface, layout-as-design-decision, motion, overlay) — those are the violations. For each, look up the matching schmancy primitive in `INDEX.md` and rewrite the element through that primitive (`<schmancy-typography type=… token=…>` for type-scale text, `<schmancy-surface type=… fill=…>` for elevated/bounded surfaces, `<schmancy-grid>`/`<schmancy-flex>` for layout primitives with design intent, the imperative `show`/`$notify`/`schmancyContentDrawer.push` services for overlays, `<schmancy-scroll>` for scroll containers). When a needed primitive is absent from the export set, design and implement it as a new component under `packages/schmancy/src/<role>/` — extending `SchmancyElement` with `static styles = [css\`...\`]`, registered in `HTMLElementTagNameMap`, exported through the package barrel, and documented with a sibling `.md` in the skill's reference set — and only then introduce the first call site in `web/**`. The audit subagent iterates the whole `web/**` tree, surfaces the violation list, applies the rewrites, runs `yarn workspace @momo/web tsc --noEmit` plus the colocated `*-view.test.ts` suites, and reports pre-existing violations that require a new schmancy primitive as a separate punch list for designer/architect approval before the implementation lands. The loop exits when every `web/**` file's visible UI elements are schmancy primitives and the typecheck plus the test suites pass.
|
|
60
60
|
|
|
61
61
|
## Non-negotiable conventions
|
|
62
62
|
|
|
63
63
|
**Component authoring**
|
|
64
|
-
- Every component extends `SchmancyElement` and declares its component-local CSS via `static styles = [css\`...\`]`. Never raw `LitElement`. Never wrap with `SignalWatcher` — the base already includes it; double-wrapping creates two nested Computeds and panics with "Detected cycle in computations" at runtime.
|
|
64
|
+
- Every component extends `SchmancyElement` and declares its component-local CSS via `static styles = [css\`...\`]`. Never raw `LitElement`. Never wrap with `SignalWatcher` — the base already includes it; double-wrapping creates two nested Computeds and panics with "Detected cycle in computations" at runtime.
|
|
65
65
|
- Every RxJS subscription ends with `.pipe(takeUntil(this.disconnecting))`.
|
|
66
66
|
- Register the tag in `HTMLElementTagNameMap` for TypeScript.
|
|
67
67
|
|
|
68
68
|
**State**
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
69
|
+
- States live at module scope. Many small states beat one monolith. Use `state('feature/name').{memory,session,local,idb}(initial)` from `@mhmo91/schmancy/state`.
|
|
70
|
+
- Reading `state.value` inside `render()` auto-tracks via the base class's `SignalWatcher` — no decorator or binding needed for the default case.
|
|
71
|
+
- `await state.ready` (or `if (state.loaded)`) before reading persisted-backend values that hydrate asynchronously.
|
|
72
|
+
- Storage tiers: `.memory()` (regenerable) · `.session()` (per-tab) · `.local()` (user prefs) · `.idb()` (>100-entry collections).
|
|
72
73
|
|
|
73
74
|
**Routing**
|
|
74
75
|
- Route guards are `Observable<boolean>`, never cached booleans.
|
|
@@ -36,7 +36,7 @@ sound.muted$.subscribe(m => {})
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
## Settings Persistence
|
|
39
|
-
Volume, mute, and custom theme persist to `localStorage` under key `schmancy-sound-settings` (via `
|
|
39
|
+
Volume, mute, and custom theme persist to `localStorage` under key `schmancy-sound-settings` (via `state(...).local(...)` from `@mhmo91/schmancy/state`).
|
|
40
40
|
|
|
41
41
|
## AI-Generated Themes
|
|
42
42
|
```typescript
|
|
@@ -38,7 +38,7 @@ discoverAnyComponent('schmancy-navigation-rail', 'schmancy-navigation-bar')
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
### `discoverElement(selector, timeout = 150)`
|
|
41
|
-
Finds any element by CSS selector across shadow DOM. Uses a request ID + universal `schmancy-discover` event. Every
|
|
41
|
+
Finds any element by CSS selector across shadow DOM. Uses a request ID + universal `schmancy-discover` event. Every `SchmancyElement` responds if it finds a match in its shadow root.
|
|
42
42
|
```typescript
|
|
43
43
|
discoverElement('[data-section="pricing"]').subscribe(section => section?.scrollIntoView())
|
|
44
44
|
```
|
|
@@ -51,12 +51,12 @@ discoverAllElements('.flagged').subscribe(all => console.log(all.length))
|
|
|
51
51
|
|
|
52
52
|
## How the Handshake Works
|
|
53
53
|
1. Caller creates a unique `requestId` and broadcasts `schmancy-discover` on `window` with `{ selector, requestId }`.
|
|
54
|
-
2. Every
|
|
54
|
+
2. Every `SchmancyElement` listens for this event (wired up in the base class).
|
|
55
55
|
3. Any matching element dispatches `schmancy-discover-response` with `{ requestId, element }`.
|
|
56
56
|
4. Caller collects responses for the timeout window and emits via RxJS.
|
|
57
57
|
|
|
58
58
|
## Pattern in Base Class
|
|
59
|
-
Every
|
|
59
|
+
Every `SchmancyElement` inherits auto-response: `discover<T>(tag)` (method on the component) and `{tagName}-where-are-you`/`{tagName}-here-i-am` events. See [mixins.md](./mixins.md).
|
|
60
60
|
|
|
61
61
|
## When to Use
|
|
62
62
|
- Cross-shadow coordination between unrelated components.
|
|
@@ -36,4 +36,4 @@ Auto-dismisses the dialog when clicked. Renders as a `schmancy-list-item` intern
|
|
|
36
36
|
</schmancy-menu>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Uses
|
|
39
|
+
Uses `show(overlay, { anchor })` from `@mhmo91/schmancy/overlay` internally. `<schmancy-menu-item>` auto-closes the menu by dispatching a `'close'` event on click. Custom components in the default slot dismiss the menu the same way: `this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))`.
|
|
@@ -40,7 +40,7 @@ Centered is the fallback (no anchor given). Sheet is the responsive adaptation (
|
|
|
40
40
|
|
|
41
41
|
## Subscription IS the overlay lifecycle
|
|
42
42
|
|
|
43
|
-
Inside any
|
|
43
|
+
Inside any `SchmancyElement`, pipe `takeUntil(this.disconnecting)`. When the caller unmounts, the overlay auto-dismisses — no handles to track, no leaks.
|
|
44
44
|
|
|
45
45
|
```ts
|
|
46
46
|
show(MyForm, { props: { id }, anchor: ev })
|