@mhmo91/schmancy 0.10.2 → 0.10.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.
@@ -1,19 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "readme": "# Schmancy\n\nA Web Component UI library built on Lit, RxJS, and Tailwind CSS. Surfaces are glass. Depth is light. Interactions are physics.\n\n## Agent runtime\n\nFor sandboxed-iframe agents (Claude Design, Claude Artifacts, any LLM that can\nonly write HTML), schmancy ships a single-URL runtime at `@mhmo91/schmancy/agent`.\nDrop one `<script type=\"module\">` tag and every `<schmancy-*>` element is\nregistered. No bundler, no bare specifiers, no npm install.\n\n```html\n<script type=\"module\">\n import { $dialog, theme } from 'https://esm.sh/@mhmo91/schmancy/agent';\n</script>\n<schmancy-theme root scheme=\"dark\">\n <schmancy-surface type=\"solid\" fill=\"all\">\n <schmancy-button>Hi</schmancy-button>\n <schmancy-skill></schmancy-skill>\n </schmancy-surface>\n</schmancy-theme>\n```\n\nThe `<schmancy-skill>` tag installs `window.schmancy` for runtime discovery:\n\n- `window.schmancy.help()` full manifest (CEM v1 shape).\n- `window.schmancy.help('schmancy-button')` — one tag's attributes, events, slots, CSS parts.\n- `window.schmancy.tokens()` — build-time-extracted list of `--schmancy-*` theme tokens.\n- `window.schmancy.manifestUrl` — Blob URL; `fetch()` it for the same data.\n- `window.schmancy.a11yAudit()` — walks the live DOM and reports ARIA / shadow-root / form-association status per instance.\n- `window.schmancy.platformPrimitive('schmancy-dialog')` — map to the native element a component wraps (present when the component's JSDoc has `@platform`).\n- `window.schmancy.capabilities()` — runtime feature probe (`popover`, `declarativeShadowDom`, `scopedRegistries`, `trustedTypes`, `cssRegisteredProperties`, `elementInternalsAria`, `formAssociated`, `adoptedStyleSheets`). Agents use this to adapt to the sandbox they're in rather than the one they expect.\n\nEvery enum-typed attribute carries a `values` array e.g. `schmancy-button`'s `variant` ships `[\"elevated\", \"filled\", \"filled tonal\", \"tonal\", \"outlined\", \"text\"]` so agents never have to parse `\"'filled' | 'tonal' | ...\"` strings.\n\nThe manifest is also emitted as a sibling file at `@mhmo91/schmancy/agent/manifest`\nfor tooling that prefers reading JSON from disk.\n\n## Install\n\n```bash\nnpm install @mhmo91/schmancy\n```\n\n```typescript\nimport '@mhmo91/schmancy'\nimport { magnetic, cursorGlow, gravity } from '@mhmo91/schmancy/directives'\n```\n\n## Use with Claude Code\n\nSchmancy ships a Claude Code plugin. In any Claude Code session, run:\n\n```\n/plugin install https://github.com/samwaai/schmancy\n```\n\nClaude now knows every Schmancy component, foundation pattern, and convention in your project. The skill activates automatically when you work on schmancy code — no CLAUDE.md edits, no symlinks.\n\n## Quick Start\n\n```html\n<schmancy-theme root scheme=\"dark\">\n <schmancy-surface type=\"solid\" fill=\"all\">\n <schmancy-area name=\"root\" .default=${lazy(() => import('./home.page'))}>\n <schmancy-route when=\"home-page\" .component=${lazy(() => import('./home.page'))} />\n </schmancy-area>\n </schmancy-surface>\n</schmancy-theme>\n```\n\n## Design: Luminous Glass\n\n| Surface | Opacity | Blur | Purpose |\n|---------|---------|------|---------|\n| `solid` | 92% | — | Dense glass, high readability |\n| `subtle` | 78% | 8px | Frosted panel (default) |\n| `glass` | 55% | 16px | Overlays, dialogs, dropdowns |\n| `luminous` | 42% | 20px | Hero panels with glow halo |\n\n## Docs\n\nSchmancy is organized in four layers:\n\n- **Foundations** — [Area](./skills/schmancy/area.md) · [Store](./skills/schmancy/store.md) · [Mixins ($LitElement)](./skills/schmancy/mixins.md) · [Theme](./skills/schmancy/theme.md) · [Directives](./skills/schmancy/directives.md)\n- **Atoms** — [Typography](./skills/schmancy/typography.md) · [Icons](./skills/schmancy/icons.md) · [Button](./skills/schmancy/button.md) · [Surface](./skills/schmancy/surface.md) · [Divider](./skills/schmancy/divider.md) · [Avatar](./skills/schmancy/avatar.md)\n- **Composites (by job)** — Forms, Navigation, Overlays, Interaction, Feedback, Display\n- **Utilities** — [Animation](./skills/schmancy/animation.md) · [Audio](./skills/schmancy/audio.md) · [Discovery](./skills/schmancy/discovery.md) · [RxJS Utils](./skills/schmancy/rxjs-utils.md) · [Utils](./skills/schmancy/utils.md)\n\n**Full component index:** [skills/schmancy/INDEX.md](./skills/schmancy/INDEX.md) — the single-file map with every tag, service, and convention. Written primarily for AI agents; humans welcome.\n\n## Tech Stack\n\n[Lit](https://lit.dev) · [RxJS](https://rxjs.dev) · [Tailwind CSS v4](https://tailwindcss.com) · [Blackbird](./src/utils/animation.ts)\n\n## License\n\nApache-2.0\n",
3
+ "readme": "# Schmancy\n\nA Web Component UI library built on Lit, RxJS, and Tailwind CSS. Surfaces are glass. Depth is light. Interactions are physics.\n\n## Agent runtime\n\nFor sandboxed-iframe agents (Claude Design, Claude Artifacts, any LLM that can\nonly write HTML), schmancy ships a single-URL runtime at `@mhmo91/schmancy/agent`.\nDrop one `<script type=\"module\">` tag and every `<schmancy-*>` element is\nregistered. No bundler, no bare specifiers, no npm install.\n\n```html\n<script type=\"module\">\n import 'https://esm.sh/@mhmo91/schmancy/agent';\n</script>\n<schmancy-theme root scheme=\"dark\">\n <schmancy-surface type=\"solid\" fill=\"all\">\n <schmancy-button>Hi</schmancy-button>\n </schmancy-surface>\n</schmancy-theme>\n```\n\nThe same entry re-exports the full library surface for in-page script\ncode (`theme`, `area`, `state`, `show`, `lazy`, every directive, every\nservice, `SchmancyElement`). Import from the same URL.\n\nFor introspection every tag's attributes, events, slots, CSS parts,\nplus the enum `values` array on every typed attribute (so agents don't\nhave to parse `\"'filled' | 'tonal' | ...\"` strings) read the static\nmanifest at `@mhmo91/schmancy/agent/manifest`. It's a JSON file, shape\nfollows Custom Elements Manifest v1.\n\n## Install\n\n```bash\nnpm install @mhmo91/schmancy\n```\n\n```typescript\nimport '@mhmo91/schmancy'\nimport { magnetic, cursorGlow, gravity } from '@mhmo91/schmancy/directives'\n```\n\n## Use with Claude Code\n\nSchmancy ships a Claude Code plugin (manifest at `.claude-plugin/plugin.json`,\nskill source under `skills/schmancy/`). The npm tarball includes both, so\nafter `npm install @mhmo91/schmancy`, point Claude at the package directory\nwhen launching:\n\n```\nclaude --plugin-dir node_modules/@mhmo91/schmancy\n```\n\nSet a shell alias / `.envrc` so every session in the project picks it up.\nAfter editing plugin files, run `/reload-plugins` inside the session.\n\nClaude now knows every Schmancy component, foundation pattern, and\nconvention; the skill activates automatically when you work on schmancy\ncode — no CLAUDE.md edits, no symlinks.\n\n## Quick Start\n\n```html\n<schmancy-theme root scheme=\"dark\">\n <schmancy-surface type=\"solid\" fill=\"all\">\n <schmancy-area name=\"root\" .default=${lazy(() => import('./home.page'))}>\n <schmancy-route when=\"home-page\" .component=${lazy(() => import('./home.page'))} />\n </schmancy-area>\n </schmancy-surface>\n</schmancy-theme>\n```\n\n## Design: Luminous Glass\n\n| Surface | Opacity | Blur | Purpose |\n|---------|---------|------|---------|\n| `solid` | 92% | — | Dense glass, high readability |\n| `subtle` | 78% | 8px | Frosted panel (default) |\n| `glass` | 55% | 16px | Overlays, dialogs, dropdowns |\n| `luminous` | 42% | 20px | Hero panels with glow halo |\n\n## Docs\n\nSchmancy is organized in four layers:\n\n- **Foundations** — [Area](./skills/schmancy/area.md) · [State](./skills/schmancy/state.md) · [Mixins (SchmancyElement)](./skills/schmancy/mixins.md) · [Theme](./skills/schmancy/theme.md) · [Directives](./skills/schmancy/directives.md)\n- **Atoms** — [Typography](./skills/schmancy/typography.md) · [Icons](./skills/schmancy/icons.md) · [Button](./skills/schmancy/button.md) · [Surface](./skills/schmancy/surface.md) · [Divider](./skills/schmancy/divider.md) · [Avatar](./skills/schmancy/avatar.md)\n- **Composites (by job)** — Forms, Navigation, Overlays, Interaction, Feedback, Display\n- **Utilities** — [Animation](./skills/schmancy/animation.md) · [Audio](./skills/schmancy/audio.md) · [Discovery](./skills/schmancy/discovery.md) · [RxJS Utils](./skills/schmancy/rxjs-utils.md) · [Utils](./skills/schmancy/utils.md)\n\n**Full component index:** [skills/schmancy/INDEX.md](./skills/schmancy/INDEX.md) — the single-file map with every tag, service, and convention. Written primarily for AI agents; humans welcome.\n\n## Tech Stack\n\n[Lit](https://lit.dev) · [RxJS](https://rxjs.dev) · [Tailwind CSS v4](https://tailwindcss.com) · [Blackbird](./src/utils/animation.ts)\n\n## License\n\nApache-2.0\n",
4
4
  "modules": [
5
- {
6
- "kind": "javascript-module",
7
- "path": "agent/schmancy-skill.ts",
8
- "declarations": [
9
- {
10
- "kind": "class",
11
- "name": "SchmancySkill",
12
- "tagName": "schmancy-skill",
13
- "description": "Self-describing runtime helper. Drop `<schmancy-skill></schmancy-skill>` once on a page and `window.schmancy.help('schmancy-button')` returns the machine-readable entry for any tag. Renders nothing."
14
- }
15
- ]
16
- },
17
5
  {
18
6
  "kind": "javascript-module",
19
7
  "path": "area/area.component.ts",
@@ -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.2` in `handover/**/*.md` against `package.json`'s `version` field on every build. `dist/handover/**/*.md` gets the rendered version; the source stays templated.
206
+ **Fix.** A build step that substitutes `0.10.4` 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.2
11
- https://esm.sh/@mhmo91/schmancy/agent/manifest@0.10.2
10
+ https://esm.sh/@mhmo91/schmancy/agent@0.10.4
11
+ https://esm.sh/@mhmo91/schmancy/agent/manifest@0.10.4
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.2';
23
+ import { $dialog, theme } from 'https://esm.sh/@mhmo91/schmancy/agent@0.10.4';
24
24
  </script>
25
25
  <schmancy-theme root scheme="dark">
26
26
  <schmancy-surface type="solid" fill="all">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhmo91/schmancy",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "UI library build with web components",
5
5
  "main": "./dist/index.js",
6
6
  "customElements": "custom-elements.json",
@@ -3,8 +3,6 @@ import { resolve } from 'node:path'
3
3
  import { Project, type ClassDeclaration, type SourceFile } from 'ts-morph'
4
4
  import type { Plugin } from 'vite'
5
5
 
6
- const VIRTUAL_ID = 'virtual:schmancy-manifest'
7
- const RESOLVED_VIRTUAL_ID = '\0' + VIRTUAL_ID
8
6
 
9
7
  type Attribute = {
10
8
  name: string
@@ -415,17 +413,6 @@ export default function schmancyManifestPlugin(options: SchmancyManifestPluginOp
415
413
  compute()
416
414
  },
417
415
 
418
- resolveId(id) {
419
- if (id === VIRTUAL_ID) return RESOLVED_VIRTUAL_ID
420
- return null
421
- },
422
-
423
- load(id) {
424
- if (id !== RESOLVED_VIRTUAL_ID) return null
425
- const manifest = cachedManifest ?? compute()
426
- return `export default ${JSON.stringify(manifest)};`
427
- },
428
-
429
416
  generateBundle() {
430
417
  const manifest = cachedManifest ?? compute()
431
418
  this.emitFile({
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import './agent-entry'
3
+
4
+ // Minimal smoke gate for the publish workflow. Loads the agent bundle entry
5
+ // in a real browser and asserts that the side-effect tag registration the
6
+ // esm.sh script-tag use case relies on actually fires. If the entry throws
7
+ // at import time or fails to register a representative tag, the publish step
8
+ // fails before the package goes out.
9
+ describe('agent bundle', () => {
10
+ it('registers core schmancy-* tags on import', () => {
11
+ expect(customElements.get('schmancy-button')).toBeDefined()
12
+ expect(customElements.get('schmancy-theme')).toBeDefined()
13
+ expect(customElements.get('schmancy-surface')).toBeDefined()
14
+ })
15
+ })
@@ -1,18 +1,13 @@
1
+ // Single-URL bundle for sandboxed-iframe agents (Claude Design, Artifacts,
2
+ // any host that can only write HTML and consume one esm.sh URL). Side-effect
3
+ // import of the root registers every `<schmancy-*>` tag; re-exporting the
4
+ // root gives in-page script code the full library surface from the same URL.
5
+ //
6
+ // `SchmancyElement` is re-exported from `../../mixins/index` because the
7
+ // root index doesn't currently surface mixins. The deprecated `$LitElement`
8
+ // alias is intentionally NOT re-exported here — agent contexts get the
9
+ // canonical base class.
1
10
  import '../index'
2
- import './schmancy-skill'
3
11
 
4
- export {
5
- $dialog,
6
- $notify,
7
- sheet,
8
- SchmancySheetPosition,
9
- schmancyContentDrawer,
10
- theme,
11
- area,
12
- lazy,
13
- state,
14
- bindState,
15
- computed,
16
- stateFromObservable,
17
- } from '../index'
18
- export { $LitElement } from '../../mixins/index'
12
+ export * from '../index'
13
+ export { SchmancyElement } from '../../mixins/index'
@@ -1,4 +1,3 @@
1
1
  import '../index';
2
- import './schmancy-skill';
3
- export { $dialog, $notify, sheet, SchmancySheetPosition, schmancyContentDrawer, theme, area, lazy, state, bindState, computed, stateFromObservable, } from '../index';
4
- export { $LitElement } from '../../mixins/index';
2
+ export * from '../index';
3
+ export { SchmancyElement } from '../../mixins/index';
@@ -1,92 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import './agent-entry'
3
-
4
- /**
5
- * Acceptance test per the Claude Design handover §4.4:
6
- *
7
- * > "CI check: load the bundle in a headless browser, assert
8
- * > `customElements.get('schmancy-button')` resolves, assert
9
- * > `window.schmancy.help()` returns non-empty."
10
- *
11
- * This test is the runtime smoke test. It imports the agent bundle entry
12
- * (which side-effect registers every <schmancy-*> tag plus <schmancy-skill>)
13
- * and then verifies the self-describing surface is installed.
14
- */
15
- describe('agent bundle — handover §4.4 acceptance', () => {
16
- it('registers `schmancy-button` on import', () => {
17
- expect(customElements.get('schmancy-button')).toBeDefined()
18
- })
19
-
20
- it('registers `schmancy-skill` on import', () => {
21
- expect(customElements.get('schmancy-skill')).toBeDefined()
22
- })
23
-
24
- it('installs `window.schmancy` when a <schmancy-skill> connects', async () => {
25
- const host = document.createElement('div')
26
- const skill = document.createElement('schmancy-skill')
27
- host.appendChild(skill)
28
- document.body.appendChild(host)
29
-
30
- await customElements.whenDefined('schmancy-skill')
31
- // One microtask for connectedCallback to finish installing globals.
32
- await new Promise(requestAnimationFrame)
33
-
34
- expect(typeof window.schmancy).toBe('object')
35
- expect(typeof window.schmancy?.help).toBe('function')
36
- expect(typeof window.schmancy?.tokens).toBe('function')
37
- expect(typeof window.schmancy?.capabilities).toBe('function')
38
-
39
- host.remove()
40
- })
41
-
42
- it('`window.schmancy.help()` returns a non-empty manifest summary', async () => {
43
- const skill = document.createElement('schmancy-skill')
44
- document.body.appendChild(skill)
45
- await customElements.whenDefined('schmancy-skill')
46
- await new Promise(requestAnimationFrame)
47
-
48
- const help = window.schmancy!.help() as { elements: unknown[]; services: unknown[] }
49
- expect(Array.isArray(help.elements)).toBe(true)
50
- expect(help.elements.length).toBeGreaterThan(50)
51
-
52
- skill.remove()
53
- })
54
-
55
- it('`window.schmancy.help("schmancy-button")` returns attribute enum values', async () => {
56
- const skill = document.createElement('schmancy-skill')
57
- document.body.appendChild(skill)
58
- await customElements.whenDefined('schmancy-skill')
59
- await new Promise(requestAnimationFrame)
60
-
61
- const btn = window.schmancy!.help('schmancy-button') as {
62
- attributes?: Array<{ name: string; values?: string[] }>
63
- }
64
- expect(btn).toBeTruthy()
65
- expect(btn.attributes?.length ?? 0).toBeGreaterThan(0)
66
- const variant = btn.attributes?.find(a => a.name === 'variant')
67
- expect(variant?.values).toContain('filled')
68
-
69
- skill.remove()
70
- })
71
-
72
- it('`window.schmancy.capabilities()` reports every probed feature', async () => {
73
- const skill = document.createElement('schmancy-skill')
74
- document.body.appendChild(skill)
75
- await customElements.whenDefined('schmancy-skill')
76
- await new Promise(requestAnimationFrame)
77
-
78
- const caps = window.schmancy!.capabilities()
79
- expect(caps).toMatchObject({
80
- popover: expect.any(Boolean),
81
- declarativeShadowDom: expect.any(Boolean),
82
- scopedRegistries: expect.any(Boolean),
83
- trustedTypes: expect.any(Boolean),
84
- cssRegisteredProperties: expect.any(Boolean),
85
- elementInternalsAria: expect.any(Boolean),
86
- formAssociated: expect.any(Boolean),
87
- adoptedStyleSheets: expect.any(Boolean),
88
- })
89
-
90
- skill.remove()
91
- })
92
- })
@@ -1,159 +0,0 @@
1
- import manifest from 'virtual:schmancy-manifest'
2
-
3
- export type ElementEntry = {
4
- kind: 'class'
5
- name: string
6
- tagName?: string
7
- description?: string
8
- summary?: string
9
- attributes?: Array<{
10
- name: string
11
- description?: string
12
- type?: { text?: string }
13
- default?: string
14
- values?: string[]
15
- }>
16
- events?: Array<{ name: string; description?: string; type?: { text?: string } }>
17
- slots?: Array<{ name: string; description?: string }>
18
- cssProperties?: Array<{ name: string; description?: string }>
19
- cssParts?: Array<{ name: string; description?: string }>
20
- whenToUse?: string
21
- platformPrimitive?: { tag: string; mode?: string; note?: string }
22
- contexts?: { provides?: string[]; consumes?: string[] }
23
- }
24
-
25
- export type ServiceEntry = {
26
- kind: 'variable'
27
- name: string
28
- description?: string
29
- summary?: string
30
- service: true
31
- methods?: Array<{ signature: string; summary?: string }>
32
- }
33
-
34
- type Declaration = ElementEntry | ServiceEntry | { kind: string; name: string; [key: string]: unknown }
35
-
36
- function allDeclarations(): Declaration[] {
37
- const out: Declaration[] = []
38
- for (const mod of manifest.modules ?? []) {
39
- const decls = (mod as unknown as { declarations?: Declaration[] }).declarations ?? []
40
- for (const decl of decls) out.push(decl)
41
- }
42
- return out
43
- }
44
-
45
- function elements(): ElementEntry[] {
46
- return allDeclarations().filter(
47
- (d): d is ElementEntry => d.kind === 'class' && typeof (d as ElementEntry).tagName === 'string',
48
- )
49
- }
50
-
51
- function services(): ServiceEntry[] {
52
- return allDeclarations().filter((d): d is ServiceEntry => d.kind === 'variable' && (d as ServiceEntry).service === true)
53
- }
54
-
55
- export function help(tag?: string): unknown {
56
- if (!tag) {
57
- return {
58
- elements: elements().map(e => ({ tag: e.tagName, summary: e.summary ?? e.description })),
59
- services: services().map(s => ({ name: s.name, summary: s.summary ?? s.description })),
60
- }
61
- }
62
- const el = elements().find(e => e.tagName === tag)
63
- if (el) return el
64
- const svc = services().find(s => s.name === tag)
65
- if (svc) return svc
66
- return null
67
- }
68
-
69
- export function tokens(): string[] {
70
- return (manifest as { tokens?: string[] }).tokens ?? []
71
- }
72
-
73
- export function platformPrimitive(tag: string): ElementEntry['platformPrimitive'] | null {
74
- return elements().find(e => e.tagName === tag)?.platformPrimitive ?? null
75
- }
76
-
77
- export function registeredTags(): string[] {
78
- return elements()
79
- .map(e => e.tagName!)
80
- .filter(tag => typeof customElements.get(tag) !== 'undefined')
81
- }
82
-
83
- export function a11yAudit(): Array<{
84
- tag: string
85
- role: string | null
86
- ariaLabel: string | null
87
- hasShadowRoot: boolean
88
- formAssociated: boolean
89
- }> {
90
- const tags = new Set(elements().map(e => e.tagName!))
91
- const report: Array<{
92
- tag: string
93
- role: string | null
94
- ariaLabel: string | null
95
- hasShadowRoot: boolean
96
- formAssociated: boolean
97
- }> = []
98
- const all = document.querySelectorAll('*')
99
- for (const node of Array.from(all)) {
100
- const tag = node.tagName.toLowerCase()
101
- if (!tags.has(tag)) continue
102
- const ctor = customElements.get(tag) as (CustomElementConstructor & { formAssociated?: boolean }) | undefined
103
- report.push({
104
- tag,
105
- role: node.getAttribute('role'),
106
- ariaLabel: node.getAttribute('aria-label'),
107
- hasShadowRoot: Boolean((node as Element & { shadowRoot?: ShadowRoot | null }).shadowRoot),
108
- formAssociated: Boolean(ctor?.formAssociated),
109
- })
110
- }
111
- return report
112
- }
113
-
114
- export type Capabilities = {
115
- popover: boolean
116
- declarativeShadowDom: boolean
117
- scopedRegistries: boolean
118
- trustedTypes: boolean
119
- cssRegisteredProperties: boolean
120
- elementInternalsAria: boolean
121
- formAssociated: boolean
122
- adoptedStyleSheets: boolean
123
- }
124
-
125
- /**
126
- * Runtime feature probe. Tells an agent which platform capabilities the
127
- * current sandbox exposes, so it can adapt without assuming the sandbox CSP
128
- * or browser version. Every check is feature-detect, not UA-sniff.
129
- */
130
- export function capabilities(): Capabilities {
131
- const anyTemplate = typeof HTMLTemplateElement !== 'undefined' ? HTMLTemplateElement.prototype : null
132
- const anyElInternals = typeof ElementInternals !== 'undefined' ? ElementInternals.prototype : null
133
- return {
134
- popover: typeof HTMLElement !== 'undefined' && 'popover' in HTMLElement.prototype,
135
- declarativeShadowDom: Boolean(anyTemplate && 'shadowRootMode' in anyTemplate),
136
- scopedRegistries: (() => {
137
- try {
138
- // Native scoped registries require a constructible CustomElementRegistry.
139
- // Pre-Safari-26/Chrome-146, the constructor throws Illegal constructor.
140
- void new (window as { CustomElementRegistry?: new () => unknown }).CustomElementRegistry!()
141
- return true
142
- } catch {
143
- return false
144
- }
145
- })(),
146
- trustedTypes: typeof (globalThis as { trustedTypes?: unknown }).trustedTypes !== 'undefined',
147
- cssRegisteredProperties: typeof (window as { CSS?: { registerProperty?: unknown } }).CSS?.registerProperty === 'function',
148
- elementInternalsAria: Boolean(anyElInternals && 'role' in anyElInternals),
149
- formAssociated: typeof ElementInternals !== 'undefined',
150
- adoptedStyleSheets: typeof Document !== 'undefined' && 'adoptedStyleSheets' in Document.prototype,
151
- }
152
- }
153
-
154
- export function manifestUrl(): string {
155
- const blob = new Blob([JSON.stringify(manifest)], { type: 'application/json' })
156
- return URL.createObjectURL(blob)
157
- }
158
-
159
- export { manifest }
@@ -1,71 +0,0 @@
1
- import { SchmancyElement } from '../../mixins/index'
2
- import { html } from 'lit'
3
- import { customElement } from 'lit/decorators.js'
4
- import {
5
- a11yAudit,
6
- capabilities,
7
- help,
8
- manifest,
9
- manifestUrl,
10
- platformPrimitive,
11
- registeredTags,
12
- tokens,
13
- } from './helpers'
14
-
15
- declare global {
16
- interface Window {
17
- schmancy?: {
18
- manifest: typeof manifest
19
- manifestUrl: string
20
- help: typeof help
21
- tokens: typeof tokens
22
- platformPrimitive: typeof platformPrimitive
23
- registeredTags: typeof registeredTags
24
- a11yAudit: typeof a11yAudit
25
- capabilities: typeof capabilities
26
- }
27
- }
28
- }
29
-
30
- let installedUrl: string | null = null
31
-
32
- function install() {
33
- if (typeof window === 'undefined') return
34
- if (installedUrl) return
35
- installedUrl = manifestUrl()
36
- window.schmancy = {
37
- manifest,
38
- manifestUrl: installedUrl,
39
- help,
40
- tokens,
41
- platformPrimitive,
42
- registeredTags,
43
- a11yAudit,
44
- capabilities,
45
- }
46
- }
47
-
48
- /**
49
- * Self-describing runtime helper. Drop `<schmancy-skill></schmancy-skill>`
50
- * once on a page and `window.schmancy.help('schmancy-button')` returns the
51
- * machine-readable entry for any tag. Renders nothing.
52
- *
53
- * @element schmancy-skill
54
- */
55
- @customElement('schmancy-skill')
56
- export class SchmancySkill extends SchmancyElement {
57
- connectedCallback() {
58
- super.connectedCallback()
59
- install()
60
- }
61
-
62
- render() {
63
- return html``
64
- }
65
- }
66
-
67
- declare global {
68
- interface HTMLElementTagNameMap {
69
- 'schmancy-skill': SchmancySkill
70
- }
71
- }
@@ -1,10 +0,0 @@
1
- declare module 'virtual:schmancy-manifest' {
2
- type ManifestModule = { kind: 'javascript-module'; path: string; declarations: Array<Record<string, unknown>> }
3
- const manifest: {
4
- schemaVersion: '1.0.0'
5
- readme?: string
6
- modules: ManifestModule[]
7
- tokens: string[]
8
- }
9
- export default manifest
10
- }
@@ -1,86 +0,0 @@
1
- import manifest from 'virtual:schmancy-manifest';
2
- export type ElementEntry = {
3
- kind: 'class';
4
- name: string;
5
- tagName?: string;
6
- description?: string;
7
- summary?: string;
8
- attributes?: Array<{
9
- name: string;
10
- description?: string;
11
- type?: {
12
- text?: string;
13
- };
14
- default?: string;
15
- values?: string[];
16
- }>;
17
- events?: Array<{
18
- name: string;
19
- description?: string;
20
- type?: {
21
- text?: string;
22
- };
23
- }>;
24
- slots?: Array<{
25
- name: string;
26
- description?: string;
27
- }>;
28
- cssProperties?: Array<{
29
- name: string;
30
- description?: string;
31
- }>;
32
- cssParts?: Array<{
33
- name: string;
34
- description?: string;
35
- }>;
36
- whenToUse?: string;
37
- platformPrimitive?: {
38
- tag: string;
39
- mode?: string;
40
- note?: string;
41
- };
42
- contexts?: {
43
- provides?: string[];
44
- consumes?: string[];
45
- };
46
- };
47
- export type ServiceEntry = {
48
- kind: 'variable';
49
- name: string;
50
- description?: string;
51
- summary?: string;
52
- service: true;
53
- methods?: Array<{
54
- signature: string;
55
- summary?: string;
56
- }>;
57
- };
58
- export declare function help(tag?: string): unknown;
59
- export declare function tokens(): string[];
60
- export declare function platformPrimitive(tag: string): ElementEntry['platformPrimitive'] | null;
61
- export declare function registeredTags(): string[];
62
- export declare function a11yAudit(): Array<{
63
- tag: string;
64
- role: string | null;
65
- ariaLabel: string | null;
66
- hasShadowRoot: boolean;
67
- formAssociated: boolean;
68
- }>;
69
- export type Capabilities = {
70
- popover: boolean;
71
- declarativeShadowDom: boolean;
72
- scopedRegistries: boolean;
73
- trustedTypes: boolean;
74
- cssRegisteredProperties: boolean;
75
- elementInternalsAria: boolean;
76
- formAssociated: boolean;
77
- adoptedStyleSheets: boolean;
78
- };
79
- /**
80
- * Runtime feature probe. Tells an agent which platform capabilities the
81
- * current sandbox exposes, so it can adapt without assuming the sandbox CSP
82
- * or browser version. Every check is feature-detect, not UA-sniff.
83
- */
84
- export declare function capabilities(): Capabilities;
85
- export declare function manifestUrl(): string;
86
- export { manifest };
@@ -1,32 +0,0 @@
1
- import { SchmancyElement } from '../../mixins/index';
2
- import { a11yAudit, capabilities, help, manifest, platformPrimitive, registeredTags, tokens } from './helpers';
3
- declare global {
4
- interface Window {
5
- schmancy?: {
6
- manifest: typeof manifest;
7
- manifestUrl: string;
8
- help: typeof help;
9
- tokens: typeof tokens;
10
- platformPrimitive: typeof platformPrimitive;
11
- registeredTags: typeof registeredTags;
12
- a11yAudit: typeof a11yAudit;
13
- capabilities: typeof capabilities;
14
- };
15
- }
16
- }
17
- /**
18
- * Self-describing runtime helper. Drop `<schmancy-skill></schmancy-skill>`
19
- * once on a page and `window.schmancy.help('schmancy-button')` returns the
20
- * machine-readable entry for any tag. Renders nothing.
21
- *
22
- * @element schmancy-skill
23
- */
24
- export declare class SchmancySkill extends SchmancyElement {
25
- connectedCallback(): void;
26
- render(): import("lit-html").TemplateResult<1>;
27
- }
28
- declare global {
29
- interface HTMLElementTagNameMap {
30
- 'schmancy-skill': SchmancySkill;
31
- }
32
- }