@adia-ai/web-components 0.6.34 → 0.6.36

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 (280) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/color/index.js +1 -1
  3. package/components/accordion/accordion-item.yaml +2 -2
  4. package/components/accordion/accordion.js +1 -1
  5. package/components/action-list/action-item.yaml +2 -2
  6. package/components/action-list/action-list.js +1 -1
  7. package/components/agent-artifact/{class.js → agent-artifact.class.js} +1 -1
  8. package/components/agent-artifact/agent-artifact.js +1 -1
  9. package/components/agent-feedback-bar/agent-feedback-bar.js +1 -1
  10. package/components/agent-questions/agent-questions.js +1 -1
  11. package/components/agent-reasoning/agent-reasoning.js +1 -1
  12. package/components/agent-suggestions/agent-suggestions.js +1 -1
  13. package/components/alert/alert.a2ui.json +64 -1
  14. package/components/alert/{class.js → alert.class.js} +189 -2
  15. package/components/alert/alert.css +78 -0
  16. package/components/alert/alert.d.ts +14 -0
  17. package/components/alert/alert.js +1 -1
  18. package/components/alert/alert.test.js +184 -0
  19. package/components/alert/alert.yaml +114 -1
  20. package/components/avatar/avatar-group.yaml +2 -2
  21. package/components/avatar/avatar.js +1 -1
  22. package/components/badge/badge.js +1 -1
  23. package/components/block/block.js +1 -1
  24. package/components/breadcrumb/breadcrumb.js +1 -1
  25. package/components/button/button.js +1 -1
  26. package/components/calendar-grid/calendar-grid.a2ui.json +10 -0
  27. package/components/calendar-grid/{class.js → calendar-grid.class.js} +30 -4
  28. package/components/calendar-grid/calendar-grid.css +20 -0
  29. package/components/calendar-grid/calendar-grid.d.ts +4 -0
  30. package/components/calendar-grid/calendar-grid.js +1 -1
  31. package/components/calendar-grid/calendar-grid.yaml +20 -0
  32. package/components/calendar-picker/calendar-picker.js +1 -1
  33. package/components/card/card.js +1 -1
  34. package/components/chart/chart.js +1 -1
  35. package/components/chart-legend/chart-legend.js +1 -1
  36. package/components/chat-thread/chat-input.a2ui.json +1 -1
  37. package/components/chat-thread/chat-input.js +6 -1
  38. package/components/chat-thread/chat-input.yaml +4 -1
  39. package/components/chat-thread/chat-thread.js +1 -1
  40. package/components/check/check.js +1 -1
  41. package/components/code/code.js +1 -1
  42. package/components/col/col.js +1 -1
  43. package/components/color-input/color-input.js +1 -1
  44. package/components/color-picker/color-picker.js +1 -1
  45. package/components/combobox/combobox.css +12 -0
  46. package/components/combobox/combobox.js +1 -1
  47. package/components/command/command.js +1 -1
  48. package/components/date-range-picker/{class.js → date-range-picker.class.js} +19 -3
  49. package/components/date-range-picker/date-range-picker.css +55 -6
  50. package/components/date-range-picker/date-range-picker.js +1 -1
  51. package/components/datetime-picker/{class.js → datetime-picker.class.js} +1 -1
  52. package/components/datetime-picker/datetime-picker.css +7 -1
  53. package/components/datetime-picker/datetime-picker.js +1 -1
  54. package/components/demo-toggle/demo-toggle.js +1 -1
  55. package/components/description-list/description-list.js +1 -1
  56. package/components/divider/divider.js +1 -1
  57. package/components/drawer/drawer.js +1 -1
  58. package/components/embed/embed.js +1 -1
  59. package/components/empty-state/empty-state.js +1 -1
  60. package/components/feed/feed.js +1 -1
  61. package/components/field/field.js +1 -1
  62. package/components/field/field.test.js +1 -1
  63. package/components/fields/fields.js +1 -1
  64. package/components/grid/grid.js +1 -1
  65. package/components/heatmap/heatmap.js +1 -1
  66. package/components/icon/icon.js +1 -1
  67. package/components/image/image.js +1 -1
  68. package/components/index.js +3 -0
  69. package/components/inline-message/inline-message.a2ui.json +143 -0
  70. package/components/inline-message/inline-message.class.js +169 -0
  71. package/components/inline-message/inline-message.css +75 -0
  72. package/components/inline-message/inline-message.d.ts +31 -0
  73. package/components/inline-message/inline-message.examples.md +19 -0
  74. package/components/inline-message/inline-message.js +17 -0
  75. package/components/inline-message/inline-message.test.js +203 -0
  76. package/components/inline-message/inline-message.yaml +205 -0
  77. package/components/input/input.css +16 -2
  78. package/components/input/input.js +1 -1
  79. package/components/input/input.test.js +40 -0
  80. package/components/input/input.yaml +5 -4
  81. package/components/inspector/inspector.js +1 -1
  82. package/components/integration-card/integration-card.js +1 -1
  83. package/components/kbd/kbd.js +1 -1
  84. package/components/link/link.js +1 -1
  85. package/components/list/list-item.yaml +2 -2
  86. package/components/list/list.js +1 -1
  87. package/components/list-window/list-window.js +1 -1
  88. package/components/loading-overlay/loading-overlay.a2ui.json +176 -0
  89. package/components/loading-overlay/loading-overlay.class.js +203 -0
  90. package/components/loading-overlay/loading-overlay.css +81 -0
  91. package/components/loading-overlay/loading-overlay.d.ts +24 -0
  92. package/components/loading-overlay/loading-overlay.examples.md +50 -0
  93. package/components/loading-overlay/loading-overlay.js +17 -0
  94. package/components/loading-overlay/loading-overlay.test.js +257 -0
  95. package/components/loading-overlay/loading-overlay.yaml +260 -0
  96. package/components/menu/menu-divider.yaml +1 -1
  97. package/components/menu/menu-item.yaml +1 -1
  98. package/components/menu/menu.a2ui.json +3 -0
  99. package/components/menu/menu.js +1 -1
  100. package/components/menu/menu.yaml +7 -0
  101. package/components/modal/{class.js → modal.class.js} +12 -1
  102. package/components/modal/modal.css +11 -1
  103. package/components/modal/modal.js +1 -1
  104. package/components/nav/nav.js +1 -1
  105. package/components/nav-group/nav-group.js +1 -1
  106. package/components/nav-item/nav-item.js +1 -1
  107. package/components/noodles/noodles.js +1 -1
  108. package/components/option-card/option-card.js +1 -1
  109. package/components/otp-input/otp-input.js +1 -1
  110. package/components/page/page.js +1 -1
  111. package/components/pagination/pagination.js +1 -1
  112. package/components/pane/pane.js +1 -1
  113. package/components/pipeline-status/pipeline-status.js +1 -1
  114. package/components/popover/popover.a2ui.json +8 -1
  115. package/components/popover/popover.js +1 -1
  116. package/components/popover/popover.yaml +14 -1
  117. package/components/progress/progress.js +1 -1
  118. package/components/progress-row/progress-row.js +1 -1
  119. package/components/radio/radio.js +1 -1
  120. package/components/range/range.js +1 -1
  121. package/components/rating/rating.js +1 -1
  122. package/components/richtext/richtext.js +1 -1
  123. package/components/row/row.js +1 -1
  124. package/components/search/{class.js → search.class.js} +2 -0
  125. package/components/search/search.js +1 -1
  126. package/components/segment/segment.js +1 -1
  127. package/components/segmented/segmented.js +1 -1
  128. package/components/select/select.a2ui.json +58 -4
  129. package/components/select/{class.js → select.class.js} +415 -6
  130. package/components/select/select.css +158 -0
  131. package/components/select/select.d.ts +31 -1
  132. package/components/select/select.js +1 -1
  133. package/components/select/select.test.js +202 -0
  134. package/components/select/select.yaml +126 -5
  135. package/components/skeleton/skeleton.js +1 -1
  136. package/components/slider/slider.js +1 -1
  137. package/components/spinner/spinner.a2ui.json +3 -2
  138. package/components/spinner/{class.js → spinner.class.js} +33 -3
  139. package/components/spinner/spinner.css +91 -35
  140. package/components/spinner/spinner.d.ts +2 -2
  141. package/components/spinner/spinner.js +1 -1
  142. package/components/spinner/spinner.test.js +49 -11
  143. package/components/spinner/spinner.yaml +9 -1
  144. package/components/stack/stack.js +1 -1
  145. package/components/step-progress/step-progress.js +1 -1
  146. package/components/stepper/stepper-item.yaml +1 -1
  147. package/components/stepper/stepper.js +1 -1
  148. package/components/stream/stream.js +1 -1
  149. package/components/swatch/swatch.js +1 -1
  150. package/components/swiper/swiper.js +1 -1
  151. package/components/switch/switch.js +1 -1
  152. package/components/table/table.css +1 -1
  153. package/components/table/table.js +1 -1
  154. package/components/table-toolbar/{class.js → table-toolbar.class.js} +2 -1
  155. package/components/table-toolbar/table-toolbar.js +1 -1
  156. package/components/tabs/tab.yaml +2 -2
  157. package/components/tabs/tabs.js +1 -1
  158. package/components/tag/tag.a2ui.json +9 -0
  159. package/components/tag/{class.js → tag.class.js} +8 -1
  160. package/components/tag/tag.css +84 -20
  161. package/components/tag/tag.js +1 -1
  162. package/components/tag/tag.test.js +75 -1
  163. package/components/tag/tag.yaml +14 -0
  164. package/components/tags-input/tags-input.a2ui.json +337 -0
  165. package/components/tags-input/tags-input.class.js +783 -0
  166. package/components/tags-input/tags-input.css +210 -0
  167. package/components/tags-input/tags-input.d.ts +120 -0
  168. package/components/tags-input/tags-input.examples.md +92 -0
  169. package/components/tags-input/tags-input.js +17 -0
  170. package/components/tags-input/tags-input.test.js +368 -0
  171. package/components/tags-input/tags-input.yaml +367 -0
  172. package/components/text/text.js +1 -1
  173. package/components/textarea/textarea.a2ui.json +1 -1
  174. package/components/textarea/textarea.css +10 -1
  175. package/components/textarea/textarea.js +1 -1
  176. package/components/textarea/textarea.yaml +11 -8
  177. package/components/time-picker/time-picker.js +1 -1
  178. package/components/timeline/timeline-item.yaml +2 -2
  179. package/components/timeline/{class.js → timeline.class.js} +1 -1
  180. package/components/timeline/timeline.js +1 -1
  181. package/components/toast/toast.js +1 -1
  182. package/components/toggle-group/toggle-group.js +1 -1
  183. package/components/toggle-group/toggle-option.yaml +1 -1
  184. package/components/toggle-scheme/toggle-scheme.js +1 -1
  185. package/components/toolbar/toolbar-group.yaml +1 -1
  186. package/components/toolbar/toolbar.js +1 -1
  187. package/components/tooltip/tooltip.js +1 -1
  188. package/components/tree/tree-item.yaml +1 -1
  189. package/components/tree/tree.js +1 -1
  190. package/components/upload/upload.js +1 -1
  191. package/core/provider.js +19 -2
  192. package/dist/web-components.min.css +1 -1
  193. package/dist/web-components.min.js +112 -90
  194. package/package.json +3 -3
  195. package/styles/components.css +3 -0
  196. /package/components/accordion/{class.js → accordion.class.js} +0 -0
  197. /package/components/action-list/{class.js → action-list.class.js} +0 -0
  198. /package/components/agent-feedback-bar/{class.js → agent-feedback-bar.class.js} +0 -0
  199. /package/components/agent-questions/{class.js → agent-questions.class.js} +0 -0
  200. /package/components/agent-reasoning/{class.js → agent-reasoning.class.js} +0 -0
  201. /package/components/agent-suggestions/{class.js → agent-suggestions.class.js} +0 -0
  202. /package/components/avatar/{class.js → avatar.class.js} +0 -0
  203. /package/components/badge/{class.js → badge.class.js} +0 -0
  204. /package/components/block/{class.js → block.class.js} +0 -0
  205. /package/components/breadcrumb/{class.js → breadcrumb.class.js} +0 -0
  206. /package/components/button/{class.js → button.class.js} +0 -0
  207. /package/components/calendar-picker/{class.js → calendar-picker.class.js} +0 -0
  208. /package/components/card/{class.js → card.class.js} +0 -0
  209. /package/components/chart/{class.js → chart.class.js} +0 -0
  210. /package/components/chart-legend/{class.js → chart-legend.class.js} +0 -0
  211. /package/components/chat-thread/{class.js → chat-thread.class.js} +0 -0
  212. /package/components/check/{class.js → check.class.js} +0 -0
  213. /package/components/code/{class.js → code.class.js} +0 -0
  214. /package/components/col/{class.js → col.class.js} +0 -0
  215. /package/components/color-input/{class.js → color-input.class.js} +0 -0
  216. /package/components/color-picker/{class.js → color-picker.class.js} +0 -0
  217. /package/components/combobox/{class.js → combobox.class.js} +0 -0
  218. /package/components/command/{class.js → command.class.js} +0 -0
  219. /package/components/demo-toggle/{class.js → demo-toggle.class.js} +0 -0
  220. /package/components/description-list/{class.js → description-list.class.js} +0 -0
  221. /package/components/divider/{class.js → divider.class.js} +0 -0
  222. /package/components/drawer/{class.js → drawer.class.js} +0 -0
  223. /package/components/embed/{class.js → embed.class.js} +0 -0
  224. /package/components/empty-state/{class.js → empty-state.class.js} +0 -0
  225. /package/components/feed/{class.js → feed.class.js} +0 -0
  226. /package/components/field/{class.js → field.class.js} +0 -0
  227. /package/components/fields/{class.js → fields.class.js} +0 -0
  228. /package/components/grid/{class.js → grid.class.js} +0 -0
  229. /package/components/heatmap/{class.js → heatmap.class.js} +0 -0
  230. /package/components/icon/{class.js → icon.class.js} +0 -0
  231. /package/components/image/{class.js → image.class.js} +0 -0
  232. /package/components/input/{class.js → input.class.js} +0 -0
  233. /package/components/inspector/{class.js → inspector.class.js} +0 -0
  234. /package/components/integration-card/{class.js → integration-card.class.js} +0 -0
  235. /package/components/kbd/{class.js → kbd.class.js} +0 -0
  236. /package/components/link/{class.js → link.class.js} +0 -0
  237. /package/components/list/{class.js → list.class.js} +0 -0
  238. /package/components/list-window/{class.js → list-window.class.js} +0 -0
  239. /package/components/menu/{class.js → menu.class.js} +0 -0
  240. /package/components/nav/{class.js → nav.class.js} +0 -0
  241. /package/components/nav-group/{class.js → nav-group.class.js} +0 -0
  242. /package/components/nav-item/{class.js → nav-item.class.js} +0 -0
  243. /package/components/noodles/{class.js → noodles.class.js} +0 -0
  244. /package/components/option-card/{class.js → option-card.class.js} +0 -0
  245. /package/components/otp-input/{class.js → otp-input.class.js} +0 -0
  246. /package/components/page/{class.js → page.class.js} +0 -0
  247. /package/components/pagination/{class.js → pagination.class.js} +0 -0
  248. /package/components/pane/{class.js → pane.class.js} +0 -0
  249. /package/components/pipeline-status/{class.js → pipeline-status.class.js} +0 -0
  250. /package/components/popover/{class.js → popover.class.js} +0 -0
  251. /package/components/progress/{class.js → progress.class.js} +0 -0
  252. /package/components/progress-row/{class.js → progress-row.class.js} +0 -0
  253. /package/components/radio/{class.js → radio.class.js} +0 -0
  254. /package/components/range/{class.js → range.class.js} +0 -0
  255. /package/components/rating/{class.js → rating.class.js} +0 -0
  256. /package/components/richtext/{class.js → richtext.class.js} +0 -0
  257. /package/components/row/{class.js → row.class.js} +0 -0
  258. /package/components/segment/{class.js → segment.class.js} +0 -0
  259. /package/components/segmented/{class.js → segmented.class.js} +0 -0
  260. /package/components/skeleton/{class.js → skeleton.class.js} +0 -0
  261. /package/components/slider/{class.js → slider.class.js} +0 -0
  262. /package/components/stack/{class.js → stack.class.js} +0 -0
  263. /package/components/step-progress/{class.js → step-progress.class.js} +0 -0
  264. /package/components/stepper/{class.js → stepper.class.js} +0 -0
  265. /package/components/stream/{class.js → stream.class.js} +0 -0
  266. /package/components/swatch/{class.js → swatch.class.js} +0 -0
  267. /package/components/swiper/{class.js → swiper.class.js} +0 -0
  268. /package/components/switch/{class.js → switch.class.js} +0 -0
  269. /package/components/table/{class.js → table.class.js} +0 -0
  270. /package/components/tabs/{class.js → tabs.class.js} +0 -0
  271. /package/components/text/{class.js → text.class.js} +0 -0
  272. /package/components/textarea/{class.js → textarea.class.js} +0 -0
  273. /package/components/time-picker/{class.js → time-picker.class.js} +0 -0
  274. /package/components/toast/{class.js → toast.class.js} +0 -0
  275. /package/components/toggle-group/{class.js → toggle-group.class.js} +0 -0
  276. /package/components/toggle-scheme/{class.js → toggle-scheme.class.js} +0 -0
  277. /package/components/toolbar/{class.js → toolbar.class.js} +0 -0
  278. /package/components/tooltip/{class.js → tooltip.class.js} +0 -0
  279. /package/components/tree/{class.js → tree.class.js} +0 -0
  280. /package/components/upload/{class.js → upload.class.js} +0 -0
