@scion/components 22.5.0 → 22.7.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.
Files changed (39) hide show
  1. package/_index.scss +32 -88
  2. package/design/components/_scion-component-dark-tokens.scss +15 -0
  3. package/design/components/_scion-component-light-tokens.scss +15 -0
  4. package/fesm2022/scion-components-common.mjs +156 -5
  5. package/fesm2022/scion-components-common.mjs.map +1 -1
  6. package/fesm2022/scion-components-dimension.mjs +3 -3
  7. package/fesm2022/scion-components-dimension.mjs.map +1 -1
  8. package/fesm2022/scion-components-icon.mjs +134 -98
  9. package/fesm2022/scion-components-icon.mjs.map +1 -1
  10. package/fesm2022/scion-components-menu.mjs +58 -51
  11. package/fesm2022/scion-components-menu.mjs.map +1 -1
  12. package/fesm2022/scion-components-sashbox.mjs +1 -1
  13. package/fesm2022/scion-components-sashbox.mjs.map +1 -1
  14. package/fesm2022/scion-components-splitter.mjs +1 -1
  15. package/fesm2022/scion-components-splitter.mjs.map +1 -1
  16. package/fesm2022/scion-components-table.mjs +1544 -1008
  17. package/fesm2022/scion-components-table.mjs.map +1 -1
  18. package/fesm2022/scion-components-text.mjs +83 -40
  19. package/fesm2022/scion-components-text.mjs.map +1 -1
  20. package/fesm2022/scion-components-throbber.mjs +1 -1
  21. package/fesm2022/scion-components-throbber.mjs.map +1 -1
  22. package/fesm2022/scion-components-tree.mjs +306 -0
  23. package/fesm2022/scion-components-tree.mjs.map +1 -0
  24. package/fesm2022/scion-components-viewport.mjs +31 -18
  25. package/fesm2022/scion-components-viewport.mjs.map +1 -1
  26. package/package.json +6 -2
  27. package/tree/package.json +4 -0
  28. package/types/scion-components-common.d.ts +111 -4
  29. package/types/scion-components-icon.d.ts +42 -15
  30. package/types/scion-components-menu.d.ts +7 -2
  31. package/types/scion-components-sashbox.d.ts +1 -1
  32. package/types/scion-components-splitter.d.ts +1 -1
  33. package/types/scion-components-table.d.ts +1112 -300
  34. package/types/scion-components-text.d.ts +6 -5
  35. package/types/scion-components-throbber.d.ts +1 -1
  36. package/types/scion-components-tree.d.ts +559 -0
  37. package/types/scion-components-viewport.d.ts +20 -11
  38. package/viewport/scrollbar/_scrollbar.scss +12 -0
  39. package/design/icons/_scion-icon-font.scss +0 -50
