@getaster/elements 0.3.5 → 0.4.5
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/NOTICE +4 -0
- package/README.md +13 -4
- package/bin/aster-theme-check.js +35 -4
- package/dist/base/element.d.ts +8 -1
- package/dist/base/element.js +7 -2
- package/dist/button/button.d.ts +17 -2
- package/dist/button/button.js +42 -8
- package/dist/composition/builtins.d.ts +623 -1
- package/dist/composition/builtins.js +232 -4
- package/dist/date/calendar.d.ts +3 -0
- package/dist/date/calendar.js +8 -2
- package/dist/date/date-field.d.ts +23 -3
- package/dist/date/date-field.js +77 -9
- package/dist/date/dates.d.ts +10 -2
- package/dist/date/dates.js +23 -3
- package/dist/dialog/config.d.ts +4 -0
- package/dist/dialog/config.js +8 -0
- package/dist/dialog/dialog.d.ts +34 -6
- package/dist/dialog/dialog.js +151 -14
- package/dist/field/bound-field.d.ts +17 -1
- package/dist/field/bound-field.js +68 -7
- package/dist/field/check.js +1 -0
- package/dist/field/field.js +1 -1
- package/dist/field/input.d.ts +1 -0
- package/dist/field/input.js +2 -2
- package/dist/field/number-field.js +2 -2
- package/dist/filter/filter-builder.d.ts +7 -1
- package/dist/filter/filter-builder.js +8 -1
- package/dist/form/controls.d.ts +40 -8
- package/dist/form/controls.js +58 -15
- package/dist/form/custom-field.d.ts +1 -0
- package/dist/form/custom-field.js +23 -0
- package/dist/form/features.d.ts +27 -0
- package/dist/form/features.js +52 -0
- package/dist/form/form.d.ts +67 -7
- package/dist/form/form.js +267 -24
- package/dist/form/policy.d.ts +29 -0
- package/dist/form/policy.js +16 -0
- package/dist/grid/appearance.d.ts +365 -0
- package/dist/grid/appearance.js +814 -0
- package/dist/grid/features.d.ts +38 -0
- package/dist/grid/features.js +78 -0
- package/dist/grid/grid.d.ts +216 -4
- package/dist/grid/grid.js +1810 -308
- package/dist/grid/policy.d.ts +58 -0
- package/dist/grid/policy.js +17 -0
- package/dist/grid/view.d.ts +32 -2
- package/dist/grid/view.js +89 -4
- package/dist/index.d.ts +14 -11
- package/dist/index.js +2 -1
- package/dist/menu/config.d.ts +7 -0
- package/dist/menu/config.js +44 -0
- package/dist/menu/menu.d.ts +23 -0
- package/dist/menu/menu.js +69 -17
- package/dist/picker/picker.js +8 -3
- package/dist/section/accordion.d.ts +26 -0
- package/dist/section/accordion.js +86 -8
- package/dist/section/policy.d.ts +8 -0
- package/dist/section/policy.js +17 -0
- package/dist/section/section.d.ts +30 -0
- package/dist/section/section.js +106 -3
- package/dist/select/choice-element.d.ts +12 -0
- package/dist/select/choice-element.js +36 -0
- package/dist/select/choice.d.ts +12 -2
- package/dist/select/choice.js +93 -28
- package/dist/select/select.d.ts +12 -0
- package/dist/select/select.js +37 -1
- package/dist/styles/contract.d.ts +14 -0
- package/dist/styles/contract.js +15 -0
- package/dist/switch/switch.d.ts +16 -0
- package/dist/switch/switch.js +56 -6
- package/dist/tree/navigator.d.ts +3 -0
- package/dist/tree/navigator.js +26 -2
- package/dist/window/chrome.d.ts +5 -1
- package/dist/window/chrome.js +4 -3
- package/dist/window/config.d.ts +71 -0
- package/dist/window/config.js +40 -0
- package/dist/window/window.d.ts +51 -13
- package/dist/window/window.js +233 -38
- package/dist/yaml.d.ts +19 -0
- package/dist/yaml.js +57 -0
- package/package.json +10 -4
- package/styles/aster-ui.css +181 -10
- package/styles/base.css +14 -0
- package/styles/contract.ts +16 -0
- package/styles/elements.css +167 -10
- package/styles/fonts/OFL-bricolage-grotesque.txt +93 -0
- package/styles/fonts/OFL-fraunces.txt +93 -0
- package/styles/fonts/bricolage-grotesque-latin-opsz-normal.woff2 +0 -0
- package/styles/fonts/fraunces-latin-full-normal.woff2 +0 -0
- package/styles/fonts.css +17 -0
- package/styles/theme-harbour.css +5 -0
- package/styles/theme-lamplight.css +5 -0
package/NOTICE
CHANGED
|
@@ -3,3 +3,7 @@ Copyright 2026 Aster UI contributors
|
|
|
3
3
|
|
|
4
4
|
Aster UI code in this package is licensed under the Apache License, Version 2.0.
|
|
5
5
|
See LICENSE. Separately installed dependencies retain their respective licenses.
|
|
6
|
+
|
|
7
|
+
The font files in styles/fonts/ are licensed under the SIL Open Font License,
|
|
8
|
+
Version 1.1. Their copyright notices and license texts are in the
|
|
9
|
+
OFL-bricolage-grotesque.txt and OFL-fraunces.txt files beside them.
|
package/README.md
CHANGED
|
@@ -18,6 +18,12 @@ resolves npm modules and CSS imports. The package ships TypeScript declarations.
|
|
|
18
18
|
Its main entry registers browser elements and requires a DOM; use
|
|
19
19
|
`@getaster/data` for headless work. Package tooling requires Node 22 or later.
|
|
20
20
|
|
|
21
|
+
`@getaster/elements/styles/theme-lamplight.css` and
|
|
22
|
+
`@getaster/elements/styles/theme-harbour.css` each compose the base primitives,
|
|
23
|
+
element styles and one identity. Lamplight's entry also loads the packaged
|
|
24
|
+
Bricolage Grotesque and Fraunces Latin faces from
|
|
25
|
+
`@getaster/elements/styles/fonts.css`. Import one composed entry, not the parts.
|
|
26
|
+
|
|
21
27
|
## Connect a grid
|
|
22
28
|
|
|
23
29
|
With an OData service exposing a `Projects` entity set and JSON CSDL metadata:
|
|
@@ -52,10 +58,13 @@ keyboard interaction and semantic markup; application labels, focus flow and
|
|
|
52
58
|
accessibility still need testing in the completed application.
|
|
53
59
|
|
|
54
60
|
The package depends on Aster's data core, Lit HTML and Preact signals. Keep one
|
|
55
|
-
compatible copy of each shared runtime in your build. The
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
compatible copy of each shared runtime in your build. The YAML compiler is a
|
|
62
|
+
separate subpath, `@getaster/elements/yaml`, and is the only entry that loads
|
|
63
|
+
the `yaml` parser; a browser that imports a compiled definition never loads it.
|
|
64
|
+
The optional ECharts adapter accepts an application-supplied runtime; ECharts,
|
|
65
|
+
showcase data and the mock service are not bundled into this package. The
|
|
66
|
+
Lamplight font files and their SIL Open Font License texts are included under
|
|
67
|
+
`styles/fonts/`. There are no install scripts.
|
|
59
68
|
|
|
60
69
|
## Documentation and support
|
|
61
70
|
|
package/bin/aster-theme-check.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
|
-
// packages/elements/tools/
|
|
5
|
-
import { readFileSync } from "fs";
|
|
4
|
+
// packages/elements/tools/theme-check.ts
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { dirname, resolve as resolvePath } from "node:path";
|
|
6
7
|
|
|
7
8
|
// packages/elements/src/styles/contract.ts
|
|
8
9
|
var TOKENS = {
|
|
@@ -34,8 +35,23 @@ var TOKENS = {
|
|
|
34
35
|
var TOKEN_NAMES = Object.values(TOKENS).flat().map((t) => `--aster-${t}`);
|
|
35
36
|
var DENSITY = ["ctl", "ctl-tight", "pad-y", "row-y", "pad", "gap"];
|
|
36
37
|
var DENSITY_NAMES = DENSITY.map((t) => `--aster-${t}`);
|
|
38
|
+
var COMPONENT_VARS = {
|
|
39
|
+
form: ["label-width"],
|
|
40
|
+
grid: ["header-height", "toolbar-height", "row-min-height", "tree-indent", "summary-height"],
|
|
41
|
+
menu: ["cell-height", "icon-size"],
|
|
42
|
+
window: ["header-height"],
|
|
43
|
+
dialog: ["max-width"]
|
|
44
|
+
};
|
|
45
|
+
var COMPONENT_VAR_NAMES = Object.entries(COMPONENT_VARS).flatMap(([component, names]) => names.map((name) => `--aster-${component}-${name}`));
|
|
37
46
|
|
|
38
47
|
// packages/elements/tools/theme-check.ts
|
|
48
|
+
function readWithImports(file, seen = new Set) {
|
|
49
|
+
const path = resolvePath(file);
|
|
50
|
+
if (seen.has(path))
|
|
51
|
+
return "";
|
|
52
|
+
seen.add(path);
|
|
53
|
+
return readFileSync(path, "utf8").replace(/@import\s+(?:url\()?["']([^"']+)["']\)?[^;]*;/g, (rule, target) => target.startsWith(".") ? readWithImports(resolvePath(dirname(path), target), seen) : rule);
|
|
54
|
+
}
|
|
39
55
|
var PAIRS = [
|
|
40
56
|
["text", "surface", 4.5],
|
|
41
57
|
["text", "page", 4.5],
|
|
@@ -59,8 +75,23 @@ var PAIRS = [
|
|
|
59
75
|
["toast-text", "toast-bg", 4.5],
|
|
60
76
|
["toast-action", "toast-bg", 4.5]
|
|
61
77
|
];
|
|
62
|
-
function
|
|
78
|
+
function identityLayer(css) {
|
|
63
79
|
const text = css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
80
|
+
const start = /@layer\s+aster\.identity\s*\{/.exec(text)?.index;
|
|
81
|
+
if (start === undefined)
|
|
82
|
+
return text;
|
|
83
|
+
const open = text.indexOf("{", start);
|
|
84
|
+
let depth = 0;
|
|
85
|
+
for (let i = open;i < text.length; i++) {
|
|
86
|
+
if (text[i] === "{")
|
|
87
|
+
depth++;
|
|
88
|
+
else if (text[i] === "}" && --depth === 0)
|
|
89
|
+
return text.slice(open + 1, i);
|
|
90
|
+
}
|
|
91
|
+
return text.slice(open + 1);
|
|
92
|
+
}
|
|
93
|
+
function identities(css) {
|
|
94
|
+
const text = identityLayer(css);
|
|
64
95
|
const found = new Map;
|
|
65
96
|
for (const m of text.matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
66
97
|
const selector = m[1].trim();
|
|
@@ -298,7 +329,7 @@ if (files.length === 0) {
|
|
|
298
329
|
}
|
|
299
330
|
var failed = false;
|
|
300
331
|
for (const file of files) {
|
|
301
|
-
const found = identities(
|
|
332
|
+
const found = identities(readWithImports(file));
|
|
302
333
|
if (found.length === 0) {
|
|
303
334
|
console.log(`\u2717 ${file}: no :root rule with --aster- tokens`);
|
|
304
335
|
failed = true;
|
package/dist/base/element.d.ts
CHANGED
|
@@ -34,7 +34,14 @@ export declare abstract class AsterElement extends HTMLElement {
|
|
|
34
34
|
protected onDisconnect(cleanup: () => void): void;
|
|
35
35
|
/** Listens on `target` until the element disconnects. */
|
|
36
36
|
protected listen<K extends keyof WindowEventMap>(target: EventTarget, type: K, handler: (event: WindowEventMap[K]) => void, options?: AddEventListenerOptions): void;
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Dispatches a bubbling CustomEvent. Action events are cancelable by
|
|
39
|
+
* default; a notification that fires after the fact passes
|
|
40
|
+
* `{ cancelable: false }`.
|
|
41
|
+
*/
|
|
42
|
+
protected emit<T>(type: string, detail?: T, options?: {
|
|
43
|
+
readonly cancelable?: boolean;
|
|
44
|
+
}): boolean;
|
|
38
45
|
}
|
|
39
46
|
export declare function define(name: string, ctor: CustomElementConstructor): void;
|
|
40
47
|
/** Makes `scope` the page scope for `el` and everything inside it. */
|
package/dist/base/element.js
CHANGED
|
@@ -66,8 +66,13 @@ export class AsterElement extends HTMLElement {
|
|
|
66
66
|
target.addEventListener(type, handler, options);
|
|
67
67
|
this.onDisconnect(() => target.removeEventListener(type, handler, options));
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Dispatches a bubbling CustomEvent. Action events are cancelable by
|
|
71
|
+
* default; a notification that fires after the fact passes
|
|
72
|
+
* `{ cancelable: false }`.
|
|
73
|
+
*/
|
|
74
|
+
emit(type, detail, options = {}) {
|
|
75
|
+
return this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, cancelable: options.cancelable ?? true }));
|
|
71
76
|
}
|
|
72
77
|
#upgradeProperties() {
|
|
73
78
|
for (const name of Object.keys(this)) {
|
package/dist/button/button.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { AsterElement, type Bindable, type View } from "../base/element.ts";
|
|
2
|
+
/** A button's visual weight: neutral, accented, or destructive. */
|
|
3
|
+
export type ButtonTone = "secondary" | "primary" | "danger";
|
|
4
|
+
/** A button's size on the density scale. */
|
|
5
|
+
export type ButtonSize = "sm" | "md" | "lg";
|
|
2
6
|
/**
|
|
3
7
|
* A button with every state: rest, hover, pressed, focus, busy and
|
|
4
8
|
* disabled. Busy and confirmation swap the label in place; every label is
|
|
5
9
|
* stacked in one grid cell, so the width never changes. While busy, clicks
|
|
6
10
|
* are ignored and a submit doesn't fire.
|
|
7
11
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
12
|
+
* `disabled` is the native state: the button leaves the tab order and can't
|
|
13
|
+
* be pressed. Prefer `reason` for an advisory refusal: the button stays
|
|
14
|
+
* focusable, says why in its title, and its click is swallowed.
|
|
10
15
|
*/
|
|
11
16
|
export declare class Button extends AsterElement {
|
|
12
17
|
#private;
|
|
@@ -20,8 +25,18 @@ export declare class Button extends AsterElement {
|
|
|
20
25
|
set confirmLabel(v: string | undefined);
|
|
21
26
|
get busy(): Bindable<boolean>;
|
|
22
27
|
set busy(v: Bindable<boolean>);
|
|
28
|
+
/** Sugar for `tone`: `"primary"` or `"secondary"`. A `"danger"` tone reads back as secondary. */
|
|
23
29
|
get variant(): "secondary" | "primary";
|
|
24
30
|
set variant(v: "secondary" | "primary");
|
|
31
|
+
/** The button's visual weight. Default `"secondary"`. */
|
|
32
|
+
get tone(): ButtonTone;
|
|
33
|
+
set tone(v: ButtonTone);
|
|
34
|
+
/** The button's size. Default `"md"`. */
|
|
35
|
+
get size(): ButtonSize;
|
|
36
|
+
set size(v: ButtonSize);
|
|
37
|
+
/** The native disabled state: out of the tab order, and no click or submit. Default `false`. */
|
|
38
|
+
get disabled(): boolean;
|
|
39
|
+
set disabled(v: boolean);
|
|
25
40
|
get type(): "button" | "submit";
|
|
26
41
|
set type(v: "button" | "submit");
|
|
27
42
|
get icon(): View;
|
package/dist/button/button.js
CHANGED
|
@@ -6,8 +6,9 @@ import { AsterElement, define, read } from "../base/element.js";
|
|
|
6
6
|
* stacked in one grid cell, so the width never changes. While busy, clicks
|
|
7
7
|
* are ignored and a submit doesn't fire.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* `disabled` is the native state: the button leaves the tab order and can't
|
|
10
|
+
* be pressed. Prefer `reason` for an advisory refusal: the button stays
|
|
11
|
+
* focusable, says why in its title, and its click is swallowed.
|
|
11
12
|
*/
|
|
12
13
|
export class Button extends AsterElement {
|
|
13
14
|
#label = this.prop("");
|
|
@@ -15,7 +16,9 @@ export class Button extends AsterElement {
|
|
|
15
16
|
#confirmLabel = this.prop(undefined);
|
|
16
17
|
#busy = this.prop(false);
|
|
17
18
|
#confirming = this.prop(false);
|
|
18
|
-
#
|
|
19
|
+
#tone = this.prop("secondary");
|
|
20
|
+
#size = this.prop("md");
|
|
21
|
+
#disabled = this.prop(false);
|
|
19
22
|
#type = this.prop("button");
|
|
20
23
|
#icon = this.prop(nothing);
|
|
21
24
|
#reason = this.prop(undefined);
|
|
@@ -46,11 +49,39 @@ export class Button extends AsterElement {
|
|
|
46
49
|
set busy(v) {
|
|
47
50
|
this.#busy.value = v;
|
|
48
51
|
}
|
|
52
|
+
/** Sugar for `tone`: `"primary"` or `"secondary"`. A `"danger"` tone reads back as secondary. */
|
|
49
53
|
get variant() {
|
|
50
|
-
return this.#
|
|
54
|
+
return this.#tone.value === "primary" ? "primary" : "secondary";
|
|
51
55
|
}
|
|
52
56
|
set variant(v) {
|
|
53
|
-
|
|
57
|
+
if (v !== "secondary" && v !== "primary")
|
|
58
|
+
throw new TypeError('variant must be "secondary" or "primary"');
|
|
59
|
+
this.#tone.value = v;
|
|
60
|
+
}
|
|
61
|
+
/** The button's visual weight. Default `"secondary"`. */
|
|
62
|
+
get tone() {
|
|
63
|
+
return this.#tone.value;
|
|
64
|
+
}
|
|
65
|
+
set tone(v) {
|
|
66
|
+
if (v !== "secondary" && v !== "primary" && v !== "danger")
|
|
67
|
+
throw new TypeError('tone must be "secondary", "primary" or "danger"');
|
|
68
|
+
this.#tone.value = v;
|
|
69
|
+
}
|
|
70
|
+
/** The button's size. Default `"md"`. */
|
|
71
|
+
get size() {
|
|
72
|
+
return this.#size.value;
|
|
73
|
+
}
|
|
74
|
+
set size(v) {
|
|
75
|
+
if (v !== "sm" && v !== "md" && v !== "lg")
|
|
76
|
+
throw new TypeError('size must be "sm", "md" or "lg"');
|
|
77
|
+
this.#size.value = v;
|
|
78
|
+
}
|
|
79
|
+
/** The native disabled state: out of the tab order, and no click or submit. Default `false`. */
|
|
80
|
+
get disabled() {
|
|
81
|
+
return this.#disabled.value;
|
|
82
|
+
}
|
|
83
|
+
set disabled(v) {
|
|
84
|
+
this.#disabled.value = v;
|
|
54
85
|
}
|
|
55
86
|
get type() {
|
|
56
87
|
return this.#type.value;
|
|
@@ -90,8 +121,11 @@ export class Button extends AsterElement {
|
|
|
90
121
|
const labels = [this.#label.value, this.#busyLabel.value, this.#confirmLabel.value];
|
|
91
122
|
const showing = busy && labels[1] ? 1 : confirming && labels[2] ? 2 : 0;
|
|
92
123
|
const reason = this.#reason.value;
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
const disabled = this.#disabled.value;
|
|
125
|
+
return html `<button class="aster-button" type=${this.#type.value} data-tone=${this.#tone.value}
|
|
126
|
+
data-variant=${this.#tone.value === "primary" ? "primary" : "secondary"} data-size=${this.#size.value}
|
|
127
|
+
?disabled=${disabled}
|
|
128
|
+
aria-busy=${busy ? "true" : "false"} aria-disabled=${reason && !disabled ? "true" : nothing} title=${reason ?? nothing}>
|
|
95
129
|
${this.#icon.value}
|
|
96
130
|
<span class="aster-label-swap">
|
|
97
131
|
${labels.map((l, i) => (l === undefined ? nothing : html `<span ?data-off=${i !== showing}>${l}</span>`))}
|
|
@@ -99,7 +133,7 @@ export class Button extends AsterElement {
|
|
|
99
133
|
</button>`;
|
|
100
134
|
}
|
|
101
135
|
#guard(e) {
|
|
102
|
-
if (read(this.#busy.peek()) || this.#reason.peek()) {
|
|
136
|
+
if (this.#disabled.peek() || read(this.#busy.peek()) || this.#reason.peek()) {
|
|
103
137
|
e.preventDefault();
|
|
104
138
|
e.stopImmediatePropagation();
|
|
105
139
|
}
|