@@ -0,0 +1,205 @@
1
+ # Hand-authored — SPEC-033.
2
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json + .d.ts.
3
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
4
+ name: UIInlineMessage
5
+ tag: inline-message-ui
6
+ status: stable
7
+ component: InlineMessage
8
+ category: feedback
9
+ version: 1
10
+ description: |
11
+ In-flow message glyph + text used in form-field rows for validation
12
+ feedback, hint copy, and inline confirmations. Distinguished from
13
+ <alert-ui> (banner / surface-bearing notice) by carrying no surface
14
+ fill, no border, no padding box — severity is foreground color +
15
+ icon only. Variants map to severity (info / success / warning /
16
+ danger). Nests inside <field-ui>, <col-ui>, <row-ui> without
17
+ breaking field rhythm. Non-interactive annotation only.
18
+ # Per ADR-0027 — primitives that programmatically create other primitives
19
+ # do NOT auto-import them. Consumer (or demo shell) must explicitly import.
20
+ composes:
21
+ - icon-ui
22
+ props:
23
+ variant:
24
+ description: Semantic severity tone — drives icon + foreground color. Default carries no leading icon (pure hint copy).
25
+ type: string
26
+ default: default
27
+ reflect: true
28
+ dynamic: true
29
+ enum:
30
+ - default
31
+ - info
32
+ - success
33
+ - warning
34
+ - danger
35
+ icon:
36
+ description: Phosphor glyph override; each [variant] ships a sensible default (info / check-circle / warning / x-circle).
37
+ type: string
38
+ default: ""
39
+ reflect: true
40
+ dynamic: true
41
+ text:
42
+ description: Single-line message text. Default-slot content wins when present.
43
+ type: string
44
+ default: ""
45
+ dynamic: true
46
+ live:
47
+ description: Sets `aria-live` on the host for dynamic message updates. Empty = no live region (static annotation).
48
+ type: string
49
+ default: ""
50
+ reflect: true
51
+ enum:
52
+ - ""
53
+ - polite
54
+ - assertive
55
+ events: {}
56
+ slots:
57
+ default:
58
+ description: >-
59
+ Message body — text or inline DOM (e.g. <link-ui>, <kbd-ui>). Wins
60
+ over the [text] attribute when present. Stays inline so the
61
+ message reads as one annotation line under the field.
62
+ leading:
63
+ description: >-
64
+ Leading icon slot. Stamped automatically from [icon] or the
65
+ variant's default glyph. Consumer-provided <icon-ui slot="leading">
66
+ is preserved across [variant] changes (never overwritten).
67
+ states:
68
+ - name: idle
69
+ description: Default, ready for screen-reader pickup.
70
+ traits: []
71
+ tokens: {}
72
+ requiredIcons:
73
+ - info
74
+ - check-circle
75
+ - warning
76
+ - x-circle
77
+ a2ui:
78
+ rules:
79
+ - rule: 'In-flow annotation under a form input (validation feedback, hint copy, inline confirmation). Severity via [variant] (info, success, warning, danger).'
80
+ reason: 'Distinct from <alert-ui>: no surface fill, no padding box, no dismiss — reads as helper text, not a banner.'
81
+ - rule: 'For overlay / banner-style notices use <alert-ui> instead; for transient toasts use <toast-ui>.'
82
+ reason: 'Surface-bearing vs in-flow boundary — collision invites visual confusion.'
83
+ - rule: 'Place inside <field-ui>, <col-ui>, or <row-ui>; never as a page-level banner.'
84
+ reason: 'Inline-flow contract; banner placement breaks the WAI inline-message pattern.'
85
+ - rule: 'Do not nest a focusable child (button, link with action) — InlineMessage is non-interactive annotation.'
86
+ reason: 'A focusable child requires role=alert + focus management, breaking the static-inline WAI pattern.'
87
+ anti_patterns: []
88
+ examples:
89
+ - name: field-validation
90
+ description: Email field with a danger inline-message under the input.
91
+ a2ui: >-
92
+ [
93
+ {
94
+ "id": "root",
95
+ "component": "Field",
96
+ "label": "Email",
97
+ "children": [
98
+ "input",
99
+ "msg"
100
+ ]
101
+ },
102
+ {
103
+ "id": "input",
104
+ "component": "Input",
105
+ "type": "email"
106
+ },
107
+ {
108
+ "id": "msg",
109
+ "component": "InlineMessage",
110
+ "variant": "danger",
111
+ "text": "Email address is required"
112
+ }
113
+ ]
114
+ - name: password-hint
115
+ description: Password field with a muted hint (default variant, no icon).
116
+ a2ui: >-
117
+ [
118
+ {
119
+ "id": "root",
120
+ "component": "Field",
121
+ "label": "Password",
122
+ "children": [
123
+ "input",
124
+ "hint"
125
+ ]
126
+ },
127
+ {
128
+ "id": "input",
129
+ "component": "Input",
130
+ "type": "password"
131
+ },
132
+ {
133
+ "id": "hint",
134
+ "component": "InlineMessage",
135
+ "text": "At least 8 characters"
136
+ }
137
+ ]
138
+ - name: username-success
139
+ description: Username field with a polite live-region success confirmation.
140
+ a2ui: >-
141
+ [
142
+ {
143
+ "id": "root",
144
+ "component": "Field",
145
+ "label": "Username",
146
+ "children": [
147
+ "input",
148
+ "msg"
149
+ ]
150
+ },
151
+ {
152
+ "id": "input",
153
+ "component": "Input"
154
+ },
155
+ {
156
+ "id": "msg",
157
+ "component": "InlineMessage",
158
+ "variant": "success",
159
+ "live": "polite",
160
+ "text": "Username is available"
161
+ }
162
+ ]
163
+ keywords:
164
+ - inline
165
+ - message
166
+ - hint
167
+ - helper
168
+ - validation
169
+ - error
170
+ - field-error
171
+ - helper-text
172
+ - error-text
173
+ - form-feedback
174
+ - status
175
+ - notice
176
+ synonyms:
177
+ hint:
178
+ - hint
179
+ - tooltip
180
+ - help
181
+ helper:
182
+ - hint
183
+ - help
184
+ - tooltip
185
+ validation:
186
+ - validation
187
+ - error
188
+ - alert
189
+ error:
190
+ - error
191
+ - alert
192
+ - validation
193
+ message:
194
+ - alert
195
+ - notification
196
+ - hint
197
+ notice:
198
+ - alert
199
+ - banner
200
+ - hint
201
+ related:
202
+ - alert
203
+ - field
204
+ - input
205
+ - text
@@ -121,6 +121,10 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
121
121
  outline: none;
