@adia-ai/web-components 0.4.5 → 0.4.7

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 (316) hide show
  1. package/README.md +63 -24
  2. package/USAGE.md +604 -0
  3. package/components/accordion/accordion.d.ts +17 -0
  4. package/components/accordion/accordion.js +10 -117
  5. package/components/accordion/class.js +132 -0
  6. package/components/action-list/action-list.d.ts +15 -0
  7. package/components/action-list/action-list.js +9 -140
  8. package/components/action-list/class.js +156 -0
  9. package/components/agent-artifact/agent-artifact.d.ts +25 -0
  10. package/components/agent-artifact/agent-artifact.js +8 -181
  11. package/components/agent-artifact/class.js +200 -0
  12. package/components/agent-feedback-bar/agent-feedback-bar.d.ts +21 -0
  13. package/components/agent-feedback-bar/agent-feedback-bar.js +8 -143
  14. package/components/agent-feedback-bar/class.js +162 -0
  15. package/components/agent-questions/agent-questions.d.ts +23 -0
  16. package/components/agent-questions/agent-questions.js +8 -180
  17. package/components/agent-questions/class.js +199 -0
  18. package/components/agent-reasoning/agent-reasoning.d.ts +23 -0
  19. package/components/agent-reasoning/agent-reasoning.js +8 -494
  20. package/components/agent-reasoning/class.js +513 -0
  21. package/components/agent-suggestions/agent-suggestions.d.ts +21 -0
  22. package/components/agent-suggestions/agent-suggestions.js +8 -78
  23. package/components/agent-suggestions/class.js +97 -0
  24. package/components/agent-trace/agent-trace.d.ts +19 -0
  25. package/components/alert/alert.d.ts +29 -0
  26. package/components/alert/alert.js +8 -175
  27. package/components/alert/class.js +194 -0
  28. package/components/avatar/avatar.d.ts +27 -0
  29. package/components/avatar/avatar.js +9 -159
  30. package/components/avatar/class.js +173 -0
  31. package/components/badge/badge.d.ts +27 -0
  32. package/components/badge/badge.js +9 -75
  33. package/components/badge/class.js +93 -0
  34. package/components/block/block.d.ts +19 -0
  35. package/components/block/block.js +9 -15
  36. package/components/block/class.js +33 -0
  37. package/components/breadcrumb/breadcrumb.d.ts +23 -0
  38. package/components/breadcrumb/breadcrumb.js +8 -113
  39. package/components/breadcrumb/class.js +132 -0
  40. package/components/button/button.d.ts +34 -0
  41. package/components/button/button.js +15 -66
  42. package/components/button/class.js +80 -0
  43. package/components/calendar-picker/calendar-picker.a2ui.json +6 -1
  44. package/components/calendar-picker/calendar-picker.d.ts +27 -0
  45. package/components/calendar-picker/calendar-picker.js +8 -332
  46. package/components/calendar-picker/calendar-picker.yaml +51 -177
  47. package/components/calendar-picker/class.js +351 -0
  48. package/components/canvas/canvas.a2ui.json +6 -1
  49. package/components/canvas/canvas.d.ts +17 -0
  50. package/components/canvas/canvas.yaml +19 -36
  51. package/components/card/card.a2ui.json +3 -0
  52. package/components/card/card.d.ts +27 -0
  53. package/components/card/card.js +9 -50
  54. package/components/card/card.yaml +171 -433
  55. package/components/card/class.js +68 -0
  56. package/components/chart/chart.d.ts +41 -0
  57. package/components/chart/chart.js +8 -2131
  58. package/components/chart/class.js +2150 -0
  59. package/components/chart-legend/chart-legend.d.ts +27 -0
  60. package/components/chart-legend/chart-legend.js +8 -197
  61. package/components/chart-legend/class.js +215 -0
  62. package/components/chat-thread/chat-thread.d.ts +17 -0
  63. package/components/chat-thread/chat-thread.js +8 -157
  64. package/components/chat-thread/class.js +176 -0
  65. package/components/check/check.d.ts +30 -0
  66. package/components/check/check.js +11 -52
  67. package/components/check/class.js +68 -0
  68. package/components/code/class.js +501 -0
  69. package/components/code/code.d.ts +39 -0
  70. package/components/code/code.js +8 -482
  71. package/components/col/class.js +30 -0
  72. package/components/col/col.d.ts +23 -0
  73. package/components/col/col.js +10 -13
  74. package/components/color-picker/class.js +550 -0
  75. package/components/color-picker/color-picker.d.ts +37 -0
  76. package/components/color-picker/color-picker.js +8 -531
  77. package/components/command/class.js +364 -0
  78. package/components/command/command.a2ui.json +3 -0
  79. package/components/command/command.d.ts +19 -0
  80. package/components/command/command.js +8 -345
  81. package/components/command/command.yaml +105 -124
  82. package/components/demo-toggle/class.js +153 -0
  83. package/components/demo-toggle/demo-toggle.d.ts +23 -0
  84. package/components/demo-toggle/demo-toggle.js +8 -135
  85. package/components/description-list/class.js +86 -0
  86. package/components/description-list/description-list.d.ts +21 -0
  87. package/components/description-list/description-list.js +8 -67
  88. package/components/divider/class.js +57 -0
  89. package/components/divider/divider.d.ts +19 -0
  90. package/components/divider/divider.js +10 -40
  91. package/components/drawer/class.js +306 -0
  92. package/components/drawer/drawer.d.ts +25 -0
  93. package/components/drawer/drawer.js +8 -287
  94. package/components/embed/class.js +73 -0
  95. package/components/embed/embed.d.ts +23 -0
  96. package/components/embed/embed.js +9 -55
  97. package/components/empty-state/class.js +108 -0
  98. package/components/empty-state/empty-state.d.ts +21 -0
  99. package/components/empty-state/empty-state.js +9 -90
  100. package/components/feed/class.js +381 -0
  101. package/components/feed/feed.d.ts +19 -0
  102. package/components/feed/feed.js +9 -367
  103. package/components/field/class.js +266 -0
  104. package/components/field/field.d.ts +23 -0
  105. package/components/field/field.js +8 -247
  106. package/components/fields/class.js +106 -0
  107. package/components/fields/fields.d.ts +19 -0
  108. package/components/fields/fields.js +8 -87
  109. package/components/grid/class.js +31 -0
  110. package/components/grid/grid.d.ts +23 -0
  111. package/components/grid/grid.js +10 -14
  112. package/components/heatmap/class.js +305 -0
  113. package/components/heatmap/heatmap.d.ts +31 -0
  114. package/components/heatmap/heatmap.js +8 -286
  115. package/components/icon/class.js +54 -0
  116. package/components/icon/icon.d.ts +23 -0
  117. package/components/icon/icon.js +13 -40
  118. package/components/image/class.js +112 -0
  119. package/components/image/image.d.ts +33 -0
  120. package/components/image/image.js +9 -94
  121. package/components/index.js +1 -0
  122. package/components/input/class.js +773 -0
  123. package/components/input/input.a2ui.json +3 -0
  124. package/components/input/input.d.ts +61 -0
  125. package/components/input/input.js +8 -755
  126. package/components/input/input.yaml +171 -442
  127. package/components/inspector/class.js +142 -0
  128. package/components/inspector/inspector.a2ui.json +8 -1
  129. package/components/inspector/inspector.d.ts +17 -0
  130. package/components/inspector/inspector.js +8 -124
  131. package/components/inspector/inspector.yaml +15 -30
  132. package/components/kbd/class.js +34 -0
  133. package/components/kbd/kbd.a2ui.json +3 -0
  134. package/components/kbd/kbd.d.ts +17 -0
  135. package/components/kbd/kbd.js +10 -17
  136. package/components/kbd/kbd.yaml +54 -185
  137. package/components/link/class.js +187 -0
  138. package/components/link/link.d.ts +55 -0
  139. package/components/link/link.js +8 -168
  140. package/components/list/class.js +249 -0
  141. package/components/list/list.d.ts +23 -0
  142. package/components/list/list.js +9 -231
  143. package/components/menu/class.js +332 -0
  144. package/components/menu/menu.d.ts +21 -0
  145. package/components/menu/menu.js +11 -316
  146. package/components/modal/class.js +231 -0
  147. package/components/modal/modal.a2ui.json +5 -1
  148. package/components/modal/modal.d.ts +23 -0
  149. package/components/modal/modal.js +8 -212
  150. package/components/modal/modal.yaml +19 -39
  151. package/components/nav/class.js +150 -0
  152. package/components/nav/nav.d.ts +31 -0
  153. package/components/nav/nav.js +8 -131
  154. package/components/nav-group/class.js +152 -0
  155. package/components/nav-group/nav-group.d.ts +35 -0
  156. package/components/nav-group/nav-group.js +9 -134
  157. package/components/nav-item/class.js +86 -0
  158. package/components/nav-item/nav-item.d.ts +37 -0
  159. package/components/nav-item/nav-item.js +10 -69
  160. package/components/noodles/class.js +510 -0
  161. package/components/noodles/noodles.d.ts +33 -0
  162. package/components/noodles/noodles.js +9 -493
  163. package/components/option-card/class.js +167 -0
  164. package/components/option-card/option-card.d.ts +30 -0
  165. package/components/option-card/option-card.js +8 -149
  166. package/components/otp-input/class.js +180 -0
  167. package/components/otp-input/otp-input.a2ui.json +5 -1
  168. package/components/otp-input/otp-input.d.ts +25 -0
  169. package/components/otp-input/otp-input.js +9 -162
  170. package/components/otp-input/otp-input.yaml +45 -174
  171. package/components/page/class.js +97 -0
  172. package/components/page/page.d.ts +46 -0
  173. package/components/page/page.js +8 -79
  174. package/components/pagination/class.js +195 -0
  175. package/components/pagination/pagination.d.ts +23 -0
  176. package/components/pagination/pagination.js +9 -177
  177. package/components/pane/class.js +186 -0
  178. package/components/pane/pane.a2ui.json +12 -1
  179. package/components/pane/pane.css +10 -0
  180. package/components/pane/pane.d.ts +31 -0
  181. package/components/pane/pane.js +8 -143
  182. package/components/pane/pane.yaml +57 -157
  183. package/components/pipeline-status/class.js +189 -0
  184. package/components/pipeline-status/pipeline-status.a2ui.json +7 -1
  185. package/components/pipeline-status/pipeline-status.d.ts +21 -0
  186. package/components/pipeline-status/pipeline-status.js +9 -172
  187. package/components/pipeline-status/pipeline-status.yaml +34 -72
  188. package/components/popover/class.js +194 -0
  189. package/components/popover/popover.d.ts +23 -0
  190. package/components/popover/popover.js +9 -176
  191. package/components/progress/class.js +74 -0
  192. package/components/progress/progress.a2ui.json +3 -0
  193. package/components/progress/progress.d.ts +19 -0
  194. package/components/progress/progress.js +10 -57
  195. package/components/progress/progress.yaml +124 -287
  196. package/components/progress-row/class.js +110 -0
  197. package/components/progress-row/progress-row.d.ts +23 -0
  198. package/components/progress-row/progress-row.js +8 -92
  199. package/components/radio/class.js +83 -0
  200. package/components/radio/radio.d.ts +28 -0
  201. package/components/radio/radio.js +11 -67
  202. package/components/range/class.js +194 -0
  203. package/components/range/range.d.ts +31 -0
  204. package/components/range/range.js +9 -176
  205. package/components/rating/class.js +148 -0
  206. package/components/rating/rating.d.ts +33 -0
  207. package/components/rating/rating.js +9 -130
  208. package/components/richtext/class.js +87 -0
  209. package/components/richtext/richtext.a2ui.json +7 -1
  210. package/components/richtext/richtext.d.ts +19 -0
  211. package/components/richtext/richtext.js +8 -68
  212. package/components/richtext/richtext.yaml +30 -65
  213. package/components/row/class.js +50 -0
  214. package/components/row/row.d.ts +27 -0
  215. package/components/row/row.js +10 -33
  216. package/components/search/class.js +134 -0
  217. package/components/search/search.d.ts +35 -0
  218. package/components/search/search.js +10 -117
  219. package/components/segment/class.js +62 -0
  220. package/components/segment/segment.d.ts +25 -0
  221. package/components/segment/segment.js +10 -45
  222. package/components/segmented/class.js +165 -0
  223. package/components/segmented/segmented.a2ui.json +4 -0
  224. package/components/segmented/segmented.d.ts +24 -0
  225. package/components/segmented/segmented.js +10 -148
  226. package/components/segmented/segmented.yaml +41 -59
  227. package/components/select/class.js +408 -0
  228. package/components/select/select.d.ts +57 -0
  229. package/components/select/select.js +15 -396
  230. package/components/skeleton/class.js +52 -0
  231. package/components/skeleton/skeleton.d.ts +23 -0
  232. package/components/skeleton/skeleton.js +8 -34
  233. package/components/slider/class.js +184 -0
  234. package/components/slider/slider.d.ts +31 -0
  235. package/components/slider/slider.js +9 -166
  236. package/components/stack/class.js +28 -0
  237. package/components/stack/stack.d.ts +17 -0
  238. package/components/stack/stack.js +10 -11
  239. package/components/step-progress/class.js +98 -0
  240. package/components/step-progress/step-progress.d.ts +27 -0
  241. package/components/step-progress/step-progress.js +8 -79
  242. package/components/stepper/class.js +126 -0
  243. package/components/stepper/stepper.d.ts +19 -0
  244. package/components/stepper/stepper.js +9 -112
  245. package/components/stream/class.js +109 -0
  246. package/components/stream/stream.d.ts +19 -0
  247. package/components/stream/stream.js +8 -90
  248. package/components/swatch/class.js +131 -0
  249. package/components/swatch/swatch.d.ts +28 -0
  250. package/components/swatch/swatch.js +8 -112
  251. package/components/swiper/class.js +373 -0
  252. package/components/swiper/swiper.a2ui.json +4 -0
  253. package/components/swiper/swiper.d.ts +31 -0
  254. package/components/swiper/swiper.js +8 -354
  255. package/components/swiper/swiper.yaml +68 -212
  256. package/components/switch/class.js +63 -0
  257. package/components/switch/switch.a2ui.json +6 -1
  258. package/components/switch/switch.d.ts +30 -0
  259. package/components/switch/switch.js +11 -47
  260. package/components/switch/switch.yaml +70 -265
  261. package/components/table/class.js +1453 -0
  262. package/components/table/table.d.ts +37 -0
  263. package/components/table/table.js +8 -1435
  264. package/components/table-toolbar/class.js +680 -0
  265. package/components/table-toolbar/table-toolbar.d.ts +33 -0
  266. package/components/table-toolbar/table-toolbar.js +8 -689
  267. package/components/tabs/class.js +242 -0
  268. package/components/tabs/tabs.d.ts +21 -0
  269. package/components/tabs/tabs.js +8 -223
  270. package/components/tag/class.js +99 -0
  271. package/components/tag/tag.d.ts +27 -0
  272. package/components/tag/tag.js +8 -80
  273. package/components/text/class.js +46 -0
  274. package/components/text/text.d.ts +25 -0
  275. package/components/text/text.js +9 -28
  276. package/components/textarea/class.js +134 -0
  277. package/components/textarea/textarea.d.ts +31 -0
  278. package/components/textarea/textarea.js +11 -118
  279. package/components/timeline/class.js +176 -0
  280. package/components/timeline/timeline.d.ts +19 -0
  281. package/components/timeline/timeline.js +9 -162
  282. package/components/toast/class.js +92 -0
  283. package/components/toast/toast.d.ts +23 -0
  284. package/components/toast/toast.js +9 -76
  285. package/components/toggle-group/class.js +154 -0
  286. package/components/toggle-group/toggle-group.d.ts +19 -0
  287. package/components/toggle-group/toggle-group.js +11 -140
  288. package/components/toggle-scheme/class.js +286 -0
  289. package/components/toggle-scheme/toggle-scheme.a2ui.json +197 -0
  290. package/components/toggle-scheme/toggle-scheme.css +20 -0
  291. package/components/toggle-scheme/toggle-scheme.d.ts +41 -0
  292. package/components/toggle-scheme/toggle-scheme.js +17 -0
  293. package/components/toggle-scheme/toggle-scheme.yaml +173 -0
  294. package/components/toolbar/class.js +388 -0
  295. package/components/toolbar/toolbar.d.ts +23 -0
  296. package/components/toolbar/toolbar.js +10 -376
  297. package/components/tooltip/class.js +299 -0
  298. package/components/tooltip/tooltip.d.ts +27 -0
  299. package/components/tooltip/tooltip.js +8 -280
  300. package/components/tree/class.js +245 -0
  301. package/components/tree/tree.d.ts +15 -0
  302. package/components/tree/tree.js +9 -244
  303. package/components/upload/class.js +199 -0
  304. package/components/upload/upload.d.ts +27 -0
  305. package/components/upload/upload.js +11 -183
  306. package/core/element.d.ts +174 -0
  307. package/core/form.d.ts +108 -0
  308. package/core/index.d.ts +11 -0
  309. package/core/index.js +1 -0
  310. package/core/register.d.ts +25 -0
  311. package/core/register.js +58 -0
  312. package/core/signals.d.ts +94 -0
  313. package/core/template.d.ts +70 -0
  314. package/index.d.ts +315 -0
  315. package/package.json +25 -6
  316. package/traits/CATEGORIES.md +1 -1