@@ -0,0 +1,306 @@
1
+ import * as i0 from '@angular/core';
2
+ import { assertNotInReactiveContext, assertInInjectionContext, inject, Injector, runInInjectionContext, DestroyRef, input, output, createComponent, inputBinding, computed, outputBinding, ElementRef, EnvironmentInjector, ApplicationRef, Component } from '@angular/core';
3
+ import { ɵSciTable as _SciTable, SciTableComponent, provideTableDatasource, ɵprovideTableDatasource as _provideTableDatasource } from '@scion/components/table';
4
+
5
+ /*
6
+ * Copyright (c) 2018-2026 Swiss Federal Railways
7
+ *
8
+ * This program and the accompanying materials are made
9
+ * available under the terms of the Eclipse Public License 2.0
10
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
11
+ *
12
+ * SPDX-License-Identifier: EPL-2.0
13
+ */
14
+ class ɵSciTree {
15
+ activeItem;
16
+ selectedItems;
17
+ selectable;
18
+ _table;
19
+ constructor(descriptor) {
20
+ const tableDescriptor = {
21
+ datasource: descriptor.datasource,
22
+ selectable: descriptor.selectable,
23
+ sortable: false,
24
+ resizable: false,
25
+ showHeader: false,
26
+ rowActions: descriptor.nodeActions,
27
+ rowBindings: (bindings, item, index) => descriptor.nodeBindings?.(bindings, item, index),
28
+ bufferSize: descriptor.bufferSize,
29
+ pageSize: descriptor.pageSize,
30
+ trackBy: descriptor.trackBy,
31
+ columns: table => {
32
+ if (typeof descriptor.label === 'function') {
33
+ return table.addStringColumn({
34
+ value: descriptor.label,
35
+ filterable: descriptor.matcher ? { matcher: descriptor.matcher } : undefined,
36
+ });
37
+ }
38
+ if ('component' in descriptor.label) {
39
+ return table.addComponentColumn({
40
+ component: descriptor.label.component,
41
+ padding: descriptor.label.padding,
42
+ filterable: descriptor.matcher ? { matcher: descriptor.matcher } : undefined,
43
+ });
44
+ }
45
+ if ('template' in descriptor.label) {
46
+ return table.addTemplateColumn({
47
+ template: descriptor.label.template,
48
+ padding: descriptor.label.padding,
49
+ filterable: descriptor.matcher ? { matcher: descriptor.matcher } : undefined,
50
+ });
51
+ }
52
+ throw Error('[TreeConfigurationError] Tree label must be `string`, `SciTreeNodeComponentDescriptor`, or `SciTreeNodeTemplateDescriptor`.');
53
+ },
54
+ };
55
+ this._table = new _SciTable({ ...tableDescriptor, type: 'tree' });
56
+ this.activeItem = this._table.activeItem;
57
+ this.selectedItems = this._table.selectedItems;
58
+ this.selectable = this._table.selectable;
59
+ }
60
+ get table() {
61
+ return this._table;
62
+ }
63
+ filter(text) {
64
+ this._table.filter(text);
65
+ }
66
+ select(ids) {
67
+ this._table.select(ids);
68
+ }
69
+ expandAll() {
70
+ this._table.expandAll();
71
+ }
72
+ collapseAll() {
73
+ this._table.collapseAll();
74
+ }
75
+ dispose() {
76
+ this._table.dispose();
77
+ }
78
+ }
79
+
80
+ /*
81
+ * Copyright (c) 2018-2026 Swiss Federal Railways
82
+ *
83
+ * This program and the accompanying materials are made
84
+ * available under the terms of the Eclipse Public License 2.0
85
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
86
+ *
87
+ * SPDX-License-Identifier: EPL-2.0
88
+ */
89
+ function tree(descriptor) {
90
+ assertNotInReactiveContext(tree, 'Call tree in a non-reactive (non-tracking) context, such as within the untracked() function.');
91
+ if (!descriptor.injector) {
92
+ assertInInjectionContext(tree);
93
+ }
94
+ const injector = descriptor.injector ?? inject(Injector);
95
+ const sciTree = runInInjectionContext(injector, () => new ɵSciTree(descriptor));
96
+ injector.get(DestroyRef).onDestroy(() => sciTree.dispose());
97
+ return sciTree;
98
+ }
99
+
100
+ /*
101
+ * Copyright (c) 2018-2026 Swiss Federal Railways
102
+ *
103
+ * This program and the accompanying materials are made
104
+ * available under the terms of the Eclipse Public License 2.0
105
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
106
+ *
107
+ * SPDX-License-Identifier: EPL-2.0
108
+ */
109
+ /**
110
+ * Provides a tree to display a tree structure.
111
+ *
112
+ * ### Usage
113
+ *
114
+ * Create a tree using the `tree()` function, passing a descriptor to configure the datasource and the display of node labels.
115
+ *
116
+ * Use the {@link provideTreeDatasource} function to create a datasource, passing a signal containing the root items and a
117
+ * function that returns the children of a given item.
118
+ *
119
+ * ```ts
120
+ * import {SciTreeComponent, tree, provideTreeDatasource} from '@scion/components/tree';
121
+ * import {httpResource} from '@angular/common/http';
122
+ *
123
+ * // Load data to display in the tree.
124
+ * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});
125
+ *
126
+ * // Create the tree and pass data.
127
+ * const fileTree = tree({
128
+ * label: file => file.name,
129
+ * datasource: provideTreeDatasource(files.value, file => file.children),
130
+ * });
131
+ * ```
132
+ *
133
+ * In the HTML, bind the created tree instance to `<sci-tree>` and assign it a name.
134
+ * The name must start with the `tree:` prefix and is used to store user settings.
135
+ *
136
+ * ```html
137
+ * <sci-tree name="tree:files" [tree]="fileTree"/>
138
+ * ```
139
+ *
140
+ * ### Fixed Node Height
141
+ *
142
+ * All nodes in the tree must have equal height, which is `2em` by default. The height can be changed per tree using the CSS variable `--sci-tree-node-height`.
143
+ *
144
+ * ```scss
145
+ * sci-tree {
146
+ * --sci-tree-node-height: 30px;
147
+ * }
148
+ * ```
149
+ *
150
+ * ### Styling
151
+ *
152
+ * The appearance of the tree can be customized using the following CSS variables, either globally in the `:root` or at the tree level.
153
+ *
154
+ * - `--sci-tree-node-height`
155
+ * - `--sci-tree-node-indent`
156
+ * - `--sci-tree-node-background-color-hover`
157
+ * - `--sci-tree-node-background-color-selected`
158
+ * - `--sci-tree-node-border-radius`
159
+ * - `--sci-tree-node-outline-color`
160
+ * - `--sci-tree-node-outline-width`
161
+ * - `--sci-tree-node-outline-style`
162
+ * - `--sci-tree-node-action-background-color`
163
+ * - `--sci-tree-node-action-background-color-selected`
164
+ *
165
+ * @experimental since 22.7.0; API and behavior may change in any version without notice.
166
+ */
167
+ class SciTreeComponent {
168
+ /**
169
+ * Specifies a unique tree identifier, used as the key for storing user preferences.
170
+ */
171
+ name = input.required(/* @ts-ignore */
172
+ ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
173
+ /**
174
+ * Specifies the tree definition and datasource.
175
+ */
176
+ tree = input.required({ ...(ngDevMode ? { debugName: "tree" } : /* istanbul ignore next */ {}), transform: (tree) => tree });
177
+ /**
178
+ * Emits when the user double-clicks a node or presses `Enter` on selected nodes.
179
+ */
180
+ primaryAction = output();
181
+ constructor() {
182
+ this.attachVirtualTable();
183
+ }
184
+ /**
185
+ * Creates and attaches a {@link SciTableComponent} using this component as host.
186
+ */
187
+ attachVirtualTable() {
188
+ const componentRef = createComponent(SciTableComponent, {
189
+ elementInjector: inject(Injector),
190
+ environmentInjector: inject(EnvironmentInjector),
191
+ hostElement: inject(ElementRef).nativeElement,
192
+ bindings: [
193
+ inputBinding('name', computed(() => this.name())),
194
+ inputBinding('table', computed(() => this.tree().table)),
195
+ outputBinding('primaryAction', (event) => this.primaryAction.emit(event)),
196
+ ],
197
+ });
198
+ // Attach component to Angular component tree for change detection.
199
+ inject(ApplicationRef).attachView(componentRef.hostView);
200
+ // Destroy component when host is destroyed.
201
+ inject(DestroyRef).onDestroy(() => componentRef.destroy());
202
+ }
203
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
204
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: SciTreeComponent, isStandalone: true, selector: "sci-tree", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { primaryAction: "primaryAction" }, ngImport: i0, template: '', isInline: true, styles: [":host{--sci-table-cell-padding-inline: 0px;--sci-table-row-height: var(--sci-tree-node-height);--sci-table-row-indent: var(--sci-tree-node-indent);--sci-table-row-background-color-hover: var(--sci-tree-node-background-color-hover);--sci-table-row-background-color-selected: var(--sci-tree-node-background-color-selected);--sci-table-row-border-radius: var(--sci-tree-node-border-radius);--sci-table-row-outline-color: var(--sci-tree-node-outline-color);--sci-table-row-outline-width: var(--sci-tree-node-outline-width);--sci-table-row-outline-style: var(--sci-tree-node-outline-style);--sci-table-row-action-background-color: var(--sci-tree-node-action-background-color);--sci-table-row-action-background-color-selected: var(--sci-tree-node-action-background-color-selected)}\n"] });
205
+ }
206
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTreeComponent, decorators: [{
207
+ type: Component,
208
+ args: [{ selector: 'sci-tree', template: '', styles: [":host{--sci-table-cell-padding-inline: 0px;--sci-table-row-height: var(--sci-tree-node-height);--sci-table-row-indent: var(--sci-tree-node-indent);--sci-table-row-background-color-hover: var(--sci-tree-node-background-color-hover);--sci-table-row-background-color-selected: var(--sci-tree-node-background-color-selected);--sci-table-row-border-radius: var(--sci-tree-node-border-radius);--sci-table-row-outline-color: var(--sci-tree-node-outline-color);--sci-table-row-outline-width: var(--sci-tree-node-outline-width);--sci-table-row-outline-style: var(--sci-tree-node-outline-style);--sci-table-row-action-background-color: var(--sci-tree-node-action-background-color);--sci-table-row-action-background-color-selected: var(--sci-tree-node-action-background-color-selected)}\n"] }]
209
+ }], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: true }] }], primaryAction: [{ type: i0.Output, args: ["primaryAction"] }] } });
210
+
211
+ /**
212
+ * Provides an in-memory datasource for {@link SciTree} with built-in filtering.
213
+ *
214
+ * A datasource provides data to {@link SciTree}, passing each item to {@link SciTreeDescriptor.label} for display.
215
+ *
216
+ * This datasource requires all data to be loaded upfront. It invokes the passed child selector function for each item
217
+ * to construct the tree. Data is filtered in memory.
218
+ *
219
+ * If using custom labels, a {@link SciTreeDescriptor.matcher} is required to support {@link SciTree.filter}.
220
+ *
221
+ * For large datasets requiring pagination or server-side filtering and sorting, prefer implementing a custom datasource using {@link ɵprovideTreeDatasource}.
222
+ *
223
+ * IMPORTANT: Custom datasource support is experimental and currently exposed only as `ɵprovideTableDatasource`. The API and behavior may change in any version without notice.
224
+ *
225
+ * @example - Usage
226
+ * ```ts
227
+ * import {tree, provideTreeDatasource} from '@scion/components/tree';
228
+ * import {httpResource} from '@angular/common/http';
229
+ *
230
+ * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});
231
+ *
232
+ * const fileTree = tree({
233
+ * label: file => file.name,
234
+ * datasource: provideTreeDatasource(files.value, file => file.children),
235
+ * });
236
+ * ```
237
+ *
238
+ * @param root - Provides the root items to display in the tree.
239
+ * @param children - Function returning an item's children, or an empty array if the item has no children or is a leaf.
240
+ * Called eagerly for each item when initializing the tree, inside a reactive context that re-evaluates when tracked signals change.
241
+ *
242
+ * @see SciTreeDescriptor.datasource
243
+ */
244
+ function provideTreeDatasource(root, children) {
245
+ return provideTableDatasource(root, children);
246
+ }
247
+ /**
248
+ * Provides a datasource for {@link SciTree}.
249
+ *
250
+ * A datasource provides data to {@link SciTree}, passing each item to {@link SciTreeDescriptor.label} for display.
251
+ * Filtering and sorting must be implemented by the datasource based on the provided filter and sort criteria.
252
+ *
253
+ * A tree is a hierarchical structure of nodes, represented by the datasource as a flat list of tree nodes.
254
+ * Each node references an item and its parent by ID, without containing the item itself. The tree requests items on demand when scrolled into view,
255
+ * allowing large datasets to be displayed without loading all items upfront. If the entire dataset is available locally, use {@link provideTreeDatasource}.
256
+ *
257
+ * {@link SciTree} constructs the tree from the returned nodes, starting with root nodes (nodes without a parent) and appending child nodes in array order.
258
+ * Child nodes can appear anywhere in the nodes list; they do not need to follow their parent.
259
+ *
260
+ * @example - Usage
261
+ * ```ts
262
+ * import {tree, provideTreeDatasource} from '@scion/components/tree';
263
+ * import {SciTreeNode} from '@scion/components/table';
264
+ * import {httpResource} from '@angular/common/http';
265
+ * import {toObservable} from '@angular/core/rxjs-interop';
266
+ *
267
+ * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});
268
+ *
269
+ * const fileTree = tree<File, string>({
270
+ * label: file => file.name,
271
+ * datasource: provideTreeDatasource({
272
+ * getTreeNodes: query => toObservable(httpResource<SciTreeNode<string>[]>(() => `/api/files?filter=${query.filter}`, {defaultValue: []}).value),
273
+ * getItems: guids => toObservable(httpResource<File[]>(() => ({url: `/api/files`, params: {guids}}), {defaultValue: []}).value),
274
+ * }),
275
+ * trackBy: file => file.guid,
276
+ * });
277
+ * ```
278
+ *
279
+ * @param datasource - Specifies the datasource.
280
+ *
281
+ * @docs-private Not public API. For internal use only.
282
+ * @experimental since 22.7.0; API and behavior may change in any version without notice.
283
+ */
284
+ function ɵprovideTreeDatasource(datasource) {
285
+ return _provideTableDatasource({
286
+ getTreeTableNodes: query => datasource.getTreeNodes({ filter: query.tableFilter }),
287
+ getItems: ids => datasource.getItems(ids),
288
+ });
289
+ }
290
+
291
+ /*
292
+ * Copyright (c) 2018-2026 Swiss Federal Railways
293
+ *
294
+ * This program and the accompanying materials are made
295
+ * available under the terms of the Eclipse Public License 2.0
296
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
297
+ *
298
+ * SPDX-License-Identifier: EPL-2.0
299
+ */
300
+
301
+ /**
302
+ * Generated bundle index. Do not edit.
303
+ */
304
+
305
+ export { SciTreeComponent, provideTreeDatasource, tree, ɵprovideTreeDatasource };
306
+ //# sourceMappingURL=scion-components-tree.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scion-components-tree.mjs","sources":["../../../../projects/scion/components/tree/src/ɵtree.model.ts","../../../../projects/scion/components/tree/src/tree.factory.ts","../../../../projects/scion/components/tree/src/tree.component.ts","../../../../projects/scion/components/tree/src/tree-datasource.ts","../../../../projects/scion/components/tree/src/public_api.ts","../../../../projects/scion/components/tree/src/scion-components-tree.ts"],"sourcesContent":["/*\n * Copyright (c) 2018-2026 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {SciTree, SciTreeDescriptor} from './tree.model';\nimport {SciTableDescriptor, SciTableRowBindingFactory, ɵSciTable, ɵSciTableRowBindingFactory} from '@scion/components/table';\nimport {Signal, WritableSignal} from '@angular/core';\nimport {MaybeArray} from '@scion/toolkit/types';\n\nexport class ɵSciTree<T = unknown, ID = T> implements SciTree<ID> {\n\n public readonly activeItem: Signal<ID | undefined>;\n public readonly selectedItems: Signal<Array<ID>>;\n public readonly selectable: WritableSignal<'single' | 'multi' | false>;\n\n private readonly _table: ɵSciTable<T, ID>;\n\n constructor(descriptor: SciTreeDescriptor<T, ID>) {\n const tableDescriptor: SciTableDescriptor<T, ID> = {\n datasource: descriptor.datasource,\n selectable: descriptor.selectable,\n sortable: false,\n resizable: false,\n showHeader: false,\n rowActions: descriptor.nodeActions,\n rowBindings: (bindings: SciTableRowBindingFactory, item, index) => descriptor.nodeBindings?.((bindings as ɵSciTableRowBindingFactory), item, index),\n bufferSize: descriptor.bufferSize,\n pageSize: descriptor.pageSize,\n trackBy: descriptor.trackBy,\n columns: table => {\n if (typeof descriptor.label === 'function') {\n return table.addStringColumn({\n value: descriptor.label,\n filterable: descriptor.matcher ? {matcher: descriptor.matcher} : undefined,\n });\n }\n\n if ('component' in descriptor.label) {\n return table.addComponentColumn({\n component: descriptor.label.component,\n padding: descriptor.label.padding,\n filterable: descriptor.matcher ? {matcher: descriptor.matcher} : undefined,\n });\n }\n\n if ('template' in descriptor.label) {\n return table.addTemplateColumn({\n template: descriptor.label.template,\n padding: descriptor.label.padding,\n filterable: descriptor.matcher ? {matcher: descriptor.matcher} : undefined,\n });\n }\n\n throw Error('[TreeConfigurationError] Tree label must be `string`, `SciTreeNodeComponentDescriptor`, or `SciTreeNodeTemplateDescriptor`.');\n },\n };\n\n this._table = new ɵSciTable<T, ID>({...tableDescriptor, type: 'tree'});\n\n this.activeItem = this._table.activeItem;\n this.selectedItems = this._table.selectedItems;\n this.selectable = this._table.selectable;\n }\n\n public get table(): ɵSciTable<T, ID> {\n return this._table;\n }\n\n public filter(text: string | null): void {\n this._table.filter(text);\n }\n\n public select(ids: MaybeArray<ID>): void {\n this._table.select(ids);\n }\n\n public expandAll(): void {\n this._table.expandAll();\n }\n\n public collapseAll(): void {\n this._table.collapseAll();\n }\n\n public dispose(): void {\n this._table.dispose();\n }\n}\n","/*\n * Copyright (c) 2018-2026 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {assertInInjectionContext, assertNotInReactiveContext, DestroyRef, inject, Injector, runInInjectionContext} from '@angular/core';\nimport {SciTree, SciTreeDescriptor} from './tree.model';\nimport {ɵSciTree} from './ɵtree.model';\n\n/**\n * Creates a tree for displaying a tree structure in {@link SciTreeComponent}.\n *\n * Pass a descriptor to configure the datasource and the display of node labels.\n *\n * Use the {@link provideTreeDatasource} function to create a datasource, passing a signal containing the root items and a\n * function that returns the children of a given item.\n *\n * ```ts\n * import {SciTreeComponent, tree, provideTreeDatasource} from '@scion/components/tree';\n * import {httpResource} from '@angular/common/http';\n *\n * // Load data to display in the tree.\n * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});\n *\n * // Create the tree and pass data.\n * const fileTree = tree({\n * label: file => file.name,\n * datasource: provideTreeDatasource(files.value, file => file.children),\n * });\n * ```\n *\n * In the HTML, bind the created tree instance to `<sci-tree>`.\n *\n * ```html\n * <sci-tree name=\"tree:files\" [tree]=\"fileTree\"/>\n * ```\n *\n * Callback functions:\n * - Run in a reactive context and re-evaluate when tracked signals change.\n * - Can call `inject` to get required dependencies. The injection context is destroyed each time the function is called anew.\n *\n * This function:\n * - Must be called within an injection context, or an explicit {@link Injector} passed.\n * - Must be called in a non-reactive (non-tracking) context.\n *\n * @see SciTreeComponent\n * @experimental since 22.7.0; API and behavior may change in any version without notice.\n *\n * @param descriptor - Configures the tree. Requires a datasource and node label function.\n * @return Handle to bind to `<sci-tree>` and interact with the tree.\n */\nexport function tree<T>(descriptor: SciTreeDescriptor<T>): SciTree<T>;\n\n/**\n * Creates a tree for displaying a tree structure in {@link SciTreeComponent}.\n *\n * Pass a descriptor to configure the datasource and the display of node labels.\n *\n * Use the {@link provideTreeDatasource} function to create a datasource, passing a signal containing the root items and a\n * function that returns the children of a given item.\n *\n * ```ts\n * import {SciTreeComponent, tree, provideTreeDatasource} from '@scion/components/tree';\n * import {httpResource} from '@angular/common/http';\n *\n * // Load data to display in the tree.\n * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});\n *\n * // Create the tree and pass data.\n * const fileTree = tree({\n * label: file => file.name,\n * datasource: provideTreeDatasource(files.value, file => file.children),\n * });\n * ```\n *\n * In the HTML, bind the created tree instance to `<sci-tree>`.\n *\n * ```html\n * <sci-tree name=\"tree:files\" [tree]=\"fileTree\"/>\n * ```\n *\n * Callback functions:\n * - Run in a reactive context and re-evaluate when tracked signals change.\n * - Can call `inject` to get required dependencies. The injection context is destroyed each time the function is called anew.\n *\n * This function:\n * - Must be called within an injection context, or an explicit {@link Injector} passed.\n * - Must be called in a non-reactive (non-tracking) context.\n *\n * @see SciTreeComponent\n * @experimental since 22.7.0; API and behavior may change in any version without notice.\n *\n * @param descriptor - Configures the tree. Requires a datasource and node label function.\n * @return Handle to bind to `<sci-tree>` and interact with the tree.\n */\nexport function tree<T, ID = T>(descriptor: SciTreeDescriptor<T, ID> & {trackBy: (item: T) => ID}): SciTree<ID>;\n\nexport function tree<T, ID = T>(descriptor: SciTreeDescriptor<T, ID>): SciTree<ID> {\n assertNotInReactiveContext(tree, 'Call tree in a non-reactive (non-tracking) context, such as within the untracked() function.');\n\n if (!descriptor.injector) {\n assertInInjectionContext(tree);\n }\n\n const injector = descriptor.injector ?? inject(Injector);\n const sciTree = runInInjectionContext(injector, () => new ɵSciTree(descriptor));\n injector.get(DestroyRef).onDestroy(() => sciTree.dispose());\n\n return sciTree;\n}\n","/*\n * Copyright (c) 2018-2026 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {ApplicationRef, Component, computed, createComponent, DestroyRef, ElementRef, EnvironmentInjector, inject, Injector, input, inputBinding, output, outputBinding} from '@angular/core';\nimport {SciTree, SciTreeEvent} from './tree.model';\nimport {ɵSciTree} from './ɵtree.model';\nimport {SciTableComponent, SciTableEvent} from '@scion/components/table';\n\n/**\n * Provides a tree to display a tree structure.\n *\n * ### Usage\n *\n * Create a tree using the `tree()` function, passing a descriptor to configure the datasource and the display of node labels.\n *\n * Use the {@link provideTreeDatasource} function to create a datasource, passing a signal containing the root items and a\n * function that returns the children of a given item.\n *\n * ```ts\n * import {SciTreeComponent, tree, provideTreeDatasource} from '@scion/components/tree';\n * import {httpResource} from '@angular/common/http';\n *\n * // Load data to display in the tree.\n * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});\n *\n * // Create the tree and pass data.\n * const fileTree = tree({\n * label: file => file.name,\n * datasource: provideTreeDatasource(files.value, file => file.children),\n * });\n * ```\n *\n * In the HTML, bind the created tree instance to `<sci-tree>` and assign it a name.\n * The name must start with the `tree:` prefix and is used to store user settings.\n *\n * ```html\n * <sci-tree name=\"tree:files\" [tree]=\"fileTree\"/>\n * ```\n *\n * ### Fixed Node Height\n *\n * All nodes in the tree must have equal height, which is `2em` by default. The height can be changed per tree using the CSS variable `--sci-tree-node-height`.\n *\n * ```scss\n * sci-tree {\n * --sci-tree-node-height: 30px;\n * }\n * ```\n *\n * ### Styling\n *\n * The appearance of the tree can be customized using the following CSS variables, either globally in the `:root` or at the tree level.\n *\n * - `--sci-tree-node-height`\n * - `--sci-tree-node-indent`\n * - `--sci-tree-node-background-color-hover`\n * - `--sci-tree-node-background-color-selected`\n * - `--sci-tree-node-border-radius`\n * - `--sci-tree-node-outline-color`\n * - `--sci-tree-node-outline-width`\n * - `--sci-tree-node-outline-style`\n * - `--sci-tree-node-action-background-color`\n * - `--sci-tree-node-action-background-color-selected`\n *\n * @experimental since 22.7.0; API and behavior may change in any version without notice.\n */\n@Component({\n selector: 'sci-tree',\n template: '',\n styleUrl: './tree.component.scss',\n})\nexport class SciTreeComponent<T = unknown, ID = T> {\n\n /**\n * Specifies a unique tree identifier, used as the key for storing user preferences.\n */\n public readonly name = input.required<`tree:${string}`>();\n\n /**\n * Specifies the tree definition and datasource.\n */\n public readonly tree = input.required({transform: (tree: SciTree<ID>) => tree as ɵSciTree<T, ID>});\n\n /**\n * Emits when the user double-clicks a node or presses `Enter` on selected nodes.\n */\n public readonly primaryAction = output<SciTreeEvent<ID>>();\n\n constructor() {\n this.attachVirtualTable();\n }\n\n /**\n * Creates and attaches a {@link SciTableComponent} using this component as host.\n */\n private attachVirtualTable(): void {\n const componentRef = createComponent(SciTableComponent, {\n elementInjector: inject(Injector),\n environmentInjector: inject(EnvironmentInjector),\n hostElement: inject(ElementRef).nativeElement as HTMLElement,\n bindings: [\n inputBinding('name', computed(() => this.name())),\n inputBinding('table', computed(() => this.tree().table)),\n outputBinding('primaryAction', (event: SciTableEvent<ID>) => this.primaryAction.emit(event)),\n ],\n });\n\n // Attach component to Angular component tree for change detection.\n inject(ApplicationRef).attachView(componentRef.hostView);\n\n // Destroy component when host is destroyed.\n inject(DestroyRef).onDestroy(() => componentRef.destroy());\n }\n}\n","import {provideTableDatasource, SciTableDatasourceProvider, SciTreeTableNode, ɵprovideTableDatasource} from '@scion/components/table';\nimport {MaybeAsync} from '@scion/toolkit/types';\nimport {Signal} from '@angular/core';\n\nexport type SciTreeDatasourceProvider<T, ID = never> = SciTableDatasourceProvider<T, ID>;\nexport type SciTreeNode<T> = SciTreeTableNode<T>;\n\n/**\n * Provides an in-memory datasource for {@link SciTree} with built-in filtering.\n *\n * A datasource provides data to {@link SciTree}, passing each item to {@link SciTreeDescriptor.label} for display.\n *\n * This datasource requires all data to be loaded upfront. It invokes the passed child selector function for each item\n * to construct the tree. Data is filtered in memory.\n *\n * If using custom labels, a {@link SciTreeDescriptor.matcher} is required to support {@link SciTree.filter}.\n *\n * For large datasets requiring pagination or server-side filtering and sorting, prefer implementing a custom datasource using {@link ɵprovideTreeDatasource}.\n *\n * IMPORTANT: Custom datasource support is experimental and currently exposed only as `ɵprovideTableDatasource`. The API and behavior may change in any version without notice.\n *\n * @example - Usage\n * ```ts\n * import {tree, provideTreeDatasource} from '@scion/components/tree';\n * import {httpResource} from '@angular/common/http';\n *\n * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});\n *\n * const fileTree = tree({\n * label: file => file.name,\n * datasource: provideTreeDatasource(files.value, file => file.children),\n * });\n * ```\n *\n * @param root - Provides the root items to display in the tree.\n * @param children - Function returning an item's children, or an empty array if the item has no children or is a leaf.\n * Called eagerly for each item when initializing the tree, inside a reactive context that re-evaluates when tracked signals change.\n *\n * @see SciTreeDescriptor.datasource\n */\nexport function provideTreeDatasource<T>(root: Signal<T[]>, children: (item: T) => T[]): SciTreeDatasourceProvider<T> {\n return provideTableDatasource(root, children);\n}\n\n/**\n * Provides a datasource for {@link SciTree}.\n *\n * A datasource provides data to {@link SciTree}, passing each item to {@link SciTreeDescriptor.label} for display.\n * Filtering and sorting must be implemented by the datasource based on the provided filter and sort criteria.\n *\n * A tree is a hierarchical structure of nodes, represented by the datasource as a flat list of tree nodes.\n * Each node references an item and its parent by ID, without containing the item itself. The tree requests items on demand when scrolled into view,\n * allowing large datasets to be displayed without loading all items upfront. If the entire dataset is available locally, use {@link provideTreeDatasource}.\n *\n * {@link SciTree} constructs the tree from the returned nodes, starting with root nodes (nodes without a parent) and appending child nodes in array order.\n * Child nodes can appear anywhere in the nodes list; they do not need to follow their parent.\n *\n * @example - Usage\n * ```ts\n * import {tree, provideTreeDatasource} from '@scion/components/tree';\n * import {SciTreeNode} from '@scion/components/table';\n * import {httpResource} from '@angular/common/http';\n * import {toObservable} from '@angular/core/rxjs-interop';\n *\n * const files = httpResource<File[]>(() => '/api/files', {defaultValue: []});\n *\n * const fileTree = tree<File, string>({\n * label: file => file.name,\n * datasource: provideTreeDatasource({\n * getTreeNodes: query => toObservable(httpResource<SciTreeNode<string>[]>(() => `/api/files?filter=${query.filter}`, {defaultValue: []}).value),\n * getItems: guids => toObservable(httpResource<File[]>(() => ({url: `/api/files`, params: {guids}}), {defaultValue: []}).value),\n * }),\n * trackBy: file => file.guid,\n * });\n * ```\n *\n * @param datasource - Specifies the datasource.\n *\n * @docs-private Not public API. For internal use only.\n * @experimental since 22.7.0; API and behavior may change in any version without notice.\n */\nexport function ɵprovideTreeDatasource<T, ID>(datasource: SciTreeDatasource<T, ID>): SciTableDatasourceProvider<T, ID> {\n return ɵprovideTableDatasource({\n getTreeTableNodes: query => datasource.getTreeNodes({filter: query.tableFilter}),\n getItems: ids => datasource.getItems(ids),\n });\n}\n\nexport interface SciTreeDatasourceQuery {\n filter?: string;\n}\n\n/**\n * Represents a datasource for {@link SciTree}.\n *\n * A datasource provides data to {@link SciTree}, passing each item to {@link SciTreeDescriptor.label} for display.\n * Filtering and sorting must be implemented by the datasource based on the provided filter and sort criteria.\n *\n * A tree is a hierarchical structure of nodes, represented by the datasource as a flat list of tree nodes.\n * Each node references an item and its parent by ID, without containing the item itself. The tree requests items on demand when scrolled into view,\n * allowing large datasets to be displayed without loading all items upfront. If the entire dataset is available locally, use {@link provideTreeDatasource}.\n *\n * {@link SciTree} constructs the tree from the returned nodes, starting with root nodes (nodes without a parent) and appending child nodes in array order.\n * Child nodes can appear anywhere in the nodes list; they do not need to follow their parent.\n */\nexport interface SciTreeDatasource<T, ID> {\n\n /**\n * Returns a flat list of tree nodes matching the given filter and sort criteria.\n *\n * A tree node references an item and its parent by ID, without containing the item itself.\n *\n * Child nodes can appear anywhere in the list; they do not need to follow their parent. Siblings are added in the order they appear in the list.\n *\n * If a filter is set, return only the directly matching nodes (leaf or intermediate). Do not include their ancestors.\n */\n getTreeNodes(query: SciTreeDatasourceQuery): MaybeAsync<SciTreeNode<ID>[]>;\n\n /**\n * Resolves items for the specified IDs. Called as nodes scroll into view.\n */\n getItems(ids: ID[]): MaybeAsync<T[]>;\n}\n","/*\n * Copyright (c) 2018-2026 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nexport {tree} from './tree.factory';\nexport {SciTreeComponent} from './tree.component';\nexport {type SciTree, type SciTreeDescriptor, type SciTreeNodeContext} from './tree.model';\nexport {provideTreeDatasource, ɵprovideTreeDatasource, type SciTreeDatasourceQuery, type SciTreeDatasourceProvider, type SciTreeDatasource, type SciTreeNode} from './tree-datasource';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["ɵSciTable","ɵprovideTableDatasource"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, com
3
3
  import { coerceElement } from '@angular/cdk/coercion';
