@getaster/elements 0.1.0-preview.1 → 0.3.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/NOTICE CHANGED
@@ -1,10 +1,5 @@
1
- Aster UI
1
+ @getaster/elements
2
2
  Copyright 2026 Aster UI contributors
3
3
 
4
- Aster UI source and the separately supplied OData mock WebAssembly binary are
5
- licensed under the Apache License, Version 2.0. Third-party components retain
6
- their respective licenses. The binary's attribution inventory and license texts
7
- are supplied in packages/mock/wasm/; packages include those notices when shipped.
8
-
9
- Geist and IBM Plex Mono fonts retain their SIL Open Font License notices.
10
- ECharts is an optional separately loaded third-party runtime.
4
+ Aster UI code in this package is licensed under the Apache License, Version 2.0.
5
+ See LICENSE. Separately installed dependencies retain their respective licenses.
package/README.md CHANGED
@@ -1,7 +1,72 @@
1
1
  # @getaster/elements
2
2
 
3
- Aster UI elements.
3
+ Browser-native controls for metadata-driven enterprise applications: grids,
4
+ forms, pickers, filters, dashboards and workspaces. Controls share records and
5
+ edit state through `@getaster/data` and use CSS for layout and theming.
4
6
 
5
- Documentation: https://ui.getaster.now/docs/guide/library.html
7
+ Aster is pre-1.0; production API stability is not yet promised. Experimental
8
+ controls are published separately in `@getaster/elements-preview`.
6
9
 
7
- Licensed under Apache-2.0. See LICENSE and NOTICE.
10
+ ## Install
11
+
12
+ ```sh
13
+ npm install @getaster/data @getaster/elements
14
+ ```
15
+
16
+ Use a modern browser with custom elements and ES modules, plus a bundler that
17
+ resolves npm modules and CSS imports. The package ships TypeScript declarations.
18
+ Its main entry registers browser elements and requires a DOM; use
19
+ `@getaster/data` for headless work. Package tooling requires Node 22 or later.
20
+
21
+ ## Connect a grid
22
+
23
+ With an OData service exposing a `Projects` entity set and JSON CSDL metadata:
24
+
25
+ ```ts
26
+ import { DataContext, fetchTransport } from '@getaster/data';
27
+ import { Grid } from '@getaster/elements';
28
+ import '@getaster/elements/styles/aster-ui.css';
29
+
30
+ const ctx = await DataContext.connect(
31
+ fetchTransport('https://your-service.example/odata/')
32
+ );
33
+ const grid = new Grid();
34
+ grid.ctx = ctx;
35
+ grid.set = 'Projects';
36
+ grid.label = 'Projects';
37
+ grid.style.height = '24rem';
38
+ document.body.append(grid);
39
+ ```
40
+
41
+ Replace the endpoint and entity set with your own. Give a virtualized grid a
42
+ bounded height, and supply your application's theme tokens as described in the
43
+ [theming guide](https://ui.getaster.now/docs/guide/themes.html). When the view
44
+ closes, remove the element; separately owned data models remain the host's
45
+ responsibility.
46
+
47
+ ## Compose an application
48
+
49
+ Use a shared data context to connect a grid, form and selection. JavaScript and
50
+ YAML composition support reusable workspace definitions. Controls provide
51
+ keyboard interaction and semantic markup; application labels, focus flow and
52
+ accessibility still need testing in the completed application.
53
+
54
+ 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 optional ECharts
56
+ adapter accepts an application-supplied runtime; ECharts, showcase data, fonts
57
+ and the mock service are not bundled into this package. There are no install
58
+ scripts.
59
+
60
+ ## Documentation and support
61
+
62
+ - [Get started](https://ui.getaster.now/docs/guide/getting-started.html)
63
+ - [Connected views](https://ui.getaster.now/docs/guide/connected-views.html)
64
+ - [Workspace composition](https://ui.getaster.now/docs/guide/declarative-workspace.html)
65
+ - [API reference](https://ui.getaster.now/docs/reference/)
66
+ - [Interactive showcase](https://ui.getaster.now/showcase/)
67
+ - [Report a bug](https://github.com/GetAster/aster-ui/issues)
68
+
69
+ ## License
70
+
71
+ Apache-2.0. See the included `LICENSE` and package-specific `NOTICE`.
72
+ Separately installed dependencies retain their own licenses.
@@ -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(() => (this.#overflows.value = rail.scrollWidth > rail.clientWidth + 1));
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/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"]')?.scrollIntoView({ block: "nearest", inline: "nearest", behavior: "instant" });
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].scrollIntoView({ block: "nearest", inline: "nearest", behavior: "instant" });
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.1.0-preview.1",
3
+ "version": "0.3.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.1.0-preview.1",
14
+ "@getaster/data": "0.3.0",
15
15
  "@preact/signals-core": "1.14.4",
16
16
  "lit-html": "3.3.3"
17
17
  },
@@ -24,6 +24,18 @@
24
24
  "url": "git+https://github.com/GetAster/aster-ui.git",
25
25
  "directory": "packages/elements"
26
26
  },
27
+ "description": "Browser-native grids, forms and workspace controls backed by shared Aster data models.",
28
+ "homepage": "https://ui.getaster.now/docs/guide/getting-started.html",
29
+ "bugs": {
30
+ "url": "https://github.com/GetAster/aster-ui/issues"
31
+ },
32
+ "keywords": [
33
+ "web-components",
34
+ "odata",
35
+ "grid",
36
+ "forms",
37
+ "typescript"
38
+ ],
27
39
  "types": "./dist/index.d.ts",
28
40
  "publishConfig": {
29
41
  "access": "public"
@@ -462,6 +462,10 @@
462
462
  .aster-window-bar button:hover { background: var(--aster-accent-soft); color: var(--aster-text); }
463
463
  .aster-window-bar button:focus-visible { outline: 2px solid var(--aster-focus); outline-offset: -2px; }
464
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
+ }
465
469
  .aster-window-body { flex: 1; min-height: 0; overflow: auto; padding: var(--aster-pad) 14px; }
466
470
  /* Dashboard geometry stays in CSS; stored sizes are column/row intent. */
467
471
  aster-dashboard { display: block; min-width: 0; container-type: inline-size; }
@@ -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; }