@@ -1,184 +1,17 @@
1
1
  /**
2
- * <range-input label="Width" value="63" min="0" max="100" step="1" suffix="rem"></range-input>
2
+ * `<range-ui>` auto-registers the tag on import.
3
3
  *
4
- * A draggable numeric field NOT a slider. The entire field is the scrubber surface.
5
- * Horizontal drag on the value changes it. No track, no thumb.
4
+ * For non-side-effect class import (test isolation, tag override), use
5
+ * the `class` subpath:
6
6
  *
7
- * Layout: [label] [value] [suffix]
8
- * - Label left-aligned, muted
9
- * - Value right-aligned, bold, editable via horizontal drag
10
- * - Suffix after value, muted
11
- * - While dragging: accent highlight on the field
7
+ * import { UIRange } from '@adia-ai/web-components/components/range/class';
8
+ *
9
+ * @see ../../USAGE.md#registration--auto-vs-explicit
12
10
  */
13
11
 
14
- import { UIFormElement } from '../../core/form.js';
15
-
16
- class UIRange extends UIFormElement {
17
- // Opt out of UIFormElement's per-control `label` deprecation warning.
18
- // range-ui's `label` is a first-class API: it renders as the in-track
19
- // caption next to the value (the entire field is the scrubber surface)
20
- // and the host gets `aria-label` wired from it for proper screen-reader
21
- // announcement. Same opt-out rationale as input-ui.
22
- static labelDeprecated = false;
23
-
24
- static properties = {
25
- ...UIFormElement.properties,
26
- /** value: Number — overrides UIFormElement.value (String); syncs as string on form submit. */
27
- value: { type: Number, default: 0, reflect: true },
28
- min: { type: Number, default: 0, reflect: true },
29
- max: { type: Number, default: 100, reflect: true },
30
- step: { type: Number, default: 1, reflect: true },
31
- label: { type: String, default: '', reflect: true },
32
- suffix: { type: String, default: '', reflect: true },
33
- };
34
-
35
- static template = () => null;
36
-
37
- #fieldEl = null;
38
- #valueEl = null;
39
- #dragging = false;
40
- #startX = 0;
41
- #startVal = 0;
42
-
43
- connected() {
44
- super.connected();
45
- this.setAttribute('role', 'spinbutton');
46
- this.setAttribute('tabindex', '0');
47
-
48
- if (!this.querySelector('[slot="field"]')) {
49
- const inner = `
50
- <span slot="label">${this.label}</span>
51
- <span slot="value">${this.#format(this.value)}</span>
52
- ${this.suffix ? `<span slot="suffix">${this.suffix}</span>` : ''}
53
- `;
54
- this.innerHTML = `
55
- <div slot="field">
56
- <div slot="layer" data-layer="base">${inner}</div>
57
- <div slot="layer" data-layer="fill" aria-hidden="true">${inner}</div>
58
- </div>
59
- `;
60
- }
61
-
62
- this.#fieldEl = this.querySelector('[slot="field"]');
63
- this.#valueEl = this.querySelector('[data-layer="base"] [slot="value"]');
64
-
65
- if (this.#fieldEl) this.#fieldEl.addEventListener('pointerdown', this.#onPointerDown);
66
- this.addEventListener('keydown', this.#onKey);
67
- }
68
-
69
- render() {
70
- if (!this.#fieldEl) return;
71
-
72
- const formatted = this.#format(this.value);
73
- if (this.#valueEl) this.#valueEl.textContent = formatted;
74
- const fillValueEl = this.querySelector('[data-layer="fill"] [slot="value"]');
75
- if (fillValueEl) fillValueEl.textContent = formatted;
76
-
77
- // Update fill percentage via CSS var (drives clip-path on fill layer)
78
- const range = this.max - this.min;
79
- const pct = range > 0 ? ((this.value - this.min) / range) * 100 : 0;
80
- this.style.setProperty('--range-fill-pct', `${pct}%`);
81
-
82
- this.setAttribute('aria-valuemin', this.min);
83
- this.setAttribute('aria-valuemax', this.max);
84
- this.setAttribute('aria-valuenow', this.value);
85
- this.setAttribute('aria-valuetext', `${this.value}${this.suffix ? ' ' + this.suffix : ''}`);
86
- this.setAttribute('aria-label', this.label || '');
87
-
88
- this.syncValue(String(this.value));
89
- }
90
-
91
- #format(v) {
92
- // Show decimal places matching step precision
93
- const decimals = (String(this.step).split('.')[1] || '').length;
94
- return decimals > 0 ? v.toFixed(decimals) : String(v);
95
- }
96
-
97
- #snap(raw) {
98
- const stepped = Math.round((raw - this.min) / this.step) * this.step + this.min;
99
- return Math.max(this.min, Math.min(this.max, parseFloat(stepped.toFixed(10))));
100
- }
101
-
102
- #setValue(v) {
103
- const snapped = this.#snap(v);
104
- if (snapped === this.value) return;
105
- this.value = snapped;
106
- this.dispatchEvent(new CustomEvent('input', { bubbles: true, detail: { value: this.value } }));
107
- }
108
-
109
- // ── Pointer drag ──
110
-
111
- #valueFromX(clientX) {
112
- const rect = this.#fieldEl.getBoundingClientRect();
113
- const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
114
- return this.#snap(this.min + ratio * (this.max - this.min));
115
- }
116
-
117
- #onPointerDown = (e) => {
118
- if (this.disabled) return;
119
- e.preventDefault();
120
-
121
- // Click: jump to position immediately
122
- this.#setValue(this.#valueFromX(e.clientX));
123
-
124
- // Then start drag from that position
125
- this.#dragging = true;
126
- this.#startX = e.clientX;
127
- this.#startVal = this.value;
128
- this.setAttribute('data-dragging', '');
129
- this.#fieldEl.setPointerCapture(e.pointerId);
130
- this.#fieldEl.addEventListener('pointermove', this.#onPointerMove);
131
- this.#fieldEl.addEventListener('pointerup', this.#onPointerUp);
132
- };
133
-
134
- #onPointerMove = (e) => {
135
- if (!this.#dragging) return;
136
- const dx = e.clientX - this.#startX;
137
- // 1:1 — dragging across the full field width traverses the full range
138
- const fieldWidth = this.#fieldEl.getBoundingClientRect().width;
139
- const range = this.max - this.min;
140
- const delta = (dx / fieldWidth) * range;
141
- this.#setValue(this.#startVal + delta);
142
- };
143
-
144
- #onPointerUp = (e) => {
145
- this.#dragging = false;
146
- this.removeAttribute('data-dragging');
147
- this.#fieldEl.releasePointerCapture(e.pointerId);
148
- this.#fieldEl.removeEventListener('pointermove', this.#onPointerMove);
149
- this.#fieldEl.removeEventListener('pointerup', this.#onPointerUp);
150
- this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
151
- };
152
-
153
- // ── Keyboard ──
154
-
155
- #onKey = (e) => {
156
- if (this.disabled) return;
157
- let v = this.value;
158
- switch (e.key) {
159
- case 'ArrowRight': case 'ArrowUp': v += this.step; break;
160
- case 'ArrowLeft': case 'ArrowDown': v -= this.step; break;
161
- case 'Home': v = this.min; break;
162
- case 'End': v = this.max; break;
163
- case 'PageUp': v += this.step * 10; break;
164
- case 'PageDown': v -= this.step * 10; break;
165
- default: return;
166
- }
167
- e.preventDefault();
168
- this.#setValue(v);
169
- this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
170
- };
12
+ import { defineIfFree } from '../../core/register.js';
13
+ import { UIRange } from './class.js';
171
14
 