122
122
  white-space: nowrap;
123
123
  overflow: hidden;
124
+ /* Positioning context for the [data-empty]::before placeholder
125
+ pseudo, which is taken out of inline flow so the caret renders
126
+ at the actual content-start (not after the pseudo box). */
127
+ position: relative;
124
128
  }
125
129
 
126
130
  /* Text (native input — password only) */
@@ -138,11 +142,21 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
138
142
  color: var(--input-placeholder-fg, var(--input-placeholder-fg-default));
139
143
  }
140
144
 
141
- /* Placeholder (contenteditable only) */
145
+ /* Placeholder (contenteditable only).
146
+ Out-of-flow positioning is load-bearing — an in-flow ::before with
147
+ `content: attr(...)` puts the pseudo box INLINE before the empty
148
+ text node, which means the caret-at-position-0 visually renders to
149
+ the RIGHT of the placeholder text (after the user types and deletes).
150
+ `position: absolute; inset: 0; padding: inherit` makes the pseudo
151
+ fill the host's content-box without occupying any inline-flow space,
152
+ so the caret renders at the actual content-start where it belongs. */
142
153
  span[slot="text"][data-empty]::before {
143
154
  content: attr(data-placeholder);
144
155
  color: var(--input-placeholder-fg, var(--input-placeholder-fg-default));
145
156
  pointer-events: none;
157
+ position: absolute;
158
+ inset: 0;
159
+ padding: inherit;
146
160
  }