4
4
  import { fromEvent, race, tap, merge, finalize, timer, exhaustMap, of, concatWith, mergeWith, switchMap as switchMap$1, concat, map as map$1 } from 'rxjs';
5
5
  import { debounceTime, startWith, map, distinctUntilChanged, takeUntil, withLatestFrom, switchMap } from 'rxjs/operators';
6
- import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
6
+ import { toSignal, takeUntilDestroyed, rxResource } from '@angular/core/rxjs-interop';
7
7
  import { subscribeIn } from '@scion/toolkit/operators';
8
8
  import { fromResize$, fromMutation$ } from '@scion/toolkit/observable';
9
9
  import { isBetween, clamp } from '@scion/toolkit/util';
@@ -225,24 +225,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
225
225
  * SPDX-License-Identifier: EPL-2.0
226
226
  */
227
227
  /**
228
- * Renders a vertical or horizontal scrollbar.
228
+ * Renders a vertical or horizontal scrollbar to scroll an associated viewport.
229
229
  *
230
- * The scrollbar features the following functionality:
231
- * - allows to move the thumb by mouse
232
- * - enlarges the thumb if the mouse pointer is near the thumb
233
- * - allows paging on mousedown on the scroll track
230
+ * Usage:
231
+ * ```html
232
+ * <div class="viewport" #viewport>
233
+ * ...
234
+ * </div>
235
+ * <sci-scrollbar [viewport]="viewport"/>
236
+ * ```
237
+ *
238
+ * To hide the scrollbar when not hovering the associated viewport, set `opacity` to `0`. Transitions on `opacity` fade the scrollbar in and out.
239
+ *
240
+ * ```scss
241
+ * div.viewport:not(:hover) + sci-scrollbar {
242
+ * opacity: 0;
243
+ * }
244
+ * ```
234
245
  *
235
246
  * ### Styling:
236
247
  *
237
- * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.
248
+ * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `src/styles.scss`.
238
249
  * To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component.
239
250
  *
240
- * - --sci-scrollbar-color: Sets the color of the scrollbar.
251
+ * - --sci-scrollbar-color: Sets the color of the scrollbar.
241
252
  *
242
253
  * Example:
243
- *
244
- * ```css
245
- *
254
+ * ```scss
246
255
  * sci-scrollbar {
247
256
  * --sci-scrollbar-color: blue;
248
257
  * }
@@ -458,7 +467,7 @@ class SciScrollbarComponent {
458
467
  return this.vertical() ? this._host.clientHeight : this._host.clientWidth;
459
468
  }
460
469
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciScrollbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
461
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: SciScrollbarComponent, isStandalone: true, selector: "sci-scrollbar", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, viewport: { classPropertyName: "viewport", publicName: "viewport", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.vertical": "vertical()", "class.horizontal": "horizontal()", "class.scrolling": "scrolling()", "class.overflow": "overflow()", "style.--\u0275sci-scrollbar-thumb-position-fr": "thumbPositionFr()", "style.--\u0275sci-scrollbar-thumb-size-fr": "thumbSizeFr()" } }, viewQueries: [{ propertyName: "_thumbElement", first: true, predicate: ["thumb_handle"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- scrolltrack for moving the viewport client upwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onThumbMouseDown($event)\">\n <div class=\"thumb e2e-thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack for moving the viewport client downwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;box-sizing:border-box;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column;width:8px}:host.horizontal{flex-direction:row;height:8px}:host>div.scrolltrack:first-child{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host:not(.overflow){display:none}:host:hover>div.thumb-handle>div.thumb,:host.scrolling>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host:hover>div.thumb-handle>div.thumb.vertical,:host.scrolling>div.thumb-handle>div.thumb.vertical{width:100%}:host:hover>div.thumb-handle>div.thumb.horizontal,:host.scrolling>div.thumb-handle>div.thumb.horizontal{height:100%}:host>div.thumb-handle{display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column;min-height:20px}:host>div.thumb-handle.horizontal{flex-direction:row;min-width:20px}:host>div.thumb-handle>div.thumb{flex:auto;border-radius:4px;background-color:var(--sci-scrollbar-color);opacity:.4;transition-duration:125ms;transition-property:width,height;transition-timing-function:ease-out}:host>div.thumb-handle>div.thumb.vertical{width:60%}:host>div.thumb-handle>div.thumb.horizontal{height:60%}:host>div.scrolltrack:last-child{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}\n"] });
470
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: SciScrollbarComponent, isStandalone: true, selector: "sci-scrollbar", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, viewport: { classPropertyName: "viewport", publicName: "viewport", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.vertical": "vertical()", "class.horizontal": "horizontal()", "class.scrolling": "scrolling()", "class.overflow": "overflow()", "style.--\u0275sci-scrollbar-thumb-position-fr": "thumbPositionFr()", "style.--\u0275sci-scrollbar-thumb-size-fr": "thumbSizeFr()" } }, viewQueries: [{ propertyName: "_thumbElement", first: true, predicate: ["thumb_handle"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- scrolltrack for moving the viewport client upwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onThumbMouseDown($event)\">\n <div class=\"thumb e2e-thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack for moving the viewport client downwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;box-sizing:border-box;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column;width:8px}:host.horizontal{flex-direction:row;height:8px}:host>div.scrolltrack:first-child{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host:not(.overflow){display:none}:host:is(:hover,.scrolling,#sci-reset){opacity:1}:host:hover>div.thumb-handle>div.thumb,:host.scrolling>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host:hover>div.thumb-handle>div.thumb.vertical,:host.scrolling>div.thumb-handle>div.thumb.vertical{width:100%}:host:hover>div.thumb-handle>div.thumb.horizontal,:host.scrolling>div.thumb-handle>div.thumb.horizontal{height:100%}:host>div.thumb-handle{display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column;min-height:20px}:host>div.thumb-handle.horizontal{flex-direction:row;min-width:20px}:host>div.thumb-handle>div.thumb{flex:auto;border-radius:4px;background-color:var(--sci-scrollbar-color);opacity:.4;transition-duration:125ms;transition-property:width,height;transition-timing-function:ease-out}:host>div.thumb-handle>div.thumb.vertical{width:60%}:host>div.thumb-handle>div.thumb.horizontal{height:60%}:host>div.scrolltrack:last-child{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}\n"] });
462
471
  }
463
472
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciScrollbarComponent, decorators: [{
464
473
  type: Component,
@@ -469,7 +478,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
469
478
  '[class.overflow]': 'overflow()',
470
479
  '[style.--ɵsci-scrollbar-thumb-position-fr]': 'thumbPositionFr()',
471
480
  '[style.--ɵsci-scrollbar-thumb-size-fr]': 'thumbSizeFr()',
472
- }, template: "<!-- scrolltrack for moving the viewport client upwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onThumbMouseDown($event)\">\n <div class=\"thumb e2e-thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack for moving the viewport client downwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;box-sizing:border-box;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column;width:8px}:host.horizontal{flex-direction:row;height:8px}:host>div.scrolltrack:first-child{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host:not(.overflow){display:none}:host:hover>div.thumb-handle>div.thumb,:host.scrolling>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host:hover>div.thumb-handle>div.thumb.vertical,:host.scrolling>div.thumb-handle>div.thumb.vertical{width:100%}:host:hover>div.thumb-handle>div.thumb.horizontal,:host.scrolling>div.thumb-handle>div.thumb.horizontal{height:100%}:host>div.thumb-handle{display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column;min-height:20px}:host>div.thumb-handle.horizontal{flex-direction:row;min-width:20px}:host>div.thumb-handle>div.thumb{flex:auto;border-radius:4px;background-color:var(--sci-scrollbar-color);opacity:.4;transition-duration:125ms;transition-property:width,height;transition-timing-function:ease-out}:host>div.thumb-handle>div.thumb.vertical{width:60%}:host>div.thumb-handle>div.thumb.horizontal{height:60%}:host>div.scrolltrack:last-child{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}\n"] }]
481
+ }, template: "<!-- scrolltrack for moving the viewport client upwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onThumbMouseDown($event)\">\n <div class=\"thumb e2e-thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack for moving the viewport client downwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;box-sizing:border-box;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column;width:8px}:host.horizontal{flex-direction:row;height:8px}:host>div.scrolltrack:first-child{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host:not(.overflow){display:none}:host:is(:hover,.scrolling,#sci-reset){opacity:1}:host:hover>div.thumb-handle>div.thumb,:host.scrolling>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host:hover>div.thumb-handle>div.thumb.vertical,:host.scrolling>div.thumb-handle>div.thumb.vertical{width:100%}:host:hover>div.thumb-handle>div.thumb.horizontal,:host.scrolling>div.thumb-handle>div.thumb.horizontal{height:100%}:host>div.thumb-handle{display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column;min-height:20px}:host>div.thumb-handle.horizontal{flex-direction:row;min-width:20px}:host>div.thumb-handle>div.thumb{flex:auto;border-radius:4px;background-color:var(--sci-scrollbar-color);opacity:.4;transition-duration:125ms;transition-property:width,height;transition-timing-function:ease-out}:host>div.thumb-handle>div.thumb.vertical{width:60%}:host>div.thumb-handle>div.thumb.horizontal{height:60%}:host>div.scrolltrack:last-child{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}\n"] }]
473
482
  }], ctorParameters: () => [], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], viewport: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewport", required: true }] }], _thumbElement: [{ type: i0.ViewChild, args: ['thumb_handle', { isSignal: true }] }] } });
474
483
  /**
475
484
  * Emits whenever the viewport is scrolled.
@@ -584,7 +593,7 @@ function calculateScreenOffset(mousedownEvent) {
584
593
  *
585
594
  * ## Styling
586
595
  *
587
- * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.
596
+ * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `src/styles.scss`.
588
597
  * To style a specific `sci-viewport` component, the following CSS variables can be set directly on the component.
589
598
  *
590
599
  * - sci-viewport-scrollbar-color: Sets the color of the scrollbar.
@@ -763,11 +772,15 @@ class SciViewportComponent {
763
772
  */
