@adia-ai/web-components 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +12 -0
  2. package/components/alert/alert.a2ui.json +17 -2
  3. package/components/alert/alert.js +100 -9
  4. package/components/alert/alert.test.js +180 -0
  5. package/components/alert/alert.yaml +30 -2
  6. package/components/badge/badge.a2ui.json +4 -0
  7. package/components/badge/badge.js +1 -0
  8. package/components/badge/badge.yaml +4 -0
  9. package/components/button/button.a2ui.json +14 -4
  10. package/components/button/button.js +1 -0
  11. package/components/button/button.yaml +18 -3
  12. package/components/check/check.a2ui.json +8 -1
  13. package/components/check/check.yaml +11 -2
  14. package/components/code/code.a2ui.json +4 -0
  15. package/components/code/code.js +1 -0
  16. package/components/code/code.yaml +4 -0
  17. package/components/col/col.a2ui.json +5 -0
  18. package/components/col/col.js +1 -0
  19. package/components/col/col.yaml +5 -0
  20. package/components/field/field.a2ui.json +17 -6
  21. package/components/field/field.test.js +8 -2
  22. package/components/field/field.yaml +50 -8
  23. package/components/index.js +1 -0
  24. package/components/input/input.a2ui.json +25 -0
  25. package/components/input/input.js +220 -34
  26. package/components/input/input.yaml +24 -0
  27. package/components/link/link.a2ui.json +166 -0
  28. package/components/link/link.css +102 -0
  29. package/components/link/link.js +177 -0
  30. package/components/link/link.test.js +143 -0
  31. package/components/link/link.yaml +162 -0
  32. package/components/radio/radio.a2ui.json +8 -1
  33. package/components/radio/radio.yaml +11 -2
  34. package/components/row/row.a2ui.json +5 -0
  35. package/components/row/row.js +1 -0
  36. package/components/row/row.yaml +5 -0
  37. package/components/select/select.a2ui.json +15 -0
  38. package/components/select/select.yaml +14 -0
  39. package/components/switch/switch.a2ui.json +8 -1
  40. package/components/switch/switch.yaml +11 -2
  41. package/components/table/table.a2ui.json +10 -0
  42. package/components/table/table.yaml +8 -0
  43. package/components/tag/tag.a2ui.json +4 -0
  44. package/components/tag/tag.js +1 -0
  45. package/components/tag/tag.yaml +4 -0
  46. package/components/text/text.a2ui.json +5 -0
  47. package/components/text/text.js +1 -0
  48. package/components/text/text.yaml +5 -0
  49. package/components/textarea/textarea.a2ui.json +5 -0
  50. package/components/textarea/textarea.yaml +4 -0
  51. package/package.json +1 -1