147
161
 
148
162
  /* ── Number mode (type="number") ──
@@ -278,7 +292,7 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
278
292
 
279
293
  /* §199 (v0.5.7) — Leading + trailing affordance slots inside the field.
280
294
  Consumer authors `<button-ui slot="leading|trailing">` as a direct
281
- child of <input-ui>; class.js#installAffordances moves it into
295
+ child of <input-ui>; input.class.js#installAffordances moves it into
282
296
  [slot="field"] at the right insertion point on connected(). CSS
283
297
  normalizes the chrome here.
284
298
 
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UIInput } from './class.js';
13
+ import { UIInput } from './input.class.js';
14
14
 
15
15
  defineIfFree('input-ui', UIInput);
16
16
 
@@ -10,9 +10,15 @@
10
10
  */
11
11
 
12
12
  import { describe, it, expect, beforeEach } from 'vitest';
13
+ import { readFileSync } from 'node:fs';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { dirname, resolve } from 'node:path';
13
16
  import '../../core/element.js';
14
17
  import './input.js';
15
18
 
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const INPUT_CSS = readFileSync(resolve(__dirname, 'input.css'), 'utf8');
21
+
16
22
  const tick = () => new Promise((r) => queueMicrotask(r));
17
23
 
18
24
  function mount(html) {
@@ -220,3 +226,37 @@ describe('input-ui — §220 (v0.5.9) throttle parity', () => {
220
226
  expect(events).toEqual([]);
221
227
  });
222
228
  });
