@getaster/elements 0.1.0-preview.0 → 0.2.0
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/bin/aster-theme-check.js +7 -7
- package/dist/carousel/carousel.js +12 -1
- package/dist/grid/grid.js +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tabs/tabs.js +18 -4
- package/package.json +2 -2
- package/styles/aster-ui.css +6 -0
- package/styles/base.css +2 -0
- package/styles/elements.css +4 -0
package/bin/aster-theme-check.js
CHANGED
|
@@ -171,8 +171,8 @@ function oklch(args, lookup) {
|
|
|
171
171
|
if (!base)
|
|
172
172
|
return;
|
|
173
173
|
const [l, c, h] = toOklch(base);
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
174
|
+
const parts = splitTop(from[2]);
|
|
175
|
+
if (parts.length !== 3)
|
|
176
176
|
return;
|
|
177
177
|
const channel = (p, own, key) => {
|
|
178
178
|
if (p === key)
|
|
@@ -180,12 +180,12 @@ function oklch(args, lookup) {
|
|
|
180
180
|
const calc = new RegExp(`^calc\\(${key}\\s*([+-])\\s*([\\d.]+)\\)$`).exec(p);
|
|
181
181
|
return calc ? own + (calc[1] === "+" ? 1 : -1) * Number(calc[2]) : number(p);
|
|
182
182
|
};
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
if ([
|
|
183
|
+
const L = channel(parts[0], l, "l");
|
|
184
|
+
const C = channel(parts[1], c, "c");
|
|
185
|
+
const H = channel(parts[2], h, "h");
|
|
186
|
+
if ([L, C, H].some((x) => x === undefined || Number.isNaN(x)))
|
|
187
187
|
return;
|
|
188
|
-
return { ...fromOklch(
|
|
188
|
+
return { ...fromOklch(L, C, H), a: alpha ?? base.a };
|
|
189
189
|
}
|
|
190
190
|
const parts = main.split(/\s+/).filter(Boolean);
|
|
191
191
|
if (parts.length !== 3)
|
|
@@ -14,6 +14,7 @@ export class Carousel extends AsterElement {
|
|
|
14
14
|
/** The slides don't all fit: only then are there places to move to. */
|
|
15
15
|
#overflows = this.prop(false);
|
|
16
16
|
#resize;
|
|
17
|
+
#resizeFrame = 0;
|
|
17
18
|
#id = uid("aster-carousel");
|
|
18
19
|
#observer;
|
|
19
20
|
/** Rebuilt when descriptors change or the element reconnects. */
|
|
@@ -59,6 +60,8 @@ export class Carousel extends AsterElement {
|
|
|
59
60
|
disconnectedCallback() {
|
|
60
61
|
this.#observer?.disconnect();
|
|
61
62
|
this.#resize?.disconnect();
|
|
63
|
+
cancelAnimationFrame(this.#resizeFrame);
|
|
64
|
+
this.#resizeFrame = 0;
|
|
62
65
|
this.#observed = undefined;
|
|
63
66
|
super.disconnectedCallback();
|
|
64
67
|
}
|
|
@@ -122,7 +125,15 @@ export class Carousel extends AsterElement {
|
|
|
122
125
|
for (const el of this.#slideEls())
|
|
123
126
|
this.#observer.observe(el);
|
|
124
127
|
this.#resize?.disconnect();
|
|
125
|
-
this.#resize = new ResizeObserver(() =>
|
|
128
|
+
this.#resize = new ResizeObserver(() => {
|
|
129
|
+
// Adding navigation changes the rail's layout; commit outside observer delivery.
|
|
130
|
+
if (this.#resizeFrame)
|
|
131
|
+
return;
|
|
132
|
+
this.#resizeFrame = requestAnimationFrame(() => {
|
|
133
|
+
this.#resizeFrame = 0;
|
|
134
|
+
this.#overflows.value = rail.scrollWidth > rail.clientWidth + 1;
|
|
135
|
+
});
|
|
136
|
+
});
|
|
126
137
|
this.#resize.observe(rail);
|
|
127
138
|
for (const el of this.#slideEls())
|
|
128
139
|
this.#resize.observe(el);
|
package/dist/grid/grid.js
CHANGED
|
@@ -2167,6 +2167,9 @@ export class Grid extends AsterElement {
|
|
|
2167
2167
|
}
|
|
2168
2168
|
#focusEditor(key, col) {
|
|
2169
2169
|
const row = this.querySelector(`.aster-grid-row[data-key="${CSS.escape(key)}"]`);
|
|
2170
|
+
// A user may choose another control before deferred initial focus runs.
|
|
2171
|
+
if (row?.contains(document.activeElement))
|
|
2172
|
+
return;
|
|
2170
2173
|
const cells = row ? [...row.querySelectorAll('[role="gridcell"]')] : [];
|
|
2171
2174
|
const target = cells[col]?.querySelector("input:not([readonly]), textarea:not([readonly]), [role=combobox]:not([aria-readonly])") ??
|
|
2172
2175
|
row?.querySelector("input:not([readonly]), textarea:not([readonly]), [role=combobox]:not([aria-readonly])");
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { ProgressStatus } from "./progress/status.ts";
|
|
|
2
2
|
export { provideProgressPolicy, progressPolicyOf } from "./progress/policy.ts";
|
|
3
3
|
export { asterComponents } from "./composition/builtins.ts";
|
|
4
4
|
export { Sidebar, sidebarItems, type SidebarItem } from "./sidebar/sidebar.ts";
|
|
5
|
-
export { AsterElement, define, each, provideScope, read, scopeOf, type Bindable, type View } from "./base/element.ts";
|
|
5
|
+
export { AsterElement, define, each, uid, provideScope, read, scopeOf, type Bindable, type View } from "./base/element.ts";
|
|
6
6
|
export { Composite, compositeComponent, type CompositeOptions, type CompositeChildHandle, type CompositePlacement } from "./composition/composite.ts";
|
|
7
7
|
export { CommandBar } from "./composition/command-bar.ts";
|
|
8
8
|
export { defineCompositeRegistry, defineCompositeRenderer, CompositeAuthoring, type RegistryCatalog, type CompositeDiagnostic, type CompositeCompletion } from "./composition/authoring.ts";
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export { ProgressStatus } from "./progress/status.js";
|
|
|
2
2
|
export { provideProgressPolicy, progressPolicyOf } from "./progress/policy.js";
|
|
3
3
|
export { asterComponents } from "./composition/builtins.js";
|
|
4
4
|
export { Sidebar, sidebarItems } from "./sidebar/sidebar.js";
|
|
5
|
-
export { AsterElement, define, each, provideScope, read, scopeOf } from "./base/element.js";
|
|
5
|
+
export { AsterElement, define, each, uid, provideScope, read, scopeOf } from "./base/element.js";
|
|
6
6
|
export { Composite, compositeComponent } from "./composition/composite.js";
|
|
7
7
|
export { CommandBar } from "./composition/command-bar.js";
|
|
8
8
|
export { defineCompositeRegistry, defineCompositeRenderer, CompositeAuthoring } from "./composition/authoring.js";
|
package/dist/tabs/tabs.js
CHANGED
|
@@ -108,10 +108,24 @@ export class Tabs extends AsterElement {
|
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
#revealSelected() {
|
|
111
|
-
this.querySelector(".aster-tabs")?.querySelector('[role="tab"][aria-selected="true"]')
|
|
111
|
+
const tab = this.querySelector(".aster-tabs")?.querySelector('[role="tab"][aria-selected="true"]');
|
|
112
|
+
if (tab)
|
|
113
|
+
this.#reveal(tab);
|
|
114
|
+
}
|
|
115
|
+
/** Reveal within the strip without scrolling the containing page or panel. */
|
|
116
|
+
#reveal(tab) {
|
|
117
|
+
const viewport = this.querySelector(".aster-tabs-viewport");
|
|
118
|
+
if (!viewport)
|
|
119
|
+
return;
|
|
120
|
+
const visible = viewport.getBoundingClientRect();
|
|
121
|
+
const target = tab.getBoundingClientRect();
|
|
122
|
+
const left = target.left < visible.left ? target.left - visible.left : Math.max(0, target.right - visible.right);
|
|
123
|
+
if (left)
|
|
124
|
+
viewport.scrollBy({ left, behavior: "instant" });
|
|
112
125
|
}
|
|
113
126
|
#focusSelected() {
|
|
114
|
-
this.querySelector(".aster-tabs")?.querySelector('[role="tab"][aria-selected="true"]')?.focus();
|
|
127
|
+
this.querySelector(".aster-tabs")?.querySelector('[role="tab"][aria-selected="true"]')?.focus({ preventScroll: true });
|
|
128
|
+
this.#revealSelected();
|
|
115
129
|
}
|
|
116
130
|
/** Stable for a value while the element lives; encoded so any value is a valid single id token. */
|
|
117
131
|
#tabId(value) {
|
|
@@ -193,8 +207,8 @@ export class Tabs extends AsterElement {
|
|
|
193
207
|
}
|
|
194
208
|
e.preventDefault();
|
|
195
209
|
tabs.forEach((tab, index) => { tab.tabIndex = index === n ? 0 : -1; });
|
|
196
|
-
tabs[n].focus();
|
|
197
|
-
tabs[n]
|
|
210
|
+
tabs[n].focus({ preventScroll: true });
|
|
211
|
+
this.#reveal(tabs[n]);
|
|
198
212
|
if (this.#activation.peek() === "automatic")
|
|
199
213
|
this.#choose(tabs[n].dataset.value);
|
|
200
214
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getaster/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"./styles/*": "./styles/*"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@getaster/data": "0.
|
|
14
|
+
"@getaster/data": "0.2.0",
|
|
15
15
|
"@preact/signals-core": "1.14.4",
|
|
16
16
|
"lit-html": "3.3.3"
|
|
17
17
|
},
|
package/styles/aster-ui.css
CHANGED
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
mix-blend-mode: var(--aster-texture-blend, normal);
|
|
35
35
|
}
|
|
36
36
|
button, input, select, textarea { font: inherit; color: inherit; }
|
|
37
|
+
/* Native controls inherit ink, so their surfaces must follow the same theme. */
|
|
38
|
+
select, option, optgroup { background-color: var(--aster-sunk); }
|
|
37
39
|
button { background: none; border: 0; padding: 0; margin: 0; text-align: inherit; }
|
|
38
40
|
h1, h2, h3 { text-wrap: balance; }
|
|
39
41
|
p { text-wrap: pretty; }
|
|
@@ -460,6 +462,10 @@
|
|
|
460
462
|
.aster-window-bar button:hover { background: var(--aster-accent-soft); color: var(--aster-text); }
|
|
461
463
|
.aster-window-bar button:focus-visible { outline: 2px solid var(--aster-focus); outline-offset: -2px; }
|
|
462
464
|
.aster-window-bar svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }
|
|
465
|
+
@media (max-width: 600px), (pointer: coarse) and (max-height: 500px) {
|
|
466
|
+
.aster-window { left:8px; top:8px; width:calc(100vw - 16px) !important; height:min(420px, calc(100dvh - 16px)) !important; resize:none; }
|
|
467
|
+
.aster-window-bar .aster-window-move, .aster-window-bar button[aria-describedby$="-resize-help"] { display:none; }
|
|
468
|
+
}
|
|
463
469
|
.aster-window-body { flex: 1; min-height: 0; overflow: auto; padding: var(--aster-pad) 14px; }
|
|
464
470
|
/* Dashboard geometry stays in CSS; stored sizes are column/row intent. */
|
|
465
471
|
aster-dashboard { display: block; min-width: 0; container-type: inline-size; }
|
package/styles/base.css
CHANGED
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
mix-blend-mode: var(--aster-texture-blend, normal);
|
|
35
35
|
}
|
|
36
36
|
button, input, select, textarea { font: inherit; color: inherit; }
|
|
37
|
+
/* Native controls inherit ink, so their surfaces must follow the same theme. */
|
|
38
|
+
select, option, optgroup { background-color: var(--aster-sunk); }
|
|
37
39
|
button { background: none; border: 0; padding: 0; margin: 0; text-align: inherit; }
|
|
38
40
|
h1, h2, h3 { text-wrap: balance; }
|
|
39
41
|
p { text-wrap: pretty; }
|
package/styles/elements.css
CHANGED
|
@@ -373,6 +373,10 @@
|
|
|
373
373
|
.aster-window-bar button:hover { background: var(--aster-accent-soft); color: var(--aster-text); }
|
|
374
374
|
.aster-window-bar button:focus-visible { outline: 2px solid var(--aster-focus); outline-offset: -2px; }
|
|
375
375
|
.aster-window-bar svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }
|
|
376
|
+
@media (max-width: 600px), (pointer: coarse) and (max-height: 500px) {
|
|
377
|
+
.aster-window { left:8px; top:8px; width:calc(100vw - 16px) !important; height:min(420px, calc(100dvh - 16px)) !important; resize:none; }
|
|
378
|
+
.aster-window-bar .aster-window-move, .aster-window-bar button[aria-describedby$="-resize-help"] { display:none; }
|
|
379
|
+
}
|
|
376
380
|
.aster-window-body { flex: 1; min-height: 0; overflow: auto; padding: var(--aster-pad) 14px; }
|
|
377
381
|
/* Dashboard geometry stays in CSS; stored sizes are column/row intent. */
|
|
378
382
|
aster-dashboard { display: block; min-width: 0; container-type: inline-size; }
|