@adia-ai/web-components 0.8.23 → 0.8.25
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 +30 -0
- package/components/agent-questions/agent-questions.yaml +0 -2
- package/components/alert/alert.class.js +5 -0
- package/components/alert/alert.yaml +2 -0
- package/components/anchor-bar/anchor-bar.a2ui.json +139 -0
- package/components/anchor-bar/anchor-bar.class.js +124 -0
- package/components/anchor-bar/anchor-bar.css +140 -0
- package/components/anchor-bar/anchor-bar.d.ts +35 -0
- package/components/anchor-bar/anchor-bar.examples.md +32 -0
- package/components/anchor-bar/anchor-bar.js +17 -0
- package/components/anchor-bar/anchor-bar.yaml +167 -0
- package/components/calendar-grid/calendar-grid.yaml +3 -0
- package/components/card/card.css +12 -0
- package/components/chart/chart.a2ui.json +16 -0
- package/components/chart/chart.class.js +105 -27
- package/components/chart/chart.css +27 -0
- package/components/chart/chart.d.ts +4 -0
- package/components/chart/chart.yaml +28 -0
- package/components/combobox/combobox.class.js +1 -1
- package/components/combobox/combobox.yaml +0 -1
- package/components/date-range-picker/date-range-picker.class.js +1 -1
- package/components/date-range-picker/date-range-picker.yaml +0 -1
- package/components/datetime-picker/datetime-picker.class.js +1 -1
- package/components/datetime-picker/datetime-picker.yaml +0 -1
- package/components/drawer/drawer.class.js +5 -0
- package/components/drawer/drawer.yaml +2 -0
- package/components/feed/feed.class.js +5 -0
- package/components/feed/feed.yaml +2 -0
- package/components/index.js +1 -0
- package/components/input/input.class.js +5 -0
- package/components/input/input.yaml +3 -0
- package/components/list/list.css +13 -4
- package/components/modal/modal.class.js +5 -0
- package/components/modal/modal.yaml +2 -0
- package/components/nav-group/nav-group.class.js +5 -0
- package/components/nav-group/nav-group.yaml +2 -0
- package/components/pagination/pagination.yaml +3 -0
- package/components/select/select.class.js +2 -2
- package/components/select/select.yaml +0 -1
- package/components/stat/stat.a2ui.json +8 -0
- package/components/stat/stat.css +39 -0
- package/components/stat/stat.d.ts +2 -0
- package/components/stat/stat.js +5 -0
- package/components/stat/stat.yaml +11 -0
- package/components/swiper/swiper.class.js +5 -0
- package/components/swiper/swiper.yaml +3 -0
- package/components/toolbar/toolbar.class.js +20 -0
- package/components/toolbar/toolbar.yaml +2 -0
- package/components/tooltip/tooltip.class.js +17 -11
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +2 -2
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +117 -117
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +3 -3
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +81 -93
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +12 -25
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.html +8 -52
- package/patterns/changelog-feed/changelog-feed.examples.html +3 -3
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +4 -4
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +2 -2
- package/patterns/marketing-engagement/marketing-engagement.examples.html +8 -8
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +2 -2
- package/styles/api/parametric-scope.css +81 -0
- package/styles/components.css +1 -0
- package/styles/tokens.css +1 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Edit this file; run `npm run build:components` to regenerate a2ui.json.
|
|
2
|
+
$schema: ../../../../scripts/schemas/component.yaml.schema.json
|
|
3
|
+
name: UIAnchorBar
|
|
4
|
+
tag: anchor-bar-ui
|
|
5
|
+
status: beta
|
|
6
|
+
component: AnchorBar
|
|
7
|
+
category: container
|
|
8
|
+
version: 1
|
|
9
|
+
description: >-
|
|
10
|
+
Persistent, anchored, elevated surface for chrome that must stay visible
|
|
11
|
+
while a condition holds — floating bulk-action toolbars, undo bars,
|
|
12
|
+
sticky wizard/commit footers. Distinct from <toast-ui> (auto-dismissing,
|
|
13
|
+
notification semantics) and <modal-ui>/<drawer-ui> (blocking overlays
|
|
14
|
+
with backdrop + focus-trap semantics). Default mode anchors [anchor] to
|
|
15
|
+
the nearest scroll container via `position: sticky` — the shape gh#494's
|
|
16
|
+
bulk-action-toolbar pattern hand-rolled with card-ui + position:sticky.
|
|
17
|
+
Opt into [viewport] for a surface that anchors to the browser viewport
|
|
18
|
+
instead, promoted to the top layer via the Popover API (`popover="manual"`)
|
|
19
|
+
so it wins stacking over shell chrome without a z-index war. Visibility
|
|
20
|
+
is [open] (default false, no auto-dismiss timer) — arbitrary content
|
|
21
|
+
(typically <toolbar-ui> or <text-ui> + <button-ui>) rides the default slot.
|
|
22
|
+
props:
|
|
23
|
+
anchor:
|
|
24
|
+
description: Viewport/container edge the bar sticks to.
|
|
25
|
+
type: string
|
|
26
|
+
default: bottom
|
|
27
|
+
reflect: true
|
|
28
|
+
enum:
|
|
29
|
+
- bottom
|
|
30
|
+
- top
|
|
31
|
+
align:
|
|
32
|
+
description: Horizontal alignment along the anchored edge.
|
|
33
|
+
type: string
|
|
34
|
+
default: center
|
|
35
|
+
reflect: true
|
|
36
|
+
enum:
|
|
37
|
+
- start
|
|
38
|
+
- center
|
|
39
|
+
- end
|
|
40
|
+
viewport:
|
|
41
|
+
description: >-
|
|
42
|
+
false (default) anchors to the nearest scroll container via
|
|
43
|
+
`position: sticky` — safe for content with ResizeObserver-driven
|
|
44
|
+
children (e.g. <toolbar-ui>'s overflow measurement never sees a
|
|
45
|
+
display:none reset). true anchors to the browser viewport via
|
|
46
|
+
`position: fixed` + Popover API top-layer promotion — note the
|
|
47
|
+
native Popover UA stylesheet applies `display:none` while closed,
|
|
48
|
+
which DOES reset ResizeObserver-driven children on first open;
|
|
49
|
+
prefer the default for content wrapping <toolbar-ui>.
|
|
50
|
+
type: boolean
|
|
51
|
+
default: false
|
|
52
|
+
reflect: true
|
|
53
|
+
open:
|
|
54
|
+
description: Controls visibility. No auto-dismiss — caller toggles explicitly.
|
|
55
|
+
type: boolean
|
|
56
|
+
default: false
|
|
57
|
+
reflect: true
|
|
58
|
+
events:
|
|
59
|
+
open:
|
|
60
|
+
description: Fired when [open] becomes true.
|
|
61
|
+
close:
|
|
62
|
+
description: Fired when [open] becomes false.
|
|
63
|
+
slots:
|
|
64
|
+
default:
|
|
65
|
+
description: >-
|
|
66
|
+
Arbitrary bar content — typically <toolbar-ui> (bulk-action bars) or
|
|
67
|
+
<text-ui> + <button-ui> (undo bars, wizard footers). The bar owns
|
|
68
|
+
only the elevated surface chrome (bg/border/radius/shadow) and
|
|
69
|
+
positioning; content layout is the slotted children's own.
|
|
70
|
+
states:
|
|
71
|
+
- name: idle
|
|
72
|
+
description: Default, ready for interaction.
|
|
73
|
+
traits: []
|
|
74
|
+
tokens:
|
|
75
|
+
--anchor-bar-bg:
|
|
76
|
+
description: Override background color
|
|
77
|
+
--anchor-bar-fg:
|
|
78
|
+
description: Override text color
|
|
79
|
+
--anchor-bar-border:
|
|
80
|
+
description: Override border color
|
|
81
|
+
--anchor-bar-radius:
|
|
82
|
+
description: Override corner radius
|
|
83
|
+
--anchor-bar-shadow:
|
|
84
|
+
description: Override elevation shadow
|
|
85
|
+
--anchor-bar-offset:
|
|
86
|
+
description: Override distance from the anchored edge
|
|
87
|
+
a2ui:
|
|
88
|
+
rules:
|
|
89
|
+
- rule: >-
|
|
90
|
+
Persistent, non-blocking anchored surface. Use for floating
|
|
91
|
+
bulk-action toolbars, undo bars, and wizard/commit footers — never
|
|
92
|
+
for transient notifications (use <toast-ui>) or blocking dialogs
|
|
93
|
+
(use <modal-ui> / <drawer-ui>).
|
|
94
|
+
reason: 'Lifecycle boundary vs adjacent overlay surfaces.'
|
|
95
|
+
- rule: >-
|
|
96
|
+
Default [viewport=false] anchors within the nearest scroll
|
|
97
|
+
container via position:sticky — the correct choice when the bar
|
|
98
|
+
sits over a bounded scroll region (e.g. a table's own scroll box).
|
|
99
|
+
Set [viewport] only when the surface must anchor to the browser
|
|
100
|
+
viewport regardless of ancestor scroll containers (e.g. an undo
|
|
101
|
+
bar over an arbitrary page layout).
|
|
102
|
+
reason: 'Mode selection.'
|
|
103
|
+
- rule: >-
|
|
104
|
+
Does NOT join the modal mutual-exclusion convention — it is not a
|
|
105
|
+
modal surface and coexists with page interaction and open popovers.
|
|
106
|
+
reason: 'Overlay coexistence contract (gh#495).'
|
|
107
|
+
anti_patterns: []
|
|
108
|
+
examples:
|
|
109
|
+
- name: anchor-bar-demo
|
|
110
|
+
description: >-
|
|
111
|
+
Bottom-anchored bar containing a toolbar with a selection count and
|
|
112
|
+
action buttons, shown persistently while open.
|
|
113
|
+
a2ui: >-
|
|
114
|
+
[
|
|
115
|
+
{
|
|
116
|
+
"id": "root",
|
|
117
|
+
"component": "Card",
|
|
118
|
+
"children": [
|
|
119
|
+
"bar"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "bar",
|
|
124
|
+
"component": "AnchorBar",
|
|
125
|
+
"anchor": "bottom",
|
|
126
|
+
"open": true,
|
|
127
|
+
"children": [
|
|
128
|
+
"toolbar"
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"id": "toolbar",
|
|
133
|
+
"component": "Toolbar",
|
|
134
|
+
"children": [
|
|
135
|
+
"count"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "count",
|
|
140
|
+
"component": "Text",
|
|
141
|
+
"text": "3 selected"
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
keywords:
|
|
145
|
+
- anchor
|
|
146
|
+
- bar
|
|
147
|
+
- floating
|
|
148
|
+
- toolbar
|
|
149
|
+
- undo
|
|
150
|
+
- persistent
|
|
151
|
+
- sticky
|
|
152
|
+
- footer
|
|
153
|
+
- selection
|
|
154
|
+
- bulk action
|
|
155
|
+
synonyms:
|
|
156
|
+
bar:
|
|
157
|
+
- toolbar
|
|
158
|
+
- anchor
|
|
159
|
+
- footer
|
|
160
|
+
floating:
|
|
161
|
+
- anchor
|
|
162
|
+
- sticky
|
|
163
|
+
- popover
|
|
164
|
+
undo:
|
|
165
|
+
- anchor
|
|
166
|
+
- toast
|
|
167
|
+
- alert
|
package/components/card/card.css
CHANGED
|
@@ -68,6 +68,18 @@
|
|
|
68
68
|
flex: 1 1 auto;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/* A card with a direct footer pins it to the bottom edge (gh#559):
|
|
72
|
+
in an equal-height grid/flex row, a shorter card's CTA otherwise
|
|
73
|
+
floats at content end while its siblings' sit lower. Scoped via
|
|
74
|
+
:has(> footer) so footerless cards keep plain block flow. */
|
|
75
|
+
:scope:has(> footer) {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
}
|
|
79
|
+
:scope > footer {
|
|
80
|
+
margin-top: auto;
|
|
81
|
+
}
|
|
82
|
+
|
|
71
83
|
/* ═══════ Variants — token-only overrides ═══════ */
|
|
72
84
|
|
|
73
85
|
/* `outline` is a documented alias for `outlined` (yaml). */
|
|
@@ -57,6 +57,17 @@
|
|
|
57
57
|
"description": "JS property (set programmatically — `el.data = [...]`). An array of plain objects; each object's keys are named by the `x` and `y` attributes — e.g. `<chart-ui x=\"month\" y=\"revenue\">` consumes `[{month:'Jan', revenue:3200}, {month:'Feb', revenue:4100}]`. The Chart.js `{labels, datasets}` envelope is NOT chart-ui's API — passing it (or any non-array value) renders an empty chart. May also be supplied declaratively as a JSON-array `data=\"[…]\"` attribute, hydrated once at connect. Custom accessor on the element class, not a reflected attribute.",
|
|
58
58
|
"$ref": "common_types.json#/$defs/DynamicObjectList"
|
|
59
59
|
},
|
|
60
|
+
"dots": {
|
|
61
|
+
"description": "Marker (dot) visibility for line and multi-line series. `all` draws a circle[data-dot] on every datum (default — matches pre-gh#561 behavior). `none` hides all dots so a dense series reads as a clean line. `hover` shows only the currently-hovered datum's dot. `last` shows only the terminal point per series (sparkline convention). Tooltip hit targets ([data-hit]) are a separate always-rendered layer — every mode keeps hover/click working along the whole line.",
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": [
|
|
64
|
+
"all",
|
|
65
|
+
"none",
|
|
66
|
+
"hover",
|
|
67
|
+
"last"
|
|
68
|
+
],
|
|
69
|
+
"default": "all"
|
|
70
|
+
},
|
|
60
71
|
"format": {
|
|
61
72
|
"description": "Number-format mode applied to axis labels + value overlays + donut total + gauge value + treemap value + funnel value + internal tooltip. `abbr` is the legacy 1.2K / 3M format; `decimal` fixes 2 decimals; `currency` prefixes via `--chart-currency-prefix` token (default \"$\"); `percent` multiplies × 100 and adds a % suffix.",
|
|
62
73
|
"type": "string",
|
|
@@ -93,6 +104,11 @@
|
|
|
93
104
|
"type": "number",
|
|
94
105
|
"default": null
|
|
95
106
|
},
|
|
107
|
+
"seriesEmphasis": {
|
|
108
|
+
"description": "Multi-line only. Names one series key (matching a `y` key) to render at full strength — area fill + full-opacity line. Every other series drops its area fill and renders line-only at --chart-deemphasized-opacity. Empty (default) applies full treatment to every series, unchanged from pre-gh#561 behavior.",
|
|
109
|
+
"type": "string",
|
|
110
|
+
"default": ""
|
|
111
|
+
},
|
|
96
112
|
"size": {
|
|
97
113
|
"description": "Chart size",
|
|
98
114
|
"type": "string",
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
* hide-grid — hide gridlines
|
|
27
27
|
* hide-values — hide value labels
|
|
28
28
|
* radius — bar corner radius (default: 4)
|
|
29
|
+
* dots — line/multi-line marker visibility: all|none|hover|last (default: all)
|
|
30
|
+
* series-emphasis — multi-line: series key that keeps full area+line treatment; others render line-only, dimmed
|
|
29
31
|
*
|
|
30
32
|
* JS API:
|
|
31
33
|
* .data = [{...}, ...] — array of data objects
|
|
@@ -222,6 +224,19 @@ export class UIChart extends UIElement {
|
|
|
222
224
|
size: { type: String, default: '', reflect: true },
|
|
223
225
|
format: { type: String, default: 'abbr', reflect: true },
|
|
224
226
|
loading: { type: Boolean, default: false, reflect: true },
|
|
227
|
+
/* gh#561 — dot/marker visibility for line + multi-line. `all` is the
|
|
228
|
+
pre-561 default (every datum gets a circle[data-dot]); `none` /
|
|
229
|
+
`hover` / `last` exist because a 30-point small-integer series turns
|
|
230
|
+
into an unreadable bead string at `all`. Tooltip hit targets
|
|
231
|
+
([data-hit]) are a separate always-rendered layer — every mode keeps
|
|
232
|
+
hover/click working along the whole line. */
|
|
233
|
+
dots: { type: String, default: 'all', reflect: true },
|
|
234
|
+
/* gh#561 — names one multi-line series (a `y` key) to render at full
|
|
235
|
+
strength (area + full-opacity line); every other series drops its
|
|
236
|
+
area and renders line-only at --chart-deemphasized-opacity. Empty
|
|
237
|
+
(default) applies full treatment to every series — unchanged from
|
|
238
|
+
pre-561 behavior. */
|
|
239
|
+
seriesEmphasis: { type: String, default: '', reflect: true, attribute: 'series-emphasis' },
|
|
225
240
|
};
|
|
226
241
|
|
|
227
242
|
static template = () => null;
|
|
@@ -235,6 +250,10 @@ export class UIChart extends UIElement {
|
|
|
235
250
|
/* Set of series keys hidden by external chart-legend-ui[for=self] toggles.
|
|
236
251
|
Kept at render time; repopulated lookups rebuild with the new set. */
|
|
237
252
|
#hiddenSeriesKeys = new Set();
|
|
253
|
+
/* gh#561 — dots="hover": the currently-shown dot element (a sibling of the
|
|
254
|
+
hovered [data-hit] circle), tracked so it can be cleared on leave /
|
|
255
|
+
re-render without a full DOM query. */
|
|
256
|
+
#activeDotEl = null;
|
|
238
257
|
|
|
239
258
|
/** Resolves the corner radius: the `radius` prop if explicitly set,
|
|
240
259
|
* otherwise `--a-radius` from the host's computed style. Falls back
|
|
@@ -463,7 +482,11 @@ export class UIChart extends UIElement {
|
|
|
463
482
|
}
|
|
464
483
|
this.setAttribute('data-has-data', '');
|
|
465
484
|
|
|
466
|
-
this
|
|
485
|
+
/* gh#561 — the DOM this pointed at is about to be wiped; drop the
|
|
486
|
+
reference so a stale node isn't held onto (its data-dot-active
|
|
487
|
+
attribute doesn't matter once detached, but nulling avoids leaking
|
|
488
|
+
the reference between renders). */
|
|
489
|
+
this.#activeDotEl = null;
|
|
467
490
|
|
|
468
491
|
const svgWrap = document.createElement('div');
|
|
469
492
|
if (this.type === 'sparkline') svgWrap.setAttribute('data-sparkline', '');
|
|
@@ -522,25 +545,26 @@ export class UIChart extends UIElement {
|
|
|
522
545
|
tooltip-ui[follows=pointer] lands. */
|
|
523
546
|
}
|
|
524
547
|
|
|
525
|
-
/* ── Per-series --color-{key}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
548
|
+
/* ── Per-series --color-{key} hook ──
|
|
549
|
+
gh#561 — previously this method wrote `--color-{key}: var(--chart-N)`
|
|
550
|
+
as an inline style on the HOST. Inline styles win the cascade over
|
|
551
|
+
everything except `!important`, so a consumer setting `--color-MAU` on
|
|
552
|
+
any ancestor lost to the chart's own inline default — the documented
|
|
553
|
+
"override --color-{key} to recolor a series" hook was unusable from
|
|
554
|
+
outside. The fix is to not set the host property at all: each
|
|
555
|
+
series-keyed element already carries its own inline
|
|
556
|
+
`var(--color-{key}, var(--chart-{slot}))` fallback chain (see
|
|
557
|
+
#seriesFill / #seriesStroke below), so an unset --color-{key} still
|
|
558
|
+
resolves to the right palette slot, and a consumer-set one now
|
|
559
|
+
actually wins. */
|
|
537
560
|
|
|
538
561
|
/* Render-time helpers — emit data-slice + series-key + inline style that
|
|
539
|
-
references `--color-{key}` with fallback to `--chart-{slot}`.
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
562
|
+
references `--color-{key}` with fallback to `--chart-{slot}`. Because
|
|
563
|
+
nothing sets `--color-{key}` on the host anymore, an ancestor-set
|
|
564
|
+
value flows through the normal cascade into this var() and wins. Only
|
|
565
|
+
an unset `--color-{key}` falls through to `--chart-{slot}`.
|
|
566
|
+
Non-series-keyed elements (pie/donut/segments categorical slots) keep
|
|
567
|
+
data-slice only and are coloured by the stylesheet. */
|
|
544
568
|
#seriesFill(slotIdx, seriesKey) {
|
|
545
569
|
if (!seriesKey) return ` data-slice="${slotIdx}"`;
|
|
546
570
|
return ` data-slice="${slotIdx}" data-series-key="${esc(seriesKey)}" style="fill: var(--color-${seriesKey}, var(--chart-${slotIdx}))"`;
|
|
@@ -813,6 +837,7 @@ export class UIChart extends UIElement {
|
|
|
813
837
|
|
|
814
838
|
#emitHover(target, event) {
|
|
815
839
|
this.#hoveredTarget = target;
|
|
840
|
+
if (this.dots === 'hover') this.#setActiveDot(target);
|
|
816
841
|
this.dispatchEvent(new CustomEvent('chart-hover', {
|
|
817
842
|
bubbles: true,
|
|
818
843
|
detail: this.#tipPayload(target, event),
|
|
@@ -821,9 +846,32 @@ export class UIChart extends UIElement {
|
|
|
821
846
|
|
|
822
847
|
#emitLeave() {
|
|
823
848
|
this.#hoveredTarget = null;
|
|
849
|
+
if (this.dots === 'hover') this.#clearActiveDot();
|
|
824
850
|
this.dispatchEvent(new CustomEvent('chart-leave', { bubbles: true }));
|
|
825
851
|
}
|
|
826
852
|
|
|
853
|
+
/* gh#561 — dots="hover". The dot circle for a point is always the DOM
|
|
854
|
+
sibling immediately before its [data-hit] circle (both renderers push
|
|
855
|
+
them back-to-back: `<circle data-dot>` then `<circle data-hit>`), so
|
|
856
|
+
no separate index bookkeeping is needed to pair them. */
|
|
857
|
+
#setActiveDot(target) {
|
|
858
|
+
const dot = target?.previousElementSibling;
|
|
859
|
+
if (this.#activeDotEl && this.#activeDotEl !== dot) {
|
|
860
|
+
this.#activeDotEl.removeAttribute('data-dot-active');
|
|
861
|
+
}
|
|
862
|
+
if (dot && dot.hasAttribute('data-dot')) {
|
|
863
|
+
dot.setAttribute('data-dot-active', '');
|
|
864
|
+
this.#activeDotEl = dot;
|
|
865
|
+
} else {
|
|
866
|
+
this.#activeDotEl = null;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
#clearActiveDot() {
|
|
871
|
+
if (this.#activeDotEl) this.#activeDotEl.removeAttribute('data-dot-active');
|
|
872
|
+
this.#activeDotEl = null;
|
|
873
|
+
}
|
|
874
|
+
|
|
827
875
|
/* Build the standard event payload from a hovered/clicked datum element.
|
|
828
876
|
OD-CHART-05 — per-X-column granularity. For multi-series renderers
|
|
829
877
|
(stacked-bar, grouped-bar, multi-line, composed), the pointer is
|
|
@@ -959,6 +1007,20 @@ export class UIChart extends UIElement {
|
|
|
959
1007
|
return this.y ? this.y.split(',').map(k => k.trim()).filter(Boolean) : [];
|
|
960
1008
|
}
|
|
961
1009
|
|
|
1010
|
+
/* gh#561 — dots mode. `none`/`last` decide at render time (no dot markup
|
|
1011
|
+
emitted for suppressed points); `hover` renders every dot but CSS
|
|
1012
|
+
hides them by default (`[dots="hover"] [data-dot]`), and the pointer
|
|
1013
|
+
handlers above toggle `data-dot-active` on the one under the cursor. */
|
|
1014
|
+
#shouldRenderDot(i, total) {
|
|
1015
|
+
switch (this.dots) {
|
|
1016
|
+
case 'none': return false;
|
|
1017
|
+
case 'last': return i === total - 1;
|
|
1018
|
+
case 'hover':
|
|
1019
|
+
case 'all':
|
|
1020
|
+
default: return true;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
962
1024
|
/* ── Grid + axes helper ───────────────────────────────────────── */
|
|
963
1025
|
|
|
964
1026
|
#gridAndAxes(width, height, ticks, labels, pad, dims) {
|
|
@@ -1096,13 +1158,15 @@ export class UIChart extends UIElement {
|
|
|
1096
1158
|
const showValues = !this.hideValues && !isSm;
|
|
1097
1159
|
const showAverage = !this.hideAverage && vals.length > 1 && !isSm && !this.hideGrid;
|
|
1098
1160
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1161
|
+
points.forEach((p, i) => {
|
|
1162
|
+
if (this.#shouldRenderDot(i, points.length)) {
|
|
1163
|
+
svg += `<circle data-dot cx="${p.x}" cy="${p.y}" r="${dotR}"/>`;
|
|
1164
|
+
}
|
|
1101
1165
|
svg += `<circle data-hit${tip({ label: p.label, value: p.v })} cx="${p.x}" cy="${p.y}" r="${hitR}" fill="transparent"/>`;
|
|
1102
1166
|
if (showValues) {
|
|
1103
1167
|
svg += `<text data-value x="${p.x}" y="${p.y - 8}" text-anchor="middle" font-size="${dims.valueSize}">${this.#fmtValue(p.v)}</text>`;
|
|
1104
1168
|
}
|
|
1105
|
-
}
|
|
1169
|
+
});
|
|
1106
1170
|
|
|
1107
1171
|
if (showAverage) {
|
|
1108
1172
|
const avg = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
@@ -2082,18 +2146,32 @@ export class UIChart extends UIElement {
|
|
|
2082
2146
|
const baseline = pad.top + plotH;
|
|
2083
2147
|
const t = Math.max(0, Math.min(1, this.smooth));
|
|
2084
2148
|
|
|
2085
|
-
/*
|
|
2086
|
-
|
|
2149
|
+
/* gh#561 — per-series emphasis. When `series-emphasis` names a key,
|
|
2150
|
+
only that series keeps its area fill + full-strength line; every
|
|
2151
|
+
other series drops the area and renders line-only at
|
|
2152
|
+
--chart-deemphasized-opacity (data-deemphasized, CSS-driven — no
|
|
2153
|
+
raw colors touched). Unset (default) emphasizes every series,
|
|
2154
|
+
matching pre-561 behavior. */
|
|
2155
|
+
const emphasisKey = this.seriesEmphasis;
|
|
2156
|
+
const isEmphasized = !emphasisKey || keys[k] === emphasisKey;
|
|
2157
|
+
const deemphAttr = isEmphasized ? '' : ' data-deemphasized';
|
|
2158
|
+
|
|
2159
|
+
/* Area fill — omitted entirely for deemphasized series. */
|
|
2160
|
+
if (isEmphasized) {
|
|
2161
|
+
svg += `<path data-area${this.#seriesFill(k % 10, keys[k])} d="${smoothAreaPath(points, baseline, t)}"/>`;
|
|
2162
|
+
}
|
|
2087
2163
|
|
|
2088
2164
|
/* Line */
|
|
2089
|
-
svg += `<path data-line${this.#seriesStroke(k % 10, keys[k])} d="${smoothPath(points, t)}"/>`;
|
|
2165
|
+
svg += `<path data-line${this.#seriesStroke(k % 10, keys[k])}${deemphAttr} d="${smoothPath(points, t)}"/>`;
|
|
2090
2166
|
|
|
2091
2167
|
/* Dots + hit targets. Hit circles deliberately omit data-slice so
|
|
2092
2168
|
they aren't caught by the circle[data-slice] fill rule in CSS. */
|
|
2093
|
-
|
|
2094
|
-
|
|
2169
|
+
points.forEach((p, i) => {
|
|
2170
|
+
if (this.#shouldRenderDot(i, points.length)) {
|
|
2171
|
+
svg += `<circle data-dot${this.#seriesFill(k % 10, keys[k])}${deemphAttr} cx="${p.x}" cy="${p.y}" r="3"/>`;
|
|
2172
|
+
}
|
|
2095
2173
|
svg += `<circle data-hit${tip({ label: p.label, value: p.v, series: keys[k] })} cx="${p.x}" cy="${p.y}" r="10" fill="transparent"/>`;
|
|
2096
|
-
}
|
|
2174
|
+
});
|
|
2097
2175
|
}
|
|
2098
2176
|
|
|
2099
2177
|
this.#legendData = keys.map((k, i) => ({ label: k, key: k, slot: i % 10 }));
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
--chart-area-opacity: 0.15;
|
|
26
26
|
--chart-line-width: 2;
|
|
27
27
|
--chart-radius: 4;
|
|
28
|
+
/* gh#561 — opacity applied to a multi-line series' line when
|
|
29
|
+
series-emphasis names a different series (data-deemphasized). */
|
|
30
|
+
--chart-deemphasized-opacity: 0.4;
|
|
28
31
|
|
|
29
32
|
/* Layout */
|
|
30
33
|
--chart-border: var(--md-sys-color-neutral-outline-variant);
|
|
@@ -227,6 +230,30 @@
|
|
|
227
230
|
r: 5;
|
|
228
231
|
}
|
|
229
232
|
|
|
233
|
+
/* ── gh#561 — dots mode ──
|
|
234
|
+
`all` (default) leaves [data-dot] at full opacity, matching pre-561
|
|
235
|
+
behavior. `none`/`last` decide what to render in JS (no markup
|
|
236
|
+
emitted for suppressed points) so no CSS is needed for them. `hover`
|
|
237
|
+
renders every dot but hides them by default; the pointer handlers in
|
|
238
|
+
chart.js toggle [data-dot-active] on the one under the cursor. */
|
|
239
|
+
:scope[dots="hover"] [data-dot] {
|
|
240
|
+
opacity: 0;
|
|
241
|
+
transition: opacity var(--chart-duration) var(--chart-easing), r var(--chart-duration) var(--chart-easing);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
:scope[dots="hover"] [data-dot][data-dot-active] {
|
|
245
|
+
opacity: 1;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* ── gh#561 — multi-line per-series emphasis ──
|
|
249
|
+
`series-emphasis` names one series to keep full strength; every other
|
|
250
|
+
series' [data-line] (and its dots, if rendered) carry data-deemphasized
|
|
251
|
+
and dim to this token instead. Its [data-area] is never emitted at
|
|
252
|
+
all (see chart.js), so there's no fill to dim. */
|
|
253
|
+
[data-deemphasized] {
|
|
254
|
+
opacity: var(--chart-deemphasized-opacity);
|
|
255
|
+
}
|
|
256
|
+
|
|
230
257
|
/* ── Average line ── */
|
|
231
258
|
|
|
232
259
|
[data-avg] {
|
|
@@ -24,6 +24,8 @@ export class UIChart extends UIElement {
|
|
|
24
24
|
color: 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
25
25
|
/** JS property (set programmatically — `el.data = [...]`). An array of plain objects; each object's keys are named by the `x` and `y` attributes — e.g. `<chart-ui x="month" y="revenue">` consumes `[{month:'Jan', revenue:3200}, {month:'Feb', revenue:4100}]`. The Chart.js `{labels, datasets}` envelope is NOT chart-ui's API — passing it (or any non-array value) renders an empty chart. May also be supplied declaratively as a JSON-array `data="[…]"` attribute, hydrated once at connect. Custom accessor on the element class, not a reflected attribute. */
|
|
26
26
|
data: string;
|
|
27
|
+
/** Marker (dot) visibility for line and multi-line series. `all` draws a circle[data-dot] on every datum (default — matches pre-gh#561 behavior). `none` hides all dots so a dense series reads as a clean line. `hover` shows only the currently-hovered datum's dot. `last` shows only the terminal point per series (sparkline convention). Tooltip hit targets ([data-hit]) are a separate always-rendered layer — every mode keeps hover/click working along the whole line. */
|
|
28
|
+
dots: 'all' | 'none' | 'hover' | 'last';
|
|
27
29
|
/** Number-format mode applied to axis labels + value overlays + donut total + gauge value + treemap value + funnel value + internal tooltip. `abbr` is the legacy 1.2K / 3M format; `decimal` fixes 2 decimals; `currency` prefixes via `--chart-currency-prefix` token (default "$"); `percent` multiplies × 100 and adds a % suffix. */
|
|
28
30
|
format: 'abbr' | 'decimal' | 'currency' | 'percent';
|
|
29
31
|
/** When true, suppress the overlaid average line */
|
|
@@ -36,6 +38,8 @@ export class UIChart extends UIElement {
|
|
|
36
38
|
loading: boolean;
|
|
37
39
|
/** Bar corner radius (null = let CSS tokens decide) */
|
|
38
40
|
radius: number;
|
|
41
|
+
/** Multi-line only. Names one series key (matching a `y` key) to render at full strength — area fill + full-opacity line. Every other series drops its area fill and renders line-only at --chart-deemphasized-opacity. Empty (default) applies full treatment to every series, unchanged from pre-gh#561 behavior. */
|
|
42
|
+
seriesEmphasis: string;
|
|
39
43
|
/** Chart size */
|
|
40
44
|
size: 'sm' | 'md' | 'lg';
|
|
41
45
|
/** Line smoothing factor */
|
|
@@ -92,6 +92,34 @@ props:
|
|
|
92
92
|
description: Line smoothing factor
|
|
93
93
|
type: number
|
|
94
94
|
default: 0.4
|
|
95
|
+
dots:
|
|
96
|
+
description: >-
|
|
97
|
+
Marker (dot) visibility for line and multi-line series. `all` draws a
|
|
98
|
+
circle[data-dot] on every datum (default — matches pre-gh#561
|
|
99
|
+
behavior). `none` hides all dots so a dense series reads as a clean
|
|
100
|
+
line. `hover` shows only the currently-hovered datum's dot. `last`
|
|
101
|
+
shows only the terminal point per series (sparkline convention).
|
|
102
|
+
Tooltip hit targets ([data-hit]) are a separate always-rendered
|
|
103
|
+
layer — every mode keeps hover/click working along the whole line.
|
|
104
|
+
type: string
|
|
105
|
+
default: all
|
|
106
|
+
enum:
|
|
107
|
+
- all
|
|
108
|
+
- none
|
|
109
|
+
- hover
|
|
110
|
+
- last
|
|
111
|
+
reflect: true
|
|
112
|
+
seriesEmphasis:
|
|
113
|
+
description: >-
|
|
114
|
+
Multi-line only. Names one series key (matching a `y` key) to render
|
|
115
|
+
at full strength — area fill + full-opacity line. Every other series
|
|
116
|
+
drops its area fill and renders line-only at
|
|
117
|
+
--chart-deemphasized-opacity. Empty (default) applies full treatment
|
|
118
|
+
to every series, unchanged from pre-gh#561 behavior.
|
|
119
|
+
type: string
|
|
120
|
+
default: ""
|
|
121
|
+
attribute: series-emphasis
|
|
122
|
+
reflect: true
|
|
95
123
|
loading:
|
|
96
124
|
description: >-
|
|
97
125
|
Show a skeleton placeholder instead of the chart body. Set to true
|
|
@@ -58,7 +58,7 @@ export class UICombobox extends UIFormElement {
|
|
|
58
58
|
// base-class deprecation warning that targets inert above-field labels.
|
|
59
59
|
static labelDeprecated = false;
|
|
60
60
|
|
|
61
|
-
static requiredIcons = ['caret-down', 'x-circle'
|
|
61
|
+
static requiredIcons = ['caret-down', 'x-circle'];
|
|
62
62
|
|
|
63
63
|
static properties = {
|
|
64
64
|
...UIFormElement.properties,
|
|
@@ -130,7 +130,7 @@ export class UIDateRangePicker extends UIFormElement {
|
|
|
130
130
|
// §154: Phosphor icons this primitive auto-stamps (without consumer
|
|
131
131
|
// markup). Aggregated by installIconLoadersForRegistered() across all
|
|
132
132
|
// defined elements. Audited by check-required-icons.mjs.
|
|
133
|
-
static requiredIcons = ['calendar', 'caret-down'
|
|
133
|
+
static requiredIcons = ['calendar', 'caret-down'];
|
|
134
134
|
|
|
135
135
|
static get properties() {
|
|
136
136
|
return {
|
|
@@ -195,7 +195,6 @@ tokens:
|
|
|
195
195
|
requiredIcons:
|
|
196
196
|
- calendar
|
|
197
197
|
- caret-down
|
|
198
|
-
- arrow-right
|
|
199
198
|
a2ui:
|
|
200
199
|
rules:
|
|
201
200
|
- rule: 'DateRangePicker.value MUST be `{from, to}` with both ISO 8601 dates, OR null. Either side null is invalid mid-state and the validator should reject it (use `input` event for partial state).'
|
|
@@ -122,7 +122,7 @@ export class UIDatetimePicker extends UIFormElement {
|
|
|
122
122
|
// §154: Phosphor icons this primitive auto-stamps (without consumer
|
|
123
123
|
// markup). Aggregated by installIconLoadersForRegistered() across all
|
|
124
124
|
// defined elements. Audited by check-required-icons.mjs.
|
|
125
|
-
static requiredIcons = ['calendar', '
|
|
125
|
+
static requiredIcons = ['calendar', 'caret-down'];
|
|
126
126
|
|
|
127
127
|
static get properties() {
|
|
128
128
|
return {
|
|
@@ -60,6 +60,11 @@ export class UIDrawer extends UIElement {
|
|
|
60
60
|
// doesn't carry a stale reason. Per FEEDBACK-06 §2.
|
|
61
61
|
#closeReason = 'programmatic';
|
|
62
62
|
|
|
63
|
+
// Phosphor icons this primitive auto-stamps (without consumer markup).
|
|
64
|
+
// Aggregated by installIconLoadersForRegistered() across all defined
|
|
65
|
+
// elements. Audited by check-required-icons.mjs.
|
|
66
|
+
static requiredIcons = ['x'];
|
|
67
|
+
|
|
63
68
|
static properties = {
|
|
64
69
|
text: { type: String, default: '', reflect: true },
|
|
65
70
|
side: { type: String, default: 'right', reflect: true },
|
|
@@ -43,6 +43,11 @@ import { UIElement, html } from '../../core/element.js';
|
|
|
43
43
|
/* ── Container — one per position, mounted into document.body ── */
|
|
44
44
|
|
|
45
45
|
export class UIFeedContainer extends UIElement {
|
|
46
|
+
// Phosphor icons this primitive auto-stamps (without consumer markup).
|
|
47
|
+
// Aggregated by installIconLoadersForRegistered() across all defined
|
|
48
|
+
// elements. Audited by check-required-icons.mjs.
|
|
49
|
+
static requiredIcons = ['x'];
|
|
50
|
+
|
|
46
51
|
static properties = {
|
|
47
52
|
position: { type: String, default: 'bottom-right', reflect: true },
|
|
48
53
|
max: { type: Number, default: 5, reflect: true },
|
package/components/index.js
CHANGED
|
@@ -41,6 +41,7 @@ export { UIDrawer } from './drawer/drawer.js';
|
|
|
41
41
|
export { UIModal } from './modal/modal.js';
|
|
42
42
|
export { UIToast } from './toast/toast.js';
|
|
43
43
|
export { UIFeedContainer, UIFeedItem, UIFeed } from './feed/feed.js';
|
|
44
|
+
export { UIAnchorBar } from './anchor-bar/anchor-bar.js';
|
|
44
45
|
export { UITabs } from './tabs/tabs.js';
|
|
45
46
|
export { UITab } from './tabs/tab.js';
|
|
46
47
|
export { UITooltip } from './tooltip/tooltip.js';
|