229
+
230
+ // ── Placeholder caret-position regression guard ─────────────────────
231
+ //
232
+ // Per the v0.6.35 bug report: with the `::before { content: attr(data-placeholder) }`
233
+ // pseudo rendered in inline flow, typing-then-deleting left the caret
234
+ // visually at the END of the placeholder text (not at position 0) because
235
+ // the in-flow pseudo box pushed the caret rendering position to its right.
236
+ // Fix: pseudo is `position: absolute` so it doesn't occupy inline-flow
237
+ // space; the host carries `position: relative` as its anchor.
238
+ // These tests assert the CSS-source contract that prevents accidental
239
+ // revert to the in-flow pseudo shape.
240
+
241
+ describe('input-ui — CSS source contract: placeholder pseudo is out of flow', () => {
242
+ it('host [slot="text"] declares position: relative (pseudo anchor)', () => {
243
+ expect(INPUT_CSS).toMatch(
244
+ /\[slot="text"\]\s*\{[^}]*position:\s*relative/s
245
+ );
246
+ });
247
+
248
+ it('[data-empty]::before is position: absolute (not inline-flow)', () => {
249
+ expect(INPUT_CSS).toMatch(
250
+ /span\[slot="text"\]\[data-empty\]::before\s*\{[^}]*position:\s*absolute/s
251
+ );
252
+ });
253
+
254
+ it('[data-empty]::before fills the host content-box (inset: 0 + padding: inherit)', () => {
255
+ expect(INPUT_CSS).toMatch(
256
+ /span\[slot="text"\]\[data-empty\]::before\s*\{[^}]*inset:\s*0/s
257
+ );
258
+ expect(INPUT_CSS).toMatch(
259
+ /span\[slot="text"\]\[data-empty\]::before\s*\{[^}]*padding:\s*inherit/s
260
+ );
261
+ });
262
+ });
@@ -262,10 +262,11 @@ a2ui:
262
262
  Number. Never substitute a native <input type="number">.
