@mono-lit/helper 0.0.5 → 0.0.7
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/dist/{control-tooltip-C3rA_nSH.js → control-tooltip-CoPD37_h.js} +20 -11
- package/dist/{data-source-options-Cz9fVLK8.js → data-source-options-CS0w0wlO.js} +26 -9
- package/dist/{data-source-options-QjuI73g8.js → data-source-options-lDR-g9Eb.js} +26 -9
- package/dist/{data-source-read-FxqzQkk2.js → data-source-read-Cp_h7NIf.js} +5 -2
- package/dist/{data-source-read-i6CYSUEl.js → data-source-read-DTJ_Mnez.js} +5 -2
- package/dist/{excel-BPdDt06G.js → excel-DtRpxmxs.js} +1 -1
- package/dist/{export-DgomqI_3.js → export-D27RJa1w.js} +1 -1
- package/dist/export.js +3 -3
- package/dist/{field-tooltip-FyMi9vNM.js → field-tooltip-Csk4s2ve.js} +2 -3
- package/dist/field-tooltip-addon-B32dizW_.js +22 -0
- package/dist/{control-tooltip-7vegYmq3.js → field-tooltip-addon-CWCp19mJ.js} +36 -12
- package/dist/{field-tooltip.css_raw-DEctHXKm.js → field-tooltip.css_raw-U5UeTa2d.js} +3 -4
- package/dist/{field-validation-CHHQi1zl.js → field-validation-CFmUmuDx.js} +1 -1
- package/dist/field-validation.css_raw-Cx6SGrfP.js +178 -0
- package/dist/{form-control-core-CIdMLXMo.js → form-control-core-BbiACMtL.js} +1 -1
- package/dist/{hydration-flush-DHrl4_KK.js → hydration-flush-BaE9gN3C.js} +450 -3
- package/dist/index.js +11 -11
- package/dist/{index.node-DzCuvHLg.js → index.node-Mg0Snp0t.js} +5 -5
- package/dist/index.node.js +11 -11
- package/dist/input.css_raw-Br-T8RWv.js +5 -0
- package/dist/{light-slots-DdDdZ6zs.js → light-slots-B5Ck0t_E.js} +1 -1
- package/dist/{light-slots-4ZCjOcBg.js → light-slots-_no0r2Z-.js} +1 -1
- package/dist/mono-button-CLkHg3WW.js +871 -0
- package/dist/{mono-button.shadow-D9NdMsmH.js → mono-button.shadow-DqZMpcqY.js} +1 -2
- package/dist/{mono-data-chart-ChkelNT7.js → mono-data-chart-BAH9Zb3p.js} +2 -2
- package/dist/{mono-data-dropdown-DxpUUk2y.js → mono-data-dropdown-BsY5IuIo.js} +72 -6
- package/dist/{mono-data-grid-KDpu4d4_.js → mono-data-grid-CZFjpnOD.js} +125 -18
- package/dist/{mono-data-grid-8jmeIXUU.js → mono-data-grid-kV4jYu2g.js} +124 -17
- package/dist/{mono-element-C7vCschg.js → mono-element-CKcT0rwv.js} +1 -1
- package/dist/{mono-form-controller-BkMR8g14.js → mono-form-controller-BrA10erm.js} +12 -1
- package/dist/mono-ui-kvLVIf1V.js +786 -0
- package/dist/{popup-portal-C8ttHDRX.js → popup-portal-CINuVjNY.js} +53 -6
- package/dist/src/components/accordion/mono-accordion.d.ts +0 -1
- package/dist/src/components/alert/mono-alert.d.ts +0 -1
- package/dist/src/components/breadcrumb/mono-breadcrumb-list.d.ts +0 -1
- package/dist/src/components/breadcrumb/mono-breadcrumb.d.ts +0 -1
- package/dist/src/components/button/mono-button-dropdown.d.ts +0 -1
- package/dist/src/components/button/mono-button.d.ts +0 -1
- package/dist/src/components/card/mono-card.d.ts +0 -1
- package/dist/src/components/chart/mono-chart-presets.d.ts +0 -4
- package/dist/src/components/chart/mono-chart.d.ts +0 -1
- package/dist/src/components/checkbox/mono-checkbox.d.ts +0 -1
- package/dist/src/components/chip/mono-chip.d.ts +0 -1
- package/dist/src/components/date/mono-date.d.ts +0 -1
- package/dist/src/components/drawer/mono-drawer.d.ts +0 -1
- package/dist/src/components/dropdown/mono-dropdown.d.ts +0 -1
- package/dist/src/components/dropdown-table/mono-dropdown-table.d.ts +0 -1
- package/dist/src/components/file-upload/mono-file-upload.d.ts +0 -1
- package/dist/src/components/filter/mono-filter-builder.d.ts +0 -1
- package/dist/src/components/input/mono-input.d.ts +0 -1
- package/dist/src/components/menu/mono-menu.d.ts +0 -1
- package/dist/src/components/modal/mono-modal.d.ts +0 -1
- package/dist/src/components/nav/mono-nav.d.ts +0 -1
- package/dist/src/components/otp/mono-otp.d.ts +0 -1
- package/dist/src/components/radio/mono-radio.d.ts +0 -1
- package/dist/src/components/rich-text-editor/mono-rich-text-editor.d.ts +0 -1
- package/dist/src/components/select/mono-select.d.ts +0 -1
- package/dist/src/components/sidebar/mono-sidebar.d.ts +0 -1
- package/dist/src/components/slider/mono-slider.d.ts +0 -1
- package/dist/src/components/switch/mono-switch.d.ts +0 -1
- package/dist/src/components/table/column-autosize.d.ts +96 -0
- package/dist/src/components/table/mono-data-grid.d.ts +16 -0
- package/dist/src/components/table/mono-table-checkbox.d.ts +0 -1
- package/dist/src/components/table/mono-table-detail.d.ts +0 -1
- package/dist/src/components/table/mono-table-empty.d.ts +0 -1
- package/dist/src/components/table/mono-table-error.d.ts +0 -1
- package/dist/src/components/table/mono-table-info.d.ts +0 -1
- package/dist/src/components/table/mono-table-loading.d.ts +0 -1
- package/dist/src/components/table/mono-table-page-size.d.ts +0 -1
- package/dist/src/components/table/mono-table-paging-group.d.ts +0 -1
- package/dist/src/components/table/mono-table-paging.d.ts +0 -1
- package/dist/src/components/table/mono-table-search.d.ts +0 -1
- package/dist/src/components/table/mono-table-sort.d.ts +0 -1
- package/dist/src/components/table/mono-table-summary.d.ts +0 -1
- package/dist/src/components/table/mono-table-th-core.d.ts +3 -0
- package/dist/src/components/table/mono-table-th.d.ts +0 -1
- package/dist/src/components/table/table-controller-core.d.ts +2 -0
- package/dist/src/components/table/table-types.d.ts +8 -1
- package/dist/src/components/tabs/mono-tabs.d.ts +0 -1
- package/dist/src/components/tag-input/mono-tag-input.d.ts +12 -1
- package/dist/src/components/tag-input/mono-tag-input.shadow.d.ts +9 -1
- package/dist/src/components/tag-input/tag-input-core.d.ts +9 -1
- package/dist/src/components/tag-input/tag-input-types.d.ts +2 -0
- package/dist/src/components/textarea/mono-textarea.d.ts +0 -1
- package/dist/src/components/tooltip/field-tooltip-addon.d.ts +5 -0
- package/dist/src/composables/mono-size-attrs.d.ts +10 -0
- package/dist/src/composables/popup-portal.d.ts +24 -1
- package/dist/src/entries/index.d.ts +2 -1
- package/dist/src/entries/index.node.d.ts +2 -1
- package/dist/{styles-BODNpZV1.js → styles-D-ergrfR.js} +1 -1
- package/dist/{tooltip-Drekihf5.js → tooltip-Cu5IrDS9.js} +1 -2
- package/dist/tooltip.js +2 -3
- package/dist/ui/accordion.js +4 -11
- package/dist/ui/alert.js +3 -10
- package/dist/ui/breadcrumb.js +4 -14
- package/dist/ui/button-dropdown.js +22 -15
- package/dist/ui/button.js +1 -1
- package/dist/ui/card.js +4 -11
- package/dist/ui/chart.js +4 -24
- package/dist/ui/checkbox.js +4 -11
- package/dist/ui/chip.js +6 -9
- package/dist/ui/date.js +5 -12
- package/dist/ui/drawer.js +5 -12
- package/dist/ui/dropdown-table.js +89 -38
- package/dist/ui/dropdown.js +34 -21
- package/dist/ui/file-upload.js +4 -11
- package/dist/ui/filter.js +3 -10
- package/dist/ui/form.js +1 -1
- package/dist/ui/index.css +5414 -8564
- package/dist/ui/input.js +6 -14
- package/dist/ui/menu.js +4 -11
- package/dist/ui/modal.js +6 -13
- package/dist/ui/nav.js +4 -11
- package/dist/ui/otp.js +6 -14
- package/dist/ui/radio.js +4 -11
- package/dist/ui/rich-text-editor.js +4 -12
- package/dist/ui/select.js +12 -15
- package/dist/ui/shadow/accordion.js +1 -1
- package/dist/ui/shadow/alert.js +1 -1
- package/dist/ui/shadow/breadcrumb.js +1 -1
- package/dist/ui/shadow/button-dropdown.js +21 -7
- package/dist/ui/shadow/button.js +1 -1
- package/dist/ui/shadow/card.js +1 -2
- package/dist/ui/shadow/chart.js +3 -4
- package/dist/ui/shadow/checkbox.js +2 -2
- package/dist/ui/shadow/chip.js +1 -1
- package/dist/ui/shadow/date.js +4 -5
- package/dist/ui/shadow/drawer.js +2 -2
- package/dist/ui/shadow/dropdown-table.js +159 -35
- package/dist/ui/shadow/dropdown.js +31 -11
- package/dist/ui/shadow/file-upload.js +2 -2
- package/dist/ui/shadow/filter.js +1 -2
- package/dist/ui/shadow/input.js +5 -6
- package/dist/ui/shadow/menu.js +1 -1
- package/dist/ui/shadow/modal.js +3 -3
- package/dist/ui/shadow/nav.js +1 -1
- package/dist/ui/shadow/otp.js +5 -6
- package/dist/ui/shadow/radio.js +2 -2
- package/dist/ui/shadow/rich-text-editor.js +2 -3
- package/dist/ui/shadow/select.js +11 -7
- package/dist/ui/shadow/sidebar.js +2 -2
- package/dist/ui/shadow/slider.js +4 -5
- package/dist/ui/shadow/switch.js +2 -2
- package/dist/ui/shadow/table.js +113 -20
- package/dist/ui/shadow/tabs.js +1 -1
- package/dist/ui/shadow/tag-input.js +203 -27
- package/dist/ui/shadow/textarea.js +4 -5
- package/dist/ui/sidebar.js +4 -11
- package/dist/ui/slider.js +5 -13
- package/dist/ui/switch.js +4 -11
- package/dist/ui/table.js +114 -64
- package/dist/ui/tabs.js +4 -11
- package/dist/ui/tag-input.js +215 -30
- package/dist/ui/textarea.js +6 -14
- package/dist/ui/theme/luma.css +495 -495
- package/dist/ui/theme/lyra.css +495 -495
- package/dist/ui/theme/maia.css +495 -495
- package/dist/ui/theme/mira.css +495 -495
- package/dist/ui/theme/nova.css +495 -495
- package/dist/ui/theme/one.css +742 -742
- package/dist/ui/theme/rhea.css +495 -495
- package/dist/ui/theme/sera.css +495 -495
- package/dist/ui/theme/vega.css +495 -495
- package/package.json +2 -2
- package/dist/css-size-DWAPgQdT.js +0 -38
- package/dist/field-validation.css_raw-B3Iu33rS.js +0 -178
- package/dist/input.css_raw-CQu2fAsU.js +0 -5
- package/dist/mono-button-CeDB9khW.js +0 -878
- package/dist/mono-ui-BwUc0L6B.js +0 -360
- package/dist/tooltip-loader-3U9FTOXj.js +0 -20
- package/dist/tooltip-loader-Dcp9AUZn.js +0 -23
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
//#region src/composables/mono-skeleton.ts
|
|
2
|
+
/**
|
|
3
|
+
* "Is there a DOM to render into?" — deliberately NOT lit's `isServer`. That flag is a
|
|
4
|
+
* build-time constant of lit's node entry, so it is `true` wherever Node's export
|
|
5
|
+
* conditions pick that build — including a jsdom test run, where this feature must work.
|
|
6
|
+
* On a real server (`@lit-labs/ssr` + its dom shim) there is a `customElements` but no
|
|
7
|
+
* `document`, which is exactly the distinction that matters here.
|
|
8
|
+
*/
|
|
9
|
+
const hasDom = typeof document !== "undefined" && typeof customElements !== "undefined";
|
|
10
|
+
/**
|
|
11
|
+
* ONE store per realm, on `globalThis` (same reasoning as `mono-ui.ts`): the light and
|
|
12
|
+
* shadow builds are separate bundles and a pnpm peer fork can install two copies of the
|
|
13
|
+
* package, yet all of them must agree on "active" and on the defaults.
|
|
14
|
+
*/
|
|
15
|
+
const STATE_KEY$1 = Symbol.for("mono-helper.skeleton");
|
|
16
|
+
const state$1 = globalThis[STATE_KEY$1] ??= {
|
|
17
|
+
active: false,
|
|
18
|
+
disabled: false,
|
|
19
|
+
ssr: null,
|
|
20
|
+
ssrSniffed: null,
|
|
21
|
+
defaults: {},
|
|
22
|
+
watching: false,
|
|
23
|
+
createdBeforeActive: 0,
|
|
24
|
+
createdBeforeActiveTags: [],
|
|
25
|
+
warnedLate: false,
|
|
26
|
+
waiting: /* @__PURE__ */ new Set(),
|
|
27
|
+
holders: /* @__PURE__ */ new Set()
|
|
28
|
+
};
|
|
29
|
+
const PHANTOM_TAG = "phantom-ui";
|
|
30
|
+
const DEFAULT_MAX_WAIT = 15e3;
|
|
31
|
+
/** Per-element slots the Cores can read without depending on the mixin's class shape. */
|
|
32
|
+
const TAG_DEFAULT = Symbol.for("mono-helper.skeleton.tagDefault");
|
|
33
|
+
const PENDING_ACTIVE = Symbol.for("mono-helper.skeleton.active");
|
|
34
|
+
const PENDING_GRACE = Symbol.for("mono-helper.skeleton.grace");
|
|
35
|
+
const PENDING_PHANTOM = Symbol.for("mono-helper.skeleton.phantom");
|
|
36
|
+
/** Where `applyMonoUIDefaults` parks a tag's `pending` default (not assigned to the prop). */
|
|
37
|
+
const MONO_PENDING_TAG_DEFAULT = TAG_DEFAULT;
|
|
38
|
+
function isActive() {
|
|
39
|
+
return state$1.active && !state$1.disabled;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Start following the registry. Idempotent; a no-op on the server. Called by the mono
|
|
43
|
+
* `customElement` decorator, so the watcher exists before any element constructs.
|
|
44
|
+
*/
|
|
45
|
+
function watchSkeletonActivation() {
|
|
46
|
+
if (!hasDom || state$1.watching) return;
|
|
47
|
+
state$1.watching = true;
|
|
48
|
+
const activate = () => {
|
|
49
|
+
state$1.active = true;
|
|
50
|
+
if (state$1.createdBeforeActive > 0 && !state$1.warnedLate) {
|
|
51
|
+
state$1.warnedLate = true;
|
|
52
|
+
const tags = state$1.createdBeforeActiveTags.slice(0, 5).join(", ");
|
|
53
|
+
console.warn(`[mono-skeleton] phantom-ui was defined after ${state$1.createdBeforeActive} mono element(s) had rendered (${tags}); their first paint had no skeleton. Load "@aejkatappaja/phantom-ui" before the app mounts (main.ts import, or let @mono-lit/helper/nuxt do it).`);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
if (customElements.get(PHANTOM_TAG)) {
|
|
57
|
+
activate();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
customElements.whenDefined(PHANTOM_TAG).then(activate, () => {});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Is this an SSR app? The explicit flag (`createMonoUI({ skeleton: { ssr } })`, which the
|
|
64
|
+
* Nuxt module sets from `nuxt.options.ssr`) wins; otherwise the Nuxt payload marker is
|
|
65
|
+
* sniffed once (`<script id="__NUXT_DATA__" data-ssr="true">`).
|
|
66
|
+
*/
|
|
67
|
+
function isMonoSsrApp() {
|
|
68
|
+
if (state$1.ssr !== null) return state$1.ssr;
|
|
69
|
+
if (state$1.ssrSniffed === null) state$1.ssrSniffed = hasDom && document.getElementById("__NUXT_DATA__")?.getAttribute("data-ssr") === "true";
|
|
70
|
+
return state$1.ssrSniffed;
|
|
71
|
+
}
|
|
72
|
+
/** Set the global defaults (`createMonoUI`'s `skeleton` key routes here). `false` disables the skeleton. */
|
|
73
|
+
function setMonoSkeletonDefaults(defaults) {
|
|
74
|
+
if (defaults === false) {
|
|
75
|
+
state$1.disabled = true;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
state$1.disabled = false;
|
|
79
|
+
const { ssr, ...rest } = defaults ?? {};
|
|
80
|
+
state$1.ssr = typeof ssr === "boolean" ? ssr : null;
|
|
81
|
+
state$1.defaults = { ...rest };
|
|
82
|
+
}
|
|
83
|
+
function getMonoSkeletonStatus() {
|
|
84
|
+
return {
|
|
85
|
+
active: isActive(),
|
|
86
|
+
ssr: state$1.ssr,
|
|
87
|
+
createdBeforeActive: state$1.createdBeforeActive,
|
|
88
|
+
createdBeforeActiveTags: [...state$1.createdBeforeActiveTags]
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Drop defaults / flag / counters (tests). `active` stays — an element cannot be undefined. */
|
|
92
|
+
function resetMonoSkeleton() {
|
|
93
|
+
state$1.disabled = false;
|
|
94
|
+
state$1.ssr = null;
|
|
95
|
+
state$1.ssrSniffed = null;
|
|
96
|
+
state$1.defaults = {};
|
|
97
|
+
state$1.createdBeforeActive = 0;
|
|
98
|
+
state$1.createdBeforeActiveTags = [];
|
|
99
|
+
state$1.warnedLate = false;
|
|
100
|
+
state$1.waiting.clear();
|
|
101
|
+
state$1.holders.clear();
|
|
102
|
+
}
|
|
103
|
+
const PHANTOM_KEYS = [
|
|
104
|
+
"animation",
|
|
105
|
+
"mode",
|
|
106
|
+
"shimmerDirection",
|
|
107
|
+
"shimmerColor",
|
|
108
|
+
"backgroundColor",
|
|
109
|
+
"duration",
|
|
110
|
+
"stagger",
|
|
111
|
+
"reveal",
|
|
112
|
+
"count",
|
|
113
|
+
"countGap",
|
|
114
|
+
"fallbackRadius",
|
|
115
|
+
"loadingLabel",
|
|
116
|
+
"pierceShadow",
|
|
117
|
+
"debug"
|
|
118
|
+
];
|
|
119
|
+
const kebab = (name) => name.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
120
|
+
function isPendingObject(value) {
|
|
121
|
+
return !!value && typeof value === "object";
|
|
122
|
+
}
|
|
123
|
+
/** The boolean a `pending` value carries (`undefined` = auto). */
|
|
124
|
+
function activeOf(value) {
|
|
125
|
+
if (typeof value === "boolean") return value;
|
|
126
|
+
if (isPendingObject(value)) return typeof value.active === "boolean" ? value.active : void 0;
|
|
127
|
+
}
|
|
128
|
+
/** Only the phantom options of a value (an object), as a plain record. */
|
|
129
|
+
function phantomOf(value) {
|
|
130
|
+
const out = {};
|
|
131
|
+
if (!isPendingObject(value)) return out;
|
|
132
|
+
for (const key of PHANTOM_KEYS) {
|
|
133
|
+
const v = value[key];
|
|
134
|
+
if (v !== void 0) out[key] = v;
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
function shallowEqual(a, b) {
|
|
139
|
+
const ka = Object.keys(a);
|
|
140
|
+
const kb = Object.keys(b);
|
|
141
|
+
if (ka.length !== kb.length) return false;
|
|
142
|
+
for (const k of ka) if (a[k] !== b[k]) return false;
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
/** `hasChanged` for the property: booleans by value, objects shallowly. */
|
|
146
|
+
function pendingChanged(next, prev) {
|
|
147
|
+
if (isPendingObject(next) && isPendingObject(prev)) return !shallowEqual(next, prev);
|
|
148
|
+
return next !== prev;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The attribute converter. The attribute form is boolean-only: `pending`,
|
|
152
|
+
* `pending="true"` → true; `pending="false"` → false; absent or `pending="auto"` → auto.
|
|
153
|
+
* A real boolean is accepted too (what a server renderer hands over).
|
|
154
|
+
*/
|
|
155
|
+
const pendingConverter = {
|
|
156
|
+
fromAttribute(value) {
|
|
157
|
+
if (value === null || value === void 0) return void 0;
|
|
158
|
+
if (typeof value === "boolean") return value;
|
|
159
|
+
const s = String(value).trim().toLowerCase();
|
|
160
|
+
if (s === "auto") return void 0;
|
|
161
|
+
return s === "" || s === "true";
|
|
162
|
+
},
|
|
163
|
+
toAttribute() {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Register the `pending` property on a registered element class. Called by the mono
|
|
169
|
+
* `customElement` decorator BEFORE `customElements.define`, so the attribute lands in
|
|
170
|
+
* Lit's attribute map when `observedAttributes` is read.
|
|
171
|
+
*/
|
|
172
|
+
function registerPendingProperty(cls) {
|
|
173
|
+
cls.createProperty("pending", {
|
|
174
|
+
attribute: "pending",
|
|
175
|
+
reflect: false,
|
|
176
|
+
converter: pendingConverter,
|
|
177
|
+
hasChanged: pendingChanged
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/** Whether `pending` currently resolves to true for `el` (set before each render). */
|
|
181
|
+
function monoPendingActive(el) {
|
|
182
|
+
return !!el[PENDING_ACTIVE];
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* True once one macrotask has passed since the element first resolved pending — lets a
|
|
186
|
+
* `'data'` Core say "no controller / source after one tick → nothing to wait for" without
|
|
187
|
+
* releasing before a binding made in the consumer's `onMounted`.
|
|
188
|
+
*/
|
|
189
|
+
function monoPendingGrace(el) {
|
|
190
|
+
return !!el[PENDING_GRACE];
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The phantom options resolved for `el` while pending (element object over tag default
|
|
194
|
+
* over global default), camelCase keys. Empty while not pending. For `'custom'` Cores
|
|
195
|
+
* that render their own `<phantom-ui>` and want a value in the template (e.g. `count`).
|
|
196
|
+
*/
|
|
197
|
+
function monoPhantomOptions(el) {
|
|
198
|
+
return el[PENDING_PHANTOM] ?? {};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Apply the resolved phantom options to a `<phantom-ui>` element as attributes (used by
|
|
202
|
+
* the mixin for its wrapper, and by `'custom'` Cores for the phantom they render).
|
|
203
|
+
* Diffed against what was last applied to that element, so unchanged values cost nothing.
|
|
204
|
+
*/
|
|
205
|
+
function monoApplyPhantomOptions(el, target) {
|
|
206
|
+
if (!target) return;
|
|
207
|
+
const next = el[PENDING_PHANTOM] ?? {};
|
|
208
|
+
const store = target;
|
|
209
|
+
const prev = store[PENDING_PHANTOM] ?? {};
|
|
210
|
+
if (shallowEqual(next, prev)) return;
|
|
211
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(prev), ...Object.keys(next)])) {
|
|
212
|
+
const value = next[key];
|
|
213
|
+
const attr = kebab(key);
|
|
214
|
+
if (value === void 0 || value === null || value === false) target.removeAttribute(attr);
|
|
215
|
+
else if (value === true) target.setAttribute(attr, "");
|
|
216
|
+
else target.setAttribute(attr, String(value));
|
|
217
|
+
}
|
|
218
|
+
store[PENDING_PHANTOM] = { ...next };
|
|
219
|
+
}
|
|
220
|
+
/** @internal */
|
|
221
|
+
const monoSkeletonInternals = {
|
|
222
|
+
hasDom,
|
|
223
|
+
isActive,
|
|
224
|
+
state: state$1,
|
|
225
|
+
slots: {
|
|
226
|
+
TAG_DEFAULT,
|
|
227
|
+
PENDING_ACTIVE,
|
|
228
|
+
PENDING_GRACE,
|
|
229
|
+
PENDING_PHANTOM
|
|
230
|
+
},
|
|
231
|
+
activeOf,
|
|
232
|
+
phantomOf,
|
|
233
|
+
PHANTOM_TAG,
|
|
234
|
+
DEFAULT_MAX_WAIT
|
|
235
|
+
};
|
|
236
|
+
/** The `<phantom-ui>` wrapper the skeleton mixin renders around an element's content. */
|
|
237
|
+
function isMonoSkeletonWrapper(node) {
|
|
238
|
+
return !!node && node.nodeType === 1 && node.localName === PHANTOM_TAG && node.hasAttribute("mono-skeleton");
|
|
239
|
+
}
|
|
240
|
+
/** `Array.from(host.childNodes)` minus the skeleton wrapper. */
|
|
241
|
+
function monoHostChildNodes(host) {
|
|
242
|
+
return Array.from(host.childNodes).filter((n) => !isMonoSkeletonWrapper(n));
|
|
243
|
+
}
|
|
244
|
+
/** `Array.from(host.children)` minus the skeleton wrapper. */
|
|
245
|
+
function monoHostChildren(host) {
|
|
246
|
+
return Array.from(host.children).filter((n) => !isMonoSkeletonWrapper(n));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region src/composables/css-size.ts
|
|
251
|
+
/**
|
|
252
|
+
* Normalize a sizing prop to a CSS length string.
|
|
253
|
+
* - `number` (or numeric string) → `${n}px`
|
|
254
|
+
* - any other non-empty string → passed through verbatim (`"12rem"`, `"80%"`, …)
|
|
255
|
+
* - `null` / `undefined` / `''` → `undefined` (treated as "not set")
|
|
256
|
+
*/
|
|
257
|
+
function toCssSize(value) {
|
|
258
|
+
if (value === null || value === void 0) return void 0;
|
|
259
|
+
if (typeof value === "number") return Number.isFinite(value) ? `${value}px` : void 0;
|
|
260
|
+
const trimmed = String(value).trim();
|
|
261
|
+
if (trimmed === "") return void 0;
|
|
262
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) return `${trimmed}px`;
|
|
263
|
+
return trimmed;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Build a Lit `styleMap` object from the six sizing props, normalizing each via
|
|
267
|
+
* `toCssSize` and omitting the ones that aren't set.
|
|
268
|
+
*/
|
|
269
|
+
function buildSizeStyle(src) {
|
|
270
|
+
const style = {};
|
|
271
|
+
const width = toCssSize(src.width);
|
|
272
|
+
const height = toCssSize(src.height);
|
|
273
|
+
const minWidth = toCssSize(src.minWidth);
|
|
274
|
+
const maxWidth = toCssSize(src.maxWidth);
|
|
275
|
+
const minHeight = toCssSize(src.minHeight);
|
|
276
|
+
const maxHeight = toCssSize(src.maxHeight);
|
|
277
|
+
if (width) style.width = width;
|
|
278
|
+
if (height) style.height = height;
|
|
279
|
+
if (minWidth) style["min-width"] = minWidth;
|
|
280
|
+
if (maxWidth) style["max-width"] = maxWidth;
|
|
281
|
+
if (minHeight) style["min-height"] = minHeight;
|
|
282
|
+
if (maxHeight) style["max-height"] = maxHeight;
|
|
283
|
+
return style;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/components/table/column-autosize.ts
|
|
288
|
+
/**
|
|
289
|
+
* Content-sized columns — what `mono-table-th`'s `width="auto"` drives.
|
|
290
|
+
*
|
|
291
|
+
* Under `mono-table-fixed` (`table-layout: fixed`) CSS cannot do this: an `auto` column takes
|
|
292
|
+
* the WHOLE surplus instead of fitting its content, and `min-width` / `max-width` on a cell are
|
|
293
|
+
* ignored by the table algorithm. So the column is measured here and handed a concrete px width,
|
|
294
|
+
* clamped to `minWidth` / `maxWidth`, written to its `<col>` (which wins under fixed layout) and
|
|
295
|
+
* to the header cell.
|
|
296
|
+
*
|
|
297
|
+
* Text is measured with a canvas, not read back from the cell: reading the cell's own width would
|
|
298
|
+
* return the width last written, and a column could then never shrink. Measuring text also keeps
|
|
299
|
+
* the pass free of layout reads, so re-running it on every change is cheap.
|
|
300
|
+
*
|
|
301
|
+
* What is measured: the header (caption + its icons), every body cell and every FOOTER cell of
|
|
302
|
+
* the column. The footer matters — a `<mono-table-summary>` total covers the whole set, so a
|
|
303
|
+
* virtual-scroll window that only shows small figures still sizes for the largest one.
|
|
304
|
+
*
|
|
305
|
+
* Cell content is treated as one line (what a money column is). An editor (`<input>`, including
|
|
306
|
+
* the one inside `mono-input`) counts with its value and its own padding / border.
|
|
307
|
+
*/
|
|
308
|
+
/** The text measurer — swappable so tests can run where there is no canvas (jsdom). */
|
|
309
|
+
const autosizeEnv = { measure: defaultMeasure };
|
|
310
|
+
let ctx;
|
|
311
|
+
function defaultMeasure(text, font) {
|
|
312
|
+
if (ctx === void 0) ctx = document.createElement("canvas").getContext("2d");
|
|
313
|
+
if (!ctx) return text.length * 8;
|
|
314
|
+
ctx.font = font;
|
|
315
|
+
return ctx.measureText(text).width;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* A canvas `font` string for a computed style — always built from the longhands.
|
|
319
|
+
*
|
|
320
|
+
* NOT `style.font`: the shorthand serialises to `''` whenever a longhand it cannot express is set,
|
|
321
|
+
* and `font-variant-numeric: tabular-nums` (every `mono-table-summary`) is one. The old fallback then
|
|
322
|
+
* put `fontVariant` (`tabular-nums`) into the string, canvas rejected it, kept its default
|
|
323
|
+
* `10px sans-serif`, and a footer total measured far too narrow — the largest figure ellipsed.
|
|
324
|
+
* Only `small-caps` is a variant canvas takes; tabular figures are handled in `measureStyled`.
|
|
325
|
+
*/
|
|
326
|
+
function fontOf(style) {
|
|
327
|
+
const caps = style.fontVariantCaps === "small-caps" ? "small-caps" : "";
|
|
328
|
+
return [
|
|
329
|
+
style.fontStyle,
|
|
330
|
+
caps,
|
|
331
|
+
style.fontWeight,
|
|
332
|
+
style.fontSize,
|
|
333
|
+
style.fontFamily
|
|
334
|
+
].filter(Boolean).join(" ");
|
|
335
|
+
}
|
|
336
|
+
const px = (v) => parseFloat(v) || 0;
|
|
337
|
+
/** The widest digit in `font` — a tabular figure's advance, which canvas cannot be asked for. */
|
|
338
|
+
const digitWidths = /* @__PURE__ */ new Map();
|
|
339
|
+
function maxDigit(font) {
|
|
340
|
+
let w = digitWidths.get(font);
|
|
341
|
+
if (w === void 0) {
|
|
342
|
+
w = Math.max(..."0123456789".split("").map((d) => autosizeEnv.measure(d, font)));
|
|
343
|
+
digitWidths.set(font, w);
|
|
344
|
+
}
|
|
345
|
+
return w;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* `text` as the element renders it: its `text-transform`, its `letter-spacing` (canvas ignores
|
|
349
|
+
* both) and its `font-variant-numeric: tabular-nums` (every digit at the widest digit's advance —
|
|
350
|
+
* a safe upper bound; tabular figures are wider than the proportional ones canvas measures).
|
|
351
|
+
*/
|
|
352
|
+
function measureStyled(text, style) {
|
|
353
|
+
const font = fontOf(style);
|
|
354
|
+
if (style.textTransform === "uppercase") text = text.toUpperCase();
|
|
355
|
+
else if (style.textTransform === "lowercase") text = text.toLowerCase();
|
|
356
|
+
let width;
|
|
357
|
+
if (/tabular-nums/.test(style.fontVariantNumeric ?? "")) {
|
|
358
|
+
const digits = text.replace(/\D/g, "").length;
|
|
359
|
+
width = autosizeEnv.measure(text.replace(/\d/g, ""), font) + digits * maxDigit(font);
|
|
360
|
+
} else width = autosizeEnv.measure(text, font);
|
|
361
|
+
return width + px(style.letterSpacing) * text.length;
|
|
362
|
+
}
|
|
363
|
+
/** Horizontal padding + border of an element's box. */
|
|
364
|
+
function boxX(style) {
|
|
365
|
+
return px(style.paddingLeft) + px(style.paddingRight) + px(style.borderLeftWidth) + px(style.borderRightWidth);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* A size prop as px: a number / bare numeric string / `px` → px, `rem` → × the root font size,
|
|
369
|
+
* `em` → × `el`'s font size. Anything else (`%`, `auto`, a var) → `undefined`: not a bound.
|
|
370
|
+
*/
|
|
371
|
+
function cssLengthToPx(value, el) {
|
|
372
|
+
if (value == null) return void 0;
|
|
373
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
374
|
+
const m = /^\s*(-?\d+(?:\.\d+)?)\s*(px|rem|em)?\s*$/i.exec(value);
|
|
375
|
+
if (!m) return void 0;
|
|
376
|
+
const n = parseFloat(m[1]);
|
|
377
|
+
const unit = (m[2] ?? "px").toLowerCase();
|
|
378
|
+
if (unit === "px") return n;
|
|
379
|
+
const ref = unit === "rem" ? document.documentElement : el ?? document.documentElement;
|
|
380
|
+
return n * (px(getComputedStyle(ref).fontSize) || 16);
|
|
381
|
+
}
|
|
382
|
+
/** `w` clamped to `[min, max]`; an unset bound does not clamp. `min` wins over a smaller `max`. */
|
|
383
|
+
function clampWidth(w, min, max) {
|
|
384
|
+
if (max != null) w = Math.min(w, max);
|
|
385
|
+
if (min != null) w = Math.max(w, min);
|
|
386
|
+
return w;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The grid column a header cell STARTS at — a walk over its section's rows honouring `rowspan`
|
|
390
|
+
* and `colspan`, so a leaf header under a band row (`<th colspan>` above it) maps to its real
|
|
391
|
+
* column. `cellIndex` alone would count only the cells of its own row.
|
|
392
|
+
*/
|
|
393
|
+
function headerColumnIndex(cell) {
|
|
394
|
+
const section = cell.parentElement?.parentElement;
|
|
395
|
+
if (!section) return cell.cellIndex;
|
|
396
|
+
const taken = [];
|
|
397
|
+
const rows = Array.from(section.children).filter((r) => r.tagName === "TR");
|
|
398
|
+
for (let r = 0; r < rows.length; r++) {
|
|
399
|
+
taken[r] ??= [];
|
|
400
|
+
let c = 0;
|
|
401
|
+
for (const cur of Array.from(rows[r].cells)) {
|
|
402
|
+
while (taken[r][c]) c++;
|
|
403
|
+
if (cur === cell) return c;
|
|
404
|
+
for (let dr = 0; dr < Math.max(1, cur.rowSpan); dr++) {
|
|
405
|
+
const row = taken[r + dr] ??= [];
|
|
406
|
+
for (let dc = 0; dc < Math.max(1, cur.colSpan); dc++) row[c + dc] = true;
|
|
407
|
+
}
|
|
408
|
+
c += Math.max(1, cur.colSpan);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return cell.cellIndex;
|
|
412
|
+
}
|
|
413
|
+
/** The single-column cell of `row` at grid column `col` — a spanning cell (a spacer row) is none. */
|
|
414
|
+
function cellAt(row, col) {
|
|
415
|
+
let c = 0;
|
|
416
|
+
for (const cell of Array.from(row.cells)) {
|
|
417
|
+
const span = Math.max(1, cell.colSpan);
|
|
418
|
+
if (c === col) return span === 1 ? cell : void 0;
|
|
419
|
+
if (c > col) return void 0;
|
|
420
|
+
c += span;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/** The `<col>` at grid column `col`, honouring `<col span>`. */
|
|
424
|
+
function colAt(table, col) {
|
|
425
|
+
let c = 0;
|
|
426
|
+
for (const group of Array.from(table.children).filter((e) => e.tagName === "COLGROUP")) {
|
|
427
|
+
const cols = Array.from(group.children).filter((e) => e.tagName === "COL");
|
|
428
|
+
for (const el of cols) {
|
|
429
|
+
const span = Math.max(1, el.span || 1);
|
|
430
|
+
if (col < c + span) return span === 1 ? el : void 0;
|
|
431
|
+
c += span;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/** An element hidden by `v-show` / `hidden` — its text does not show, so it does not count. */
|
|
436
|
+
function isHidden(el) {
|
|
437
|
+
return el.hidden === true || el.style?.display === "none";
|
|
438
|
+
}
|
|
439
|
+
/** The one-line width a cell's content needs, padding included. */
|
|
440
|
+
function contentWidth(cell) {
|
|
441
|
+
let width = 0;
|
|
442
|
+
const walk = (node) => {
|
|
443
|
+
for (const child of Array.from(node.childNodes)) if (child.nodeType === Node.TEXT_NODE) {
|
|
444
|
+
const text = (child.textContent ?? "").replace(/\s+/g, " ");
|
|
445
|
+
if (!text.trim()) continue;
|
|
446
|
+
const parent = child.parentElement ?? node.host ?? cell;
|
|
447
|
+
width += measureStyled(text, getComputedStyle(parent));
|
|
448
|
+
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
449
|
+
const el = child;
|
|
450
|
+
if (isHidden(el)) continue;
|
|
451
|
+
if (el.tagName === "INPUT" || el.tagName === "TEXTAREA") {
|
|
452
|
+
const input = el;
|
|
453
|
+
const style = getComputedStyle(input);
|
|
454
|
+
width += measureStyled(input.value || input.placeholder || "", style) + boxX(style);
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
if (el.tagName === "SVG" || el.tagName === "svg") {
|
|
458
|
+
width += el.getBoundingClientRect?.().width || 0;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
walk(el.shadowRoot ?? el);
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
walk(cell);
|
|
465
|
+
return width + boxX(getComputedStyle(cell));
|
|
466
|
+
}
|
|
467
|
+
/** The header cell's need: the caption text plus whatever icons sit beside it. */
|
|
468
|
+
function headerWidth(cell, host) {
|
|
469
|
+
const label = host.querySelector("[data-mono-slot=\"label\"]");
|
|
470
|
+
const text = (label?.textContent ?? host.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
471
|
+
let width = text ? measureStyled(text, getComputedStyle(label ?? host)) : 0;
|
|
472
|
+
for (const icon of Array.from(host.querySelectorAll(".mono-th-filter-ind, .mono-table-sort-btn:not(.label-trigger), .mono-th-required"))) {
|
|
473
|
+
const w = icon.getBoundingClientRect?.().width || 0;
|
|
474
|
+
width += w ? w + 4 : 0;
|
|
475
|
+
}
|
|
476
|
+
return width + boxX(getComputedStyle(cell));
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* One auto-sized column, owned by its `mono-table-th`. `schedule()` coalesces every trigger (a
|
|
480
|
+
* controller notify, a body mutation, typing in an editor) into one measurement per frame.
|
|
481
|
+
*/
|
|
482
|
+
var ColumnAutoSize = class ColumnAutoSize {
|
|
483
|
+
constructor(host) {
|
|
484
|
+
this.host = host;
|
|
485
|
+
this.growOnly = false;
|
|
486
|
+
this._floor = 0;
|
|
487
|
+
this._raf = 0;
|
|
488
|
+
this._onInput = (e) => {
|
|
489
|
+
const t = e.target;
|
|
490
|
+
if (t && this._table && !this._table.tHead?.contains(t)) this.schedule();
|
|
491
|
+
};
|
|
492
|
+
this._onFonts = () => {
|
|
493
|
+
digitWidths.clear();
|
|
494
|
+
this.schedule();
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
static {
|
|
498
|
+
this._queued = /* @__PURE__ */ new Set();
|
|
499
|
+
}
|
|
500
|
+
static {
|
|
501
|
+
this._frame = 0;
|
|
502
|
+
}
|
|
503
|
+
static _flush() {
|
|
504
|
+
ColumnAutoSize._frame = 0;
|
|
505
|
+
const batch = [...ColumnAutoSize._queued];
|
|
506
|
+
ColumnAutoSize._queued.clear();
|
|
507
|
+
const writes = batch.map((s) => {
|
|
508
|
+
s._raf = 0;
|
|
509
|
+
return s._measure();
|
|
510
|
+
});
|
|
511
|
+
for (const write of writes) write?.();
|
|
512
|
+
}
|
|
513
|
+
schedule() {
|
|
514
|
+
if (this._raf) return;
|
|
515
|
+
this._raf = 1;
|
|
516
|
+
ColumnAutoSize._queued.add(this);
|
|
517
|
+
ColumnAutoSize._frame ||= requestAnimationFrame(() => ColumnAutoSize._flush());
|
|
518
|
+
}
|
|
519
|
+
/** Forget the grow-only floor (new rows) and re-measure. */
|
|
520
|
+
resetFloor() {
|
|
521
|
+
if (!this._floor) return;
|
|
522
|
+
this._floor = 0;
|
|
523
|
+
this.schedule();
|
|
524
|
+
}
|
|
525
|
+
/** Stop watching, and hand the column back to whatever width it is given next. */
|
|
526
|
+
stop(clear = false) {
|
|
527
|
+
ColumnAutoSize._queued.delete(this);
|
|
528
|
+
this._raf = 0;
|
|
529
|
+
this._unwatch();
|
|
530
|
+
if (clear && this._wrote) {
|
|
531
|
+
if (this._wrote.col) this._wrote.col.style.width = "";
|
|
532
|
+
this._wrote.cell.style.width = "";
|
|
533
|
+
}
|
|
534
|
+
this._wrote = void 0;
|
|
535
|
+
}
|
|
536
|
+
_watch(table) {
|
|
537
|
+
if (this._table === table) return;
|
|
538
|
+
this._unwatch();
|
|
539
|
+
this._table = table;
|
|
540
|
+
this._observer = new MutationObserver((records) => {
|
|
541
|
+
const head = table.tHead;
|
|
542
|
+
if (records.some((r) => !head?.contains(r.target))) this.schedule();
|
|
543
|
+
});
|
|
544
|
+
this._observer.observe(table, {
|
|
545
|
+
childList: true,
|
|
546
|
+
characterData: true,
|
|
547
|
+
subtree: true
|
|
548
|
+
});
|
|
549
|
+
table.addEventListener("input", this._onInput, true);
|
|
550
|
+
document.fonts?.addEventListener?.("loadingdone", this._onFonts);
|
|
551
|
+
}
|
|
552
|
+
_unwatch() {
|
|
553
|
+
this._observer?.disconnect();
|
|
554
|
+
this._observer = void 0;
|
|
555
|
+
this._table?.removeEventListener("input", this._onInput, true);
|
|
556
|
+
document.fonts?.removeEventListener?.("loadingdone", this._onFonts);
|
|
557
|
+
this._table = void 0;
|
|
558
|
+
}
|
|
559
|
+
/** Measure now (reads only); returns the write to apply after every sizer has measured. */
|
|
560
|
+
_measure() {
|
|
561
|
+
const cell = this.host.closest("th, td");
|
|
562
|
+
const table = cell?.closest("table");
|
|
563
|
+
if (!cell || !table || !this.host.isConnected) return null;
|
|
564
|
+
this._watch(table);
|
|
565
|
+
const index = headerColumnIndex(cell);
|
|
566
|
+
let width = headerWidth(cell, this.host);
|
|
567
|
+
const sections = [...Array.from(table.tBodies), ...table.tFoot ? [table.tFoot] : []];
|
|
568
|
+
for (const section of sections) for (const row of Array.from(section.rows)) {
|
|
569
|
+
const target = cellAt(row, index);
|
|
570
|
+
if (target) width = Math.max(width, contentWidth(target));
|
|
571
|
+
}
|
|
572
|
+
width = Math.ceil(clampWidth(width + 1, this.min, this.max));
|
|
573
|
+
if (this.growOnly) width = this._floor = Math.max(width, this._floor);
|
|
574
|
+
else this._floor = 0;
|
|
575
|
+
const value = `${width}px`;
|
|
576
|
+
const col = colAt(table, index);
|
|
577
|
+
return () => {
|
|
578
|
+
if (cell.style.width !== value) cell.style.width = value;
|
|
579
|
+
if (col && col.style.width !== value) col.style.width = value;
|
|
580
|
+
this._wrote = {
|
|
581
|
+
col,
|
|
582
|
+
cell
|
|
583
|
+
};
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
//#endregion
|
|
589
|
+
//#region src/composables/mono-size-attrs.ts
|
|
590
|
+
const ATTRS = [
|
|
591
|
+
"mono-width",
|
|
592
|
+
"mono-min-width",
|
|
593
|
+
"mono-max-width"
|
|
594
|
+
];
|
|
595
|
+
const SELECTOR = ATTRS.map((a) => `[${a}]`).join(", ");
|
|
596
|
+
/** Auto-sized cells and their sizers — a cell that loses `auto` or the document gets stopped. */
|
|
597
|
+
const sizers = /* @__PURE__ */ new Map();
|
|
598
|
+
let observer = null;
|
|
599
|
+
const isCell = (el) => el.tagName === "TH" || el.tagName === "TD";
|
|
600
|
+
/** Apply the three attributes to one element. Re-run whenever one of them changes. */
|
|
601
|
+
function applyMonoSizeAttributes(el) {
|
|
602
|
+
const width = el.getAttribute("mono-width")?.trim() ?? "";
|
|
603
|
+
const min = el.getAttribute("mono-min-width")?.trim() ?? "";
|
|
604
|
+
const max = el.getAttribute("mono-max-width")?.trim() ?? "";
|
|
605
|
+
const auto = width.toLowerCase() === "auto";
|
|
606
|
+
el.style.minWidth = min ? toCssSize(min) ?? "" : "";
|
|
607
|
+
el.style.maxWidth = max ? toCssSize(max) ?? "" : "";
|
|
608
|
+
if (!isCell(el)) {
|
|
609
|
+
el.style.width = auto ? "fit-content" : width ? toCssSize(width) ?? "" : "";
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
let sizer = sizers.get(el);
|
|
613
|
+
if (!auto) {
|
|
614
|
+
if (sizer) {
|
|
615
|
+
sizer.stop(true);
|
|
616
|
+
sizers.delete(el);
|
|
617
|
+
}
|
|
618
|
+
el.style.width = width ? toCssSize(width) ?? "" : "";
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (!sizer) sizers.set(el, sizer = new ColumnAutoSize(el));
|
|
622
|
+
sizer.min = cssLengthToPx(min || null, el);
|
|
623
|
+
sizer.max = cssLengthToPx(max || null, el);
|
|
624
|
+
sizer.schedule();
|
|
625
|
+
}
|
|
626
|
+
/** Stop the sizers of cells that left the document. */
|
|
627
|
+
function sweep() {
|
|
628
|
+
for (const [el, sizer] of sizers) {
|
|
629
|
+
if (el.isConnected) continue;
|
|
630
|
+
sizer.stop();
|
|
631
|
+
sizers.delete(el);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function scan(root) {
|
|
635
|
+
if (root instanceof HTMLElement && root.matches(SELECTOR)) applyMonoSizeAttributes(root);
|
|
636
|
+
for (const el of Array.from(root.querySelectorAll(SELECTOR))) applyMonoSizeAttributes(el);
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Turn the attributes on for the whole document — idempotent, so every caller may call it.
|
|
640
|
+
* Returns a stop function (tests; an app never needs it).
|
|
641
|
+
*/
|
|
642
|
+
function startMonoSizeAttributes() {
|
|
643
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {};
|
|
644
|
+
if (!observer) {
|
|
645
|
+
observer = new MutationObserver((records) => {
|
|
646
|
+
let removed = false;
|
|
647
|
+
for (const r of records) {
|
|
648
|
+
if (r.type === "attributes") {
|
|
649
|
+
applyMonoSizeAttributes(r.target);
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
for (const node of Array.from(r.addedNodes)) if (node.nodeType === 1 && node.isConnected) scan(node);
|
|
653
|
+
if (r.removedNodes.length) removed = true;
|
|
654
|
+
}
|
|
655
|
+
if (removed && sizers.size) sweep();
|
|
656
|
+
});
|
|
657
|
+
observer.observe(document.documentElement, {
|
|
658
|
+
subtree: true,
|
|
659
|
+
childList: true,
|
|
660
|
+
attributes: true,
|
|
661
|
+
attributeFilter: [...ATTRS]
|
|
662
|
+
});
|
|
663
|
+
scan(document);
|
|
664
|
+
}
|
|
665
|
+
return stopMonoSizeAttributes;
|
|
666
|
+
}
|
|
667
|
+
function stopMonoSizeAttributes() {
|
|
668
|
+
observer?.disconnect();
|
|
669
|
+
observer = null;
|
|
670
|
+
for (const sizer of sizers.values()) sizer.stop();
|
|
671
|
+
sizers.clear();
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
//#endregion
|
|
675
|
+
//#region src/composables/mono-ui.ts
|
|
676
|
+
const STATE_KEY = Symbol.for("mono-helper.ui");
|
|
677
|
+
const state = globalThis[STATE_KEY] ??= {
|
|
678
|
+
store: null,
|
|
679
|
+
createdTotal: 0,
|
|
680
|
+
createdTags: [],
|
|
681
|
+
createdBeforeConfig: 0,
|
|
682
|
+
createdBeforeConfigTags: [],
|
|
683
|
+
warned: /* @__PURE__ */ new Set()
|
|
684
|
+
};
|
|
685
|
+
const SHADOW_PREFIX = "mono-shadow-";
|
|
686
|
+
function warnOnce(key, message) {
|
|
687
|
+
if (state.warned.has(key)) return;
|
|
688
|
+
state.warned.add(key);
|
|
689
|
+
console.warn(`[mono-ui] ${message}`);
|
|
690
|
+
}
|
|
691
|
+
const camel = (name) => name.replace(/-([a-z0-9])/g, (_m, c) => c.toUpperCase());
|
|
692
|
+
/** Arrays and plain objects are copied per element, so one element cannot mutate the shared config. */
|
|
693
|
+
function fresh(value) {
|
|
694
|
+
if (Array.isArray(value)) return [...value];
|
|
695
|
+
if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) return { ...value };
|
|
696
|
+
return value;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Set the app-wide default props. Call once, first — usually in `main.ts`:
|
|
700
|
+
*
|
|
701
|
+
* ```ts
|
|
702
|
+
* app.use(createMonoUI({ 'mono-button': { size: 'xs' } }))
|
|
703
|
+
* // or simply
|
|
704
|
+
* createMonoUI({ 'mono-button': { size: 'xs' } })
|
|
705
|
+
* ```
|
|
706
|
+
*
|
|
707
|
+
* A later call replaces the previous config for elements created afterwards.
|
|
708
|
+
*/
|
|
709
|
+
function createMonoUI(config = {}) {
|
|
710
|
+
const next = {};
|
|
711
|
+
setMonoSkeletonDefaults(config.skeleton);
|
|
712
|
+
for (const [tag, props] of Object.entries(config)) {
|
|
713
|
+
if (tag === "skeleton") continue;
|
|
714
|
+
if (!/^mono-[a-z0-9-]+$/.test(tag)) {
|
|
715
|
+
warnOnce(`tag:${tag}`, `"${tag}" is not a mono component tag — expected "mono-<name>". Ignored.`);
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (!props || typeof props !== "object") continue;
|
|
719
|
+
next[tag] = { ...props };
|
|
720
|
+
}
|
|
721
|
+
state.createdBeforeConfig = state.createdTotal;
|
|
722
|
+
state.createdBeforeConfigTags = [...state.createdTags];
|
|
723
|
+
if (state.createdTotal > 0 && typeof document !== "undefined") {
|
|
724
|
+
const tags = state.createdTags.slice(0, 5).join(", ") + (state.createdTags.length > 5 ? ", …" : "");
|
|
725
|
+
console.warn(`[mono-ui] createMonoUI() ran after ${state.createdTotal} mono element${state.createdTotal === 1 ? " was" : "s were"} created (${tags}); ${state.createdTotal === 1 ? "it keeps its" : "those keep their"} built-in defaults. Call createMonoUI() first in main.ts, before app.mount().`);
|
|
726
|
+
}
|
|
727
|
+
state.store = next;
|
|
728
|
+
startMonoSizeAttributes();
|
|
729
|
+
return {
|
|
730
|
+
config: { ...next },
|
|
731
|
+
install() {}
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
/** The current config, or `null` when `createMonoUI` has not been called. */
|
|
735
|
+
function getMonoUI() {
|
|
736
|
+
return state.store;
|
|
737
|
+
}
|
|
738
|
+
/** Whether the config is set, and how many elements were created before it was. */
|
|
739
|
+
function getMonoUIStatus() {
|
|
740
|
+
return {
|
|
741
|
+
configured: state.store !== null,
|
|
742
|
+
createdBefore: state.store ? state.createdBeforeConfig : state.createdTotal,
|
|
743
|
+
createdBeforeTags: state.store ? [...state.createdBeforeConfigTags] : [...state.createdTags]
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
/** Drop the config (tests, or reconfiguring before mount). Elements created afterwards get built-in defaults. */
|
|
747
|
+
function resetMonoUI() {
|
|
748
|
+
resetMonoSkeleton();
|
|
749
|
+
state.store = null;
|
|
750
|
+
state.createdTotal = 0;
|
|
751
|
+
state.createdTags.length = 0;
|
|
752
|
+
state.createdBeforeConfig = 0;
|
|
753
|
+
state.createdBeforeConfigTags = [];
|
|
754
|
+
state.warned.clear();
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Apply the configured defaults to a freshly constructed element. Called by the
|
|
758
|
+
* mono `customElement` decorator at the end of construction — not public API.
|
|
759
|
+
* @internal
|
|
760
|
+
*/
|
|
761
|
+
function applyMonoUIDefaults(el, tag) {
|
|
762
|
+
state.createdTotal++;
|
|
763
|
+
if (!state.createdTags.includes(tag)) state.createdTags.push(tag);
|
|
764
|
+
if (!state.store) return;
|
|
765
|
+
const base = tag.startsWith(SHADOW_PREFIX) ? `mono-${tag.slice(12)}` : tag;
|
|
766
|
+
const props = {
|
|
767
|
+
...state.store[base] ?? {},
|
|
768
|
+
...base !== tag ? state.store[tag] ?? {} : {}
|
|
769
|
+
};
|
|
770
|
+
for (const [key, value] of Object.entries(props)) {
|
|
771
|
+
if (value === void 0) continue;
|
|
772
|
+
const prop = camel(key);
|
|
773
|
+
if (prop === "pending") {
|
|
774
|
+
el[MONO_PENDING_TAG_DEFAULT] = fresh(value);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
if (!(prop in el)) {
|
|
778
|
+
warnOnce(`prop:${base}:${prop}`, `<${base}> has no prop "${key}". Ignored.`);
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
el[prop] = fresh(value);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
//#endregion
|
|
786
|
+
export { resetMonoSkeleton as C, registerPendingProperty as S, monoHostChildren as _, resetMonoUI as a, monoPhantomOptions as b, stopMonoSizeAttributes as c, buildSizeStyle as d, toCssSize as f, monoHostChildNodes as g, monoApplyPhantomOptions as h, getMonoUIStatus as i, ColumnAutoSize as l, isMonoSsrApp as m, createMonoUI as n, applyMonoSizeAttributes as o, getMonoSkeletonStatus as p, getMonoUI as r, startMonoSizeAttributes as s, applyMonoUIDefaults as t, cssLengthToPx as u, monoPendingActive as v, watchSkeletonActivation as w, monoSkeletonInternals as x, monoPendingGrace as y };
|