172
- disconnected() {
173
- super.disconnected();
174
- this.#fieldEl?.removeEventListener('pointerdown', this.#onPointerDown);
175
- this.#fieldEl?.removeEventListener('pointermove', this.#onPointerMove);
176
- this.#fieldEl?.removeEventListener('pointerup', this.#onPointerUp);
177
- this.removeEventListener('keydown', this.#onKey);
178
- this.#fieldEl = null;
179
- this.#valueEl = null;
180
- }
181
- }
182
- customElements.define('range-ui', UIRange);
15
+ defineIfFree('range-ui', UIRange);
183
16
 
184
17
  export { UIRange };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Non-side-effect class export for `<rating-ui>`.
3
+ *
4
+ * Importing this file gives you the class(es) without auto-registering the tag.
5
+ * Useful for test isolation, subclassing with tag-name override, or selective
6
+ * composition.
7
+ *
8
+ * The auto-register path stays at `@adia-ai/web-components/components/rating`
9
+ * (which imports this file + calls `defineIfFree()`).
10
+ *
11
+ * @see ../../USAGE.md#registration--auto-vs-explicit
12
+ */
13
+
14
+ /**
15
+ * <rating-ui> — Discrete pictorial rating (stars by default).
16
+ *
17
+ * Supports keyboard (arrows), mouse hover preview, and 0.5-step precision.
18
+ * The host is role=slider per ARIA APG for custom rating widgets.
19
+ *
20
+ * <rating-ui value="3.5" max="5" allow-half name="review"></rating-ui>
21
+ * <rating-ui value="4" icon="heart" variant="accent"></rating-ui>
22
+ * <rating-ui value="5" readonly></rating-ui>
23
+ */
24
+
25
+ import { UIFormElement } from '../../core/form.js';
26
+
27
+ export class UIRating extends UIFormElement {
28
+ static properties = {
29
+ ...UIFormElement.properties,
30
+ /** value: Number — overrides UIFormElement.value (String); syncs as string on form submit. */
31
+ value: { type: Number, default: 0, reflect: true },
32
+ max: { type: Number, default: 5, reflect: true },
33
+ icon: { type: String, default: 'star', reflect: true },
34
+ readonly: { type: Boolean, default: false, reflect: true },
35
+ allowHalf: { type: Boolean, default: false, reflect: true, attribute: 'allow-half' },
36
+ size: { type: String, default: 'md', reflect: true },
37
+ };
38
+
39
+ static template = () => null;
40
+
41
+ #hoverValue = null;
42
+
43
+ connected() {
44
+ super.connected();
45
+ this.setAttribute('role', 'slider');
46
+ this.setAttribute('aria-orientation', 'horizontal');
47
+ this.setAttribute('aria-valuemin', '0');
48
+ if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', this.readonly ? '-1' : '0');
49
+ this.addEventListener('pointermove', this.#onPointer);
50
+ this.addEventListener('pointerleave', this.#onLeave);
51
+ this.addEventListener('click', this.#onClick);
52
+ this.addEventListener('keydown', this.#onKey);
53
+ }
54
+
55
+ render() {
56
+ const max = Number(this.max) || 5;
57
+ const display = this.#hoverValue ?? (Number(this.value) || 0);
58
+
59
+ const symbols = Array.from({ length: max }, (_, i) => {
60
+ const slotValue = i + 1;
61
+ const fill =
62
+ display >= slotValue ? 'full' :
63
+ display >= slotValue - 0.5 ? 'half' :
64
+ 'empty';
65
+ return `
66
+ <span data-rating-symbol data-fill="${fill}" aria-hidden="true">
67
+ <icon-ui name="${this.icon}" data-rating-symbol-bg></icon-ui>
68
+ <icon-ui name="${this.icon}" weight="fill" data-rating-symbol-fg></icon-ui>
69
+ </span>
70
+ `;
71
+ }).join('');
72
+
73
+ this.innerHTML = symbols;
74
+ this.setAttribute('aria-valuemax', String(max));
75
+ this.setAttribute('aria-valuenow', String(Number(this.value) || 0));
76
+ this.setAttribute('aria-valuetext', `${Number(this.value) || 0} out of ${max}`);
77
+ if (this.readonly) this.setAttribute('aria-readonly', 'true');
78
+ else this.removeAttribute('aria-readonly');
79
+ }
80
+
81
+ #valueFromEvent(e) {
82
+ const symbols = [...this.querySelectorAll('[data-rating-symbol]')];
83
+ const target = symbols.find(s => s.contains(e.target));
84
+ if (!target) return null;
85
+ const idx = symbols.indexOf(target);
86
+ if (idx === -1) return null;
87
+ if (this.allowHalf) {
88
+ const rect = target.getBoundingClientRect();
89
+ const isHalf = (e.clientX - rect.left) < rect.width / 2;
90
+ return idx + (isHalf ? 0.5 : 1);
91
+ }
92
+ return idx + 1;
93
+ }
94
+
95
+ #onPointer = (e) => {
96
+ if (this.readonly || this.disabled) return;
97
+ const v = this.#valueFromEvent(e);
98
+ if (v == null) return;
99
+ if (v !== this.#hoverValue) {
100
+ this.#hoverValue = v;
101
+ this.render();
102
+ }
103
+ };
104
+
105
+ #onLeave = () => {
106
+ if (this.#hoverValue == null) return;
107
+ this.#hoverValue = null;
108
+ this.render();
109
+ };
110
+
111
+ #onClick = (e) => {
112
+ if (this.readonly || this.disabled) return;
113
+ const v = this.#valueFromEvent(e);
114
+ if (v == null) return;
115
+ this.#commit(v);
116
+ };
117
+
118
+ #onKey = (e) => {
119
+ if (this.readonly || this.disabled) return;
120
+ const step = this.allowHalf ? 0.5 : 1;
121
+ const max = Number(this.max) || 5;
122
+ const v = Number(this.value) || 0;
123
+ let next = v;
124
+ if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { next = Math.min(max, v + step); }
125
+ else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { next = Math.max(0, v - step); }
126
+ else if (e.key === 'Home') next = 0;
127
+ else if (e.key === 'End') next = max;
128
+ else return;
129
+ e.preventDefault();
130
+ this.#commit(next);
131
+ };
132
+
133
+ #commit(v) {
134
+ this.value = v;
135
+ this.#hoverValue = null;
136
+ this.syncValue(String(v));
137
+ this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
138
+ this.render();
139
+ }
140
+
141
+ disconnected() {
142
+ super.disconnected();
143
+ this.removeEventListener('pointermove', this.#onPointer);
144
+ this.removeEventListener('pointerleave', this.#onLeave);
145
+ this.removeEventListener('click', this.#onClick);
146
+ this.removeEventListener('keydown', this.#onKey);
147
+ }
148
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `<rating-ui>` — Star rating input (or other icon set).
3
+ *
4
+ * @see https://ui-kit.exe.xyz/site/components/rating
5
+ */
6
+
7
+ import { UIFormElement } from '../../core/form.js';
8
+
9
+ export interface RatingChangeEventDetail {
10
+ value: number;
11
+ }
12
+ export type RatingChangeEvent = CustomEvent<RatingChangeEventDetail>;
13
+
14
+ export class UIRating extends UIFormElement {
15
+ /** Numeric rating value — overrides UIFormElement.value (which is String). */
16
+ value: number;
17
+ /** Maximum rating — number of icons rendered. */
18
+ max: number;
19
+ /** Phosphor icon name (default: `star`). */
20
+ icon: string;
21
+ /** Read-only mode (display only; no interaction). */
22
+ readonly: boolean;
23
+ /** Allow half-step values (0.5, 1.5, …). */
24
+ allowHalf: boolean;
25
+ size: 'sm' | 'md' | 'lg';
26
+
27
+ addEventListener<K extends keyof HTMLElementEventMap>(
28
+ type: K,
29
+ listener: (this: UIRating, ev: HTMLElementEventMap[K]) => unknown,
30
+ options?: boolean | AddEventListenerOptions,
31
+ ): void;
32
+ addEventListener(type: 'change', listener: (ev: RatingChangeEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
33
+ }
@@ -1,138 +1,17 @@
1
1
  /**
2
- * <rating-ui>Discrete pictorial rating (stars by default).
2
+ * `<rating-ui>`auto-registers the tag on import.
3
3
  *
4
- * Supports keyboard (arrows), mouse hover preview, and 0.5-step precision.
5
- * The host is role=slider per ARIA APG for custom rating widgets.
4
+ * For non-side-effect class import (test isolation, tag override), use
5
+ * the `class` subpath:
6
6
  *
7
- * <rating-ui value="3.5" max="5" allow-half name="review"></rating-ui>
8
- * <rating-ui value="4" icon="heart" variant="accent"></rating-ui>
9
- * <rating-ui value="5" readonly></rating-ui>
7
+ * import { UIRating } from '@adia-ai/web-components/components/rating/class';
8
+ *
9
+ * @see ../../USAGE.md#registration--auto-vs-explicit
10
10
  */
11
11
 
12
- import { UIFormElement } from '../../core/form.js';
13
-
14
- class UIRating extends UIFormElement {
15
- static properties = {
16
- ...UIFormElement.properties,
17
- /** value: Number — overrides UIFormElement.value (String); syncs as string on form submit. */
18
- value: { type: Number, default: 0, reflect: true },
19
- max: { type: Number, default: 5, reflect: true },
20
- icon: { type: String, default: 'star', reflect: true },
21
- readonly: { type: Boolean, default: false, reflect: true },
22
- allowHalf: { type: Boolean, default: false, reflect: true, attribute: 'allow-half' },
23
- size: { type: String, default: 'md', reflect: true },
24
- };
25
-
26
- static template = () => null;
27
-
28
- #hoverValue = null;
29
-
30
- connected() {
31
- super.connected();
32
- this.setAttribute('role', 'slider');
33
- this.setAttribute('aria-orientation', 'horizontal');
34
- this.setAttribute('aria-valuemin', '0');
35
- if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', this.readonly ? '-1' : '0');
36
- this.addEventListener('pointermove', this.#onPointer);
37
- this.addEventListener('pointerleave', this.#onLeave);
38
- this.addEventListener('click', this.#onClick);
39
- this.addEventListener('keydown', this.#onKey);
40
- }
41
-
42
- render() {
43
- const max = Number(this.max) || 5;
44
- const display = this.#hoverValue ?? (Number(this.value) || 0);
45
-
46
- const symbols = Array.from({ length: max }, (_, i) => {
47
- const slotValue = i + 1;
48
- const fill =
49
- display >= slotValue ? 'full' :
50
- display >= slotValue - 0.5 ? 'half' :
51
- 'empty';
52
- return `
53
- <span data-rating-symbol data-fill="${fill}" aria-hidden="true">
54
- <icon-ui name="${this.icon}" data-rating-symbol-bg></icon-ui>
55
- <icon-ui name="${this.icon}" weight="fill" data-rating-symbol-fg></icon-ui>
56
- </span>
57
- `;
58
- }).join('');
59
-
60
- this.innerHTML = symbols;
61
- this.setAttribute('aria-valuemax', String(max));
62
- this.setAttribute('aria-valuenow', String(Number(this.value) || 0));
63
- this.setAttribute('aria-valuetext', `${Number(this.value) || 0} out of ${max}`);
64
- if (this.readonly) this.setAttribute('aria-readonly', 'true');
65
- else this.removeAttribute('aria-readonly');
66
- }
67
-
68
- #valueFromEvent(e) {
69
- const symbols = [...this.querySelectorAll('[data-rating-symbol]')];
70
- const target = symbols.find(s => s.contains(e.target));
71
- if (!target) return null;
72
- const idx = symbols.indexOf(target);
73
- if (idx === -1) return null;
74
- if (this.allowHalf) {
75
- const rect = target.getBoundingClientRect();
76
- const isHalf = (e.clientX - rect.left) < rect.width / 2;
77
- return idx + (isHalf ? 0.5 : 1);
78
- }
79
- return idx + 1;
80
- }
81
-
82
- #onPointer = (e) => {
83
- if (this.readonly || this.disabled) return;
84
- const v = this.#valueFromEvent(e);
85
- if (v == null) return;
86
- if (v !== this.#hoverValue) {
87
- this.#hoverValue = v;
88
- this.render();
89
- }
90
- };
91
-
92
- #onLeave = () => {
93
- if (this.#hoverValue == null) return;
94
- this.#hoverValue = null;
95
- this.render();
96
- };
97
-
98
- #onClick = (e) => {
99
- if (this.readonly || this.disabled) return;
100
- const v = this.#valueFromEvent(e);
101
- if (v == null) return;
102
- this.#commit(v);
103
- };
104
-
105
- #onKey = (e) => {
106
- if (this.readonly || this.disabled) return;
107
- const step = this.allowHalf ? 0.5 : 1;
108
- const max = Number(this.max) || 5;
109
- const v = Number(this.value) || 0;
110
- let next = v;
111
- if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { next = Math.min(max, v + step); }
112
- else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { next = Math.max(0, v - step); }
113
- else if (e.key === 'Home') next = 0;
114
- else if (e.key === 'End') next = max;
115
- else return;
116
- e.preventDefault();
117
- this.#commit(next);
118
- };
119
-
120
- #commit(v) {
121
- this.value = v;
122
- this.#hoverValue = null;
123
- this.syncValue(String(v));
124
- this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
125
- this.render();
126
- }
12
+ import { defineIfFree } from '../../core/register.js';
13
+ import { UIRating } from './class.js';
127
14
 
128
- disconnected() {
129
- super.disconnected();
130
- this.removeEventListener('pointermove', this.#onPointer);
131
- this.removeEventListener('pointerleave', this.#onLeave);
132
- this.removeEventListener('click', this.#onClick);
133
- this.removeEventListener('keydown', this.#onKey);
134
- }
135
- }
15
+ defineIfFree('rating-ui', UIRating);
136
16
 
137
- customElements.define('rating-ui', UIRating);
138
17
  export { UIRating };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Non-side-effect class export for `<richtext-ui>`.
3
+ *
4
+ * Importing this file gives you the class(es) without auto-registering the tag.
5
+ * Useful for test isolation, subclassing with tag-name override, or selective
6
+ * composition.
7
+ *
8
+ * The auto-register path stays at `@adia-ai/web-components/components/richtext`
9
+ * (which imports this file + calls `defineIfFree()`).
10
+ *
11
+ * @see ../../USAGE.md#registration--auto-vs-explicit
12
+ */
13
+
14
+ import { UIElement } from '../../core/element.js';
15
+ import { renderMarkdown } from '../../core/markdown.js';
16
+
17
+ /**
18
+ * <richtext-ui> — Renders markdown to styled HTML.
19
+ *
20
+ * Takes markdown as a `src` URL (fetched) or `markdown` property (inline),
21
+ * converts it to HTML, and displays it with prose-appropriate typography.
22
+ *
23
+ * Usage:
24
+ * <richtext-ui src="/docs/readme.md"></richtext-ui>
25
+ * <richtext-ui markdown="# Hello\nSome **bold** text."></richtext-ui>
26
+ *
27
+ * Programmatic:
28
+ * const el = document.querySelector('richtext-ui');
29
+ * el.markdown = '# Title\nParagraph text.';
30
+ */
31
+ export class UIRichText extends UIElement {
32
+ static properties = {
33
+ src: { type: String, default: '', reflect: true },
34
+ // Markdown bodies can be arbitrarily large; reflecting to the attribute
35
+ // would bloat the DOM (and break parsing on multi-line content with
36
+ // unescaped quotes). The property is the source of truth.
37
+ markdown: { type: String, default: '', reflect: false },
38
+ };
39
+
40
+ static template = () => null;
41
+
42
+ #bodyEl = null;
43
+ #lastSrc = '';
44
+ #lastMd = '';
45
+
46
+ connected() {
47
+ if (!this.#bodyEl) {
48
+ this.#bodyEl = document.createElement('div');
49
+ this.#bodyEl.setAttribute('data-richtext-body', '');
50
+ this.appendChild(this.#bodyEl);
51
+ }
52
+ }
53
+
54
+ render() {
55
+ // Fetch from URL
56
+ if (this.src && this.src !== this.#lastSrc) {
57
+ this.#lastSrc = this.src;
58
+ this.#lastMd = '';
59
+ this.#load();
60
+ return;
61
+ }
62
+
63
+ // Inline markdown
64
+ if (this.markdown && this.markdown !== this.#lastMd) {
65
+ this.#lastMd = this.markdown;
66
+ this.#lastSrc = '';
67
+ this.#bodyEl.innerHTML = renderMarkdown(this.markdown);
68
+ }
69
+ }
70
+
71
+ async #load() {
72
+ try {
73
+ const res = await fetch(this.src);
74
+ if (!this.isConnected) return;
75
+ if (!res.ok) {
76
+ this.#bodyEl.innerHTML = `<p>Failed to load: ${this.src}</p>`;
77
+ return;
78
+ }
79
+ const md = await res.text();
80
+ if (!this.isConnected) return;
81
+ this.#bodyEl.innerHTML = renderMarkdown(md);
82
+ } catch (e) {
83
+ if (!this.isConnected) return;
84
+ this.#bodyEl.innerHTML = `<p>Error: ${e.message}</p>`;
85
+ }
86
+ }
87
+ }
@@ -73,7 +73,13 @@
73
73
  "name": "idle"
74
74
  }
75
75
  ],
76
- "synonyms": {},
76
+ "synonyms": {
77
+ "tags": [
78
+ "markdown",
79
+ "md-render",
80
+ "rich-text"
81
+ ]
82
+ },
77
83
  "tag": "richtext-ui",
78
84
  "tokens": {},
79
85
  "traits": [],
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `<richtext-ui>` — Renders markdown to styled HTML.
3
+ *
4
+ * @see https://ui-kit.exe.xyz/site/components/richtext
5
+ *
6
+ * Type declarations generated by scripts/build/dts-codegen.mjs from
7
+ * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
8
+ * run `npm run components`, then `npm run codegen:dts` to regenerate;
9
+ * or hand-author this file fully if rich event types are needed.
10
+ */
11
+
12
+ import { UIElement } from '../../core/element.js';
13
+
14
+ export class UIRichtext extends UIElement {
15
+ /** Component property: markdown. */
16
+ markdown: string;
17
+ /** Source URL (image, iframe, etc.). */
18
+ src: string;
19
+ }