@adia-ai/web-components 0.6.21 → 0.6.22
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.
- package/CHANGELOG.md +58 -0
- package/components/accordion/accordion-item.a2ui.json +20 -3
- package/components/accordion/accordion-item.yaml +24 -0
- package/components/accordion/accordion.a2ui.json +1 -1
- package/components/accordion/accordion.d.ts +8 -1
- package/components/accordion/accordion.yaml +15 -2
- package/components/action-list/action-item.a2ui.json +19 -3
- package/components/action-list/action-item.yaml +24 -0
- package/components/action-list/action-list.a2ui.json +12 -2
- package/components/action-list/action-list.yaml +13 -3
- package/components/agent-artifact/agent-artifact.a2ui.json +9 -2
- package/components/agent-artifact/agent-artifact.d.ts +1 -1
- package/components/agent-artifact/agent-artifact.yaml +17 -3
- package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +9 -2
- package/components/agent-feedback-bar/agent-feedback-bar.d.ts +8 -1
- package/components/agent-feedback-bar/agent-feedback-bar.yaml +19 -3
- package/components/agent-questions/agent-questions.a2ui.json +8 -2
- package/components/agent-questions/agent-questions.d.ts +8 -1
- package/components/agent-questions/agent-questions.yaml +19 -3
- package/components/agent-reasoning/agent-reasoning.yaml +9 -1
- package/components/agent-suggestions/agent-suggestions.a2ui.json +9 -2
- package/components/agent-suggestions/agent-suggestions.d.ts +7 -1
- package/components/agent-suggestions/agent-suggestions.yaml +18 -3
- package/components/agent-trace/agent-trace.a2ui.json +9 -2
- package/components/agent-trace/agent-trace.d.ts +1 -1
- package/components/agent-trace/agent-trace.yaml +16 -3
- package/components/alert/alert.a2ui.json +1 -1
- package/components/alert/alert.css +8 -0
- package/components/alert/alert.d.ts +9 -1
- package/components/alert/alert.yaml +16 -2
- package/components/aside/aside.a2ui.json +7 -1
- package/components/aside/aside.yaml +33 -2
- package/components/avatar/avatar-group.a2ui.json +20 -3
- package/components/avatar/avatar-group.yaml +24 -0
- package/components/avatar/avatar.a2ui.json +1 -1
- package/components/avatar/avatar.d.ts +7 -1
- package/components/avatar/avatar.yaml +14 -2
- package/components/badge/badge.a2ui.json +1 -1
- package/components/badge/badge.d.ts +7 -1
- package/components/badge/badge.yaml +14 -2
- package/components/block/block.a2ui.json +9 -4
- package/components/block/block.d.ts +9 -3
- package/components/block/block.yaml +25 -5
- package/components/block/class.js +23 -0
- package/components/breadcrumb/breadcrumb.a2ui.json +5 -1
- package/components/breadcrumb/breadcrumb.yaml +33 -2
- package/components/button/button.a2ui.json +22 -2
- package/components/button/button.yaml +21 -3
- package/components/calendar-picker/calendar-picker.a2ui.json +1 -1
- package/components/calendar-picker/calendar-picker.yaml +13 -2
- package/components/canvas/canvas.a2ui.json +6 -2
- package/components/canvas/canvas.yaml +20 -3
- package/components/card/card.css +23 -2
- package/components/card/card.yaml +12 -0
- package/components/chart/chart.css +4 -2
- package/components/chart/chart.yaml +9 -1
- package/components/chart-legend/chart-legend.yaml +7 -1
- package/components/chat-thread/chat-thread.a2ui.json +6 -2
- package/components/chat-thread/chat-thread.d.ts +8 -1
- package/components/chat-thread/chat-thread.yaml +21 -3
- package/components/check/check.a2ui.json +13 -3
- package/components/check/check.yaml +18 -3
- package/components/code/code.a2ui.json +1 -1
- package/components/code/code.yaml +13 -2
- package/components/col/class.js +39 -0
- package/components/col/col.a2ui.json +12 -5
- package/components/col/col.d.ts +12 -4
- package/components/col/col.yaml +27 -7
- package/components/color-input/color-input.yaml +27 -1
- package/components/color-picker/color-picker.a2ui.json +8 -2
- package/components/color-picker/color-picker.yaml +15 -3
- package/components/command/command.a2ui.json +7 -2
- package/components/command/command.d.ts +9 -1
- package/components/command/command.yaml +39 -3
- package/components/demo-toggle/demo-toggle.yaml +7 -1
- package/components/description-list/description-list.a2ui.json +5 -1
- package/components/description-list/description-list.yaml +11 -2
- package/components/divider/divider.a2ui.json +1 -1
- package/components/divider/divider.d.ts +8 -1
- package/components/divider/divider.yaml +15 -2
- package/components/drawer/drawer.yaml +32 -1
- package/components/embed/embed.a2ui.json +1 -1
- package/components/embed/embed.d.ts +8 -1
- package/components/embed/embed.yaml +17 -2
- package/components/empty-state/empty-state.a2ui.json +19 -2
- package/components/empty-state/empty-state.css +14 -0
- package/components/empty-state/empty-state.d.ts +3 -1
- package/components/empty-state/empty-state.yaml +50 -3
- package/components/feed/feed-item.a2ui.json +21 -3
- package/components/feed/feed-item.yaml +25 -0
- package/components/feed/feed.a2ui.json +23 -3
- package/components/feed/feed.yaml +26 -0
- package/components/fields/fields.yaml +7 -1
- package/components/footer/footer.a2ui.json +7 -1
- package/components/footer/footer.yaml +27 -2
- package/components/grid/class.js +57 -0
- package/components/grid/grid.a2ui.json +3 -3
- package/components/grid/grid.d.ts +3 -3
- package/components/grid/grid.yaml +22 -8
- package/components/header/header.a2ui.json +8 -1
- package/components/header/header.yaml +30 -2
- package/components/heatmap/heatmap.yaml +7 -1
- package/components/icon/icon.a2ui.json +9 -2
- package/components/icon/icon.d.ts +1 -1
- package/components/icon/icon.yaml +32 -3
- package/components/image/image.yaml +7 -1
- package/components/input/input.yaml +29 -1
- package/components/inspector/inspector.a2ui.json +7 -2
- package/components/inspector/inspector.d.ts +9 -1
- package/components/inspector/inspector.yaml +23 -3
- package/components/kbd/kbd.a2ui.json +1 -1
- package/components/kbd/kbd.d.ts +1 -1
- package/components/kbd/kbd.yaml +11 -2
- package/components/list/list-item.a2ui.json +21 -3
- package/components/list/list-item.yaml +25 -0
- package/components/list/list.a2ui.json +7 -2
- package/components/list/list.d.ts +9 -1
- package/components/list/list.yaml +21 -3
- package/components/menu/menu-divider.a2ui.json +17 -3
- package/components/menu/menu-divider.yaml +35 -0
- package/components/menu/menu-item.a2ui.json +19 -3
- package/components/menu/menu-item.yaml +42 -0
- package/components/menu/menu.a2ui.json +7 -1
- package/components/menu/menu.yaml +33 -2
- package/components/modal/modal.a2ui.json +7 -2
- package/components/modal/modal.d.ts +10 -1
- package/components/modal/modal.yaml +48 -3
- package/components/nav/nav.a2ui.json +16 -2
- package/components/nav/nav.yaml +40 -3
- package/components/nav-group/nav-group.a2ui.json +12 -2
- package/components/nav-group/nav-group.yaml +37 -3
- package/components/nav-item/nav-item.a2ui.json +13 -2
- package/components/nav-item/nav-item.yaml +40 -3
- package/components/noodles/noodles.a2ui.json +12 -2
- package/components/noodles/noodles.yaml +14 -3
- package/components/option-card/option-card.yaml +27 -1
- package/components/otp-input/otp-input.yaml +24 -1
- package/components/page/page.a2ui.json +7 -1
- package/components/page/page.yaml +9 -2
- package/components/pagination/pagination.a2ui.json +1 -1
- package/components/pagination/pagination.d.ts +1 -1
- package/components/pagination/pagination.yaml +13 -2
- package/components/pane/pane.a2ui.json +1 -1
- package/components/pane/pane.d.ts +7 -1
- package/components/pane/pane.yaml +33 -2
- package/components/pipeline-status/pipeline-status.a2ui.json +6 -2
- package/components/pipeline-status/pipeline-status.d.ts +1 -1
- package/components/pipeline-status/pipeline-status.yaml +18 -3
- package/components/popover/popover.yaml +30 -1
- package/components/progress/progress.a2ui.json +1 -1
- package/components/progress/progress.d.ts +1 -1
- package/components/progress/progress.yaml +13 -2
- package/components/progress-row/progress-row.a2ui.json +12 -2
- package/components/progress-row/progress-row.yaml +13 -3
- package/components/radio/radio.a2ui.json +1 -1
- package/components/radio/radio.yaml +9 -1
- package/components/range/range.yaml +7 -1
- package/components/rating/rating.a2ui.json +4 -1
- package/components/rating/rating.yaml +10 -2
- package/components/richtext/richtext.a2ui.json +6 -2
- package/components/richtext/richtext.d.ts +9 -1
- package/components/richtext/richtext.yaml +20 -3
- package/components/row/class.js +34 -0
- package/components/row/row.a2ui.json +11 -5
- package/components/row/row.d.ts +11 -4
- package/components/row/row.yaml +25 -7
- package/components/search/search.a2ui.json +5 -1
- package/components/search/search.yaml +11 -2
- package/components/section/section.a2ui.json +7 -1
- package/components/section/section.yaml +36 -2
- package/components/segment/segment.a2ui.json +8 -2
- package/components/segment/segment.d.ts +7 -1
- package/components/segment/segment.yaml +16 -3
- package/components/segmented/segmented.a2ui.json +6 -1
- package/components/segmented/segmented.css +5 -0
- package/components/segmented/segmented.yaml +12 -2
- package/components/select/select.a2ui.json +1 -1
- package/components/select/select.yaml +34 -2
- package/components/skeleton/skeleton.a2ui.json +7 -2
- package/components/skeleton/skeleton.d.ts +1 -1
- package/components/skeleton/skeleton.yaml +17 -3
- package/components/slider/slider.yaml +7 -1
- package/components/stack/stack.a2ui.json +14 -3
- package/components/stack/stack.d.ts +9 -1
- package/components/stack/stack.yaml +22 -4
- package/components/stat/stat.a2ui.json +6 -2
- package/components/stat/stat.css +5 -2
- package/components/stat/stat.d.ts +1 -1
- package/components/stat/stat.yaml +16 -3
- package/components/step-progress/step-progress.yaml +7 -1
- package/components/stepper/stepper-item.a2ui.json +20 -3
- package/components/stepper/stepper-item.yaml +24 -0
- package/components/stepper/stepper.a2ui.json +1 -1
- package/components/stepper/stepper.d.ts +1 -1
- package/components/stepper/stepper.yaml +13 -2
- package/components/stream/stream.a2ui.json +12 -2
- package/components/stream/stream.yaml +15 -3
- package/components/swatch/swatch.yaml +7 -1
- package/components/swiper/swiper.yaml +7 -1
- package/components/switch/switch.a2ui.json +6 -2
- package/components/switch/switch.yaml +16 -2
- package/components/table/cell-types.js +23 -10
- package/components/table/class.js +6 -2
- package/components/table/table.css +49 -1
- package/components/table/table.yaml +27 -1
- package/components/table-toolbar/table-toolbar.yaml +27 -1
- package/components/tabs/tab.a2ui.json +17 -3
- package/components/tabs/tab.yaml +39 -0
- package/components/tabs/tabs.a2ui.json +1 -1
- package/components/tabs/tabs.d.ts +1 -1
- package/components/tabs/tabs.yaml +36 -2
- package/components/tag/tag.a2ui.json +6 -2
- package/components/tag/tag.d.ts +9 -1
- package/components/tag/tag.yaml +38 -3
- package/components/text/class.js +13 -0
- package/components/text/text.a2ui.json +9 -2
- package/components/text/text.d.ts +1 -1
- package/components/text/text.yaml +12 -5
- package/components/textarea/textarea.a2ui.json +15 -3
- package/components/textarea/textarea.yaml +41 -4
- package/components/timeline/timeline-item.a2ui.json +20 -3
- package/components/timeline/timeline-item.yaml +24 -0
- package/components/timeline/timeline.a2ui.json +8 -1
- package/components/timeline/timeline.yaml +9 -2
- package/components/toast/toast.a2ui.json +6 -2
- package/components/toast/toast.yaml +19 -3
- package/components/toggle-group/toggle-group.a2ui.json +13 -3
- package/components/toggle-group/toggle-group.d.ts +1 -1
- package/components/toggle-group/toggle-group.yaml +19 -4
- package/components/toggle-group/toggle-option.a2ui.json +18 -3
- package/components/toggle-group/toggle-option.yaml +23 -0
- package/components/toggle-scheme/toggle-scheme.yaml +4 -0
- package/components/toolbar/toolbar-group.a2ui.json +18 -3
- package/components/toolbar/toolbar-group.yaml +23 -0
- package/components/toolbar/toolbar.yaml +7 -1
- package/components/tooltip/tooltip.yaml +24 -1
- package/components/tree/tree-item.a2ui.json +19 -3
- package/components/tree/tree-item.yaml +42 -0
- package/components/tree/tree.a2ui.json +6 -1
- package/components/tree/tree.yaml +31 -2
- package/components/upload/upload.yaml +7 -1
- package/core/index.js +1 -0
- package/core/responsive.d.ts +29 -0
- package/core/responsive.js +120 -0
- package/core/responsive.test.js +121 -0
- package/package.json +1 -1
- package/styles/tokens.css +6 -6
|
@@ -44,7 +44,13 @@ requiredIcons:
|
|
|
44
44
|
- caret-down
|
|
45
45
|
- caret-right
|
|
46
46
|
a2ui:
|
|
47
|
-
rules:
|
|
47
|
+
rules:
|
|
48
|
+
- rule: 'Use for chronological event lists (audit log, activity feed, version history).'
|
|
49
|
+
reason: 'Visual rhythm: line + dot + content per row.'
|
|
50
|
+
- rule: 'Hosts <timeline-item-ui> children only.'
|
|
51
|
+
reason: 'Cluster contract — children are family-scoped.'
|
|
52
|
+
- rule: 'For multi-step processes with progress state use <stepper-ui> instead; timeline is read-only history.'
|
|
53
|
+
reason: 'Stepper has current/upcoming/complete states; timeline is event-time.'
|
|
48
54
|
anti_patterns: []
|
|
49
55
|
examples:
|
|
50
56
|
- name: order-tracking
|
|
@@ -188,6 +194,7 @@ examples:
|
|
|
188
194
|
]
|
|
189
195
|
keywords:
|
|
190
196
|
- timeline
|
|
191
|
-
synonyms:
|
|
197
|
+
synonyms:
|
|
198
|
+
timeline: [activity-log, event-log, history, audit-trail]
|
|
192
199
|
related:
|
|
193
200
|
- timeline-item
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/Toast.json",
|
|
4
4
|
"title": "Toast",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Transient global notification popup with auto-dismiss + animated\nenter/exit. Variants map to severity (info / success / warning /\ndanger). Distinct from <alert-ui> (inline persistent banner) and\n<empty-state-ui> (zero-data placeholder). Use toast-ui for\nshort-lived feedback after user actions (\"Saved\", \"Copied to\nclipboard\"); the toast positions itself relative to viewport\n[position] regardless of where in the DOM it's rendered.\n",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -86,7 +86,11 @@
|
|
|
86
86
|
"alert"
|
|
87
87
|
],
|
|
88
88
|
"name": "UIToast",
|
|
89
|
-
"related": [
|
|
89
|
+
"related": [
|
|
90
|
+
"Feed",
|
|
91
|
+
"Alert",
|
|
92
|
+
"FeedItem"
|
|
93
|
+
],
|
|
90
94
|
"slots": {},
|
|
91
95
|
"states": [
|
|
92
96
|
{
|
|
@@ -6,7 +6,14 @@ tag: toast-ui
|
|
|
6
6
|
component: Toast
|
|
7
7
|
category: container
|
|
8
8
|
version: 1
|
|
9
|
-
description:
|
|
9
|
+
description: |
|
|
10
|
+
Transient global notification popup with auto-dismiss + animated
|
|
11
|
+
enter/exit. Variants map to severity (info / success / warning /
|
|
12
|
+
danger). Distinct from <alert-ui> (inline persistent banner) and
|
|
13
|
+
<empty-state-ui> (zero-data placeholder). Use toast-ui for
|
|
14
|
+
short-lived feedback after user actions ("Saved", "Copied to
|
|
15
|
+
clipboard"); the toast positions itself relative to viewport
|
|
16
|
+
[position] regardless of where in the DOM it's rendered.
|
|
10
17
|
props:
|
|
11
18
|
duration:
|
|
12
19
|
description: Auto-dismiss time in milliseconds. 0 disables auto-dismiss.
|
|
@@ -73,7 +80,13 @@ tokens:
|
|
|
73
80
|
--toast-foreground:
|
|
74
81
|
description: Override text color
|
|
75
82
|
a2ui:
|
|
76
|
-
rules:
|
|
83
|
+
rules:
|
|
84
|
+
- rule: 'Single ephemeral notification item — auto-dismissing or manually-closable.'
|
|
85
|
+
reason: 'Toast pattern.'
|
|
86
|
+
- rule: 'Typically posted into <feed-ui> via UIFeed.post(...); for inline persistent alerts use <alert-ui> instead.'
|
|
87
|
+
reason: 'Posting model + surface boundary.'
|
|
88
|
+
- rule: 'Variant maps to severity (info, success, warn, error); same tokens as <alert-ui>.'
|
|
89
|
+
reason: 'Visual consistency.'
|
|
77
90
|
anti_patterns: []
|
|
78
91
|
examples:
|
|
79
92
|
- name: toast-notification
|
|
@@ -184,4 +197,7 @@ synonyms:
|
|
|
184
197
|
- alert
|
|
185
198
|
- error
|
|
186
199
|
- toast
|
|
187
|
-
related:
|
|
200
|
+
related:
|
|
201
|
+
- Feed
|
|
202
|
+
- Alert
|
|
203
|
+
- FeedItem
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/ToggleGroup.json",
|
|
4
4
|
"title": "ToggleGroup",
|
|
5
|
-
"description": "Multi-select button group (unlike segmented which is single-select).",
|
|
5
|
+
"description": "Multi-select button group (unlike <segmented-ui> which is single-select). Hosts <toggle-option-ui> children, each independently toggleable; emits change events with the active value set. Use for filter chips or feature flag clusters; for single-select option groups use <segmented-ui> instead.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -60,7 +60,11 @@
|
|
|
60
60
|
"group"
|
|
61
61
|
],
|
|
62
62
|
"name": "UIToggleGroup",
|
|
63
|
-
"related": [
|
|
63
|
+
"related": [
|
|
64
|
+
"ToggleOption",
|
|
65
|
+
"Segmented",
|
|
66
|
+
"Radio"
|
|
67
|
+
],
|
|
64
68
|
"slots": {
|
|
65
69
|
"default": {
|
|
66
70
|
"description": "Default slot — primary child content."
|
|
@@ -72,7 +76,13 @@
|
|
|
72
76
|
"name": "idle"
|
|
73
77
|
}
|
|
74
78
|
],
|
|
75
|
-
"synonyms": {
|
|
79
|
+
"synonyms": {
|
|
80
|
+
"toggle-group": [
|
|
81
|
+
"segmented-control",
|
|
82
|
+
"option-group",
|
|
83
|
+
"toggle-set"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
76
86
|
"tag": "toggle-group-ui",
|
|
77
87
|
"tokens": {
|
|
78
88
|
"--toggle-group-border": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `<toggle-group-ui>` — Multi-select button group (unlike segmented which is single-select).
|
|
2
|
+
* `<toggle-group-ui>` — Multi-select button group (unlike <segmented-ui> which is single-select). Hosts <toggle-option-ui> children, each independently toggleable; emits change events with the active value set. Use for filter chips or feature flag clusters; for single-select option groups use <segmented-ui> instead.
|
|
3
3
|
*
|
|
4
4
|
* @see https://ui-kit.exe.xyz/site/components/toggle-group
|
|
5
5
|
*
|
|
@@ -6,7 +6,12 @@ tag: toggle-group-ui
|
|
|
6
6
|
component: ToggleGroup
|
|
7
7
|
category: navigation
|
|
8
8
|
version: 1
|
|
9
|
-
description:
|
|
9
|
+
description: >-
|
|
10
|
+
Multi-select button group (unlike <segmented-ui> which is
|
|
11
|
+
single-select). Hosts <toggle-option-ui> children, each independently
|
|
12
|
+
toggleable; emits change events with the active value set. Use for
|
|
13
|
+
filter chips or feature flag clusters; for single-select option groups
|
|
14
|
+
use <segmented-ui> instead.
|
|
10
15
|
props:
|
|
11
16
|
single:
|
|
12
17
|
description: When true, restrict to one active option (single-select).
|
|
@@ -66,7 +71,13 @@ tokens:
|
|
|
66
71
|
--toggle-option-selected-fg:
|
|
67
72
|
description: Text color when selected
|
|
68
73
|
a2ui:
|
|
69
|
-
rules:
|
|
74
|
+
rules:
|
|
75
|
+
- rule: 'Multi-select button cluster — hosts <toggle-option-ui> children, each independently toggleable.'
|
|
76
|
+
reason: 'Multi-select cluster contract.'
|
|
77
|
+
- rule: 'Different from <segmented-ui> (single-select) — toggle-group emits a SET of active values.'
|
|
78
|
+
reason: 'Selection model distinction.'
|
|
79
|
+
- rule: 'Use for filter chips, multi-flag toggles, day-of-week pickers; for binary on/off use <switch-ui>.'
|
|
80
|
+
reason: 'Capacity guidance.'
|
|
70
81
|
anti_patterns: []
|
|
71
82
|
examples:
|
|
72
83
|
- name: basic-toggle-group
|
|
@@ -98,5 +109,9 @@ keywords:
|
|
|
98
109
|
- toggle-group
|
|
99
110
|
- toggle
|
|
100
111
|
- group
|
|
101
|
-
synonyms:
|
|
102
|
-
|
|
112
|
+
synonyms:
|
|
113
|
+
toggle-group: [segmented-control, option-group, toggle-set]
|
|
114
|
+
related:
|
|
115
|
+
- ToggleOption
|
|
116
|
+
- Segmented
|
|
117
|
+
- Radio
|
|
@@ -47,12 +47,27 @@
|
|
|
47
47
|
"composes": [],
|
|
48
48
|
"events": {},
|
|
49
49
|
"examples": [],
|
|
50
|
-
"keywords": [
|
|
50
|
+
"keywords": [
|
|
51
|
+
"toggle-option",
|
|
52
|
+
"toggle-segment",
|
|
53
|
+
"option-toggle",
|
|
54
|
+
"segmented-option"
|
|
55
|
+
],
|
|
51
56
|
"name": "UIToggleOption",
|
|
52
|
-
"related": [
|
|
57
|
+
"related": [
|
|
58
|
+
"ToggleGroup",
|
|
59
|
+
"Segment",
|
|
60
|
+
"Radio"
|
|
61
|
+
],
|
|
53
62
|
"slots": {},
|
|
54
63
|
"states": [],
|
|
55
|
-
"synonyms": {
|
|
64
|
+
"synonyms": {
|
|
65
|
+
"toggle-option": [
|
|
66
|
+
"toggle-segment",
|
|
67
|
+
"option-button",
|
|
68
|
+
"segmented-option"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
56
71
|
"tag": "toggle-option-ui",
|
|
57
72
|
"tokens": {},
|
|
58
73
|
"traits": [],
|
|
@@ -31,3 +31,26 @@ props:
|
|
|
31
31
|
description: Disabled state — blocks pointer + keyboard activation.
|
|
32
32
|
type: boolean
|
|
33
33
|
default: false
|
|
34
|
+
|
|
35
|
+
keywords:
|
|
36
|
+
- toggle-option
|
|
37
|
+
- toggle-segment
|
|
38
|
+
- option-toggle
|
|
39
|
+
- segmented-option
|
|
40
|
+
|
|
41
|
+
synonyms:
|
|
42
|
+
toggle-option: [toggle-segment, option-button, segmented-option]
|
|
43
|
+
|
|
44
|
+
related:
|
|
45
|
+
- ToggleGroup
|
|
46
|
+
- Segment
|
|
47
|
+
- Radio
|
|
48
|
+
|
|
49
|
+
a2ui:
|
|
50
|
+
rules:
|
|
51
|
+
- rule: 'Child of <toggle-group-ui> — one independently-toggleable button in a multi-select cluster.'
|
|
52
|
+
reason: 'Multi-select cluster contract.'
|
|
53
|
+
- rule: 'Different from <segment-ui> (which is single-select inside <segmented-ui>).'
|
|
54
|
+
reason: 'Selection model boundary.'
|
|
55
|
+
- rule: 'Active state controlled via the toggle-option''s own active attribute (independent of siblings).'
|
|
56
|
+
reason: 'Parent does not own state in multi-select.'
|
|
@@ -156,6 +156,10 @@ a2ui:
|
|
|
156
156
|
<admin-content>. It is a persistent, app-wide preference control;
|
|
157
157
|
never put it in a sidebar footer / <admin-statusbar>, which hosts
|
|
158
158
|
user-account items only.
|
|
159
|
+
- rule: 'Stores user override in localStorage and writes color-scheme inline-style to the target; falls back to prefers-color-scheme if no override is set.'
|
|
160
|
+
reason: 'Behavior contract — explains why first-paint resolution happens correctly.'
|
|
161
|
+
- rule: 'Singleton per page — placing more than one in DOM creates conflicting writes to the same target.'
|
|
162
|
+
reason: 'Cardinality constraint.'
|
|
159
163
|
anti_patterns: []
|
|
160
164
|
examples:
|
|
161
165
|
- name: header-action
|
|
@@ -27,12 +27,27 @@
|
|
|
27
27
|
"composes": [],
|
|
28
28
|
"events": {},
|
|
29
29
|
"examples": [],
|
|
30
|
-
"keywords": [
|
|
30
|
+
"keywords": [
|
|
31
|
+
"toolbar-group",
|
|
32
|
+
"button-group",
|
|
33
|
+
"action-cluster",
|
|
34
|
+
"toolbar-cluster"
|
|
35
|
+
],
|
|
31
36
|
"name": "UIToolbarGroup",
|
|
32
|
-
"related": [
|
|
37
|
+
"related": [
|
|
38
|
+
"Toolbar",
|
|
39
|
+
"Button",
|
|
40
|
+
"Divider"
|
|
41
|
+
],
|
|
33
42
|
"slots": {},
|
|
34
43
|
"states": [],
|
|
35
|
-
"synonyms": {
|
|
44
|
+
"synonyms": {
|
|
45
|
+
"toolbar-group": [
|
|
46
|
+
"button-group",
|
|
47
|
+
"action-cluster",
|
|
48
|
+
"toolbar-section"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
36
51
|
"tag": "toolbar-group-ui",
|
|
37
52
|
"tokens": {},
|
|
38
53
|
"traits": [],
|
|
@@ -14,3 +14,26 @@ category: navigation
|
|
|
14
14
|
version: 1
|
|
15
15
|
description: |-
|
|
16
16
|
Visual cluster of related actions inside a `<toolbar-ui>`. Provides role="group" for assistive-tech grouping; no own visual chrome beyond a margin-collapsing gap with sibling groups.
|
|
17
|
+
|
|
18
|
+
keywords:
|
|
19
|
+
- toolbar-group
|
|
20
|
+
- button-group
|
|
21
|
+
- action-cluster
|
|
22
|
+
- toolbar-cluster
|
|
23
|
+
|
|
24
|
+
synonyms:
|
|
25
|
+
toolbar-group: [button-group, action-cluster, toolbar-section]
|
|
26
|
+
|
|
27
|
+
related:
|
|
28
|
+
- Toolbar
|
|
29
|
+
- Button
|
|
30
|
+
- Divider
|
|
31
|
+
|
|
32
|
+
a2ui:
|
|
33
|
+
rules:
|
|
34
|
+
- rule: 'Child of <toolbar-ui> — clusters related action buttons with token-driven internal gap.'
|
|
35
|
+
reason: 'Visual grouping primitive.'
|
|
36
|
+
- rule: 'Separate clusters with <divider-ui> siblings inside <toolbar-ui>.'
|
|
37
|
+
reason: 'Convention for toolbar rhythm.'
|
|
38
|
+
- rule: 'Do not nest toolbar-groups; flat hierarchy only.'
|
|
39
|
+
reason: 'Visual complexity guard.'
|
|
@@ -41,7 +41,13 @@ states:
|
|
|
41
41
|
traits: []
|
|
42
42
|
tokens: {}
|
|
43
43
|
a2ui:
|
|
44
|
-
rules:
|
|
44
|
+
rules:
|
|
45
|
+
- rule: 'Horizontal action bar — hosts <button-ui>, <toolbar-group-ui>, and <divider-ui> children.'
|
|
46
|
+
reason: 'Canonical action-row primitive.'
|
|
47
|
+
- rule: 'Cluster related buttons inside <toolbar-group-ui> with <divider-ui> separating clusters.'
|
|
48
|
+
reason: 'Visual grouping convention.'
|
|
49
|
+
- rule: 'For navigation use <nav-ui>; for modal/popover action bars use the modal''s footer slot. Toolbar is for inline action bars within content regions.'
|
|
50
|
+
reason: 'Context boundary.'
|
|
45
51
|
anti_patterns: []
|
|
46
52
|
examples:
|
|
47
53
|
- name: toolbar-buttons
|
|
@@ -71,7 +71,30 @@ states:
|
|
|
71
71
|
traits: []
|
|
72
72
|
tokens: {}
|
|
73
73
|
a2ui:
|
|
74
|
-
rules:
|
|
74
|
+
rules:
|
|
75
|
+
- >-
|
|
76
|
+
Use <tooltip-ui> to label icon-only <button-ui> elements
|
|
77
|
+
(text="Save" on a save-icon button, etc.) and for short
|
|
78
|
+
descriptive hover hints. Never use it for content the user
|
|
79
|
+
must read carefully (the bubble is transient + non-focusable).
|
|
80
|
+
- >-
|
|
81
|
+
Never place INTERACTIVE children inside <tooltip-ui> — it is a
|
|
82
|
+
read-only hint, not a surface. If the user must click or type,
|
|
83
|
+
use <popover-ui> instead. Tooltips never receive keyboard focus.
|
|
84
|
+
- >-
|
|
85
|
+
[follows="pointer"] mode requires [for] pointing at a <chart-ui>
|
|
86
|
+
or <heatmap-ui> [id]; the tooltip subscribes to that target's
|
|
87
|
+
`chart-hover` / `chart-leave` events to render data-viz
|
|
88
|
+
annotations that track the cursor. Without [for] the tooltip
|
|
89
|
+
renders nothing in pointer mode.
|
|
90
|
+
- >-
|
|
91
|
+
Set [delay=0] only for high-frequency exploratory surfaces
|
|
92
|
+
(sparkline ticks, chart hover). Keep the default 400ms delay
|
|
93
|
+
elsewhere to avoid hover noise.
|
|
94
|
+
- >-
|
|
95
|
+
[indicator] (dot | line | dashed) is meaningful only in pointer
|
|
96
|
+
mode for per-series swatches. Omit it or leave default "none"
|
|
97
|
+
for text-mode tooltips.
|
|
75
98
|
anti_patterns: []
|
|
76
99
|
examples:
|
|
77
100
|
- name: tooltip-buttons
|
|
@@ -51,12 +51,28 @@
|
|
|
51
51
|
"composes": [],
|
|
52
52
|
"events": {},
|
|
53
53
|
"examples": [],
|
|
54
|
-
"keywords": [
|
|
54
|
+
"keywords": [
|
|
55
|
+
"tree-item",
|
|
56
|
+
"tree-row",
|
|
57
|
+
"tree-node",
|
|
58
|
+
"hierarchy-item"
|
|
59
|
+
],
|
|
55
60
|
"name": "UITreeItem",
|
|
56
|
-
"related": [
|
|
61
|
+
"related": [
|
|
62
|
+
"Tree",
|
|
63
|
+
"List",
|
|
64
|
+
"Nav",
|
|
65
|
+
"Accordion"
|
|
66
|
+
],
|
|
57
67
|
"slots": {},
|
|
58
68
|
"states": [],
|
|
59
|
-
"synonyms": {
|
|
69
|
+
"synonyms": {
|
|
70
|
+
"tree-item": [
|
|
71
|
+
"tree-node",
|
|
72
|
+
"tree-row",
|
|
73
|
+
"hierarchy-row"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
60
76
|
"tag": "tree-item-ui",
|
|
61
77
|
"tokens": {},
|
|
62
78
|
"traits": [],
|
|
@@ -39,3 +39,45 @@ props:
|
|
|
39
39
|
|
|
40
40
|
Added in §184 (v0.5.5, FEEDBACK-08 §1).
|
|
41
41
|
type: string
|
|
42
|
+
|
|
43
|
+
a2ui:
|
|
44
|
+
rules:
|
|
45
|
+
- >-
|
|
46
|
+
<tree-item-ui> MUST be a direct or nested descendant of
|
|
47
|
+
<tree-ui>. It is not a standalone primitive — outside a <tree-ui>
|
|
48
|
+
parent, selection / expansion / keyboard nav don't wire.
|
|
49
|
+
- >-
|
|
50
|
+
Provide a stable [value] attribute on every <tree-item-ui> that
|
|
51
|
+
consumers will select. The `tree-select` event's detail.value is
|
|
52
|
+
the identifier downstream code reads to know which node was
|
|
53
|
+
picked.
|
|
54
|
+
- >-
|
|
55
|
+
Use [open] to pre-expand branch nodes on initial render. Do NOT
|
|
56
|
+
set [selected] declaratively on more than one item — the parent
|
|
57
|
+
<tree-ui> manages selection. The host listens for click /
|
|
58
|
+
Enter / Space / ArrowRight (expand) / ArrowLeft (collapse) per
|
|
59
|
+
WAI-ARIA tree-view APG.
|
|
60
|
+
- >-
|
|
61
|
+
Use [icon] (Phosphor name) for affordance (folder / file /
|
|
62
|
+
component icons); use [badge] for counts or short status labels
|
|
63
|
+
(§184 v0.5.5).
|
|
64
|
+
- >-
|
|
65
|
+
Nest further <tree-item-ui> in the default slot only — no
|
|
66
|
+
<list-item-ui>, <nav-item-ui>, or arbitrary content inside a
|
|
67
|
+
tree row. The chevron is auto-stamped when the row has nested
|
|
68
|
+
tree-item-ui children.
|
|
69
|
+
|
|
70
|
+
keywords:
|
|
71
|
+
- tree-item
|
|
72
|
+
- tree-row
|
|
73
|
+
- tree-node
|
|
74
|
+
- hierarchy-item
|
|
75
|
+
|
|
76
|
+
related:
|
|
77
|
+
- Tree
|
|
78
|
+
- List
|
|
79
|
+
- Nav
|
|
80
|
+
- Accordion
|
|
81
|
+
|
|
82
|
+
synonyms:
|
|
83
|
+
tree-item: [tree-node, tree-row, hierarchy-row]
|
|
@@ -70,7 +70,12 @@
|
|
|
70
70
|
"folder"
|
|
71
71
|
],
|
|
72
72
|
"name": "UITree",
|
|
73
|
-
"related": [
|
|
73
|
+
"related": [
|
|
74
|
+
"TreeItem",
|
|
75
|
+
"Nav",
|
|
76
|
+
"List",
|
|
77
|
+
"Accordion"
|
|
78
|
+
],
|
|
74
79
|
"slots": {
|
|
75
80
|
"default (tree-item-ui children)": {
|
|
76
81
|
"description": "Child content region for the `default (tree-item-ui children)` slot."
|
|
@@ -92,7 +92,32 @@ tokens:
|
|
|
92
92
|
requiredIcons:
|
|
93
93
|
- caret-right
|
|
94
94
|
a2ui:
|
|
95
|
-
rules:
|
|
95
|
+
rules:
|
|
96
|
+
- >-
|
|
97
|
+
Use <tree-ui> only when data is hierarchical with arbitrary
|
|
98
|
+
nesting AND a single selected node is meaningful. For flat
|
|
99
|
+
lists use <list-ui>; for flat sidebar navigation use <nav-ui>;
|
|
100
|
+
for one-level collapsible groups use <accordion-ui>.
|
|
101
|
+
- >-
|
|
102
|
+
Canonical mount: inside <editor-sidebar slot="leading"> →
|
|
103
|
+
<pane-ui side="leading" resizable> → <section> → <tree-ui id="…">
|
|
104
|
+
as the structure / navigator pane of the three-pane editor shell.
|
|
105
|
+
Pair with a <header> in the same pane (e.g. "Structure",
|
|
106
|
+
"Layers", "Files").
|
|
107
|
+
- >-
|
|
108
|
+
Direct children of <tree-ui> MUST be <tree-item-ui>. No other
|
|
109
|
+
element types in the default slot. <tree-ui> manages
|
|
110
|
+
single-selection across the whole subtree and implements
|
|
111
|
+
WAI-ARIA tree-view keyboard navigation (Arrow keys, Enter /
|
|
112
|
+
Space, Home / End).
|
|
113
|
+
- >-
|
|
114
|
+
Listen for `tree-select` on the <tree-ui>, NOT on individual
|
|
115
|
+
rows — selection is managed by the parent and bubbles once.
|
|
116
|
+
Detail = {item, text, value, ctrlKey, metaKey, shiftKey}.
|
|
117
|
+
- >-
|
|
118
|
+
Per ADR-0027, <tree-ui> composes <icon-ui> (for chevrons) but
|
|
119
|
+
does NOT auto-import its children. Consumer pages must
|
|
120
|
+
explicitly import both <tree-ui> and <tree-item-ui>.
|
|
96
121
|
anti_patterns: []
|
|
97
122
|
examples:
|
|
98
123
|
- name: basic-tree
|
|
@@ -128,4 +153,8 @@ synonyms:
|
|
|
128
153
|
- sidebar
|
|
129
154
|
- nav
|
|
130
155
|
- tree
|
|
131
|
-
related:
|
|
156
|
+
related:
|
|
157
|
+
- TreeItem
|
|
158
|
+
- Nav
|
|
159
|
+
- List
|
|
160
|
+
- Accordion
|
|
@@ -66,7 +66,13 @@ states:
|
|
|
66
66
|
traits: []
|
|
67
67
|
tokens: {}
|
|
68
68
|
a2ui:
|
|
69
|
-
rules:
|
|
69
|
+
rules:
|
|
70
|
+
- rule: 'File-upload input with drop zone + browse button. Form-associated; emits file-list change events.'
|
|
71
|
+
reason: 'File-input canonical primitive.'
|
|
72
|
+
- rule: 'Multiple attribute enables multi-file selection; accept= constrains file types.'
|
|
73
|
+
reason: 'Standard file-input knobs.'
|
|
74
|
+
- rule: 'For agent chat attachments use <chat-composer-ui>''s built-in upload affordance instead.'
|
|
75
|
+
reason: 'Chat composer has its own attachment lane.'
|
|
70
76
|
anti_patterns: []
|
|
71
77
|
examples:
|
|
72
78
|
- name: data-import
|
package/core/index.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Signal } from './signals.js';
|
|
2
|
+
|
|
3
|
+
/** Min-width px thresholds keyed by breakpoint name. */
|
|
4
|
+
export declare const BREAKPOINTS: { xs: 0; sm: 480; md: 768; lg: 1024; xl: 1280 };
|
|
5
|
+
|
|
6
|
+
/** Ordered breakpoint names, narrowest → widest. */
|
|
7
|
+
export declare const BP_NAMES: string[];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared signal holding the current viewport breakpoint name.
|
|
11
|
+
* Read inside a UIElement `render()` to subscribe; the component
|
|
12
|
+
* re-renders automatically on breakpoint change.
|
|
13
|
+
*/
|
|
14
|
+
export declare const breakpoint: Signal<'xs' | 'sm' | 'md' | 'lg' | 'xl'>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a responsive attribute value for the given breakpoint.
|
|
18
|
+
*
|
|
19
|
+
* Syntax: `"base @bp:override ..."` — e.g. `"1 2@sm 4@lg"`.
|
|
20
|
+
* Mobile-first: `@bp` applies at that breakpoint and all wider ones.
|
|
21
|
+
* Returns the unannotated default when no annotation matches.
|
|
22
|
+
*
|
|
23
|
+
* @param value Raw attribute string (e.g. `"1 2@sm 4@lg"`).
|
|
24
|
+
* @param activeBp Breakpoint to resolve for. Defaults to `breakpoint.value`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseResponsive(
|
|
27
|
+
value: string | null | undefined,
|
|
28
|
+
activeBp?: string,
|
|
29
|
+
): string | null;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdiaUI Responsive — viewport-breakpoint signal + `@bp` attribute parser.
|
|
3
|
+
*
|
|
4
|
+
* Components that support responsive attribute values read `breakpoint.value`
|
|
5
|
+
* inside their `render()` method. UIElement wraps render() in an effect, so
|
|
6
|
+
* the component automatically re-renders whenever the viewport crosses a
|
|
7
|
+
* breakpoint boundary — no manual subscription needed.
|
|
8
|
+
*
|
|
9
|
+
* ## Syntax
|
|
10
|
+
*
|
|
11
|
+
* "4" → scalar, fast-path (no parsing)
|
|
12
|
+
* "1 2@sm 4@lg" → 1 on xs, 2 from sm, 4 from lg/xl
|
|
13
|
+
* "4 1@sm" → 4 on md/lg/xl, 1 on xs/sm
|
|
14
|
+
* "2@md" → 2 from md+, inherits component default below md
|
|
15
|
+
*
|
|
16
|
+
* Semantics: mobile-first / min-width — `@bp` means "apply at this
|
|
17
|
+
* breakpoint and all wider viewports, unless overridden by a larger
|
|
18
|
+
* annotation". The unannotated value is the base (smallest screens).
|
|
19
|
+
*
|
|
20
|
+
* Resolution: largest `@bp` whose index ≤ active-bp-index wins.
|
|
21
|
+
* If no annotation matches, the unannotated default is returned.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* import { parseResponsive, breakpoint } from '../../core/responsive.js';
|
|
25
|
+
*
|
|
26
|
+
* render() {
|
|
27
|
+
* const bp = breakpoint.value; // subscribe
|
|
28
|
+
* const cols = parseResponsive(this.columns, bp);
|
|
29
|
+
* this.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { signal } from './signals.js';
|
|
34
|
+
|
|
35
|
+
// ─── Breakpoint scale ─────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
/** Min-width px thresholds, narrowest first. */
|
|
38
|
+
export const BREAKPOINTS = /** @type {Record<string, number>} */ ({
|
|
39
|
+
xs: 0,
|
|
40
|
+
sm: 480,
|
|
41
|
+
md: 768,
|
|
42
|
+
lg: 1024,
|
|
43
|
+
xl: 1280,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/** Ordered list of breakpoint names, narrowest → widest. */
|
|
47
|
+
export const BP_NAMES = /** @type {string[]} */ (Object.keys(BREAKPOINTS));
|
|
48
|
+
const BP_VALS = /** @type {number[]} */ (Object.values(BREAKPOINTS));
|
|
49
|
+
|
|
50
|
+
// ─── Active-breakpoint signal ─────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
function _detect() {
|
|
53
|
+
if (typeof window === 'undefined') return 'lg'; // SSR / non-browser fallback
|
|
54
|
+
const w = window.innerWidth;
|
|
55
|
+
for (let i = BP_NAMES.length - 1; i >= 0; i--) {
|
|
56
|
+
if (w >= BP_VALS[i]) return BP_NAMES[i];
|
|
57
|
+
}
|
|
58
|
+
return 'xs';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Shared signal — current viewport breakpoint name.
|
|
63
|
+
* Reading `.value` inside a UIElement `render()` creates a subscription;
|
|
64
|
+
* the component re-renders automatically on breakpoint change.
|
|
65
|
+
*
|
|
66
|
+
* @type {import('./signals.js').Signal<string>}
|
|
67
|
+
*/
|
|
68
|
+
export const breakpoint = signal(_detect());
|
|
69
|
+
|
|
70
|
+
// Wire matchMedia listeners once (browser only, skipped in SSR / tests)
|
|
71
|
+
if (typeof window !== 'undefined') {
|
|
72
|
+
// One listener per non-zero threshold; fires whenever the viewport crosses
|
|
73
|
+
// that boundary in either direction.
|
|
74
|
+
for (let i = 1; i < BP_VALS.length; i++) {
|
|
75
|
+
window
|
|
76
|
+
.matchMedia(`(min-width: ${BP_VALS[i]}px)`)
|
|
77
|
+
.addEventListener('change', () => { breakpoint.value = _detect(); });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─── Parser ───────────────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolve a responsive attribute value for the given breakpoint.
|
|
85
|
+
*
|
|
86
|
+
* @param {string | null | undefined} value Raw attribute string.
|
|
87
|
+
* @param {string} activeBp Current breakpoint name.
|
|
88
|
+
* @returns {string | null} Resolved scalar, or null.
|
|
89
|
+
*/
|
|
90
|
+
export function parseResponsive(value, activeBp = breakpoint.value) {
|
|
91
|
+
if (!value) return null;
|
|
92
|
+
if (!value.includes('@')) return value; // fast path — plain scalar
|
|
93
|
+
|
|
94
|
+
let defaultVal = /** @type {string | null} */ (null);
|
|
95
|
+
const bpMap = /** @type {Map<string, string>} */ (new Map());
|
|
96
|
+
|
|
97
|
+
for (const token of value.trim().split(/\s+/)) {
|
|
98
|
+
const at = token.lastIndexOf('@');
|
|
99
|
+
if (at === -1) {
|
|
100
|
+
defaultVal = token;
|
|
101
|
+
} else {
|
|
102
|
+
bpMap.set(token.slice(at + 1), token.slice(0, at));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Find the largest @bp annotation whose index ≤ active-bp index.
|
|
107
|
+
const activeIdx = BP_NAMES.indexOf(activeBp);
|
|
108
|
+
let best = /** @type {string | null} */ (null);
|
|
109
|
+
let bestIdx = -1;
|
|
110
|
+
|
|
111
|
+
for (const [bp, val] of bpMap) {
|
|
112
|
+
const idx = BP_NAMES.indexOf(bp);
|
|
113
|
+
if (idx !== -1 && idx <= activeIdx && idx > bestIdx) {
|
|
114
|
+
best = val;
|
|
115
|
+
bestIdx = idx;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return best ?? defaultVal;
|
|
120
|
+
}
|