263
263
  - >-
264
264
  Inside <chat-composer>, the canonical inner input is
265
- <chat-input-ui submit-on-enter> (chat variant subclass — owns
266
- the submit-on-enter contract explicitly). The plain <input-ui>
267
- primitive already fires `submit` on Enter, but only chat-input-ui
268
- reflects the [submit-on-enter] attribute.
265
+ <chat-input-ui> (chat variant subclass — adds the send button +
266
+ model picker + paste-to-attach plumbing). The plain <input-ui>
267
+ primitive ALSO fires a bubbling `submit` event on Enter
268
+ (unconditional, no opt-in attribute); <chat-input-ui> simply
269
+ builds on that semantic.
269
270
  anti_patterns: []
270
271
  examples:
271
272
  - name: quantity-stepper
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UIInspector } from './class.js';
13
+ import { UIInspector } from './inspector.class.js';
14
14
 
15
15
  defineIfFree('inspector-ui', UIInspector);
16
16
 
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UIIntegrationCard } from './class.js';
13
+ import { UIIntegrationCard } from './integration-card.class.js';
14
14
 
15
15
  defineIfFree('integration-card-ui', UIIntegrationCard);
16
16
 
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UIKbd } from './class.js';
13
+ import { UIKbd } from './kbd.class.js';
14
14
 
15
15
  defineIfFree('kbd-ui', UIKbd);
