@mhmo91/schmancy 0.9.4 → 0.9.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.
Files changed (217) hide show
  1. package/.claude-plugin/plugin.json +13 -0
  2. package/README.md +14 -4
  3. package/dist/.claude-plugin/plugin.json +13 -0
  4. package/dist/skills/SKILL.md +120 -0
  5. package/dist/skills/schmancy/SKILL.md +120 -0
  6. package/package.json +3 -3
  7. package/skills/schmancy/INDEX.md +72 -0
  8. package/skills/schmancy/SKILL.md +120 -0
  9. package/skills/schmancy/animation.md +64 -0
  10. package/skills/schmancy/area.md +141 -0
  11. package/skills/schmancy/audio.md +69 -0
  12. package/skills/schmancy/autocomplete.md +53 -0
  13. package/skills/schmancy/avatar.md +47 -0
  14. package/skills/schmancy/badge.md +41 -0
  15. package/skills/schmancy/boat.md +47 -0
  16. package/skills/schmancy/busy.md +36 -0
  17. package/skills/schmancy/button.md +59 -0
  18. package/skills/schmancy/card.md +53 -0
  19. package/skills/schmancy/charts.md +93 -0
  20. package/skills/schmancy/checkbox.md +36 -0
  21. package/skills/schmancy/chips.md +87 -0
  22. package/skills/schmancy/code-highlight.md +47 -0
  23. package/skills/schmancy/connectivity.md +36 -0
  24. package/skills/schmancy/content-drawer.md +65 -0
  25. package/skills/schmancy/date-range-inline.md +44 -0
  26. package/skills/schmancy/date-range.md +50 -0
  27. package/skills/schmancy/delay.md +50 -0
  28. package/skills/schmancy/details.md +66 -0
  29. package/skills/schmancy/dialog.md +69 -0
  30. package/skills/schmancy/directives.md +298 -0
  31. package/skills/schmancy/discovery.md +67 -0
  32. package/skills/schmancy/divider.md +31 -0
  33. package/skills/schmancy/dropdown.md +47 -0
  34. package/skills/schmancy/expand.md +63 -0
  35. package/skills/schmancy/extra.md +59 -0
  36. package/skills/schmancy/float.md +14 -0
  37. package/skills/schmancy/form.md +49 -0
  38. package/skills/schmancy/icons.md +44 -0
  39. package/skills/schmancy/iframe.md +44 -0
  40. package/skills/schmancy/input.md +56 -0
  41. package/skills/schmancy/json.md +33 -0
  42. package/skills/schmancy/layout.md +63 -0
  43. package/skills/schmancy/lightbox.md +36 -0
  44. package/skills/schmancy/list.md +67 -0
  45. package/skills/schmancy/mailbox.md +102 -0
  46. package/skills/schmancy/map.md +55 -0
  47. package/skills/schmancy/menu.md +39 -0
  48. package/skills/schmancy/mixins.md +99 -0
  49. package/skills/schmancy/nav-drawer.md +52 -0
  50. package/skills/schmancy/navigation-bar.md +48 -0
  51. package/skills/schmancy/navigation-rail.md +62 -0
  52. package/skills/schmancy/notification.md +60 -0
  53. package/skills/schmancy/option.md +43 -0
  54. package/skills/schmancy/page.md +42 -0
  55. package/skills/schmancy/progress.md +30 -0
  56. package/skills/schmancy/qr-scanner.md +51 -0
  57. package/skills/schmancy/radio-group.md +50 -0
  58. package/skills/schmancy/range.md +47 -0
  59. package/skills/schmancy/rxjs-utils.md +60 -0
  60. package/skills/schmancy/select.md +49 -0
  61. package/skills/schmancy/sheet.md +76 -0
  62. package/skills/schmancy/slider.md +43 -0
  63. package/skills/schmancy/steps.md +53 -0
  64. package/skills/schmancy/store.md +126 -0
  65. package/skills/schmancy/surface.md +86 -0
  66. package/skills/schmancy/table.md +60 -0
  67. package/skills/schmancy/tabs.md +49 -0
  68. package/skills/schmancy/teleport.md +55 -0
  69. package/skills/schmancy/textarea.md +48 -0
  70. package/skills/schmancy/theme-button.md +26 -0
  71. package/skills/schmancy/theme.md +58 -0
  72. package/skills/schmancy/tooltip.md +38 -0
  73. package/skills/schmancy/tree.md +53 -0
  74. package/skills/schmancy/typewriter.md +46 -0
  75. package/skills/schmancy/typography.md +53 -0
  76. package/skills/schmancy/utils.md +95 -0
  77. package/skills/schmancy/window.md +67 -0
  78. /package/{ai → dist/skills}/INDEX.md +0 -0
  79. /package/{ai → dist/skills}/animation.md +0 -0
  80. /package/{ai → dist/skills}/area.md +0 -0
  81. /package/{ai → dist/skills}/audio.md +0 -0
  82. /package/{ai → dist/skills}/autocomplete.md +0 -0
  83. /package/{ai → dist/skills}/avatar.md +0 -0
  84. /package/{ai → dist/skills}/badge.md +0 -0
  85. /package/{ai → dist/skills}/boat.md +0 -0
  86. /package/{ai → dist/skills}/busy.md +0 -0
  87. /package/{ai → dist/skills}/button.md +0 -0
  88. /package/{ai → dist/skills}/card.md +0 -0
  89. /package/{ai → dist/skills}/charts.md +0 -0
  90. /package/{ai → dist/skills}/checkbox.md +0 -0
  91. /package/{ai → dist/skills}/chips.md +0 -0
  92. /package/{ai → dist/skills}/code-highlight.md +0 -0
  93. /package/{ai → dist/skills}/connectivity.md +0 -0
  94. /package/{ai → dist/skills}/content-drawer.md +0 -0
  95. /package/{ai → dist/skills}/date-range-inline.md +0 -0
  96. /package/{ai → dist/skills}/date-range.md +0 -0
  97. /package/{ai → dist/skills}/delay.md +0 -0
  98. /package/{ai → dist/skills}/details.md +0 -0
  99. /package/{ai → dist/skills}/dialog.md +0 -0
  100. /package/{ai → dist/skills}/directives.md +0 -0
  101. /package/{ai → dist/skills}/discovery.md +0 -0
  102. /package/{ai → dist/skills}/divider.md +0 -0
  103. /package/{ai → dist/skills}/dropdown.md +0 -0
  104. /package/{ai → dist/skills}/expand.md +0 -0
  105. /package/{ai → dist/skills}/extra.md +0 -0
  106. /package/{ai → dist/skills}/float.md +0 -0
  107. /package/{ai → dist/skills}/form.md +0 -0
  108. /package/{ai → dist/skills}/icons.md +0 -0
  109. /package/{ai → dist/skills}/iframe.md +0 -0
  110. /package/{ai → dist/skills}/input.md +0 -0
  111. /package/{ai → dist/skills}/json.md +0 -0
  112. /package/{ai → dist/skills}/layout.md +0 -0
  113. /package/{ai → dist/skills}/lightbox.md +0 -0
  114. /package/{ai → dist/skills}/list.md +0 -0
  115. /package/{ai → dist/skills}/mailbox.md +0 -0
  116. /package/{ai → dist/skills}/map.md +0 -0
  117. /package/{ai → dist/skills}/menu.md +0 -0
  118. /package/{ai → dist/skills}/mixins.md +0 -0
  119. /package/{ai → dist/skills}/nav-drawer.md +0 -0
  120. /package/{ai → dist/skills}/navigation-bar.md +0 -0
  121. /package/{ai → dist/skills}/navigation-rail.md +0 -0
  122. /package/{ai → dist/skills}/notification.md +0 -0
  123. /package/{ai → dist/skills}/option.md +0 -0
  124. /package/{ai → dist/skills}/page.md +0 -0
  125. /package/{ai → dist/skills}/progress.md +0 -0
  126. /package/{ai → dist/skills}/qr-scanner.md +0 -0
  127. /package/{ai → dist/skills}/radio-group.md +0 -0
  128. /package/{ai → dist/skills}/range.md +0 -0
  129. /package/{ai → dist/skills}/rxjs-utils.md +0 -0
  130. /package/dist/{ai → skills/schmancy}/INDEX.md +0 -0
  131. /package/dist/{ai → skills/schmancy}/animation.md +0 -0
  132. /package/dist/{ai → skills/schmancy}/area.md +0 -0
  133. /package/dist/{ai → skills/schmancy}/audio.md +0 -0
  134. /package/dist/{ai → skills/schmancy}/autocomplete.md +0 -0
  135. /package/dist/{ai → skills/schmancy}/avatar.md +0 -0
  136. /package/dist/{ai → skills/schmancy}/badge.md +0 -0
  137. /package/dist/{ai → skills/schmancy}/boat.md +0 -0
  138. /package/dist/{ai → skills/schmancy}/busy.md +0 -0
  139. /package/dist/{ai → skills/schmancy}/button.md +0 -0
  140. /package/dist/{ai → skills/schmancy}/card.md +0 -0
  141. /package/dist/{ai → skills/schmancy}/charts.md +0 -0
  142. /package/dist/{ai → skills/schmancy}/checkbox.md +0 -0
  143. /package/dist/{ai → skills/schmancy}/chips.md +0 -0
  144. /package/dist/{ai → skills/schmancy}/code-highlight.md +0 -0
  145. /package/dist/{ai → skills/schmancy}/connectivity.md +0 -0
  146. /package/dist/{ai → skills/schmancy}/content-drawer.md +0 -0
  147. /package/dist/{ai → skills/schmancy}/date-range-inline.md +0 -0
  148. /package/dist/{ai → skills/schmancy}/date-range.md +0 -0
  149. /package/dist/{ai → skills/schmancy}/delay.md +0 -0
  150. /package/dist/{ai → skills/schmancy}/details.md +0 -0
  151. /package/dist/{ai → skills/schmancy}/dialog.md +0 -0
  152. /package/dist/{ai → skills/schmancy}/directives.md +0 -0
  153. /package/dist/{ai → skills/schmancy}/discovery.md +0 -0
  154. /package/dist/{ai → skills/schmancy}/divider.md +0 -0
  155. /package/dist/{ai → skills/schmancy}/dropdown.md +0 -0
  156. /package/dist/{ai → skills/schmancy}/expand.md +0 -0
  157. /package/dist/{ai → skills/schmancy}/extra.md +0 -0
  158. /package/dist/{ai → skills/schmancy}/float.md +0 -0
  159. /package/dist/{ai → skills/schmancy}/form.md +0 -0
  160. /package/dist/{ai → skills/schmancy}/icons.md +0 -0
  161. /package/dist/{ai → skills/schmancy}/iframe.md +0 -0
  162. /package/dist/{ai → skills/schmancy}/input.md +0 -0
  163. /package/dist/{ai → skills/schmancy}/json.md +0 -0
  164. /package/dist/{ai → skills/schmancy}/layout.md +0 -0
  165. /package/dist/{ai → skills/schmancy}/lightbox.md +0 -0
  166. /package/dist/{ai → skills/schmancy}/list.md +0 -0
  167. /package/dist/{ai → skills/schmancy}/mailbox.md +0 -0
  168. /package/dist/{ai → skills/schmancy}/map.md +0 -0
  169. /package/dist/{ai → skills/schmancy}/menu.md +0 -0
  170. /package/dist/{ai → skills/schmancy}/mixins.md +0 -0
  171. /package/dist/{ai → skills/schmancy}/nav-drawer.md +0 -0
  172. /package/dist/{ai → skills/schmancy}/navigation-bar.md +0 -0
  173. /package/dist/{ai → skills/schmancy}/navigation-rail.md +0 -0
  174. /package/dist/{ai → skills/schmancy}/notification.md +0 -0
  175. /package/dist/{ai → skills/schmancy}/option.md +0 -0
  176. /package/dist/{ai → skills/schmancy}/page.md +0 -0
  177. /package/dist/{ai → skills/schmancy}/progress.md +0 -0
  178. /package/dist/{ai → skills/schmancy}/qr-scanner.md +0 -0
  179. /package/dist/{ai → skills/schmancy}/radio-group.md +0 -0
  180. /package/dist/{ai → skills/schmancy}/range.md +0 -0
  181. /package/dist/{ai → skills/schmancy}/rxjs-utils.md +0 -0
  182. /package/{ai → dist/skills/schmancy}/select.md +0 -0
  183. /package/{ai → dist/skills/schmancy}/sheet.md +0 -0
  184. /package/{ai → dist/skills/schmancy}/slider.md +0 -0
  185. /package/{ai → dist/skills/schmancy}/steps.md +0 -0
  186. /package/{ai → dist/skills/schmancy}/store.md +0 -0
  187. /package/{ai → dist/skills/schmancy}/surface.md +0 -0
  188. /package/{ai → dist/skills/schmancy}/table.md +0 -0
  189. /package/{ai → dist/skills/schmancy}/tabs.md +0 -0
  190. /package/{ai → dist/skills/schmancy}/teleport.md +0 -0
  191. /package/{ai → dist/skills/schmancy}/textarea.md +0 -0
  192. /package/{ai → dist/skills/schmancy}/theme-button.md +0 -0
  193. /package/{ai → dist/skills/schmancy}/theme.md +0 -0
  194. /package/{ai → dist/skills/schmancy}/tooltip.md +0 -0
  195. /package/{ai → dist/skills/schmancy}/tree.md +0 -0
  196. /package/{ai → dist/skills/schmancy}/typewriter.md +0 -0
  197. /package/{ai → dist/skills/schmancy}/typography.md +0 -0
  198. /package/{ai → dist/skills/schmancy}/utils.md +0 -0
  199. /package/{ai → dist/skills/schmancy}/window.md +0 -0
  200. /package/dist/{ai → skills}/select.md +0 -0
  201. /package/dist/{ai → skills}/sheet.md +0 -0
  202. /package/dist/{ai → skills}/slider.md +0 -0
  203. /package/dist/{ai → skills}/steps.md +0 -0
  204. /package/dist/{ai → skills}/store.md +0 -0
  205. /package/dist/{ai → skills}/surface.md +0 -0
  206. /package/dist/{ai → skills}/table.md +0 -0
  207. /package/dist/{ai → skills}/tabs.md +0 -0
  208. /package/dist/{ai → skills}/teleport.md +0 -0
  209. /package/dist/{ai → skills}/textarea.md +0 -0
  210. /package/dist/{ai → skills}/theme-button.md +0 -0
  211. /package/dist/{ai → skills}/theme.md +0 -0
  212. /package/dist/{ai → skills}/tooltip.md +0 -0
  213. /package/dist/{ai → skills}/tree.md +0 -0
  214. /package/dist/{ai → skills}/typewriter.md +0 -0
  215. /package/dist/{ai → skills}/typography.md +0 -0
  216. /package/dist/{ai → skills}/utils.md +0 -0
  217. /package/dist/{ai → skills}/window.md +0 -0