@@ -0,0 +1,162 @@
1
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
+ name: UILink
3
+ tag: link-ui
4
+ component: Link
5
+ category: content
6
+ version: 1
7
+ description: |
8
+ Inline navigation primitive — semantic `<a href>` wrapper. Use for
9
+ cross-page navigation, footer / Terms-of-Service / Privacy-Policy
10
+ inline references, "Sign in" / "Sign up" cross-page links, and any
11
+ affordance whose purpose is to take the user somewhere (not to
12
+ perform an action).
13
+
14
+ Sibling of `<button-ui>` — they have separate semantics and must
15
+ not be substituted for each other:
16
+
17
+ | Affordance | Use |
18
+ |---------------------------|----------------|
19
+ | Submit form | `<button-ui>` |
20
+ | Trigger action / modal | `<button-ui>` |
21
+ | Copy to clipboard | `<button-ui>` |
22
+ | Open modal / drawer | `<button-ui>` |
23
+ | Navigate to another page | `<link-ui>` |
24
+ | Open external URL | `<link-ui>` |
25
+ | Anchor jump (#section) | `<link-ui>` |
26
+ | Inline reference in prose | `<link-ui>` |
27
+
28
+ Renders `<a href="…">` internally so middle-click open-in-new-tab,
29
+ right-click context menu, hover URL preview, search-engine
30
+ crawlability, and bookmark-ability all work without any custom
31
+ wiring. ARIA role is "link" (set automatically by `<a>` element).
32
+
33
+ props:
34
+ text:
35
+ description: Visible link text. Falls back to default-slot content if unset.
36
+ type: string
37
+ default: ""
38
+ href:
39
+ description: >-
40
+ Destination URL or anchor. Required for SEO / middle-click / hover
41
+ preview semantics. If omitted, the link still dispatches the
42
+ `press` event (so it can be wired through the A2UI action handler
43
+ system via `handler: "navigate"`), but loses native link behaviors.
44
+ type: string
45
+ default: ""
46
+ target:
47
+ description: >-
48
+ Anchor target — same semantics as HTML `<a target>`. Use
49
+ `_blank` to open in new tab; the implementation automatically
50
+ adds `rel="noopener noreferrer"` for `_blank` to prevent
51
+ tab-napping / privacy leaks.
52
+ type: string
53
+ default: ""
54
+ enum:
55
+ - ""
56
+ - _self
57
+ - _blank
58
+ - _parent
59
+ - _top
60
+ rel:
61
+ description: >-
62
+ Explicit `rel` attribute. Defaults to `noopener noreferrer` when
63
+ `target="_blank"` is set without an explicit rel.
64
+ type: string
65
+ default: ""
66
+ variant:
67
+ description: >-
68
+ Visual treatment. `default` underlines on rest + hover (standard
69
+ link affordance). `subtle` underlines only on hover (for tighter
70
+ designs where always-underlined would be noisy). `quiet` drops
71
+ the link color and matches surrounding text color (used for
72
+ footer-link rows where the link affordance is implied by
73
+ context, not by color).
74
+ type: string
75
+ default: default
76
+ enum:
77
+ - default
78
+ - subtle
79
+ - quiet
80
+ block:
81
+ description: Stretches the link to fill its container; useful for standalone link rows.
82
+ type: boolean
83
+ default: false
84
+ disabled:
85
+ description: Suppresses navigation + applies muted styling. Sets aria-disabled.
86
+ type: boolean
87
+ default: false
88
+ icon:
89
+ description: >-
90
+ Optional leading icon (Phosphor name). Use sparingly — most inline
91
+ links don't need an icon. For "open in new tab" affordance, the
92
+ `target="_blank"` attribute auto-renders a trailing arrow-up-right
93
+ glyph; the `icon` prop is for leading semantic icons.
94
+ type: string
95
+ default: ""
96
+
97
+ events:
98
+ press:
99
+ description: >-
100
+ Bubbles when the link is activated by click or Enter. Detail:
101
+ `{ href, target }`. Fires BEFORE the browser's native navigation
102
+ so handlers can `preventDefault()` and route through the A2UI
103
+ action handler system. If no handler intercepts, native
104
+ navigation proceeds.
105
+
106
+ slots:
107
+ default:
108
+ description: Link text content when the `text` prop is unused.
109
+
110
+ states:
111
+ - name: idle
112
+ description: Default rest state — underlined (or per variant).
113
+ - name: hover
114
+ description: Color shifts to `--a-link-hover`.
115
+ - name: visited
116
+ description: Auto-styled via `:visited` pseudo when navigating to a previously-visited URL.
117
+ - name: disabled
118
+ description: Suppressed activation; muted text color; aria-disabled.
119
+
120
+ traits: []
121
+ tokens:
122
+ --link-color:
123
+ description: Resting link color. Default `var(--a-link)`.
124
+ --link-color-hover:
125
+ description: Hover-state color. Default `var(--a-link-hover)`.
126
+ --link-color-visited:
127
+ description: Visited-state color. Default `var(--a-link-visited)`.
128
+ --link-underline-offset:
129
+ description: Distance between baseline and underline. Default `2px`.
130
+ a2ui:
131
+ rules:
132
+ - "Use `<link-ui>` for navigation; use `<button-ui>` for actions. They are NOT interchangeable."
133
+ - "When wrapping action affordances that visually mimic links (e.g. 'Forgot password?' that triggers a reset flow), prefer `<button-ui variant=\"ghost\">` over a fake `<link-ui>` — the affordance is semantically a button, just visually understated."
134
+ - "For inline-sentence affordances ('I agree to the [Terms] and [Privacy]'), nest `<link-ui>` directly inside `<text-ui>` so it inherits the paragraph's font / size / line-height."
135
+ anti_patterns:
136
+ - "❌ `<button-ui variant=\"link\">` — was removed. Migrate to `<link-ui>` if the affordance is navigation, or to `<button-ui variant=\"ghost\">` if the affordance is an action that wants understated styling."
137
+ - "❌ `<link-ui>` with no `href` AND no `press` handler — a link to nowhere is a bug. Either set `href` or wire a navigate action handler."
138
+ - "❌ `<link-ui>` for form submission — submission is a button concern. Use `<button-ui type=\"submit\">`."
139
+
140
+ examples:
141
+ - title: Inline link in a sentence
142
+ code: |
143
+ <text-ui>
144
+ I agree to the
145
+ <link-ui text="Terms of Service" href="/terms"></link-ui>
146
+ and
147
+ <link-ui text="Privacy Policy" href="/privacy"></link-ui>.
148
+ </text-ui>
149
+ - title: External link with new-tab target
150
+ code: |
151
+ <link-ui text="Read the spec" href="https://example.com/spec" target="_blank"></link-ui>
152
+ - title: Footer link row
153
+ code: |
154
+ <row-ui justify="center" gap="2">
155
+ <link-ui text="Already have an account?" variant="quiet" href="/signin"></link-ui>
156
+ <link-ui text="Sign in" href="/signin"></link-ui>
157
+ </row-ui>
158
+
159
+ keywords: [link, anchor, navigation, hyperlink, href, navigate, route, url]
160
+ synonyms:
161
+ Link: [Anchor, Hyperlink, NavLink]
162
+ related: [Button, NavItem, Breadcrumb]
@@ -67,7 +67,14 @@
67
67
  ],