764
773
  computeScrolling(viewport) {
765
774
  const zone = inject(NgZone);
766
- return toSignal(toObservable(viewport)
767
- .pipe(switchMap$1(viewport => fromEvent(viewport.nativeElement, 'scroll', { passive: true }).pipe(subscribeIn(fn => zone.runOutsideAngular(fn)))), tap(event => this.scroll.emit(event)), switchMap$1(() => concat(of(true), timer(150).pipe(map$1(() => false))))), { initialValue: false });
775
+ return rxResource({
776
+ defaultValue: false,
777
+ params: () => viewport().nativeElement,
778
+ stream: ({ params: viewport }) => fromEvent(viewport, 'scroll', { passive: true })
779
+ .pipe(tap(event => this.scroll.emit(event)), switchMap$1(() => concat(of(true), timer(150).pipe(map$1(() => false)))), startWith(false), subscribeIn(fn => zone.runOutsideAngular(fn))),
780
+ }).value;
768
781
  }
769
782
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciViewportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
770
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciViewportComponent, isStandalone: true, selector: "sci-viewport", inputs: { scrollbarStyle: { classPropertyName: "scrollbarStyle", publicName: "scrollbarStyle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scroll: "scroll" }, host: { listeners: { "focus": "focus()" } }, viewQueries: [{ propertyName: "_viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "_viewportClient", first: true, predicate: ["viewport_client"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\" #sciScrollable=\"sciScrollable\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && sciScrollable.isNativeScrollbarCropped()) {\n <sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport\"/>\n <sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host:is(:not(:hover):not(:active),:host(:not(:hover):not(:active))) sci-scrollbar:not(.scrolling){opacity:0}:host>div.viewport{display:grid;position:relative;outline:none;-webkit-overflow-scrolling:touch}:host>div.viewport>div.viewport-client{display:grid}:host>sci-scrollbar{--sci-scrollbar-color: var(--sci-viewport-scrollbar-color);position:absolute}:host>sci-scrollbar.vertical{top:2px;right:1px;bottom:2px}:host>sci-scrollbar.horizontal{left:2px;bottom:1px;right:2px}\n"], dependencies: [{ kind: "directive", type: SciScrollableDirective, selector: "[sciScrollable]", inputs: ["sciScrollableDisplayNativeScrollbar"], exportAs: ["sciScrollable"] }, { kind: "component", type: SciScrollbarComponent, selector: "sci-scrollbar", inputs: ["direction", "viewport"] }, { kind: "directive", type: CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }], changeDetection: i0.ChangeDetectionStrategy.Eager, encapsulation: i0.ViewEncapsulation.ShadowDom });
783
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciViewportComponent, isStandalone: true, selector: "sci-viewport", inputs: { scrollbarStyle: { classPropertyName: "scrollbarStyle", publicName: "scrollbarStyle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scroll: "scroll" }, host: { listeners: { "focus": "focus()" } }, viewQueries: [{ propertyName: "_viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "_viewportClient", first: true, predicate: ["viewport_client"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\" #sciScrollable=\"sciScrollable\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && sciScrollable.isNativeScrollbarCropped()) {\n <sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport\"/>\n <sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host>div.viewport{display:grid;position:relative;outline:none;-webkit-overflow-scrolling:touch}:host>div.viewport>div.viewport-client{display:grid}:host>div.viewport:not(:hover)~sci-scrollbar{opacity:0}:host>sci-scrollbar{--sci-scrollbar-color: var(--sci-viewport-scrollbar-color);position:absolute}:host>sci-scrollbar[direction=vscroll]{inset:2px 1px 2px auto}:host>sci-scrollbar[direction=hscroll]{inset:auto 2px 1px}\n"], dependencies: [{ kind: "directive", type: SciScrollableDirective, selector: "[sciScrollable]", inputs: ["sciScrollableDisplayNativeScrollbar"], exportAs: ["sciScrollable"] }, { kind: "component", type: SciScrollbarComponent, selector: "sci-scrollbar", inputs: ["direction", "viewport"] }, { kind: "directive", type: CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }], changeDetection: i0.ChangeDetectionStrategy.Eager, encapsulation: i0.ViewEncapsulation.ShadowDom });
771
784
  }