@@ -0,0 +1,53 @@
1
+ # schmancy-steps-container / schmancy-step
2
+
3
+ > Vertical stepper with collapsible steps, completion state, and navigation.
4
+
5
+ ## Usage
6
+ ```html
7
+ <schmancy-steps-container currentStep="1" @change=${(e) => handleStep(e.detail.value)}>
8
+ <schmancy-step position="1" title="Account" description="Create your account">
9
+ <schmancy-input label="Email" required></schmancy-input>
10
+ </schmancy-step>
11
+ <schmancy-step position="2" title="Profile" description="Set up profile">
12
+ <schmancy-input label="Name" required></schmancy-input>
13
+ </schmancy-step>
14
+ </schmancy-steps-container>
15
+ ```
16
+
17
+ ## Properties (schmancy-steps-container)
18
+ | Property | Type | Default | Description |
19
+ |----------|------|---------|-------------|
20
+ | currentStep | number | `1` | Currently active step (1-based) |
21
+ | gap | number | `4` | Gap between steps (Tailwind scale) |
22
+
23
+ ## Properties (schmancy-step)
24
+ | Property | Type | Default | Description |
25
+ |----------|------|---------|-------------|
26
+ | position | number | `1` | Step position (1-based) |
27
+ | title | string | `''` | Step title |
28
+ | description | string | `''` | Step description |
29
+ | completed | boolean | `false` | Explicitly mark as complete |
30
+ | lockBack | boolean | `false` | Prevent navigating to previous steps |
31
+
32
+ ## Events (schmancy-steps-container)
33
+ | Event | Detail | Description |
34
+ |-------|--------|-------------|
35
+ | change | `{ value: number }` | When current step changes |
36
+
37
+ ## Examples
38
+ ```html
39
+ <!-- With locked steps -->
40
+ <schmancy-steps-container currentStep="2">
41
+ <schmancy-step position="1" title="Step 1" completed lockBack>
42
+ <!-- Already completed, cannot go back -->
43
+ </schmancy-step>
44
+ <schmancy-step position="2" title="Step 2">
45
+ <p>Current step content</p>
46
+ </schmancy-step>
47
+ <schmancy-step position="3" title="Step 3">
48
+ <!-- Not yet reachable -->
49
+ </schmancy-step>
50
+ </schmancy-steps-container>
51
+ ```
52
+
53
+ Only the active step renders its slotted content. Completed steps show a checkmark. Active step expands with `flex: 1`.
@@ -0,0 +1,126 @@
1
+ # Store — Context System
2
+
3
+ Reactive state management: `createContext`, `@select`, `@selectItem`.
4
+
5
+ ## Creating a context
6
+
7
+ ```typescript
8
+ import { createContext } from '@mhmo91/schmancy'
9
+
10
+ // Object
11
+ const userContext = createContext<User>(new User(), 'local', 'user')
12
+
13
+ // Map (collection)
14
+ const itemsContext = createContext<Map<string, Item>>(new Map(), 'indexeddb', 'items')
15
+
16
+ // Array
17
+ const tagsContext = createContext<string[]>([], 'memory', 'tags')
18
+ ```
19
+
20
+ Signature: `createContext(initial, storage, key)`.
21
+
22
+ ## Storage backends
23
+
24
+ | Mode | Backing | Survives refresh | Survives tab close | Capacity |
25
+ |------|---------|------------------|--------------------|----------|
26
+ | `'memory'` | JS heap | ❌ | ❌ | RAM |
27
+ | `'session'` | `sessionStorage` | ✅ | ❌ (per-tab) | ~5 MB |
28
+ | `'local'` | `localStorage` | ✅ | ✅ | ~5 MB |
29
+ | `'indexeddb'` | IndexedDB | ✅ | ✅ | GB |
30
+
31
+ Pick by data size and lifetime:
32
+ - User prefs, long-lived drafts → `'local'`
33
+ - Per-tab ephemeral (cart, wizard) → `'session'`
34
+ - Fetched from API, regenerable → `'memory'`
35
+ - Collections with >100 entries you want cached → `'indexeddb'`
36
+
37
+ ## Reading with `@select`
38
+
39
+ ```typescript
40
+ import { select } from '@mhmo91/schmancy'
41
+
42
+ @customElement('my-component')
43
+ class MyComponent extends $LitElement() {
44
+ @select(userContext) user!: User
45
+
46
+ // Selector narrows the dependency
47
+ @select(itemsContext, m => m.size) count!: number
48
+
49
+ @select(itemsContext) items!: Map<string, Item>
50
+ }
51
+ ```
52
+
53
+ `@select` options:
54
+ - `required` (default `true`) — wait for `.ready` before `connectedCallback` completes.
55
+ - `updateOnly` — call `requestUpdate` without assigning.
56
+ - `deepClone` — `structuredClone` the value.
57
+ - `debug` — log every emission.
58
+
59
+ ## `@selectItem`
60
+
61
+ Pick one entry from a collection context, keyed off a component property:
62
+
63
+ ```typescript
64
+ @selectItem(itemsContext, component => component.itemId)
65
+ item!: Item | undefined
66
+ ```
67
+
68
+ ## Writing
69
+
70
+ ```typescript
71
+ // Object
72
+ userContext.set({ name: 'Alice' })
73
+ userContext.set({ ...userContext.value, name: 'Bob' })
74
+
75
+ // Map
76
+ itemsContext.set('id-1', item)
77
+ itemsContext.delete('id-1')
78
+ itemsContext.replace(newMap)
79
+
80
+ // Array
81
+ tagsContext.push('new')
82
+ tagsContext.replace(['a', 'b'])
83
+ ```
84
+
85
+ ## Observable API
86
+
87
+ ```typescript
88
+ userContext.$.pipe(
89
+ filter(() => userContext.ready),
90
+ takeUntil(this.disconnecting),
91
+ ).subscribe(user => { /* ... */ })
92
+
93
+ userContext.value // synchronous snapshot
94
+ userContext.ready // true once the backing store has loaded
95
+ ```
96
+
97
+ Gate subscriptions on `.ready` — `'local'` / `'session'` / `'indexeddb'` contexts emit their default value before the real stored value hydrates.
98
+
99
+ ## Dynamic contexts
100
+
101
+ For per-instance state with persistence, create the context inside `connectedCallback` with an instance-scoped key:
102
+
103
+ ```typescript
104
+ private draftCtx: IStore<{ text: string }> | null = null
105
+
106
+ connectedCallback() {
107
+ super.connectedCallback()
108
+ if (this.draftKey) {
109
+ this.draftCtx = createContext<{ text: string }>(
110
+ { text: '' },
111
+ 'session',
112
+ this.draftKey,
113
+ )
114
+ }
115
+ }
116
+ ```
117
+
118
+ ## Rules
119
+
120
+ - Declare contexts at module scope (except dynamic per-instance ones).
121
+ - Name the storage key even for `'memory'` contexts — it helps debugging.
122
+ - Keep each context single-purpose. One write shouldn't invalidate unrelated readers.
123
+ - Only the owning component writes. Others read via `@select`.
124
+ - Every subscription uses `takeUntil(this.disconnecting)`.
125
+ - Gate on `.ready` before async cascading work.
126
+ - Don't store Promises, Observables, functions, or class instances in persistent contexts.
@@ -0,0 +1,86 @@
1
+ # Surface
2
+
3
+ > Glass depth container. Every surface is translucent — depth comes from blur intensity.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <schmancy-surface type="subtle" rounded="all" fill="all">
9
+ Content on frosted glass
10
+ </schmancy-surface>
11
+ ```
12
+
13
+ ## Properties
14
+
15
+ | Property | Type | Default | Description |
16
+ |----------|------|---------|-------------|
17
+ | `type` | string | `'subtle'` | Glass depth level (see below) |
18
+ | `fill` | string | `'auto'` | `'all'`, `'width'`, `'height'`, `'auto'` |
19
+ | `rounded` | string | `'none'` | `'none'`, `'top'`, `'bottom'`, `'left'`, `'right'`, `'all'` |
20
+ | `elevation` | number | `0` | Glow intensity 0-5 (primary-colored glow, not shadow) |
21
+ | `clickable` | boolean | `false` | Adds luminous hover + spring press |
22
+
23
+ ## Surface Types
24
+
25
+ ### Structural (glass depth model)
26
+
27
+ | Type | Opacity | Blur | Use for |
28
+ |------|---------|------|---------|
29
+ | `solid` | 92% | — | Dense glass ground layer, highest readability |
30
+ | `subtle` | 78% | 8px | Frosted panels, default containers |
31
+ | `glass` | 55% | 16px | Dialogs, dropdowns, overlays |
32
+ | `luminous` | 42% | 20px | Hero panels, featured content |
33
+
34
+ ### Semantic (tinted glass)
35
+ `primary`, `secondary`, `tertiary`, `error`, `success`, `warning`, `info`
36
+ Each applies a translucent tint of its color + 4px blur.
37
+
38
+ ### Utility
39
+ - `transparent` — no background
40
+ - `outlined` — border only
41
+
42
+ ## Examples
43
+
44
+ ```html
45
+ <!-- Page background -->
46
+ <schmancy-surface type="solid" fill="all" rounded="none">
47
+ <slot></slot>
48
+ </schmancy-surface>
49
+
50
+ <!-- Card-like container -->
51
+ <schmancy-surface type="subtle" rounded="all" elevation="1">
52
+ <div class="p-4">Frosted panel with glow</div>
53
+ </schmancy-surface>
54
+
55
+ <!-- Dialog surface (used internally by schmancy-dialog) -->
56
+ <schmancy-surface type="glass" rounded="all">
57
+ <div class="p-6">Glass overlay content</div>
58
+ </schmancy-surface>
59
+
60
+ <!-- Hero panel with glow halo -->
61
+ <schmancy-surface type="luminous" rounded="all" elevation="3">
62
+ <div class="p-8">Featured content</div>
63
+ </schmancy-surface>
64
+
65
+ <!-- Clickable surface with spring physics -->
66
+ <schmancy-surface type="subtle" rounded="all" clickable @click=${handler}>
67
+ Hover: lift + glow. Press: spring compress.
68
+ </schmancy-surface>
69
+
70
+ <!-- Error state -->
71
+ <schmancy-surface type="error" rounded="all">
72
+ <div class="p-3">Something went wrong</div>
73
+ </schmancy-surface>
74
+ ```
75
+
76
+ ## Elevation (Glow-based)
77
+
78
+ Elevation 1-5 applies a primary-colored glow underneath the surface:
79
+ ```
80
+ Level 1: subtle glow (15% primary)
81
+ Level 5: strong glow (42% primary)
82
+ ```
83
+
84
+ ## Paint Containment
85
+
86
+ `glass` and `luminous` types automatically apply `contain: content` for GPU optimization.
@@ -0,0 +1,60 @@
1
+ # schmancy-table
2
+
3
+ > Virtualized data table with sorting, custom column rendering, and sticky headers.
4
+
5
+ ## Usage
6
+ ```typescript
7
+ html`
8
+ <schmancy-table
9
+ .columns=${columns}
10
+ .data=${items}
11
+ keyField="id"
12
+ cols="1fr 2fr 1fr"
13
+ sortable
14
+ @click=${(e) => selectRow(e.detail)}>
15
+ </schmancy-table>
16
+ `
17
+ ```
18
+
19
+ ## Properties
20
+ | Property | Type | Default | Description |
21
+ |----------|------|---------|-------------|
22
+ | columns | `TableColumn[]` | `[]` | Column definitions |
23
+ | data | `T[]` | `[]` | Data array |
24
+ | keyField | string | `'id'` | Unique key property on each item |
25
+ | cols | string | `'1fr'` | CSS grid-template-columns |
26
+ | sortable | boolean | `false` | Enable column sorting |
27
+
28
+ ## TableColumn Interface
29
+ ```typescript
30
+ interface TableColumn<T> {
31
+ name: string // Column header text
32
+ key?: keyof T // Data property key
33
+ align?: 'left' | 'right' | 'center'
34
+ weight?: 'normal' | 'bold'
35
+ render?: (item: T) => TemplateResult | string | number
36
+ sortable?: boolean // Per-column sort toggle
37
+ value?: (item: T) => any // Custom sort value function
38
+ }
39
+ ```
40
+
41
+ ## Events
42
+ | Event | Detail | Description |
43
+ |-------|--------|-------------|
44
+ | click | `{ item: T, index: number }` | Row clicked |
45
+ | sort-change | `{ column, direction }` | Sort state changed |
46
+
47
+ ## Examples
48
+ ```typescript
49
+ const columns = [
50
+ { name: 'Name', key: 'name', sortable: true },
51
+ { name: 'Status', key: 'status', render: (item) =>
52
+ html`<schmancy-badge color=${item.active ? 'success' : 'neutral'}>
53
+ ${item.active ? 'Active' : 'Inactive'}
54
+ </schmancy-badge>` },
55
+ { name: 'Created', key: 'createdAt', sortable: true,
56
+ value: (item) => new Date(item.createdAt).getTime() },
57
+ ]
58
+ ```
59
+
60
+ Uses `lit-virtualizer` for efficient rendering of large datasets. Header is sticky with glass surface.
@@ -0,0 +1,49 @@
1
+ # schmancy-tab-group / schmancy-tab
2
+
3
+ > Tab container with tab navigation and scroll-spy mode.
4
+
5
+ ## Usage
6
+ ```html
7
+ <schmancy-tab-group activeTab="overview">
8
+ <schmancy-tab label="Overview" value="overview">
9
+ <p>Overview content</p>
10
+ </schmancy-tab>
11
+ <schmancy-tab label="Details" value="details">
12
+ <p>Details content</p>
13
+ </schmancy-tab>
14
+ </schmancy-tab-group>
15
+ ```
16
+
17
+ ## Properties (schmancy-tab-group)
18
+ | Property | Type | Default | Description |
19
+ |----------|------|---------|-------------|
20
+ | activeTab | string | first tab | Currently active tab value |
21
+ | mode | `'tabs'\|'scroll'` | `'tabs'` | Display mode (tabs or scroll-spy) |
22
+ | rounded | boolean | `true` | Rounded tab bar |
23
+
24
+ ## Properties (schmancy-tab)
25
+ | Property | Type | Default | Description |
26
+ |----------|------|---------|-------------|
27
+ | label | string | - | Tab label text |
28
+ | value | string | - | Unique tab identifier |
29
+ | active | boolean | `false` | Whether this tab is active |
30
+
31
+ ## Events (schmancy-tab-group)
32
+ | Event | Detail | Description |
33
+ |-------|--------|-------------|
34
+ | tab-changed | string | Active tab value when changed |
35
+
36
+ ## Examples
37
+ ```html
38
+ <!-- Scroll-spy mode (tabs follow scroll position) -->
39
+ <schmancy-tab-group mode="scroll">
40
+ <schmancy-tab label="Section 1" value="s1">
41
+ <div style="height: 500px">Long content</div>
42
+ </schmancy-tab>
43
+ <schmancy-tab label="Section 2" value="s2">
44
+ <div style="height: 500px">More content</div>
45
+ </schmancy-tab>
46
+ </schmancy-tab-group>
47
+ ```
48
+
49
+ In `tabs` mode, only the active tab renders content. In `scroll` mode, all tabs render and the nav highlights the visible section.
@@ -0,0 +1,55 @@
1
+ # schmancy-teleport
2
+
3
+ > Move DOM between locations with a FLIP-animated transition. Two instances sharing an `id` handshake via broadcast events — when one mounts, it finds the other and flies the content between them.
4
+
5
+ ## Usage
6
+ ```html
7
+ <!-- Start position -->
8
+ <schmancy-teleport id="hero-image">
9
+ <img src="portrait.jpg" alt="" />
10
+ </schmancy-teleport>
11
+
12
+ <!-- Later, in a different view -->
13
+ <schmancy-teleport id="hero-image"></schmancy-teleport>
14
+ ```
15
+
16
+ When the second instance mounts, the image smoothly animates from its old bounding rect to the new one.
17
+
18
+ ## Properties
19
+ | Property | Type | Default | Description |
20
+ |----------|------|---------|-------------|
21
+ | `id` | string | **required** | Shared identifier between source and target |
22
+ | `uuid` | number | auto | Instance UUID for disambiguation (read-only) |
23
+ | `delay` | number | `0` | Delay before teleporting (ms) |
24
+
25
+ ## Discovery Events
26
+ The service broadcasts on `window`:
27
+ - `FINDING_MORTIES` — "is anyone mounted with id X?"
28
+ - `HERE_RICKY` — instances reply with self reference
29
+ - `WhereAreYouRicky` / `HereMorty` — instance-to-instance handshake
30
+
31
+ Uses RxJS with a race/throwIfEmpty pattern to handle missing counterparts gracefully.
32
+
33
+ ## Typical Pattern — route transitions
34
+ ```html
35
+ <!-- List view -->
36
+ ${repeat(items, item => item.id, item => html`
37
+ <schmancy-teleport id=${`card-${item.id}`}>
38
+ <schmancy-card @click=${() => router.push(`/item/${item.id}`)}>
39
+ <img src=${item.thumbnail} />
40
+ </schmancy-card>
41
+ </schmancy-teleport>
42
+ `)}
43
+
44
+ <!-- Detail view -->
45
+ <schmancy-teleport id=${`card-${this.params.id}`}></schmancy-teleport>
46
+ ```
47
+
48
+ ## Notes
49
+ - Uses `watchElementRect` (ResizeObserver + scroll tracking) to keep source/target in sync.
50
+ - Animation uses the FLIP technique: capture first rect, invert on mount, play to final.
51
+ - All subscriptions clean up via `takeUntil(this.disconnecting)`.
52
+ - Each teleport pair must share a unique `id` string.
53
+
54
+ ## See Also
55
+ - For programmatic teleportation from JS: import `teleportationService` from `@mhmo91/schmancy/teleport`.
@@ -0,0 +1,48 @@
1
+ # schmancy-textarea
2
+
3
+ > Multi-line text input with auto-resize and form integration.
4
+
5
+ ## Usage
6
+ ```html
7
+ <schmancy-textarea label="Description" placeholder="Enter details..."></schmancy-textarea>
8
+ ```
9
+
10
+ ## Properties
11
+ | Property | Type | Default | Description |
12
+ |----------|------|---------|-------------|
13
+ | value | string | `''` | Current text value |
14
+ | label | string | `''` | Label text above the textarea |
15
+ | placeholder | string | `''` | Placeholder text |
16
+ | name | string | auto | Form submission name |
17
+ | required | boolean | `false` | Whether the field is required |
18
+ | disabled | boolean | `false` | Whether the field is disabled |
19
+ | readonly | boolean | `false` | Whether the field is read-only |
20
+ | error | boolean | `false` | Whether the field shows an error state |
21
+ | hint | string | `undefined` | Hint text below the field |
22
+ | rows | number | `undefined` | Fixed visible rows (omit for auto-size) |
23
+ | cols | number | `20` | Column width |
24
+ | maxlength | number | `undefined` | Maximum character length |
25
+ | minlength | number | `undefined` | Minimum character length |
26
+ | autoHeight | boolean | `true` | Auto-grow height with content |
27
+ | fillHeight | boolean | `false` | Fill container height |
28
+ | resize | `'none'\|'vertical'\|'horizontal'\|'both'` | `'vertical'` | Resize handle |
29
+ | align | `'left'\|'center'\|'right'` | `'left'` | Text alignment |
30
+ | wrap | `'hard'\|'soft'` | `'soft'` | Text wrapping mode |
31
+
32
+ ## Events
33
+ | Event | Detail | Description |
34
+ |-------|--------|-------------|
35
+ | change | `{ value: string }` | On input or native change |
36
+ | enter | `{ value: string }` | When Enter key is pressed |
37
+
38
+ ## Examples
39
+ ```html
40
+ <!-- Auto-sizing textarea -->
41
+ <schmancy-textarea label="Notes" autoHeight></schmancy-textarea>
42
+
43
+ <!-- Fixed height, no resize -->
44
+ <schmancy-textarea rows="5" resize="none" placeholder="Comments..."></schmancy-textarea>
45
+
46
+ <!-- Fill container -->
47
+ <schmancy-textarea fillHeight label="Content"></schmancy-textarea>
48
+ ```
@@ -0,0 +1,26 @@
1
+ # schmancy-theme-button
2
+
3
+ > Minimal palette-icon button that spins 360° on click. Hook its `click` to toggle/regenerate your theme.
4
+
5
+ ## Usage
6
+ ```html
7
+ <schmancy-theme-button @click=${() => this.toggleTheme()}></schmancy-theme-button>
8
+ ```
9
+
10
+ ## Behavior
11
+ - Renders a `schmancy-button` (variant `text`) wrapping a palette `schmancy-icon`.
12
+ - On click: Web Animations API rotates the icon 360° over 300ms.
13
+ - No properties — it's a UI affordance; wire the theme logic via `@click`.
14
+
15
+ ## Typical Wiring
16
+ ```typescript
17
+ import { theme } from '@mhmo91/schmancy'
18
+
19
+ // Toggle dark/light
20
+ <schmancy-theme-button @click=${() => theme.toggleScheme()}></schmancy-theme-button>
21
+
22
+ // Randomize primary color
23
+ <schmancy-theme-button @click=${() => theme.randomize()}></schmancy-theme-button>
24
+ ```
25
+
26
+ See [theme.md](./theme.md) for the full theme service API.
@@ -0,0 +1,58 @@
1
+ # schmancy-theme
2
+
3
+ > Root theme provider that generates color tokens from a source color and distributes them as CSS custom properties.
4
+
5
+ ## Usage
6
+ ```html
7
+ <schmancy-theme color="#6200ee" scheme="auto" root>
8
+ <your-app></your-app>
9
+ </schmancy-theme>
10
+ ```
11
+
12
+ ## Properties
13
+ | Property | Type | Default | Description |
14
+ |----------|------|---------|-------------|
15
+ | `color` | `string` | Random hex | Primary source color in hex format (e.g. `#6200ee`) |
16
+ | `scheme` | `'dark' \| 'light' \| 'auto'` | `'auto'` | Color scheme. `auto` follows system preference |
17
+ | `root` | `boolean` | `false` | Apply CSS variables to `document.body` instead of shadow host |
18
+ | `locale` | `string` | `navigator.language` | Locale for number/date formatting (e.g. `de-DE`, `ar-SA`) |
19
+ | `name` | `string` | Auto-generated | Unique name for session storage persistence |
20
+
21
+ ## Theme Service (`theme`)
22
+ ```typescript
23
+ import { theme } from '@mhmo91/schmancy'
24
+
25
+ theme.scheme // 'dark' | 'light' | 'auto' (sync)
26
+ theme.color // Current hex color (sync)
27
+ theme.scheme$ // Observable<string>
28
+ theme.resolvedScheme$ // Observable<'dark'|'light'> (resolves 'auto')
29
+
30
+ theme.setScheme('dark')
31
+ theme.setColor('#2196f3')
32
+ theme.toggleScheme()
33
+ theme.isDarkMode() // Observable<boolean>
34
+ theme.setFullscreen(true)
35
+ ```
36
+
37
+ ## Examples
38
+ ```html
39
+ <!-- App root with dark blue theme -->
40
+ <schmancy-theme color="#1565c0" scheme="dark" root>
41
+ <my-app></my-app>
42
+ </schmancy-theme>
43
+
44
+ <!-- Nested theme override for a section -->
45
+ <schmancy-theme color="#e91e63" scheme="light">
46
+ <div class="accent-section">...</div>
47
+ </schmancy-theme>
48
+
49
+ <!-- Arabic locale -->
50
+ <schmancy-theme color="#4caf50" locale="ar-SA" root>
51
+ <my-app></my-app>
52
+ </schmancy-theme>
53
+ ```
54
+
55
+ ## Notes
56
+ - Color and scheme persist to `sessionStorage` per instance
57
+ - Generates success/warning/info/error semantic color tokens automatically
58
+ - Wraps content in a `schmancy-container` with `containerLowest` surface
@@ -0,0 +1,38 @@
1
+ # tooltip (directive)
2
+
3
+ > Lit directive that adds a positioned tooltip to any element on hover/focus.
4
+
5
+ ## Usage
6
+ ```typescript
7
+ import { tooltip } from '@mhmo91/schmancy'
8
+
9
+ html`<button ${tooltip('Click to save')}>Save</button>`
10
+ ```
11
+
12
+ ## Parameters
13
+ | Parameter | Type | Default | Description |
14
+ |-----------|------|---------|-------------|
15
+ | text | string | required | Tooltip text content |
16
+ | options.position | `'top'\|'right'\|'bottom'\|'left'` | `'top'` | Tooltip placement |
17
+ | options.delay | number | `300` | Show delay in ms |
18
+ | options.showArrow | boolean | `true` | Show arrow indicator |
19
+
20
+ ## Examples
21
+ ```html
22
+ <!-- Bottom positioned -->
23
+ <schmancy-icon-button ${tooltip('Delete item', { position: 'bottom' })}>
24
+ delete
25
+ </schmancy-icon-button>
26
+
27
+ <!-- No delay, no arrow -->
28
+ <span ${tooltip('Status: Active', { delay: 0, showArrow: false })}>
29
+ Active
30
+ </span>
31
+
32
+ <!-- Right positioned -->
33
+ <div ${tooltip('More info here', { position: 'right' })}>
34
+ Hover me
35
+ </div>
36
+ ```
37
+
38
+ Uses Floating UI for smart positioning with automatic flipping when near viewport edges. Accessible via `aria-describedby`. Closes on Escape key.
@@ -0,0 +1,53 @@
1
+ # schmancy-tree
2
+
3
+ > Collapsible tree node with animated expand/collapse and chevron rotation.
4
+
5
+ ## Usage
6
+ ```html
7
+ <schmancy-tree>
8
+ <span slot="root">Parent Item</span>
9
+ <div>Child content here</div>
10
+ </schmancy-tree>
11
+ ```
12
+
13
+ ## Properties
14
+ | Property | Type | Default | Description |
15
+ |----------|------|---------|-------------|
16
+ | open | boolean | `false` | Whether children are visible |
17
+
18
+ ## Slots
19
+ | Slot | Description |
20
+ |------|-------------|
21
+ | root | The clickable root element (toggles open/close) |
22
+ | default | Child content (shown when open) |
23
+
24
+ ## Events
25
+ | Event | Detail | Description |
26
+ |-------|--------|-------------|
27
+ | toggle | - | When the tree node is toggled |
28
+
29
+ ## Examples
30
+ ```html
31
+ <!-- Nested trees -->
32
+ <schmancy-tree>
33
+ <span slot="root">Documents</span>
34
+ <schmancy-tree>
35
+ <span slot="root">Reports</span>
36
+ <div>Q1 Report</div>
37
+ <div>Q2 Report</div>
38
+ </schmancy-tree>
39
+ <schmancy-tree>
40
+ <span slot="root">Invoices</span>
41
+ <div>Invoice #001</div>
42
+ </schmancy-tree>
43
+ </schmancy-tree>
44
+
45
+ <!-- Initially open -->
46
+ <schmancy-tree open>
47
+ <span slot="root">Settings</span>
48
+ <div>General</div>
49
+ <div>Security</div>
50
+ </schmancy-tree>
51
+ ```
52
+
53
+ Clicking the root slot or the chevron button toggles visibility. Animations use the Web Animations API with 150ms duration.