68
68
  "unevaluatedProperties": false,
69
69
  "x-adiaui": {
70
- "anti_patterns": [],
70
+ "anti_patterns": [
71
+ {
72
+ "description": "Wrapping a radio-ui in field-ui. The widget already self-labels.",
73
+ "right": "<radio-ui label=\"Basic plan\" name=\"plan\" value=\"basic\"></radio-ui>\n",
74
+ "rule": "Use [label] on radio-ui directly; do not wrap in field-ui.",
75
+ "wrong": "<field-ui inline label=\"Basic plan\">\n <radio-ui name=\"plan\" value=\"basic\"></radio-ui>\n</field-ui>\n"
76
+ }
77
+ ],
71
78
  "category": "input",
72
79
  "events": {
73
80
  "change": {
@@ -107,8 +107,17 @@ tokens:
107
107
  --radio-transition:
108
108
  description: Override transition timing
109
109
  a2ui:
110
- rules: []
111
- anti_patterns: []
110
+ rules:
111
+ - "Self-labeling widget — use the [label] attribute directly; do NOT wrap in <field-ui>. The widget renders its own label inline via CSS attr() pattern. For radio groups, the canonical pattern is a column of bare <radio-ui label='…'> elements sharing a [name=] — no field-ui wrapper around each radio."
112
+ anti_patterns:
113
+ - description: Wrapping a radio-ui in field-ui. The widget already self-labels.
114
+ wrong: |
115
+ <field-ui inline label="Basic plan">
116
+ <radio-ui name="plan" value="basic"></radio-ui>
117
+ </field-ui>
118
+ right: |
119
+ <radio-ui label="Basic plan" name="plan" value="basic"></radio-ui>
120
+ rule: Use [label] on radio-ui directly; do not wrap in field-ui.
112
121
  examples:
113
122
  - name: radio-group
114
123
  description: "Card with radio group for plan selection: Basic, Pro, and Enterprise tiers."
@@ -31,6 +31,11 @@
31
31
  "type": "string",
32
32
  "default": "md"
33
33
  },
34
+ "grow": {
35
+ "description": "Fills remaining space in a flex parent. CSS-only attribute via :scope[grow] in row.css.",
36
+ "type": "boolean",
37
+ "default": false
38
+ },
34
39
  "justify": {
35
40
  "description": "Justify content",
36
41
  "type": "string",
@@ -13,6 +13,7 @@ class UIRow extends UIElement {
13
13
  justify: { type: String, default: 'start', reflect: true },
14
14
  align: { type: String, default: 'center', reflect: true },
15
15
  gap: { type: String, default: 'md', reflect: true },
16
+ grow: { type: Boolean, default: false, reflect: true },
16
17
  wrap: { type: Boolean, default: false, reflect: true },
17
18
  draggable: { type: Boolean, default: false, reflect: true },
18
19
  };
@@ -23,6 +23,11 @@ props:
23
23
  or a numeric rung on the spacing scale ("1"…"16").
24
24
  type: string
25
25
  default: md
26
+ grow:
27
+ description: Fills remaining space in a flex parent. CSS-only attribute via :scope[grow] in row.css.
28
+ type: boolean
29
+ default: false
30
+ reflect: true
26
31
  justify:
27
32
  description: Justify content
28
33
  type: string
@@ -81,6 +81,11 @@
81
81
  "type": "boolean",
82
82
  "default": false
83
83
  },
84
+ "options": {
85
+ "description": "Option list. Array of {value, label, disabled?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children.",
86
+ "type": "array",
87
+ "default": []
88
+ },
84
89
  "pattern": {
85
90
  "description": "Regex pattern for validation",
86
91
  "type": "string",
@@ -101,6 +106,16 @@
101
106
  "type": "boolean",
102
107
  "default": false
103
108
  },
109
+ "size": {
110
+ "description": "Sizing scale via universal `[size]` attribute system (packages/web-components/styles/tokens.css). Matches Input's sizing tokens so a Select rendered alongside an Input feels coherent in a form row.",
111
+ "type": "string",
112
+ "enum": [
113
+ "sm",
114
+ "md",
115
+ "lg"
116
+ ],
117
+ "default": "md"
118
+ },
104
119
  "value": {
105
120
  "description": "Currently selected option value",
106
121
  "type": "string",
@@ -17,6 +17,16 @@ props:
17
17
  type: string
18
18
  default: default
19
19
  enum: [default, outline, ghost, soft]
20
+ size:
21
+ description: >-
22
+ Sizing scale via universal `[size]` attribute system
23
+ (packages/web-components/styles/tokens.css). Matches Input's
24
+ sizing tokens so a Select rendered alongside an Input feels
25
+ coherent in a form row.
26
+ type: string
27
+ default: md
28
+ enum: [sm, md, lg]
29
+ reflect: true
20
30
  required:
21
31
  description: Marks the field as required for form validation
22
32
  type: boolean
@@ -70,6 +80,10 @@ props:
70
80
  type: boolean
71
81
  default: false
72
82
  reflect: true
83
+ options:
84
+ description: "Option list. Array of {value, label, disabled?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children."
85
+ type: array
86
+ default: []
73
87
  pattern:
74
88
  description: Regex pattern for validation
75
89
  type: string
@@ -69,7 +69,14 @@
69
69
  ],
70
70
  "unevaluatedProperties": false,
71
71
  "x-adiaui": {
72
- "anti_patterns": [],
72
+ "anti_patterns": [
73
+ {
74
+ "description": "Wrapping a switch-ui in field-ui. The widget already self-labels.",
75
+ "right": "<switch-ui label=\"Email notifications\"></switch-ui>\n",
76
+ "rule": "Use [label] on switch-ui directly; do not wrap in field-ui.",
77
+ "wrong": "<field-ui inline label=\"Email notifications\">\n <switch-ui></switch-ui>\n</field-ui>\n"
78
+ }
79
+ ],
73
80
  "category": "layout",
74
81
  "events": {
75
82
  "change": {
@@ -83,8 +83,17 @@ tokens:
83
83
  --toggle-track-width:
84
84
  description: Track width
85
85
  a2ui:
86
- rules: []
87
- anti_patterns: []
86
+ rules:
87
+ - "Self-labeling widget — use the [label] attribute directly; do NOT wrap in <field-ui>. The widget renders its own label inline via CSS attr() pattern. For settings rows (label-left, switch-right), put the descriptive text in switch-ui's own [label] attribute; do not introduce a field-ui wrapper. For descriptive helper text below the switch, use <text-ui variant='caption'> as a sibling — not field-ui's hint slot."
88
+ anti_patterns:
89
+ - description: Wrapping a switch-ui in field-ui. The widget already self-labels.
90
+ wrong: |
91
+ <field-ui inline label="Email notifications">
92
+ <switch-ui></switch-ui>
93
+ </field-ui>
94
+ right: |
95
+ <switch-ui label="Email notifications"></switch-ui>
96
+ rule: Use [label] on switch-ui directly; do not wrap in field-ui.
88
97
  examples:
89
98
  - name: notification-preferences
90
99
  description: Notification preferences card with toggle switches for different notification channels
@@ -13,9 +13,19 @@
13
13
  }
14
14
  ],
15
15
  "properties": {
16
+ "columns": {
17
+ "description": "Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, accessor?, format?, render?, sortFn?, filterType?, meta?}. Alternative to declarative <col-def> children.",
18
+ "type": "array",
19
+ "default": []
20
+ },
16
21
  "component": {
17
22
  "const": "Table"
18
23
  },
24
+ "data": {
25
+ "description": "Row records. Array of plain objects keyed to columns[].key.",
26
+ "type": "array",
27
+ "default": []
28
+ },
19
29
  "density": {
20
30
  "description": "Controls cell padding and row height. 'compact' for dense data, 'standard' for default spacing, 'comfortable' for spacious rows.",
21
31
  "type": "string",
@@ -9,6 +9,14 @@ version: 1
9
9
  description: Data table with sorting, selection, pagination, search, column resize, keyboard nav,
10
10
  cell types, and CSV export. CSS grid + ARIA grid roles.
11
11
  props:
12
+ columns:
13
+ description: Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, accessor?, format?, render?, sortFn?, filterType?, meta?}. Alternative to declarative <col-def> children.
14
+ type: array
15
+ default: []
16
+ data:
17
+ description: Row records. Array of plain objects keyed to columns[].key.
18
+ type: array
19
+ default: []
12
20
  density:
13
21
  description: Controls cell padding and row height. 'compact' for dense data, 'standard' for default
14
22
  spacing, 'comfortable' for spacious rows.
@@ -40,6 +40,10 @@
40
40
  "type": "string",
41
41
  "default": ""
42
42
  },
43
+ "textContent": {
44
+ "description": "Tag label. Renderer routes this to the `text` attribute, rendered via CSS attr(text) on ::after.",
45
+ "$ref": "common_types.json#/$defs/DynamicString"
46
+ },
43
47
  "variant": {
44
48
  "description": "Semantic variant — `default | info | success | warning | danger`.",
45
49
  "type": "string",
@@ -16,6 +16,7 @@ import { UIElement } from '../../core/element.js';
16
16
  class UITag extends UIElement {
17
17
  static properties = {
18
18
  text: { type: String, default: '', reflect: true },
19
+ textContent: { type: String, default: '' },
19
20
  variant: { type: String, default: 'default', reflect: true },
20
21
  size: { type: String, default: 'md', reflect: true },
21
22
  removable: { type: Boolean, default: false, reflect: true },
@@ -28,6 +28,10 @@ props:
28
28
  description: Tag text content.
29
29
  type: string
30
30
  default: ""
31
+ textContent:
32
+ description: Tag label. Renderer routes this to the `text` attribute, rendered via CSS attr(text) on ::after.
33
+ type: string
34
+ dynamic: true
31
35
  variant:
32
36
  description: Semantic variant — `default | info | success | warning | danger`.
33
37
  type: string
@@ -21,6 +21,11 @@
21
21
  "type": "number",
22
22
  "default": 0
23
23
  },
24
+ "strong": {
25
+ "description": "When true, applies stronger emphasis (heavier weight + accent color). Styled via :scope[strong] in text.css. Use instead of variant=heading when you want a single emphasized word inline in body copy.",
26
+ "type": "boolean",
27
+ "default": false
28
+ },
24
29
  "textContent": {
25
30
  "description": "Display text content. The main payload field for Text components extracted from HTML.",
26
31
  "$ref": "common_types.json#/$defs/DynamicString"
@@ -16,6 +16,7 @@ import { UIElement } from '../../core/element.js';
16
16
  class UIText extends UIElement {
17
17
  static properties = {
18
18
  variant: { type: String, default: 'body', reflect: true },
19
+ strong: { type: Boolean, default: false, reflect: true },
19
20
  truncate: { type: Boolean, default: false, reflect: true },
20
21
  lines: { type: Number, default: 0, reflect: true },
21
22
  };
@@ -12,6 +12,11 @@ props:
12
12
  description: Multi-line clamp count (0 = no clamp)
13
13
  type: number
14
14
  default: 0
15
+ strong:
16
+ description: When true, applies stronger emphasis (heavier weight + accent color). Styled via :scope[strong] in text.css. Use instead of variant=heading when you want a single emphasized word inline in body copy.
17
+ type: boolean
18
+ default: false
19
+ reflect: true
15
20
  truncate:
16
21
  description: Single-line truncation with ellipsis. Ignored when `lines` is set.
17
22
  type: boolean
@@ -26,6 +26,11 @@
26
26
  "type": "string",
27
27
  "default": ""
28
28
  },
29
+ "name": {
30
+ "description": "Form control name for form data submission. Inherited from UIFormElement.",
31
+ "type": "string",
32
+ "default": ""
33
+ },
29
34
  "placeholder": {
30
35
  "description": "Placeholder text shown when textarea is empty.",
31
36
  "type": "string",
@@ -16,6 +16,10 @@ props:
16
16
  description: Label text displayed above the textarea.
17
17
  type: string
18
18
  default: ""
19
+ name:
20
+ description: Form control name for form data submission. Inherited from UIFormElement.
21
+ type: string
22
+ default: ""
19
23
  placeholder:
20
24
  description: Placeholder text shown when textarea is empty.
21
25
  type: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/web-components",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "AdiaUI web components — vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
5
5
  "type": "module",
6
6
  "exports": {