16
16
 
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UILink } from './class.js';
13
+ import { UILink } from './link.class.js';
14
14
 
15
15
  defineIfFree('link-ui', UILink);
16
16
 
@@ -1,9 +1,9 @@
1
1
  # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
2
  #
3
3
  # §176 (v0.5.5): authored to close the §175 baseline-orphan class. The
4
- # component already existed as a sibling class in the parent's class.js
4
+ # component already existed as a sibling class in the parent's list.class.js
5
5
  # + was registered alongside the parent (e.g. UIList + UIListItem both
6
- # from list/class.js). The catalog just lacked its own entry. With the
6
+ # from list/list.class.js). The catalog just lacked its own entry. With the
7
7
  # §172 sibling-yaml scanner, this file gets picked up next to the parent
8
8
  # yaml.
9
9
 
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UIList, UIListItem } from './class.js';
13
+ import { UIList, UIListItem } from './list.class.js';
14
14
 
15
15
  defineIfFree('list-ui', UIList);
16
16
  defineIfFree('list-item-ui', UIListItem);
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { defineIfFree } from '../../core/register.js';
13
- import { UIListWindow } from './class.js';
13
+ import { UIListWindow } from './list-window.class.js';
14
14
 
15
15
  defineIfFree('list-window-ui', UIListWindow);
16
16
 
