@zeyos/zx 2.3.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +138 -0
- package/DESIGN-SYSTEM.md +96 -0
- package/README.md +29 -39
- package/dist/types/components/account-menu/account-menu.d.ts +144 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +243 -0
- package/dist/types/components/avatar/avatar.d.ts +100 -0
- package/dist/types/components/card/card.d.ts +128 -0
- package/dist/types/components/chart/chart.d.ts +322 -0
- package/dist/types/components/date-picker/month-picker.d.ts +6 -0
- package/dist/types/components/dialog/dialog.d.ts +9 -0
- package/dist/types/components/dock/dock.d.ts +495 -0
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/field/field.d.ts +14 -0
- package/dist/types/components/field-upload/field-upload.d.ts +37 -4
- package/dist/types/components/form/form.d.ts +25 -3
- package/dist/types/components/grid/grid.d.ts +172 -0
- package/dist/types/components/launcher/launcher.d.ts +359 -0
- package/dist/types/components/layout/layout.d.ts +4 -4
- package/dist/types/components/menu-button/menu-button.d.ts +10 -2
- package/dist/types/components/modal/modal.d.ts +25 -0
- package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +7 -1
- package/dist/types/components/questionnaire/items.d.ts +327 -0
- package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
- package/dist/types/components/select/select.d.ts +51 -0
- package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
- package/dist/types/components/sheet/sheet.d.ts +294 -0
- package/dist/types/components/split-view/split-view.d.ts +2 -21
- package/dist/types/components/table/table.d.ts +223 -15
- package/dist/types/components/tooltip/tooltip.d.ts +2 -2
- package/dist/types/components/value-list/value-list.d.ts +24 -3
- package/dist/types/core/dom.d.ts +122 -0
- package/dist/types/core/drag-axis.d.ts +111 -0
- package/dist/types/core/position.d.ts +4 -2
- package/dist/types/index.d.ts +13 -2
- package/dist/types/internal/app-rail.d.ts +265 -0
- package/dist/types/zeyos/icons.d.ts +5 -0
- package/dist/types/zeyos/index.d.ts +2 -1
- package/dist/types/zeyos/launcher.d.ts +147 -0
- package/dist/types/zeyos/select.d.ts +39 -0
- package/dist/zx-zeyos.esm.js +1870 -133
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +2006 -267
- package/dist/zx.esm.js +8987 -2757
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +8987 -2757
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +4396 -2344
- package/docs/llms.md +463 -86
- package/docs/llms.txt +32 -19
- package/package.json +10 -17
- package/src/components/account-menu/account-menu.css +70 -0
- package/src/components/account-menu/account-menu.js +208 -0
- package/src/components/app-rail/app-rail.css +107 -0
- package/src/components/app-sidebar/app-sidebar.css +80 -0
- package/src/components/app-sidebar/app-sidebar.js +588 -0
- package/src/components/avatar/avatar.css +61 -0
- package/src/components/avatar/avatar.js +222 -0
- package/src/components/button/button.css +0 -1
- package/src/components/card/card.css +149 -0
- package/src/components/card/card.js +285 -0
- package/src/components/chart/chart.css +61 -0
- package/src/components/chart/chart.js +523 -0
- package/src/components/date-picker/month-picker.js +9 -0
- package/src/components/dialog/dialog.js +11 -4
- package/src/components/dock/dock.css +228 -0
- package/src/components/dock/dock.js +977 -0
- package/src/components/dropdown/dropdown.js +1 -1
- package/src/components/field/field.js +2 -0
- package/src/components/field-upload/field-upload.js +9 -4
- package/src/components/form/form.js +6 -3
- package/src/components/grid/grid.css +6 -0
- package/src/components/grid/grid.js +220 -0
- package/src/components/launcher/launcher.css +210 -0
- package/src/components/launcher/launcher.js +765 -0
- package/src/components/layout/layout.js +2 -2
- package/src/components/menu-button/menu-button.js +27 -2
- package/src/components/modal/modal.css +5 -1
- package/src/components/modal/modal.js +37 -2
- package/src/components/multi-value-editor/multi-value-editor.js +2 -1
- package/src/components/questionnaire/items.js +370 -0
- package/src/components/questionnaire/questionnaire.css +387 -0
- package/src/components/questionnaire/questionnaire.js +1033 -0
- package/src/components/select/field-adapter.js +9 -4
- package/src/components/select/select.css +144 -11
- package/src/components/select/select.js +259 -27
- package/src/components/sheet/sheet-stack.js +304 -0
- package/src/components/sheet/sheet.css +351 -0
- package/src/components/sheet/sheet.js +551 -0
- package/src/components/split-view/split-view.js +76 -161
- package/src/components/table/table.css +43 -0
- package/src/components/table/table.js +531 -52
- package/src/components/tooltip/tooltip.js +5 -2
- package/src/components/value-list/value-list.js +6 -3
- package/src/core/dom.js +322 -0
- package/src/core/drag-axis.js +203 -0
- package/src/core/position.js +68 -22
- package/src/index.js +20 -2
- package/src/internal/app-rail.js +718 -0
- package/src/zeyos/icons.js +8 -3
- package/src/zeyos/index.js +7 -1
- package/src/zeyos/launcher.js +338 -0
- package/src/zeyos/modules.js +1 -0
- package/src/zeyos/select.js +115 -1
- package/styles/tokens/dark.css +2 -3
- package/styles/tokens/global.css +6 -6
- package/styles/tokens/modules.css +1 -0
- package/styles/tokens/semantic.css +5 -3
- package/styles/tokens/themes.css +1 -1
- package/styles/zx.css +11 -1
- package/MIGRATION.md +0 -598
- package/dist/types/compat/base.d.ts +0 -156
- package/dist/types/compat/globals.d.ts +0 -20
- package/dist/types/compat/index.d.ts +0 -128
- package/dist/types/compat/map/basic.d.ts +0 -175
- package/dist/types/compat/map/data.d.ts +0 -102
- package/dist/types/compat/map/date-time.d.ts +0 -80
- package/dist/types/compat/map/factory.d.ts +0 -9
- package/dist/types/compat/map/form.d.ts +0 -98
- package/dist/types/compat/map/helpers.d.ts +0 -12
- package/dist/types/compat/map/http.d.ts +0 -36
- package/dist/types/compat/map/layout.d.ts +0 -106
- package/dist/types/compat/map/options.d.ts +0 -80
- package/dist/types/compat/map/select.d.ts +0 -95
- package/dist/types/compat/map/stubs.d.ts +0 -32
- package/dist/types/compat/map/utilities.d.ts +0 -37
- package/dist/types/compat-entry.d.ts +0 -5
- package/dist/types/components/permission/permission.d.ts +0 -96
- package/dist/zx-compat.esm.js +0 -17484
- package/dist/zx-compat.esm.min.js +0 -1
- package/dist/zx-compat.global.js +0 -23635
- package/dist/zx-compat.global.min.js +0 -3
- package/src/compat/base.js +0 -291
- package/src/compat/globals.js +0 -165
- package/src/compat/index.js +0 -84
- package/src/compat/map/basic.js +0 -464
- package/src/compat/map/data.js +0 -232
- package/src/compat/map/date-time.js +0 -177
- package/src/compat/map/factory.js +0 -45
- package/src/compat/map/form.js +0 -330
- package/src/compat/map/helpers.js +0 -46
- package/src/compat/map/http.js +0 -117
- package/src/compat/map/layout.js +0 -256
- package/src/compat/map/options.js +0 -267
- package/src/compat/map/select.js +0 -198
- package/src/compat/map/stubs.js +0 -26
- package/src/compat/map/utilities.js +0 -113
- package/src/compat-entry.js +0 -11
- package/src/components/permission/permission.css +0 -47
- package/src/components/permission/permission.js +0 -201
package/src/compat/map/select.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { Http, Select as ZxSelect, zeyosService } from '../../index.js';
|
|
2
|
-
import { GxWrapper } from '../base.js';
|
|
3
|
-
import { LEGACY_EVENT_ARGS, translateSelectOptions } from './options.js';
|
|
4
|
-
|
|
5
|
-
/** Shared Select facade; concrete subclasses choose filtering and warning identity. */
|
|
6
|
-
class SelectBase extends GxWrapper {
|
|
7
|
-
static legacyName = 'gx.zeyos.Select';
|
|
8
|
-
/*
|
|
9
|
-
* Widened deliberately: the subclasses below set `'local' | 'async' | 'priority' | 'rest'`, and
|
|
10
|
-
* a static field annotated with that union would still clash with the `string` each subclass
|
|
11
|
-
* infers from its own literal. The static sides have to agree or the emitted declarations do
|
|
12
|
-
* not type-check for a consumer running without `skipLibCheck`.
|
|
13
|
-
*/
|
|
14
|
-
/** @type {string|false} */
|
|
15
|
-
static filterMode = false;
|
|
16
|
-
|
|
17
|
-
/** @param {Element|string|null} display @param {Record<string, any>} [options={}] */
|
|
18
|
-
constructor(display, options = {}) {
|
|
19
|
-
super(options, { data: [], elementIndex: 'ID', elementLabel: 'name', elementSelect: 'name', value: null });
|
|
20
|
-
const translated = translateSelectOptions(options);
|
|
21
|
-
translated.items = initialItems(options);
|
|
22
|
-
translated.valueKey = valueReader(options.elementIndex ?? 'ID');
|
|
23
|
-
translated.labelKey = labelReader(options.elementLabel ?? 'name');
|
|
24
|
-
translated.renderItem = typeof options.elementLabel === 'function' ? options.elementLabel : null;
|
|
25
|
-
translated.renderValue = selectionReader(options.elementSelect ?? options.elementLabel ?? 'name');
|
|
26
|
-
translated.value = options.value ?? null;
|
|
27
|
-
translated.filter = this.constructor.filterMode === 'local' ? 'local' :
|
|
28
|
-
(['async', 'rest'].includes(this.constructor.filterMode) ? (query) => this._load(query) : false);
|
|
29
|
-
translated.debounce = options.debounce ?? 200;
|
|
30
|
-
const component = this.constructor.filterMode === 'priority'
|
|
31
|
-
? ZxSelect.priority(display, translated)
|
|
32
|
-
: new ZxSelect(display, translated);
|
|
33
|
-
this._attach(component, {
|
|
34
|
-
events: {
|
|
35
|
-
select: {
|
|
36
|
-
type: 'change', filter: (detail) => detail.item != null,
|
|
37
|
-
args: (detail) => LEGACY_EVENT_ARGS.select(detail, this)
|
|
38
|
-
},
|
|
39
|
-
noselect: {
|
|
40
|
-
type: 'change', filter: (detail) => detail.item == null,
|
|
41
|
-
args: (detail) => LEGACY_EVENT_ARGS.noselect(detail, this)
|
|
42
|
-
},
|
|
43
|
-
show: { type: 'open', args: () => [this] },
|
|
44
|
-
hide: { type: 'close', args: () => [this] },
|
|
45
|
-
requestSuccess: { type: 'loaded', args: (detail) => [detail.items] }
|
|
46
|
-
},
|
|
47
|
-
ui: { fieldset: 'control', textbox: 'input', dropdown: 'list', icon: 'toggle' },
|
|
48
|
-
setters: { data: 'setData', value: 'setId', disabled: (value) => value ? this.disable() : this.enable() }
|
|
49
|
-
});
|
|
50
|
-
this._http = null;
|
|
51
|
-
this.data = translated.items;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** @param {unknown} selection @param {boolean} [noEvents=false] @returns {this} */
|
|
55
|
-
set(selection, noEvents = false) { this._zx.set(selection, { silent: Boolean(noEvents) }); return this; }
|
|
56
|
-
/** @param {unknown} id @param {boolean} [noEvents=false] @returns {this} */
|
|
57
|
-
setId(id, noEvents = false) {
|
|
58
|
-
const item = this.data?.find((candidate) => readValue(candidate, this.options.elementIndex ?? 'ID') == id);
|
|
59
|
-
this._zx.set(item ?? id, { silent: Boolean(noEvents) }); return this;
|
|
60
|
-
}
|
|
61
|
-
/** @param {unknown} [item] @returns {unknown} */
|
|
62
|
-
getId(item) { return item == null ? this._zx.value : readValue(item, this.options.elementIndex ?? 'ID'); }
|
|
63
|
-
/** @returns {unknown} */
|
|
64
|
-
getValue() { return this._zx.value; }
|
|
65
|
-
/** @returns {unknown} */
|
|
66
|
-
getSelected() { return this._zx.selected; }
|
|
67
|
-
/** @param {unknown[]} data @returns {this} */
|
|
68
|
-
setData(data) { this.data = Array.isArray(data) ? data.slice() : []; this._zx.setItems(this.data); return this; }
|
|
69
|
-
/** @returns {Element[]} */
|
|
70
|
-
getRows() { return Array.from(this.display('dropdown')?.querySelectorAll?.('[role="option"]') ?? []); }
|
|
71
|
-
/** @param {boolean} [noEvents=false] @returns {this} */
|
|
72
|
-
reset(noEvents = false) { this._zx.set(null, { silent: Boolean(noEvents) }); return this; }
|
|
73
|
-
/** @returns {this} */
|
|
74
|
-
enable() { this._zx.enable(); return this; }
|
|
75
|
-
/** @returns {this} */
|
|
76
|
-
disable() { this._zx.disable(); return this; }
|
|
77
|
-
/** @returns {this} */
|
|
78
|
-
show() { this._zx.open(); return this; }
|
|
79
|
-
/** @returns {this} */
|
|
80
|
-
hide() { this._zx.close(); return this; }
|
|
81
|
-
/** @returns {boolean} */
|
|
82
|
-
isOpen() { return this.toElement().getAttribute('data-state') === 'open'; }
|
|
83
|
-
/** @returns {this} */
|
|
84
|
-
search() { this._zx.open(); return this; }
|
|
85
|
-
/** @returns {this} */
|
|
86
|
-
showLoader() { return this; }
|
|
87
|
-
/** @returns {this} */
|
|
88
|
-
hideLoader() { return this; }
|
|
89
|
-
|
|
90
|
-
/** @param {string} query @returns {Promise<unknown[]>} */
|
|
91
|
-
async _load(query) {
|
|
92
|
-
try {
|
|
93
|
-
const result = this.constructor.filterMode === 'rest'
|
|
94
|
-
? await this._loadRest(query)
|
|
95
|
-
: await this._loadUrl(query);
|
|
96
|
-
const rows = Array.isArray(result) ? result : [];
|
|
97
|
-
this.data = rows;
|
|
98
|
-
return rows;
|
|
99
|
-
} catch (error) {
|
|
100
|
-
this.fireEvent('requestFailure', [error]);
|
|
101
|
-
throw error;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** @param {string} query @returns {Promise<unknown>} */
|
|
106
|
-
_loadUrl(query) {
|
|
107
|
-
this._http ??= new Http({ headers: this.options.requestHeader ?? {} });
|
|
108
|
-
const requestData = { ...(this.options.requestData ?? {}) };
|
|
109
|
-
const queryData = typeof this.options.queryParam === 'function'
|
|
110
|
-
? this.options.queryParam(query, requestData)
|
|
111
|
-
: { ...requestData, [this.options.queryParam ?? 'query']: query };
|
|
112
|
-
const method = String(this.options.method ?? 'GET').toUpperCase();
|
|
113
|
-
return this._http.request(String(this.options.url ?? './'), method === 'GET'
|
|
114
|
-
? { method, query: queryData }
|
|
115
|
-
: { method, data: queryData });
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** @param {string} query @returns {Promise<unknown>} */
|
|
119
|
-
_loadRest(query) {
|
|
120
|
-
this._http ??= zeyosService(String(this.options.entity ?? ''), String(this.options.accesskey ?? ''), {
|
|
121
|
-
apiBase: this.options.apiBase ?? '../remotecall/'
|
|
122
|
-
});
|
|
123
|
-
return this._http.get('', { ...(this.options.requestData ?? {}), search: query, limit: this.options.limit ?? 50 });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Legacy ZeyOS select. */
|
|
128
|
-
export class Select extends SelectBase { static legacyName = 'gx.zeyos.Select'; }
|
|
129
|
-
/** Legacy ZeyOS locally filterable select. */
|
|
130
|
-
export class SelectFilter extends SelectBase { static legacyName = 'gx.zeyos.SelectFilter'; static filterMode = 'local'; }
|
|
131
|
-
/** Legacy ZeyOS HTTP-backed select. */
|
|
132
|
-
export class SelectDyn extends SelectBase { static legacyName = 'gx.zeyos.SelectDyn'; static filterMode = 'async'; }
|
|
133
|
-
/** Legacy ZeyOS priority select. */
|
|
134
|
-
export class SelectPrio extends SelectBase { static legacyName = 'gx.zeyos.SelectPrio'; static filterMode = 'priority'; }
|
|
135
|
-
|
|
136
|
-
/** Legacy bootstrap select. */
|
|
137
|
-
export class BootstrapSelect extends SelectBase { static legacyName = 'gx.bootstrap.Select'; }
|
|
138
|
-
/** Legacy bootstrap locally filterable select. */
|
|
139
|
-
export class BootstrapSelectFilter extends SelectBase { static legacyName = 'gx.bootstrap.SelectFilter'; static filterMode = 'local'; }
|
|
140
|
-
/** Legacy bootstrap HTTP-backed select. */
|
|
141
|
-
export class BootstrapSelectDyn extends SelectBase { static legacyName = 'gx.bootstrap.SelectDyn'; static filterMode = 'async'; }
|
|
142
|
-
/** Legacy bootstrap REST-backed select. */
|
|
143
|
-
export class SelectDynREST extends SelectBase {
|
|
144
|
-
static legacyName = 'gx.bootstrap.SelectDynREST';
|
|
145
|
-
static filterMode = 'rest';
|
|
146
|
-
|
|
147
|
-
/** Loads and selects a REST item by ID when it is not already cached. @param {unknown} id @returns {Promise<void>} */
|
|
148
|
-
async setEntityId(id) {
|
|
149
|
-
const cached = this.data?.find((item) => Object.is(readValue(item, this.options.elementIndex ?? 'ID'), id));
|
|
150
|
-
if (cached) { this.set(cached); return; }
|
|
151
|
-
if (id == null || id === '') return;
|
|
152
|
-
try {
|
|
153
|
-
this._http ??= zeyosService(String(this.options.entity ?? ''), String(this.options.accesskey ?? ''), {
|
|
154
|
-
apiBase: this.options.apiBase ?? '../remotecall/'
|
|
155
|
-
});
|
|
156
|
-
const item = await this._http.get(String(id));
|
|
157
|
-
if (item) this.set(item);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
this.fireEvent('requestFailure', [error]);
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
/** Legacy bootstrap priority select. */
|
|
165
|
-
export class BootstrapSelectPrio extends SelectBase { static legacyName = 'gx.bootstrap.SelectPrio'; static filterMode = 'priority'; }
|
|
166
|
-
|
|
167
|
-
/** @param {Record<string, any>} options @returns {unknown[]} */
|
|
168
|
-
function initialItems(options) {
|
|
169
|
-
const items = Array.isArray(options.data) ? options.data.slice() : [];
|
|
170
|
-
return options.elementDefault == null ? items : [options.elementDefault, ...items];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** @param {string|Function} reader @returns {string|Function} */
|
|
174
|
-
function valueReader(reader) {
|
|
175
|
-
return typeof reader === 'function' ? reader : String(reader);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** @param {string|Function} reader @returns {string|Function} */
|
|
179
|
-
function labelReader(reader) {
|
|
180
|
-
if (typeof reader !== 'function') return String(reader);
|
|
181
|
-
return (item) => renderedText(reader(item));
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/** @param {string|Function} reader @returns {(item: unknown) => string} */
|
|
185
|
-
function selectionReader(reader) {
|
|
186
|
-
return (item) => renderedText(readValue(item, reader));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** @param {unknown} item @param {string|Function} reader @returns {unknown} */
|
|
190
|
-
function readValue(item, reader) {
|
|
191
|
-
return typeof reader === 'function' ? reader(item) : item?.[reader];
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** @param {unknown} value @returns {string} */
|
|
195
|
-
function renderedText(value) {
|
|
196
|
-
if (value?.nodeType) return value.textContent ?? '';
|
|
197
|
-
return String(value ?? '');
|
|
198
|
-
}
|
package/src/compat/map/stubs.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** Creates a direct-construction stub with an actionable migration error. */
|
|
2
|
-
function migrationStub(legacyName, replacement) {
|
|
3
|
-
return class LegacyMigrationStub {
|
|
4
|
-
/** @throws {Error} Always; this API needs an explicit migration. */
|
|
5
|
-
constructor() {
|
|
6
|
-
throw new Error(`${legacyName} is not emulated by Zx; migrate to ${replacement}`);
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Direct Settings subclassing is intentionally outside the compatibility contract. */
|
|
12
|
-
export const Settings = migrationStub('gx.core.Settings', 'plain option objects');
|
|
13
|
-
/** Direct Container subclassing is intentionally outside the compatibility contract. */
|
|
14
|
-
export const Container = migrationStub('gx.ui.Container', 'zx.Component');
|
|
15
|
-
/** Legacy collapse animation stub. */
|
|
16
|
-
export const Collapse = migrationStub('gx.ui.Collapse', 'CSS transitions');
|
|
17
|
-
/** Legacy blend animation stub. */
|
|
18
|
-
export const Blend = migrationStub('gx.ui.Blend', 'CSS transitions');
|
|
19
|
-
/** Legacy HUD stub. */
|
|
20
|
-
export const Hud = migrationStub('gx.ui.Hud', 'zx.Dialog');
|
|
21
|
-
/** Legacy toggling helper stub. */
|
|
22
|
-
export const Toggling = migrationStub('gx.ui.Toggling', 'zx.Toggle');
|
|
23
|
-
/** Legacy horizontal group stub. */
|
|
24
|
-
export const HGroup = migrationStub('gx.ui.HGroup', 'CSS layout');
|
|
25
|
-
/** Legacy templates stub. */
|
|
26
|
-
export const Templates = migrationStub('gx.ui.Templates', 'native template elements');
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { parse } from '../globals.js';
|
|
2
|
-
|
|
3
|
-
/** Legacy utility namespace backed by dependency-free implementations. */
|
|
4
|
-
export const util = Object.freeze({
|
|
5
|
-
initValue,
|
|
6
|
-
initNum,
|
|
7
|
-
formatTime,
|
|
8
|
-
getMinutes,
|
|
9
|
-
formatNum,
|
|
10
|
-
getNumber,
|
|
11
|
-
printf,
|
|
12
|
-
parseResult,
|
|
13
|
-
Parse: parse,
|
|
14
|
-
isArray: Array.isArray,
|
|
15
|
-
isObject: (value) => value !== null && typeof value === 'object' && !Array.isArray(value) &&
|
|
16
|
-
!(typeof Node !== 'undefined' && value instanceof Node) && !(value instanceof Date),
|
|
17
|
-
isFunction: (value) => typeof value === 'function',
|
|
18
|
-
isString: (value) => typeof value === 'string',
|
|
19
|
-
isNumber: (value) => typeof value === 'number' && Number.isFinite(value),
|
|
20
|
-
isElement: (value) => typeof Element !== 'undefined' && value instanceof Element,
|
|
21
|
-
isNode: (value) => typeof Node !== 'undefined' && value instanceof Node,
|
|
22
|
-
Console: (source, message) => {
|
|
23
|
-
if (typeof console === 'undefined') return;
|
|
24
|
-
if (message instanceof Error) console.error(source, message.stack);
|
|
25
|
-
else console.log(`${source}: ${message}`);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
/** @param {Record<string, unknown>} object @param {string} key @param {unknown} fallback @returns {unknown} */
|
|
30
|
-
export function initValue(object, key, fallback) {
|
|
31
|
-
return object?.[key] == null ? fallback : object[key];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** @param {unknown} value @returns {number} */
|
|
35
|
-
export function initNum(value) {
|
|
36
|
-
if (typeof value === 'number') return value;
|
|
37
|
-
if (typeof value === 'string') return Number.parseFloat(value);
|
|
38
|
-
return 0;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** @param {unknown} value @returns {string} */
|
|
42
|
-
export function formatTime(value) {
|
|
43
|
-
let minutes = value;
|
|
44
|
-
if (typeof minutes === 'string') {
|
|
45
|
-
if (/^[0-9]+:[0-9]{2}$/.test(minutes)) return minutes;
|
|
46
|
-
if (/^[0-9]+:[0-9]{2,}$/.test(minutes)) {
|
|
47
|
-
const digits = minutes.replace(/[^0-9]/g, '');
|
|
48
|
-
return digits.replace(/([0-9]{2})$/, ':$1');
|
|
49
|
-
}
|
|
50
|
-
minutes = Number.parseInt(minutes.replace(/[^0-9]/g, ''), 10);
|
|
51
|
-
}
|
|
52
|
-
if (minutes == null || Number.isNaN(Number(minutes))) return '0:00';
|
|
53
|
-
let number = Number(minutes);
|
|
54
|
-
const prefix = number < 0 ? '-' : '';
|
|
55
|
-
number = Math.abs(number);
|
|
56
|
-
return `${prefix}${Math.floor(number / 60)}:${pad(number % 60)}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** @param {unknown} value @returns {number} */
|
|
60
|
-
export function getMinutes(value) {
|
|
61
|
-
const parts = String(value ?? '').replace(/[^0-9:]/, '').split(':');
|
|
62
|
-
if (parts.length === 1) return Number.parseInt(parts[0], 10);
|
|
63
|
-
return Number.parseInt(parts[0], 10) * 60 + Number.parseInt(parts[1], 10);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** @param {unknown} value @param {string} [decimal='.'] @param {string} [thousands=','] @param {number} [decimals=2] @returns {string} */
|
|
67
|
-
export function formatNum(value, decimal = '.', thousands = ',', decimals = 2) {
|
|
68
|
-
let number = value;
|
|
69
|
-
if (typeof number === 'string') {
|
|
70
|
-
number = Number.parseFloat(number.replace(new RegExp(`[^0-9${escapeRegExp(decimal)}]`), '').replace(decimal, '.'));
|
|
71
|
-
}
|
|
72
|
-
if (Number.isNaN(Number(number))) number = 0;
|
|
73
|
-
const precision = typeof decimals === 'number' ? decimals : 2;
|
|
74
|
-
let formatted = Math.round(Number(number) * (10 ** precision)).toString();
|
|
75
|
-
for (let index = formatted.length; index <= precision; index += 1) formatted = `0${formatted}`;
|
|
76
|
-
const position = formatted.length - precision;
|
|
77
|
-
if (precision > 0) formatted = `${formatted.slice(0, position)}${decimal}${formatted.slice(position)}`;
|
|
78
|
-
for (let index = position - 3; index > 0; index -= 3) {
|
|
79
|
-
formatted = `${formatted.slice(0, index)}${thousands}${formatted.slice(index)}`;
|
|
80
|
-
}
|
|
81
|
-
return formatted;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** @param {unknown} value @param {string} [decimal=','] @returns {number} */
|
|
85
|
-
export function getNumber(value, decimal = '.') {
|
|
86
|
-
return Number.parseFloat(String(value ?? '').replace(new RegExp(`[^0-9${escapeRegExp(decimal)}]`), '').replace(decimal, '.'));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** @param {unknown} template @param {unknown|unknown[]} [values=[]] @returns {string} */
|
|
90
|
-
export function printf(template, values = []) {
|
|
91
|
-
const replacements = Array.isArray(values) ? values : [values];
|
|
92
|
-
let index = 0;
|
|
93
|
-
return String(template ?? '').replace(/%arg%/g, (match) => index < replacements.length ? String(replacements[index++]) : match);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** @param {unknown} response @returns {unknown} */
|
|
97
|
-
export function parseResult(response) {
|
|
98
|
-
const data = typeof response === 'string' ? JSON.parse(response) : response;
|
|
99
|
-
if (!data || typeof data !== 'object') throw new Error('Invalid server response');
|
|
100
|
-
if (data.error) throw new Error(String(data.error.message ?? data.error));
|
|
101
|
-
if (!Object.hasOwn(data, 'result') || data.result == null) throw new Error('Undefined result');
|
|
102
|
-
return data.result;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** @param {number} value @returns {string} */
|
|
106
|
-
function pad(value) {
|
|
107
|
-
return String(value).padStart(2, '0');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** @param {string} value @returns {string} */
|
|
111
|
-
function escapeRegExp(value) {
|
|
112
|
-
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
113
|
-
}
|
package/src/compat-entry.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/** Browser entry point for the gx compatibility bundle. */
|
|
2
|
-
import * as zx from './index.js';
|
|
3
|
-
import gx, { install, installElementStorage } from './compat/index.js';
|
|
4
|
-
|
|
5
|
-
const host = typeof window === 'undefined' ? globalThis : window;
|
|
6
|
-
installElementStorage(host);
|
|
7
|
-
install(host);
|
|
8
|
-
host.zx = zx;
|
|
9
|
-
|
|
10
|
-
export { gx, zx };
|
|
11
|
-
export default gx;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
.zx-permission {
|
|
2
|
-
min-inline-size: 0;
|
|
3
|
-
color: var(--zx-color-text);
|
|
4
|
-
font-size: var(--zx-control-font-size);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.zx-permission__choices {
|
|
8
|
-
display: grid;
|
|
9
|
-
grid-template-columns: repeat(3, max-content) minmax(160px, 1fr);
|
|
10
|
-
align-items: center;
|
|
11
|
-
gap: var(--zx-space-2) var(--zx-space-4);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.zx-permission__choice {
|
|
15
|
-
display: inline-flex;
|
|
16
|
-
align-items: center;
|
|
17
|
-
gap: var(--zx-space-2);
|
|
18
|
-
min-block-size: var(--zx-control-height);
|
|
19
|
-
cursor: pointer;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.zx-permission__choice input {
|
|
23
|
-
accent-color: var(--zx-color-accent);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.zx-permission__choice:has(input:focus-visible) {
|
|
27
|
-
border-radius: var(--zx-radius-sm);
|
|
28
|
-
box-shadow: var(--zx-focus-ring);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.zx-permission__groups {
|
|
32
|
-
min-inline-size: 160px;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.zx-permission:not([data-state="group"]) .zx-permission__groups {
|
|
36
|
-
color: var(--zx-color-text-muted);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@media (max-width: 640px) {
|
|
40
|
-
.zx-permission__choices {
|
|
41
|
-
grid-template-columns: 1fr;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.zx-permission__groups {
|
|
45
|
-
inline-size: 100%;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { Component } from '../../core/component.js';
|
|
2
|
-
import { h } from '../../core/dom.js';
|
|
3
|
-
import { uid } from '../../core/util.js';
|
|
4
|
-
import { Select } from '../select/select.js';
|
|
5
|
-
|
|
6
|
-
/** @typedef {Record<string, any>|string|number|boolean|symbol|bigint|null|undefined} PermissionGroup */
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {Object} PermissionOptions
|
|
9
|
-
* @property {boolean|string|number|symbol|bigint|null} [value=true] Public, private, or group ID.
|
|
10
|
-
* @property {PermissionGroup[]} [groups=[]] Available groups.
|
|
11
|
-
* @property {string|((item: PermissionGroup) => unknown)} [groupsValueKey='ID'] Group ID property or reader.
|
|
12
|
-
* @property {string|((item: PermissionGroup) => string)} [groupsLabelKey='name'] Group label property or reader.
|
|
13
|
-
* @property {Record<string, string>|Record<string, Record<string, string>>} [msg] Localized messages.
|
|
14
|
-
* @property {(event: CustomEvent<PermissionChangeDetail>) => void} [onchange] Change listener.
|
|
15
|
-
*/
|
|
16
|
-
/** @typedef {{value: unknown}} PermissionChangeDetail */
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Record-permission choice for private, public, and group access.
|
|
20
|
-
*
|
|
21
|
-
* @deprecated Use `Select.permission(target, {groups})`, which carries the same tri-state value in
|
|
22
|
-
* one control and accepts a loader function for installations whose group list is too long to ship
|
|
23
|
-
* with the form. This class stays for `gx.zeyos.Permission` and will be removed in 3.0.
|
|
24
|
-
* @fires Permission#change
|
|
25
|
-
* @extends {Component<PermissionOptions>}
|
|
26
|
-
*/
|
|
27
|
-
export class Permission extends Component {
|
|
28
|
-
static cssName = 'permission';
|
|
29
|
-
|
|
30
|
-
/** @type {PermissionOptions} */
|
|
31
|
-
static defaults = {
|
|
32
|
-
value: true,
|
|
33
|
-
groups: [],
|
|
34
|
-
groupsValueKey: 'ID',
|
|
35
|
-
groupsLabelKey: 'name'
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/** @returns {HTMLElement} */
|
|
40
|
-
render() {
|
|
41
|
-
// Instance state initialized here because render() runs inside the base
|
|
42
|
-
// constructor, before class-field initializers would run (and clobber it).
|
|
43
|
-
this._mode = 'public'; this._groupValue = null; this._groupSelect = null; this._createdRoot = false; this._originalChildren = []; this._root = null; this._originalState = null;
|
|
44
|
-
this._createdRoot = this.el === null;
|
|
45
|
-
const root = /** @type {HTMLElement} */ (this.el ?? h('div'));
|
|
46
|
-
this.el = root;
|
|
47
|
-
this._root = root;
|
|
48
|
-
if (!this._createdRoot) {
|
|
49
|
-
this._originalChildren = Array.from(root.childNodes);
|
|
50
|
-
this._originalState = root.getAttribute('data-state');
|
|
51
|
-
}
|
|
52
|
-
const name = uid('zx-permission');
|
|
53
|
-
const choices = h('div', {
|
|
54
|
-
class: 'zx-permission__choices',
|
|
55
|
-
role: 'radiogroup',
|
|
56
|
-
ariaLabel: this._message('permission.label', 'Permission')
|
|
57
|
-
});
|
|
58
|
-
const privateChoice = this._choice(name, 'private', this._message('permission.private', 'Private'));
|
|
59
|
-
const publicChoice = this._choice(name, 'public', this._message('permission.public', 'Public'));
|
|
60
|
-
const groupChoice = this._choice(name, 'group', this._message('permission.group', 'Group'));
|
|
61
|
-
const groupHost = h('div', { ref: 'groupHost', class: 'zx-permission__groups' });
|
|
62
|
-
choices.append(privateChoice.label, publicChoice.label, groupChoice.label, groupHost);
|
|
63
|
-
root.replaceChildren(choices);
|
|
64
|
-
this.refs.private = privateChoice.input;
|
|
65
|
-
this.refs.public = publicChoice.input;
|
|
66
|
-
this.refs.group = groupChoice.input;
|
|
67
|
-
|
|
68
|
-
this._groupSelect = new Select(groupHost, {
|
|
69
|
-
items: Array.isArray(this.options.groups) ? this.options.groups : [],
|
|
70
|
-
valueKey: this.options.groupsValueKey,
|
|
71
|
-
labelKey: this.options.groupsLabelKey,
|
|
72
|
-
placeholder: this._message('permission.group', 'Group')
|
|
73
|
-
});
|
|
74
|
-
this._groupSelect.refs.input.setAttribute(
|
|
75
|
-
'aria-label',
|
|
76
|
-
this._message('permission.group', 'Group')
|
|
77
|
-
);
|
|
78
|
-
for (const input of [privateChoice.input, publicChoice.input, groupChoice.input]) {
|
|
79
|
-
this.listen(input, 'change', () => {
|
|
80
|
-
if (!input.checked) return;
|
|
81
|
-
if (input.value === 'group') this._selectGroupMode();
|
|
82
|
-
else this.set(input.value);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
this.listen(groupHost, 'zx-change', (event) => {
|
|
86
|
-
event.stopPropagation();
|
|
87
|
-
if (this._mode !== 'group') return;
|
|
88
|
-
const previous = this.get();
|
|
89
|
-
this._groupValue = /** @type {CustomEvent} */ (event).detail.value;
|
|
90
|
-
const value = this.get();
|
|
91
|
-
if (!Object.is(previous, value)) this.emit('change', { value });
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
this.set(this.options.value, { silent: true });
|
|
95
|
-
return root;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Returns the normalized permission value. @returns {'private'|'public'|unknown} */
|
|
99
|
-
get() {
|
|
100
|
-
if (this._mode === 'private') return 'private';
|
|
101
|
-
if (this._mode === 'public') return 'public';
|
|
102
|
-
return this._groupValue;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Sets a public, private, or group permission.
|
|
107
|
-
* @param {boolean|string|number|symbol|bigint|null} value Permission value.
|
|
108
|
-
* @param {{silent?: boolean}} [options={}] Update behavior.
|
|
109
|
-
* @returns {this}
|
|
110
|
-
* @fires Permission#change
|
|
111
|
-
*/
|
|
112
|
-
set(value, { silent = false } = {}) {
|
|
113
|
-
const previous = this.get();
|
|
114
|
-
if (value === true || value === 'public') {
|
|
115
|
-
this._mode = 'public';
|
|
116
|
-
} else if (value === false || value === 'private') {
|
|
117
|
-
this._mode = 'private';
|
|
118
|
-
} else {
|
|
119
|
-
this._mode = 'group';
|
|
120
|
-
this._groupValue = value;
|
|
121
|
-
this._groupSelect?.set(value, { silent: true });
|
|
122
|
-
}
|
|
123
|
-
this._sync();
|
|
124
|
-
const next = this.get();
|
|
125
|
-
if (!silent && !Object.is(previous, next)) this.emit('change', { value: next });
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/** Destroys the embedded Select and restores an enhanced target. @returns {void} */
|
|
130
|
-
destroy() {
|
|
131
|
-
this._groupSelect?.destroy();
|
|
132
|
-
this._groupSelect = null;
|
|
133
|
-
if (!this._createdRoot && this.el) {
|
|
134
|
-
this.el.replaceChildren(...this._originalChildren);
|
|
135
|
-
if (this._originalState === null) this.el.removeAttribute('data-state');
|
|
136
|
-
else this.el.setAttribute('data-state', this._originalState);
|
|
137
|
-
}
|
|
138
|
-
super.destroy();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** @returns {void} */
|
|
142
|
-
_selectGroupMode() {
|
|
143
|
-
const previous = this.get();
|
|
144
|
-
this._mode = 'group';
|
|
145
|
-
if (this._groupValue == null) {
|
|
146
|
-
const first = Array.isArray(this.options.groups) ? this.options.groups[0] : null;
|
|
147
|
-
this._groupValue = first == null ? null : read(first, this.options.groupsValueKey);
|
|
148
|
-
}
|
|
149
|
-
this._groupSelect?.set(this._groupValue, { silent: true });
|
|
150
|
-
this._sync();
|
|
151
|
-
const next = this.get();
|
|
152
|
-
if (!Object.is(previous, next)) this.emit('change', { value: next });
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** @returns {void} */
|
|
156
|
-
_sync() {
|
|
157
|
-
/** @type {HTMLInputElement} */ (this.refs.private).checked = this._mode === 'private';
|
|
158
|
-
/** @type {HTMLInputElement} */ (this.refs.public).checked = this._mode === 'public';
|
|
159
|
-
/** @type {HTMLInputElement} */ (this.refs.group).checked = this._mode === 'group';
|
|
160
|
-
if (this._mode === 'group') this._groupSelect?.enable();
|
|
161
|
-
else this._groupSelect?.disable();
|
|
162
|
-
this._root?.setAttribute('data-state', this._mode);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* @param {string} name
|
|
167
|
-
* @param {'private'|'public'|'group'} value
|
|
168
|
-
* @param {string} text
|
|
169
|
-
* @returns {{label: HTMLLabelElement, input: HTMLInputElement}}
|
|
170
|
-
*/
|
|
171
|
-
_choice(name, value, text) {
|
|
172
|
-
const input = /** @type {HTMLInputElement} */ (h('input', {
|
|
173
|
-
type: 'radio',
|
|
174
|
-
name,
|
|
175
|
-
value
|
|
176
|
-
}));
|
|
177
|
-
const label = /** @type {HTMLLabelElement} */ (h('label', {
|
|
178
|
-
class: 'zx-permission__choice'
|
|
179
|
-
}, input, h('span', {}, text)));
|
|
180
|
-
return { label, input };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** @param {string} key @param {string} fallback @returns {string} */
|
|
184
|
-
_message(key, fallback) {
|
|
185
|
-
const message = this.msg(key);
|
|
186
|
-
return message === key ? fallback : message;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** Permission-value change. @event Permission#change @type {CustomEvent<PermissionChangeDetail>} */
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* @param {PermissionGroup} item
|
|
194
|
-
* @param {string|((item: PermissionGroup) => unknown)} reader
|
|
195
|
-
* @returns {unknown}
|
|
196
|
-
*/
|
|
197
|
-
function read(item, reader) {
|
|
198
|
-
if (typeof reader === 'function') return reader(item);
|
|
199
|
-
if (item === null || typeof item !== 'object') return item;
|
|
200
|
-
return item[reader];
|
|
201
|
-
}
|