772
785
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciViewportComponent, decorators: [{
773
786
  type: Component,
@@ -777,7 +790,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
777
790
  CdkScrollable,
778
791
  ], changeDetection: ChangeDetectionStrategy.Eager, host: {
779
792
  '(focus)': 'focus()',
780
- }, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\" #sciScrollable=\"sciScrollable\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && sciScrollable.isNativeScrollbarCropped()) {\n <sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport\"/>\n <sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host:is(:not(:hover):not(:active),:host(:not(:hover):not(:active))) sci-scrollbar:not(.scrolling){opacity:0}:host>div.viewport{display:grid;position:relative;outline:none;-webkit-overflow-scrolling:touch}:host>div.viewport>div.viewport-client{display:grid}:host>sci-scrollbar{--sci-scrollbar-color: var(--sci-viewport-scrollbar-color);position:absolute}:host>sci-scrollbar.vertical{top:2px;right:1px;bottom:2px}:host>sci-scrollbar.horizontal{left:2px;bottom:1px;right:2px}\n"] }]
793
+ }, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\" #sciScrollable=\"sciScrollable\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && sciScrollable.isNativeScrollbarCropped()) {\n <sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport\"/>\n <sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host>div.viewport{display:grid;position:relative;outline:none;-webkit-overflow-scrolling:touch}:host>div.viewport>div.viewport-client{display:grid}:host>div.viewport:not(:hover)~sci-scrollbar{opacity:0}:host>sci-scrollbar{--sci-scrollbar-color: var(--sci-viewport-scrollbar-color);position:absolute}:host>sci-scrollbar[direction=vscroll]{inset:2px 1px 2px auto}:host>sci-scrollbar[direction=hscroll]{inset:auto 2px 1px}\n"] }]
781
794
  }], propDecorators: { scrollbarStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarStyle", required: false }] }], scroll: [{ type: i0.Output, args: ["scroll"] }], _viewport: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], _viewportClient: [{ type: i0.ViewChild, args: ['viewport_client', { isSignal: true }] }] } });
782
795
 
783
796
  /*