@@ -0,0 +1,176 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/LoadingOverlay.json",
4
+ "title": "LoadingOverlay",
5
+ "description": "Container-scoped busy overlay. Covers a positioned parent region with a centered spinner (auto-stamped) or slotted indicator (skeleton-ui, progress-ui, custom) while async work is in flight. Wires aria-busy onto the parent on connect; applies a [delay] grace window to avoid flash on fast loads. For viewport-scoped / route loaders use a dedicated route-loader pattern; for submit-button busy use <button-ui loading>.",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "active": {
17
+ "description": "When set, overlay is visible and the parent container is marked aria-busy. Toggle from consumer code; default hidden.",
18
+ "$ref": "common_types.json#/$defs/DynamicBoolean"
19
+ },
20
+ "component": {
21
+ "const": "LoadingOverlay"
22
+ },
23
+ "delay": {
24
+ "description": "Suppress the overlay until this many ms elapse. Prevents flash on fast loads. Default 200ms.",
25
+ "$ref": "common_types.json#/$defs/DynamicNumber"
26
+ },
27
+ "label": {
28
+ "description": "Accessible operation name used by the host aria-label and forwarded to the auto-stamped spinner.",
29
+ "$ref": "common_types.json#/$defs/DynamicString"
30
+ },
31
+ "variant": {
32
+ "description": "Backdrop treatment — default (muted scrim), transparent (no backdrop fill — useful with full-area skeleton indicators), blur (light scrim with backdrop-filter blur).",
33
+ "$ref": "common_types.json#/$defs/DynamicString"
34
+ }
35
+ },
36
+ "required": [
37
+ "component"
38
+ ],
39
+ "unevaluatedProperties": false,
40
+ "x-adiaui": {
41
+ "anti_patterns": [
42
+ {
43
+ "fix": "{\"component\": \"Card\", \"children\": [\n {\"component\": \"LoadingOverlay\", \"active\": true},\n {\"component\": \"Table\", \"data-stream-src\": \"...\"}\n]}\n",
44
+ "why": "LoadingOverlay is container-scoped. Attaching it directly to Page\ncovers the entire viewport but lacks the route-loader's wiring\n(skeleton routing, route-level animation). Use the route loader.\n",
45
+ "wrong": "{\"component\": \"Page\", \"children\": [\n {\"component\": \"LoadingOverlay\", \"active\": true}\n]}\n"
46
+ },
47
+ {
48
+ "fix": "{\"component\": \"Modal\", \"open\": true, \"loading\": true}\n",
49
+ "why": "Modal owns its own busy state and focus trap; nesting a\nLoadingOverlay introduces two competing inert toggles.\n",
50
+ "wrong": "{\"component\": \"Modal\", \"open\": true, \"children\": [\n {\"component\": \"LoadingOverlay\", \"active\": true}\n]}\n"
51
+ },
52
+ {
53
+ "fix": "{\"component\": \"Form\", \"children\": [\n {\"component\": \"Button\", \"text\": \"Submitting\", \"type\": \"submit\", \"loading\": true, \"disabled\": true}\n]}\n",
54
+ "why": "A form-submit affordance belongs on the button itself, not as an\noverlay over the entire form region. Use Button[loading].\n",
55
+ "wrong": "{\"component\": \"Form\", \"children\": [\n {\"component\": \"Button\", \"text\": \"Submit\", \"type\": \"submit\"},\n {\"component\": \"LoadingOverlay\", \"active\": true}\n]}\n"
56
+ }
57
+ ],
58
+ "category": "feedback",
59
+ "composes": [],
60
+ "events": {},
61
+ "examples": [
62
+ {
63
+ "description": "Card containing a table that loads on mount; the overlay covers the card's body while data streams.",
64
+ "a2ui": "[\n {\n \"id\": \"card\",\n \"component\": \"Card\",\n \"children\": [\"sec\"]\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\"overlay\", \"table\"]\n },\n {\n \"id\": \"overlay\",\n \"component\": \"LoadingOverlay\",\n \"active\": true,\n \"label\": \"Loading orders…\"\n },\n {\n \"id\": \"table\",\n \"component\": \"Table\",\n \"data-stream-src\": \"/api/orders\"\n }\n]",
65
+ "name": "card-with-loading-table"
66
+ },
67
+ {
68
+ "description": "Skeleton-shaped placeholder overlay using the transparent variant — slot a stack of <Skeleton> rows.",
69
+ "a2ui": "[\n {\n \"id\": \"ov\",\n \"component\": \"LoadingOverlay\",\n \"active\": true,\n \"variant\": \"transparent\",\n \"label\": \"Loading content…\",\n \"children\": [\"sk-stack\"]\n },\n {\n \"id\": \"sk-stack\",\n \"component\": \"Column\",\n \"gap\": \"2\",\n \"children\": [\"sk1\", \"sk2\", \"sk3\"]\n },\n {\n \"id\": \"sk1\",\n \"component\": \"Skeleton\",\n \"width\": \"100%\",\n \"height\": \"1rem\"\n },\n {\n \"id\": \"sk2\",\n \"component\": \"Skeleton\",\n \"width\": \"80%\",\n \"height\": \"1rem\"\n },\n {\n \"id\": \"sk3\",\n \"component\": \"Skeleton\",\n \"width\": \"60%\",\n \"height\": \"1rem\"\n }\n]",
70
+ "name": "skeleton-overlay"
71
+ },
72
+ {
73
+ "description": "Overlay with the default 200ms grace window. If the underlying load resolves in less than 200ms, the overlay never paints.",
74
+ "a2ui": "[\n {\n \"id\": \"ov\",\n \"component\": \"LoadingOverlay\",\n \"active\": true,\n \"delay\": 200,\n \"label\": \"Loading\"\n }\n]",
75
+ "name": "fast-load-no-flash"
76
+ }
77
+ ],
78
+ "keywords": [
79
+ "loading",
80
+ "overlay",
81
+ "busy",
82
+ "spinner",
83
+ "skeleton",
84
+ "placeholder",
85
+ "feedback",
86
+ "progress",
87
+ "indicator",
88
+ "wait"
89
+ ],
90
+ "name": "UILoadingOverlay",
91
+ "related": [
92
+ "Spinner",
93
+ "Skeleton",
94
+ "Progress",
95
+ "Card",
96
+ "Table",
97
+ "Modal"
98
+ ],
99
+ "slots": {
100
+ "default": {
101
+ "description": "Busy indicator content — <spinner-ui>, <skeleton-ui>, <progress-ui>, or custom. If empty, a centered <spinner-ui size=\"lg\"> is auto-stamped."
102
+ }
103
+ },
104
+ "states": [
105
+ {
106
+ "description": "Default, hidden. Parent interactive.",
107
+ "name": "idle"
108
+ },
109
+ {
110
+ "description": "Overlay visible; parent has aria-busy=\"true\".",
111
+ "attribute": "active",
112
+ "name": "active"
113
+ }
114
+ ],
115
+ "status": "stable",
116
+ "synonyms": {
117
+ "busy": [
118
+ "loading",
119
+ "overlay",
120
+ "busy",
121
+ "spinner"
122
+ ],
123
+ "loader": [
124
+ "loading",
125
+ "overlay",
126
+ "spinner"
127
+ ],
128
+ "loading": [
129
+ "loading",
130
+ "overlay",
131
+ "busy",
132
+ "spinner",
133
+ "skeleton"
134
+ ],
135
+ "overlay": [
136
+ "loading",
137
+ "overlay",
138
+ "busy"
139
+ ],
140
+ "spinner": [
141
+ "loading",
142
+ "overlay",
143
+ "spinner"
144
+ ]
145
+ },
146
+ "tag": "loading-overlay-ui",
147
+ "tokens": {
148
+ "--loading-overlay-bg": {
149
+ "description": "Backdrop fill color. Default uses the generic neutral scrim token.",
150
+ "default": "var(--a-scrim-default)"
151
+ },
152
+ "--loading-overlay-duration": {
153
+ "description": "Fade in / fade out duration.",
154
+ "default": "var(--a-duration)"
155
+ },
156
+ "--loading-overlay-easing": {
157
+ "description": "Fade easing curve.",
158
+ "default": "var(--a-easing-out)"
159
+ },
160
+ "--loading-overlay-gap": {
161
+ "description": "Vertical gap between the indicator and any sibling content (e.g. label, skeleton stack).",
162
+ "default": "var(--a-space-3)"
163
+ },
164
+ "--loading-overlay-radius": {
165
+ "description": "Backdrop corner radius. Matches the parent surface by default.",
166
+ "default": "var(--a-radius-md)"
167
+ },
168
+ "--loading-overlay-z": {
169
+ "description": "Stacking order. Sits above sibling content, below modal-ui (which uses ::backdrop on top-layer dialog).",
170
+ "default": "50"
171
+ }
172
+ },
173
+ "traits": [],
174
+ "version": 1
175
+ }
176
+ }