@mono-lit/helper 0.0.1 → 0.0.2
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/LICENSE.md +55 -55
- package/README.md +35 -35
- package/dist/data-source-controller-B_rgHCjw.js +241 -0
- package/dist/{data-source-controller-C50Qyfzh.js → data-source-controller-Dbb4fd8I.js} +69 -6
- package/dist/{data-source-options-BTpfrOZ_.js → data-source-options-CP-X62Pa.js} +2 -2
- package/dist/{data-source-options-CQSTZHPE.js → data-source-options-Jqj7LU3Z.js} +1 -1
- package/dist/{data-source-read-CUX-lgrQ.js → data-source-read-B4DGp6UQ.js} +1 -1
- package/dist/{export-BvlBx_GZ.js → export-BiGVyxt6.js} +2 -2
- package/dist/{field-icons-BoOG6KrL.js → field-icons-DELrSdqJ.js} +36 -1
- package/dist/index.js +7 -7
- package/dist/{index.node-DjvYOL-J.js → index.node-BIqEGehH.js} +5 -4
- package/dist/index.node.js +7 -7
- package/dist/{mono-button-CoVnBLav.js → mono-button-simcTQdW.js} +2 -2
- package/dist/{mono-button.shadow-FfP_hMH4.js → mono-button.shadow-B_rKOY9N.js} +2 -2
- package/dist/{mono-data-chart-ChU4Ii3p.js → mono-data-chart-CEv29_NS.js} +53 -12
- package/dist/{mono-data-dropdown-BAUl58kW.js → mono-data-dropdown-Wnoke6zO.js} +1 -1
- package/dist/{mono-data-grid-CLBK8clE.js → mono-data-grid-CjkEqxgE.js} +5 -232
- package/dist/{mono-data-grid-Db80FzdZ.js → mono-data-grid-YjR3n9Ar.js} +3 -230
- package/dist/{data-search-Bwo5bg8K.js → normalize-error-Gcgmgh5i.js} +299 -1
- package/dist/{reactive-BHsqVjRh.js → reactive-Di3mTMnV.js} +299 -1
- package/dist/src/components/card/card-core.d.ts +1 -0
- package/dist/src/components/chart/chart-types.d.ts +19 -0
- package/dist/src/components/select/select-types.d.ts +26 -0
- package/dist/src/components/tag-input/tag-input-types.d.ts +26 -0
- package/dist/src/composables/data-source-controller.d.ts +29 -0
- package/dist/src/composables/field-icons.d.ts +8 -0
- package/dist/src/utils/normalize-error.d.ts +30 -0
- package/dist/{tooltip-CysgRgBi.js → tooltip-DQqNpqk2.js} +62 -27
- package/dist/tooltip.js +1 -1
- package/dist/ui/alert.js +1 -1
- package/dist/ui/button-dropdown.js +1 -1
- package/dist/ui/button.js +1 -1
- package/dist/ui/card.js +15 -2
- package/dist/ui/chart.js +81 -4
- package/dist/ui/dropdown-table.js +2 -2
- package/dist/ui/index.css +181 -18
- package/dist/ui/modal.js +3 -2
- package/dist/ui/select.js +153 -19
- package/dist/ui/shadow/alert.js +1 -1
- package/dist/ui/shadow/button-dropdown.js +1 -1
- package/dist/ui/shadow/button.js +1 -1
- package/dist/ui/shadow/card.js +16 -2
- package/dist/ui/shadow/chart.js +133 -17
- package/dist/ui/shadow/dropdown-table.js +2 -2
- package/dist/ui/shadow/modal.js +3 -2
- package/dist/ui/shadow/select.js +153 -19
- package/dist/ui/shadow/table.js +4 -4
- package/dist/ui/shadow/tag-input.js +154 -26
- package/dist/ui/table.js +3 -3
- package/dist/ui/tag-input.js +153 -25
- package/package.json +1 -1
package/LICENSE.md
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
# MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 YCEJ9999
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Third-party software
|
|
26
|
-
|
|
27
|
-
The MIT License above covers only the code written for this package. It does
|
|
28
|
-
**not** cover third-party packages these libraries depend on or work with. Each of
|
|
29
|
-
those keeps its own license.
|
|
30
|
-
|
|
31
|
-
### DevExtreme
|
|
32
|
-
|
|
33
|
-
**DevExtreme** is a product of **Developer Express Inc. ("DevExpress")** and is
|
|
34
|
-
licensed by DevExpress under its own terms, not by the copyright holder of this
|
|
35
|
-
package. `@mono-lit/helper` does not include or depend on DevExtreme. It can work with
|
|
36
|
-
DevExtreme data sources that your application supplies (for example from
|
|
37
|
-
`@mono-lit/devextreme`). If you use DevExtreme with it:
|
|
38
|
-
|
|
39
|
-
- this package does **not** provide, sublicense, transfer or grant any DevExtreme
|
|
40
|
-
license;
|
|
41
|
-
- you are responsible for obtaining a valid DevExtreme license from DevExpress and
|
|
42
|
-
for complying with its End User License Agreement;
|
|
43
|
-
- DevExpress's license terms, not this file, govern your use of DevExtreme.
|
|
44
|
-
|
|
45
|
-
Official DevExpress licensing information:
|
|
46
|
-
|
|
47
|
-
- DevExtreme licensing: https://js.devexpress.com/Licensing/
|
|
48
|
-
- DevExtreme EULA: https://js.devexpress.com/EULAs/DevExtremeComplete/
|
|
49
|
-
|
|
50
|
-
For setting up your license key, see
|
|
51
|
-
[../devextreme/README.md](../devextreme/README.md).
|
|
52
|
-
|
|
53
|
-
"DevExpress" and "DevExtreme" are trademarks or registered trademarks of
|
|
54
|
-
Developer Express Inc. This project is not affiliated with or endorsed by
|
|
55
|
-
DevExpress.
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 YCEJ9999
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Third-party software
|
|
26
|
+
|
|
27
|
+
The MIT License above covers only the code written for this package. It does
|
|
28
|
+
**not** cover third-party packages these libraries depend on or work with. Each of
|
|
29
|
+
those keeps its own license.
|
|
30
|
+
|
|
31
|
+
### DevExtreme
|
|
32
|
+
|
|
33
|
+
**DevExtreme** is a product of **Developer Express Inc. ("DevExpress")** and is
|
|
34
|
+
licensed by DevExpress under its own terms, not by the copyright holder of this
|
|
35
|
+
package. `@mono-lit/helper` does not include or depend on DevExtreme. It can work with
|
|
36
|
+
DevExtreme data sources that your application supplies (for example from
|
|
37
|
+
`@mono-lit/devextreme`). If you use DevExtreme with it:
|
|
38
|
+
|
|
39
|
+
- this package does **not** provide, sublicense, transfer or grant any DevExtreme
|
|
40
|
+
license;
|
|
41
|
+
- you are responsible for obtaining a valid DevExtreme license from DevExpress and
|
|
42
|
+
for complying with its End User License Agreement;
|
|
43
|
+
- DevExpress's license terms, not this file, govern your use of DevExtreme.
|
|
44
|
+
|
|
45
|
+
Official DevExpress licensing information:
|
|
46
|
+
|
|
47
|
+
- DevExtreme licensing: https://js.devexpress.com/Licensing/
|
|
48
|
+
- DevExtreme EULA: https://js.devexpress.com/EULAs/DevExtremeComplete/
|
|
49
|
+
|
|
50
|
+
For setting up your license key, see
|
|
51
|
+
[../devextreme/README.md](../devextreme/README.md).
|
|
52
|
+
|
|
53
|
+
"DevExpress" and "DevExtreme" are trademarks or registered trademarks of
|
|
54
|
+
Developer Express Inc. This project is not affiliated with or endorsed by
|
|
55
|
+
DevExpress.
|
package/README.md
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
# @mono-lit/helper
|
|
2
|
-
|
|
3
|
-
Lit web components (tables, forms, inputs, dialogs, charts, …) for Vue and Nuxt. Every component ships a light-DOM build (`@mono-lit/helper/ui/<name>`) and a shadow-DOM build (`@mono-lit/helper/ui/shadow/<name>`).
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
**From npmjs (public):**
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pnpm add @mono-lit/helper
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
**From the Netlify registry:** add this to your project's `.npmrc`, then run the same `pnpm add`:
|
|
14
|
-
|
|
15
|
-
```ini
|
|
16
|
-
@mono-lit:registry=https://mono-libs.netlify.app/npm/
|
|
17
|
-
//mono-libs.netlify.app/npm/:_authToken=<REGISTRY_DOWNLOAD_TOKEN>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Optional peers are only needed for the features that use them: `chart.js` (chart), `suneditor` (rich-text editor), `exceljs` / `handlebars` (table export), plus `@floating-ui/dom`, `vue`, `vite` and `@nuxt/kit` for their integrations.
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
import '@mono-lit/helper/index.css'
|
|
26
|
-
import '@mono-lit/helper/ui/button'
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
```html
|
|
30
|
-
<mono-button>Save</mono-button>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## License
|
|
34
|
-
|
|
35
|
-
MIT. See the [repository](https://github.com/mono-lit/core) for full documentation.
|
|
1
|
+
# @mono-lit/helper
|
|
2
|
+
|
|
3
|
+
Lit web components (tables, forms, inputs, dialogs, charts, …) for Vue and Nuxt. Every component ships a light-DOM build (`@mono-lit/helper/ui/<name>`) and a shadow-DOM build (`@mono-lit/helper/ui/shadow/<name>`).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
**From npmjs (public):**
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @mono-lit/helper
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**From the Netlify registry:** add this to your project's `.npmrc`, then run the same `pnpm add`:
|
|
14
|
+
|
|
15
|
+
```ini
|
|
16
|
+
@mono-lit:registry=https://mono-libs.netlify.app/npm/
|
|
17
|
+
//mono-libs.netlify.app/npm/:_authToken=<REGISTRY_DOWNLOAD_TOKEN>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Optional peers are only needed for the features that use them: `chart.js` (chart), `suneditor` (rich-text editor), `exceljs` / `handlebars` (table export), plus `@floating-ui/dom`, `vue`, `vite` and `@nuxt/kit` for their integrations.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import '@mono-lit/helper/index.css'
|
|
26
|
+
import '@mono-lit/helper/ui/button'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<mono-button>Save</mono-button>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
MIT. See the [repository](https://github.com/mono-lit/core) for full documentation.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { n as describeError, o as isCanceled } from "./normalize-error-Gcgmgh5i.js";
|
|
2
|
+
//#region src/composables/data-source-controller.ts
|
|
3
|
+
/**
|
|
4
|
+
* Encapsulates the generic DataSource + incremental-loading logic shared by
|
|
5
|
+
* `mono-select`, `mono-tag-input`, etc. The host owns the rendering and any
|
|
6
|
+
* scroll/height ergonomics; this controller owns binding, event wiring, page
|
|
7
|
+
* accumulation, and array-mode chunking.
|
|
8
|
+
*
|
|
9
|
+
* Every state mutation calls `host.requestUpdate()` so the host re-renders.
|
|
10
|
+
*/
|
|
11
|
+
var DataSourceController = class {
|
|
12
|
+
constructor(host, opts) {
|
|
13
|
+
this._dsItems = [];
|
|
14
|
+
this._dsLoading = false;
|
|
15
|
+
this._loadingMore = false;
|
|
16
|
+
this._isLastPage = false;
|
|
17
|
+
this._error = null;
|
|
18
|
+
this._hasLoaded = false;
|
|
19
|
+
this._retrying = false;
|
|
20
|
+
this._internalLoad = false;
|
|
21
|
+
this._bound = null;
|
|
22
|
+
this._onChanged = () => {
|
|
23
|
+
if (this._internalLoad) return;
|
|
24
|
+
this._markLoaded();
|
|
25
|
+
if (this.opts.getLoadMoreMode()) {
|
|
26
|
+
const ds = this._bound;
|
|
27
|
+
this._dsItems = ds ? [...ds.items?.() ?? []] : [];
|
|
28
|
+
this._isLastPage = ds?.isLastPage?.() ?? false;
|
|
29
|
+
this._dsLoading = ds?.isLoading?.() ?? false;
|
|
30
|
+
this._changed();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this._sync();
|
|
34
|
+
};
|
|
35
|
+
this._onLoadingChanged = () => {
|
|
36
|
+
this._dsLoading = this._bound?.isLoading?.() ?? false;
|
|
37
|
+
this._changed();
|
|
38
|
+
};
|
|
39
|
+
this._onLoadError = (err) => {
|
|
40
|
+
this._dsLoading = this._bound?.isLoading?.() ?? false;
|
|
41
|
+
this.setError(err ?? /* @__PURE__ */ new Error("Request failed"));
|
|
42
|
+
};
|
|
43
|
+
this.host = host;
|
|
44
|
+
this.opts = opts;
|
|
45
|
+
this._visibleCount = opts.getPageSize();
|
|
46
|
+
host.addController(this);
|
|
47
|
+
}
|
|
48
|
+
hostConnected() {
|
|
49
|
+
const ds = this.opts.getDataSource();
|
|
50
|
+
if (ds && this._bound !== ds) this.bind(ds);
|
|
51
|
+
}
|
|
52
|
+
hostDisconnected() {
|
|
53
|
+
this._detach();
|
|
54
|
+
}
|
|
55
|
+
/** Attach/detach listeners for a (possibly new) DataSource and seed state. */
|
|
56
|
+
bind(ds) {
|
|
57
|
+
if (this._bound === ds) return;
|
|
58
|
+
this._detach();
|
|
59
|
+
this._bound = ds;
|
|
60
|
+
this._error = null;
|
|
61
|
+
this._retrying = false;
|
|
62
|
+
this._hasLoaded = !!ds && (ds.items?.() ?? []).length > 0;
|
|
63
|
+
if (!ds) {
|
|
64
|
+
this._dsItems = [];
|
|
65
|
+
this._dsLoading = false;
|
|
66
|
+
this._isLastPage = false;
|
|
67
|
+
this._changed();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
ds.on("changed", this._onChanged);
|
|
71
|
+
ds.on("loadingChanged", this._onLoadingChanged);
|
|
72
|
+
ds.on("loadError", this._onLoadError);
|
|
73
|
+
this._sync();
|
|
74
|
+
this.maybeImmediateLoad();
|
|
75
|
+
}
|
|
76
|
+
maybeImmediateLoad() {
|
|
77
|
+
const ds = this._bound;
|
|
78
|
+
if (!ds || !this.opts.getImmediate()) return;
|
|
79
|
+
const hasItems = (ds.items?.() ?? []).length > 0;
|
|
80
|
+
const loading = ds.isLoading?.() ?? false;
|
|
81
|
+
if (hasItems || loading) return;
|
|
82
|
+
this._loadFirstPage();
|
|
83
|
+
}
|
|
84
|
+
/** Call when the load-more mode changes; refreshes paging assumptions. */
|
|
85
|
+
onLoadMoreModeChange() {
|
|
86
|
+
if (!this.opts.getLoadMoreMode()) return;
|
|
87
|
+
this._bound?.paginate?.(true);
|
|
88
|
+
this._isLastPage = this._bound?.isLastPage?.() ?? false;
|
|
89
|
+
this._changed();
|
|
90
|
+
}
|
|
91
|
+
/** Reset array-mode paging to the first chunk. */
|
|
92
|
+
resetVisible() {
|
|
93
|
+
this._visibleCount = this.opts.getPageSize();
|
|
94
|
+
this._changed();
|
|
95
|
+
}
|
|
96
|
+
/** Load/reveal the next page and append it to the accumulated list. */
|
|
97
|
+
async loadMore() {
|
|
98
|
+
if (!this.opts.getLoadMoreMode() || this.atLastPage) return;
|
|
99
|
+
if (this.isArrayLoadMore) {
|
|
100
|
+
this._visibleCount = Math.min(this.opts.getItems().length, this._visibleCount + this.opts.getPageSize());
|
|
101
|
+
this._changed();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const ds = this._bound;
|
|
105
|
+
if (!ds || this._loadingMore || this._dsLoading) return;
|
|
106
|
+
if (typeof ds.pageIndex !== "function") return;
|
|
107
|
+
const current = ds.pageIndex() ?? 0;
|
|
108
|
+
this._internalLoad = true;
|
|
109
|
+
this._loadingMore = true;
|
|
110
|
+
this._changed();
|
|
111
|
+
try {
|
|
112
|
+
ds.paginate?.(true);
|
|
113
|
+
ds.pageIndex(current + 1);
|
|
114
|
+
await Promise.resolve(ds.load());
|
|
115
|
+
this._dsItems = [...this._dsItems, ...ds.items?.() ?? []];
|
|
116
|
+
this._isLastPage = ds.isLastPage?.() ?? false;
|
|
117
|
+
this._error = null;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
ds.pageIndex(current);
|
|
120
|
+
this.setError(err);
|
|
121
|
+
} finally {
|
|
122
|
+
this._loadingMore = false;
|
|
123
|
+
this._internalLoad = false;
|
|
124
|
+
this._changed();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Re-run the request after a failure. Reloads the source as it stands, so a
|
|
129
|
+
* failed search is retried with the same query. While it runs the field is
|
|
130
|
+
* {@link busy} again.
|
|
131
|
+
*
|
|
132
|
+
* `load` replaces the plain `ds.load()` — a host whose failed request was a
|
|
133
|
+
* search passes one that clears the query on the source and reloads.
|
|
134
|
+
*/
|
|
135
|
+
async retry(load) {
|
|
136
|
+
if (!this._bound) return;
|
|
137
|
+
this._error = null;
|
|
138
|
+
this._retrying = true;
|
|
139
|
+
this._changed();
|
|
140
|
+
try {
|
|
141
|
+
await this._loadFirstPage(load);
|
|
142
|
+
} finally {
|
|
143
|
+
this._retrying = false;
|
|
144
|
+
this._changed();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Record a failure from a request the host drove itself (e.g. a server
|
|
149
|
+
* select-all drain). Cancelled loads are ignored.
|
|
150
|
+
*/
|
|
151
|
+
setError(raw) {
|
|
152
|
+
if (isCanceled(raw)) return;
|
|
153
|
+
this._error = describeError(raw);
|
|
154
|
+
this._changed();
|
|
155
|
+
}
|
|
156
|
+
/** Raw source array: accumulated DataSource items, or the plain `items`. */
|
|
157
|
+
get sourceItems() {
|
|
158
|
+
return this._bound ? this._dsItems : this.opts.getItems();
|
|
159
|
+
}
|
|
160
|
+
/** Rows to actually render (array-mode reveals a slice; else everything). */
|
|
161
|
+
get visibleItems() {
|
|
162
|
+
if (this.isArrayLoadMore) return this.opts.getItems().slice(0, this._visibleCount);
|
|
163
|
+
return this.sourceItems;
|
|
164
|
+
}
|
|
165
|
+
get loading() {
|
|
166
|
+
return this._dsLoading;
|
|
167
|
+
}
|
|
168
|
+
get loadingMore() {
|
|
169
|
+
return this._loadingMore;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The field must be locked: the FIRST load (or a retry) is in flight. A
|
|
173
|
+
* search / filter reload after the source has answered once does not count —
|
|
174
|
+
* the person is typing into the field and it must stay usable.
|
|
175
|
+
*/
|
|
176
|
+
get busy() {
|
|
177
|
+
return !!this._bound && (this._dsLoading && !this._hasLoaded || this._retrying);
|
|
178
|
+
}
|
|
179
|
+
/** The last load failure, described for a person; null once a load succeeds. */
|
|
180
|
+
get error() {
|
|
181
|
+
return this._error;
|
|
182
|
+
}
|
|
183
|
+
/** load-more is driving a plain `items` array (no DataSource bound). */
|
|
184
|
+
get isArrayLoadMore() {
|
|
185
|
+
return !this.opts.getDataSource() && !!this.opts.getLoadMoreMode();
|
|
186
|
+
}
|
|
187
|
+
/** Whether there's nothing left to load/reveal. */
|
|
188
|
+
get atLastPage() {
|
|
189
|
+
if (this.isArrayLoadMore) return this._visibleCount >= this.opts.getItems().length;
|
|
190
|
+
return this._isLastPage;
|
|
191
|
+
}
|
|
192
|
+
/** A load answered: the source is usable and any earlier failure is over. */
|
|
193
|
+
_markLoaded() {
|
|
194
|
+
this._hasLoaded = true;
|
|
195
|
+
this._error = null;
|
|
196
|
+
}
|
|
197
|
+
_sync() {
|
|
198
|
+
const ds = this._bound;
|
|
199
|
+
this._dsItems = ds ? [...ds.items?.() ?? []] : [];
|
|
200
|
+
this._dsLoading = ds?.isLoading?.() ?? false;
|
|
201
|
+
this._isLastPage = ds?.isLastPage?.() ?? false;
|
|
202
|
+
this._changed();
|
|
203
|
+
}
|
|
204
|
+
/** Load the first page, replacing the accumulated list. */
|
|
205
|
+
async _loadFirstPage(load) {
|
|
206
|
+
const ds = this._bound;
|
|
207
|
+
if (!ds) return;
|
|
208
|
+
this._internalLoad = true;
|
|
209
|
+
this._dsLoading = true;
|
|
210
|
+
this._changed();
|
|
211
|
+
try {
|
|
212
|
+
if (this.opts.getLoadMoreMode()) {
|
|
213
|
+
ds.paginate?.(true);
|
|
214
|
+
ds.pageIndex?.(0);
|
|
215
|
+
}
|
|
216
|
+
await Promise.resolve(load ? load() : ds.load());
|
|
217
|
+
this._dsItems = [...ds.items?.() ?? []];
|
|
218
|
+
this._isLastPage = ds.isLastPage?.() ?? false;
|
|
219
|
+
this._markLoaded();
|
|
220
|
+
} catch (err) {
|
|
221
|
+
this.setError(err);
|
|
222
|
+
} finally {
|
|
223
|
+
this._dsLoading = ds.isLoading?.() ?? false;
|
|
224
|
+
this._internalLoad = false;
|
|
225
|
+
this._changed();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
_detach() {
|
|
229
|
+
const ds = this._bound;
|
|
230
|
+
if (!ds) return;
|
|
231
|
+
ds.off("changed", this._onChanged);
|
|
232
|
+
ds.off("loadingChanged", this._onLoadingChanged);
|
|
233
|
+
ds.off("loadError", this._onLoadError);
|
|
234
|
+
this._bound = null;
|
|
235
|
+
}
|
|
236
|
+
_changed() {
|
|
237
|
+
this.host.requestUpdate();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
//#endregion
|
|
241
|
+
export { DataSourceController as t };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { a as describeError, l as isCanceled } from "./reactive-Di3mTMnV.js";
|
|
1
2
|
//#region src/composables/data-source-controller.ts
|
|
2
3
|
/**
|
|
3
4
|
* Encapsulates the generic DataSource + incremental-loading logic shared by
|
|
@@ -13,10 +14,14 @@ var DataSourceController = class {
|
|
|
13
14
|
this._dsLoading = false;
|
|
14
15
|
this._loadingMore = false;
|
|
15
16
|
this._isLastPage = false;
|
|
17
|
+
this._error = null;
|
|
18
|
+
this._hasLoaded = false;
|
|
19
|
+
this._retrying = false;
|
|
16
20
|
this._internalLoad = false;
|
|
17
21
|
this._bound = null;
|
|
18
22
|
this._onChanged = () => {
|
|
19
23
|
if (this._internalLoad) return;
|
|
24
|
+
this._markLoaded();
|
|
20
25
|
if (this.opts.getLoadMoreMode()) {
|
|
21
26
|
const ds = this._bound;
|
|
22
27
|
this._dsItems = ds ? [...ds.items?.() ?? []] : [];
|
|
@@ -31,6 +36,10 @@ var DataSourceController = class {
|
|
|
31
36
|
this._dsLoading = this._bound?.isLoading?.() ?? false;
|
|
32
37
|
this._changed();
|
|
33
38
|
};
|
|
39
|
+
this._onLoadError = (err) => {
|
|
40
|
+
this._dsLoading = this._bound?.isLoading?.() ?? false;
|
|
41
|
+
this.setError(err ?? /* @__PURE__ */ new Error("Request failed"));
|
|
42
|
+
};
|
|
34
43
|
this.host = host;
|
|
35
44
|
this.opts = opts;
|
|
36
45
|
this._visibleCount = opts.getPageSize();
|
|
@@ -48,6 +57,9 @@ var DataSourceController = class {
|
|
|
48
57
|
if (this._bound === ds) return;
|
|
49
58
|
this._detach();
|
|
50
59
|
this._bound = ds;
|
|
60
|
+
this._error = null;
|
|
61
|
+
this._retrying = false;
|
|
62
|
+
this._hasLoaded = !!ds && (ds.items?.() ?? []).length > 0;
|
|
51
63
|
if (!ds) {
|
|
52
64
|
this._dsItems = [];
|
|
53
65
|
this._dsLoading = false;
|
|
@@ -57,7 +69,7 @@ var DataSourceController = class {
|
|
|
57
69
|
}
|
|
58
70
|
ds.on("changed", this._onChanged);
|
|
59
71
|
ds.on("loadingChanged", this._onLoadingChanged);
|
|
60
|
-
ds.on("loadError", this.
|
|
72
|
+
ds.on("loadError", this._onLoadError);
|
|
61
73
|
this._sync();
|
|
62
74
|
this.maybeImmediateLoad();
|
|
63
75
|
}
|
|
@@ -102,14 +114,45 @@ var DataSourceController = class {
|
|
|
102
114
|
await Promise.resolve(ds.load());
|
|
103
115
|
this._dsItems = [...this._dsItems, ...ds.items?.() ?? []];
|
|
104
116
|
this._isLastPage = ds.isLastPage?.() ?? false;
|
|
105
|
-
|
|
117
|
+
this._error = null;
|
|
118
|
+
} catch (err) {
|
|
106
119
|
ds.pageIndex(current);
|
|
120
|
+
this.setError(err);
|
|
107
121
|
} finally {
|
|
108
122
|
this._loadingMore = false;
|
|
109
123
|
this._internalLoad = false;
|
|
110
124
|
this._changed();
|
|
111
125
|
}
|
|
112
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Re-run the request after a failure. Reloads the source as it stands, so a
|
|
129
|
+
* failed search is retried with the same query. While it runs the field is
|
|
130
|
+
* {@link busy} again.
|
|
131
|
+
*
|
|
132
|
+
* `load` replaces the plain `ds.load()` — a host whose failed request was a
|
|
133
|
+
* search passes one that clears the query on the source and reloads.
|
|
134
|
+
*/
|
|
135
|
+
async retry(load) {
|
|
136
|
+
if (!this._bound) return;
|
|
137
|
+
this._error = null;
|
|
138
|
+
this._retrying = true;
|
|
139
|
+
this._changed();
|
|
140
|
+
try {
|
|
141
|
+
await this._loadFirstPage(load);
|
|
142
|
+
} finally {
|
|
143
|
+
this._retrying = false;
|
|
144
|
+
this._changed();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Record a failure from a request the host drove itself (e.g. a server
|
|
149
|
+
* select-all drain). Cancelled loads are ignored.
|
|
150
|
+
*/
|
|
151
|
+
setError(raw) {
|
|
152
|
+
if (isCanceled(raw)) return;
|
|
153
|
+
this._error = describeError(raw);
|
|
154
|
+
this._changed();
|
|
155
|
+
}
|
|
113
156
|
/** Raw source array: accumulated DataSource items, or the plain `items`. */
|
|
114
157
|
get sourceItems() {
|
|
115
158
|
return this._bound ? this._dsItems : this.opts.getItems();
|
|
@@ -125,6 +168,18 @@ var DataSourceController = class {
|
|
|
125
168
|
get loadingMore() {
|
|
126
169
|
return this._loadingMore;
|
|
127
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* The field must be locked: the FIRST load (or a retry) is in flight. A
|
|
173
|
+
* search / filter reload after the source has answered once does not count —
|
|
174
|
+
* the person is typing into the field and it must stay usable.
|
|
175
|
+
*/
|
|
176
|
+
get busy() {
|
|
177
|
+
return !!this._bound && (this._dsLoading && !this._hasLoaded || this._retrying);
|
|
178
|
+
}
|
|
179
|
+
/** The last load failure, described for a person; null once a load succeeds. */
|
|
180
|
+
get error() {
|
|
181
|
+
return this._error;
|
|
182
|
+
}
|
|
128
183
|
/** load-more is driving a plain `items` array (no DataSource bound). */
|
|
129
184
|
get isArrayLoadMore() {
|
|
130
185
|
return !this.opts.getDataSource() && !!this.opts.getLoadMoreMode();
|
|
@@ -134,6 +189,11 @@ var DataSourceController = class {
|
|
|
134
189
|
if (this.isArrayLoadMore) return this._visibleCount >= this.opts.getItems().length;
|
|
135
190
|
return this._isLastPage;
|
|
136
191
|
}
|
|
192
|
+
/** A load answered: the source is usable and any earlier failure is over. */
|
|
193
|
+
_markLoaded() {
|
|
194
|
+
this._hasLoaded = true;
|
|
195
|
+
this._error = null;
|
|
196
|
+
}
|
|
137
197
|
_sync() {
|
|
138
198
|
const ds = this._bound;
|
|
139
199
|
this._dsItems = ds ? [...ds.items?.() ?? []] : [];
|
|
@@ -142,7 +202,7 @@ var DataSourceController = class {
|
|
|
142
202
|
this._changed();
|
|
143
203
|
}
|
|
144
204
|
/** Load the first page, replacing the accumulated list. */
|
|
145
|
-
async _loadFirstPage() {
|
|
205
|
+
async _loadFirstPage(load) {
|
|
146
206
|
const ds = this._bound;
|
|
147
207
|
if (!ds) return;
|
|
148
208
|
this._internalLoad = true;
|
|
@@ -153,10 +213,13 @@ var DataSourceController = class {
|
|
|
153
213
|
ds.paginate?.(true);
|
|
154
214
|
ds.pageIndex?.(0);
|
|
155
215
|
}
|
|
156
|
-
await Promise.resolve(ds.load());
|
|
216
|
+
await Promise.resolve(load ? load() : ds.load());
|
|
157
217
|
this._dsItems = [...ds.items?.() ?? []];
|
|
158
218
|
this._isLastPage = ds.isLastPage?.() ?? false;
|
|
159
|
-
|
|
219
|
+
this._markLoaded();
|
|
220
|
+
} catch (err) {
|
|
221
|
+
this.setError(err);
|
|
222
|
+
} finally {
|
|
160
223
|
this._dsLoading = ds.isLoading?.() ?? false;
|
|
161
224
|
this._internalLoad = false;
|
|
162
225
|
this._changed();
|
|
@@ -167,7 +230,7 @@ var DataSourceController = class {
|
|
|
167
230
|
if (!ds) return;
|
|
168
231
|
ds.off("changed", this._onChanged);
|
|
169
232
|
ds.off("loadingChanged", this._onLoadingChanged);
|
|
170
|
-
ds.off("loadError", this.
|
|
233
|
+
ds.off("loadError", this._onLoadError);
|
|
171
234
|
this._bound = null;
|
|
172
235
|
}
|
|
173
236
|
_changed() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as isPath, r as mergePatch, t as getFieldValue } from "./field-path-C92eGLg3.js";
|
|
2
|
-
import {
|
|
3
|
-
import { i as searchFilterOf, s as flattenLeaves, t as isDataSourceLike } from "./data-source-read-
|
|
2
|
+
import { A as compileFilterPredicate, O as andFilters, h as mergeSearchFields, k as andPredicates, t as resolveMaybeReactive } from "./reactive-Di3mTMnV.js";
|
|
3
|
+
import { i as searchFilterOf, s as flattenLeaves, t as isDataSourceLike } from "./data-source-read-B4DGp6UQ.js";
|
|
4
4
|
import { s as odataStringToArray, t as arrayToODataString } from "./filter-odata-C1vSGZaY.js";
|
|
5
5
|
//#region src/components/table/array-source.ts
|
|
6
6
|
/** Normalise a possibly-grouped input array to flat leaf rows when grouping. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as isPath, r as mergePatch, t as getFieldValue } from "./field-path-C92eGLg3.js";
|
|
2
2
|
import { i as searchFilterOf, s as flattenLeaves, t as isDataSourceLike } from "./data-source-read-DL88aH8t.js";
|
|
3
3
|
import { n as andPredicates, r as compileFilterPredicate, t as andFilters } from "./filter-eval-DIfU2EAn.js";
|
|
4
|
-
import {
|
|
4
|
+
import { h as mergeSearchFields } from "./normalize-error-Gcgmgh5i.js";
|
|
5
5
|
import { t as resolveMaybeReactive } from "./reactive-D3EERqgO.js";
|
|
6
6
|
import { s as odataStringToArray, t as arrayToODataString } from "./filter-odata-C1vSGZaY.js";
|
|
7
7
|
//#region src/components/table/array-source.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as toODataClause, n as isPath, t as getFieldValue } from "./field-path-C92eGLg3.js";
|
|
2
|
-
import {
|
|
2
|
+
import { O as andFilters, n as unwrapReactive } from "./reactive-Di3mTMnV.js";
|
|
3
3
|
//#region src/components/table/grouping.ts
|
|
4
4
|
/**
|
|
5
5
|
* Client-side grouping helpers shared by {@link monoArraySource} and
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as stripDirectives, d as __toESM, i as escapeCellText, n as parseMarkdown, r as encodeDirective, u as __commonJSMin } from "./markdown-DfqrfOJN.js";
|
|
2
|
-
import { n as unwrapReactive } from "./reactive-
|
|
3
|
-
import { n as isReadableSource, r as readAllRows } from "./data-source-read-
|
|
2
|
+
import { n as unwrapReactive } from "./reactive-Di3mTMnV.js";
|
|
3
|
+
import { n as isReadableSource, r as readAllRows } from "./data-source-read-B4DGp6UQ.js";
|
|
4
4
|
//#region src/export/download.ts
|
|
5
5
|
/**
|
|
6
6
|
* Browser download helper. Kept separate (and DOM-guarded) so the report engine
|
|
@@ -47,5 +47,40 @@ function chevronIcon(dir) {
|
|
|
47
47
|
<path fill-rule="evenodd" d=${dir === -1 ? "M12.79 5.23a.75.75 0 0 1-.02 1.06L9.06 10l3.71 3.71a.75.75 0 1 1-1.06 1.06l-4.24-4.24a.75.75 0 0 1 0-1.06l4.24-4.24a.75.75 0 0 1 1.08 0z" : "M7.21 14.77a.75.75 0 0 1 .02-1.06L10.94 10 7.23 6.29a.75.75 0 1 1 1.06-1.06l4.24 4.24a.75.75 0 0 1 0 1.06l-4.24 4.24a.75.75 0 0 1-1.08 0z"} clip-rule="evenodd" />
|
|
48
48
|
</svg>`;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Busy arc for a field whose data source is still answering. Spun by the
|
|
52
|
+
* component's own CSS (`[mono-ds-spinner] > svg`) so a reduced-motion rule can
|
|
53
|
+
* stop it.
|
|
54
|
+
*/
|
|
55
|
+
function spinnerIcon() {
|
|
56
|
+
return html`<svg
|
|
57
|
+
mono-icon
|
|
58
|
+
viewBox="0 0 24 24"
|
|
59
|
+
width="16"
|
|
60
|
+
height="16"
|
|
61
|
+
fill="none"
|
|
62
|
+
stroke="currentColor"
|
|
63
|
+
stroke-width="2.5"
|
|
64
|
+
stroke-linecap="round"
|
|
65
|
+
aria-hidden="true"
|
|
66
|
+
>
|
|
67
|
+
<path d="M12 3a9 9 0 1 0 9 9" />
|
|
68
|
+
</svg>`;
|
|
69
|
+
}
|
|
70
|
+
/** ↻ — the retry affordance a field shows after its data source failed. */
|
|
71
|
+
function refreshIcon() {
|
|
72
|
+
return html`<svg
|
|
73
|
+
mono-icon
|
|
74
|
+
viewBox="0 0 24 24"
|
|
75
|
+
width="16"
|
|
76
|
+
height="16"
|
|
77
|
+
fill="currentColor"
|
|
78
|
+
aria-hidden="true"
|
|
79
|
+
>
|
|
80
|
+
<path
|
|
81
|
+
d="M17.65 6.35A8 8 0 1 0 19.73 14h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"
|
|
82
|
+
/>
|
|
83
|
+
</svg>`;
|
|
84
|
+
}
|
|
50
85
|
//#endregion
|
|
51
|
-
export { chevronIcon as n, closeIcon as r, caretIcon as t };
|
|
86
|
+
export { spinnerIcon as a, refreshIcon as i, chevronIcon as n, closeIcon as r, caretIcon as t };
|