mithril-materialized 3.5.6 → 3.5.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/index.esm.js +292 -112
- package/dist/index.js +295 -111
- package/dist/index.umd.js +295 -111
- package/dist/utils.d.ts +32 -0
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -163,6 +163,76 @@
|
|
|
163
163
|
* @example: console.log(range(5, 10)); // [5, 6, 7, 8, 9, 10]
|
|
164
164
|
*/
|
|
165
165
|
const range = (a, b) => Array.from({ length: b - a + 1 }, (_, i) => a + i);
|
|
166
|
+
// Global registry for portal containers
|
|
167
|
+
const portalContainers = new Map();
|
|
168
|
+
/**
|
|
169
|
+
* Creates or retrieves a portal container appended to document.body.
|
|
170
|
+
* Uses reference counting to manage container lifecycle.
|
|
171
|
+
*
|
|
172
|
+
* @param id - Unique identifier for the portal container
|
|
173
|
+
* @param zIndex - Z-index for the portal container (default: 1004, above modals at 1003)
|
|
174
|
+
* @returns The portal container element
|
|
175
|
+
*/
|
|
176
|
+
const getPortalContainer = (id, zIndex = 1004) => {
|
|
177
|
+
let container = portalContainers.get(id);
|
|
178
|
+
if (!container) {
|
|
179
|
+
const element = document.createElement('div');
|
|
180
|
+
element.id = id;
|
|
181
|
+
element.style.position = 'fixed';
|
|
182
|
+
element.style.top = '0';
|
|
183
|
+
element.style.left = '0';
|
|
184
|
+
element.style.width = '100%';
|
|
185
|
+
element.style.height = '100%';
|
|
186
|
+
element.style.pointerEvents = 'none'; // Allow clicks through to underlying elements
|
|
187
|
+
element.style.zIndex = zIndex.toString();
|
|
188
|
+
document.body.appendChild(element);
|
|
189
|
+
container = { element, refCount: 0 };
|
|
190
|
+
portalContainers.set(id, container);
|
|
191
|
+
}
|
|
192
|
+
container.refCount++;
|
|
193
|
+
return container.element;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Decrements reference count and removes portal container if no longer needed.
|
|
197
|
+
*
|
|
198
|
+
* @param id - Portal container identifier
|
|
199
|
+
*/
|
|
200
|
+
const releasePortalContainer = (id) => {
|
|
201
|
+
const container = portalContainers.get(id);
|
|
202
|
+
if (container) {
|
|
203
|
+
container.refCount--;
|
|
204
|
+
if (container.refCount <= 0) {
|
|
205
|
+
container.element.remove();
|
|
206
|
+
portalContainers.delete(id);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Renders a Mithril vnode into a portal container using m.render().
|
|
212
|
+
* This allows components to render outside their parent DOM hierarchy,
|
|
213
|
+
* useful for modals and pickers that need to escape stacking contexts.
|
|
214
|
+
*
|
|
215
|
+
* @param containerId - Portal container identifier
|
|
216
|
+
* @param vnode - Mithril vnode to render
|
|
217
|
+
* @param zIndex - Z-index for portal container (default: 1004)
|
|
218
|
+
*/
|
|
219
|
+
const renderToPortal = (containerId, vnode, zIndex = 1004) => {
|
|
220
|
+
const container = getPortalContainer(containerId, zIndex);
|
|
221
|
+
m.render(container, vnode);
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Clears portal content and releases container reference.
|
|
225
|
+
* If this is the last reference, the container will be removed from the DOM.
|
|
226
|
+
*
|
|
227
|
+
* @param containerId - Portal container identifier
|
|
228
|
+
*/
|
|
229
|
+
const clearPortal = (containerId) => {
|
|
230
|
+
const container = portalContainers.get(containerId);
|
|
231
|
+
if (container) {
|
|
232
|
+
m.render(container.element, null);
|
|
233
|
+
releasePortalContainer(containerId);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
166
236
|
|
|
167
237
|
// import './styles/input.css';
|
|
168
238
|
const Mandatory = { view: ({ attrs }) => m('span.mandatory', Object.assign({}, attrs), '*') };
|
|
@@ -2191,6 +2261,129 @@
|
|
|
2191
2261
|
}
|
|
2192
2262
|
m.redraw();
|
|
2193
2263
|
};
|
|
2264
|
+
const handleKeyDown = (e) => {
|
|
2265
|
+
if (e.key === 'Escape' && state.isOpen) {
|
|
2266
|
+
state.isOpen = false;
|
|
2267
|
+
const options = mergeOptions({});
|
|
2268
|
+
if (options.onClose)
|
|
2269
|
+
options.onClose();
|
|
2270
|
+
clearPortal(state.portalContainerId);
|
|
2271
|
+
m.redraw();
|
|
2272
|
+
}
|
|
2273
|
+
};
|
|
2274
|
+
const renderPickerToPortal = (attrs) => {
|
|
2275
|
+
const options = mergeOptions(attrs);
|
|
2276
|
+
const pickerModal = m('.datepicker-modal-wrapper', {
|
|
2277
|
+
style: {
|
|
2278
|
+
position: 'fixed',
|
|
2279
|
+
top: '0',
|
|
2280
|
+
left: '0',
|
|
2281
|
+
width: '100%',
|
|
2282
|
+
height: '100%',
|
|
2283
|
+
pointerEvents: 'auto',
|
|
2284
|
+
display: 'flex',
|
|
2285
|
+
alignItems: 'center',
|
|
2286
|
+
justifyContent: 'center',
|
|
2287
|
+
},
|
|
2288
|
+
}, [
|
|
2289
|
+
// Modal overlay
|
|
2290
|
+
m('.modal-overlay', {
|
|
2291
|
+
style: {
|
|
2292
|
+
position: 'absolute',
|
|
2293
|
+
top: '0',
|
|
2294
|
+
left: '0',
|
|
2295
|
+
width: '100%',
|
|
2296
|
+
height: '100%',
|
|
2297
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
2298
|
+
zIndex: '1002',
|
|
2299
|
+
},
|
|
2300
|
+
onclick: () => {
|
|
2301
|
+
state.isOpen = false;
|
|
2302
|
+
if (options.onClose)
|
|
2303
|
+
options.onClose();
|
|
2304
|
+
m.redraw();
|
|
2305
|
+
},
|
|
2306
|
+
}),
|
|
2307
|
+
// Modal content
|
|
2308
|
+
m('.modal.datepicker-modal.open', {
|
|
2309
|
+
id: `modal-${state.id}`,
|
|
2310
|
+
tabindex: 0,
|
|
2311
|
+
style: {
|
|
2312
|
+
position: 'relative',
|
|
2313
|
+
zIndex: '1003',
|
|
2314
|
+
display: 'block',
|
|
2315
|
+
opacity: 1,
|
|
2316
|
+
top: 'auto',
|
|
2317
|
+
transform: 'scaleX(1) scaleY(1)',
|
|
2318
|
+
margin: '0 auto',
|
|
2319
|
+
},
|
|
2320
|
+
}, [
|
|
2321
|
+
m('.modal-content.datepicker-container', {
|
|
2322
|
+
onclick: (e) => {
|
|
2323
|
+
const target = e.target;
|
|
2324
|
+
if (!target.closest('.select-wrapper') && !target.closest('.dropdown-content')) {
|
|
2325
|
+
state.monthDropdownOpen = false;
|
|
2326
|
+
state.yearDropdownOpen = false;
|
|
2327
|
+
}
|
|
2328
|
+
},
|
|
2329
|
+
}, [
|
|
2330
|
+
m(DateDisplay, { options }),
|
|
2331
|
+
m('.datepicker-calendar-container', [
|
|
2332
|
+
m('.datepicker-calendar', [
|
|
2333
|
+
m(DateControls, {
|
|
2334
|
+
options,
|
|
2335
|
+
randId: `datepicker-title-${Math.random().toString(36).slice(2)}`,
|
|
2336
|
+
}),
|
|
2337
|
+
m(Calendar, {
|
|
2338
|
+
year: state.calendars[0].year,
|
|
2339
|
+
month: state.calendars[0].month,
|
|
2340
|
+
options,
|
|
2341
|
+
}),
|
|
2342
|
+
]),
|
|
2343
|
+
m('.datepicker-footer', [
|
|
2344
|
+
options.showClearBtn &&
|
|
2345
|
+
m('button.btn-flat.datepicker-clear.waves-effect', {
|
|
2346
|
+
type: 'button',
|
|
2347
|
+
onclick: () => {
|
|
2348
|
+
setDate(null, false, options);
|
|
2349
|
+
state.isOpen = false;
|
|
2350
|
+
},
|
|
2351
|
+
}, options.i18n.clear),
|
|
2352
|
+
m('button.btn-flat.datepicker-cancel.waves-effect', {
|
|
2353
|
+
type: 'button',
|
|
2354
|
+
onclick: () => {
|
|
2355
|
+
state.isOpen = false;
|
|
2356
|
+
if (options.onClose)
|
|
2357
|
+
options.onClose();
|
|
2358
|
+
},
|
|
2359
|
+
}, options.i18n.cancel),
|
|
2360
|
+
m('button.btn-flat.datepicker-done.waves-effect', {
|
|
2361
|
+
type: 'button',
|
|
2362
|
+
onclick: () => {
|
|
2363
|
+
state.isOpen = false;
|
|
2364
|
+
if (options.dateRange) {
|
|
2365
|
+
if (state.startDate && state.endDate && attrs.onchange) {
|
|
2366
|
+
const startStr = formatDate(state.startDate, 'yyyy-mm-dd', options);
|
|
2367
|
+
const endStr = formatDate(state.endDate, 'yyyy-mm-dd', options);
|
|
2368
|
+
attrs.onchange(`${startStr} - ${endStr}`);
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
else {
|
|
2372
|
+
if (state.date && attrs.onchange) {
|
|
2373
|
+
attrs.onchange(toString(state.date, 'yyyy-mm-dd'));
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
if (options.onClose)
|
|
2377
|
+
options.onClose();
|
|
2378
|
+
},
|
|
2379
|
+
}, options.i18n.done),
|
|
2380
|
+
]),
|
|
2381
|
+
]),
|
|
2382
|
+
]),
|
|
2383
|
+
]),
|
|
2384
|
+
]);
|
|
2385
|
+
renderToPortal(state.portalContainerId, pickerModal, 1004);
|
|
2386
|
+
};
|
|
2194
2387
|
return {
|
|
2195
2388
|
oninit: (vnode) => {
|
|
2196
2389
|
const attrs = vnode.attrs;
|
|
@@ -2206,6 +2399,7 @@
|
|
|
2206
2399
|
calendars: [{ month: 0, year: 0 }],
|
|
2207
2400
|
monthDropdownOpen: false,
|
|
2208
2401
|
yearDropdownOpen: false,
|
|
2402
|
+
portalContainerId: `datepicker-portal-${uniqueId()}`,
|
|
2209
2403
|
formats: {
|
|
2210
2404
|
d: () => { var _a; return ((_a = state.date) === null || _a === void 0 ? void 0 : _a.getDate()) || 0; },
|
|
2211
2405
|
dd: () => {
|
|
@@ -2259,10 +2453,26 @@
|
|
|
2259
2453
|
}
|
|
2260
2454
|
// Add document click listener to close dropdowns
|
|
2261
2455
|
document.addEventListener('click', handleDocumentClick);
|
|
2456
|
+
// Add ESC key listener
|
|
2457
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
2262
2458
|
},
|
|
2263
2459
|
onremove: () => {
|
|
2264
|
-
// Clean up event
|
|
2460
|
+
// Clean up event listeners
|
|
2265
2461
|
document.removeEventListener('click', handleDocumentClick);
|
|
2462
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
2463
|
+
// Clean up portal if picker was open
|
|
2464
|
+
if (state.isOpen) {
|
|
2465
|
+
clearPortal(state.portalContainerId);
|
|
2466
|
+
}
|
|
2467
|
+
},
|
|
2468
|
+
onupdate: (vnode) => {
|
|
2469
|
+
// Render to portal when picker is open, clear when closed
|
|
2470
|
+
if (state.isOpen) {
|
|
2471
|
+
renderPickerToPortal(vnode.attrs);
|
|
2472
|
+
}
|
|
2473
|
+
else {
|
|
2474
|
+
clearPortal(state.portalContainerId);
|
|
2475
|
+
}
|
|
2266
2476
|
},
|
|
2267
2477
|
view: (vnode) => {
|
|
2268
2478
|
const attrs = vnode.attrs;
|
|
@@ -2378,93 +2588,7 @@
|
|
|
2378
2588
|
}, label || dateLabel),
|
|
2379
2589
|
// Helper text
|
|
2380
2590
|
helperText && m('span.helper-text', helperText),
|
|
2381
|
-
// Modal
|
|
2382
|
-
state.isOpen && [
|
|
2383
|
-
m('.modal.datepicker-modal.open', {
|
|
2384
|
-
id: `modal-${state.id}`,
|
|
2385
|
-
tabindex: 0,
|
|
2386
|
-
style: {
|
|
2387
|
-
zIndex: 1003,
|
|
2388
|
-
display: 'block',
|
|
2389
|
-
opacity: 1,
|
|
2390
|
-
top: '10%',
|
|
2391
|
-
transform: 'scaleX(1) scaleY(1)',
|
|
2392
|
-
},
|
|
2393
|
-
}, [
|
|
2394
|
-
m('.modal-content.datepicker-container', {
|
|
2395
|
-
onclick: (e) => {
|
|
2396
|
-
// Close dropdowns when clicking anywhere in the modal content
|
|
2397
|
-
const target = e.target;
|
|
2398
|
-
if (!target.closest('.select-wrapper') && !target.closest('.dropdown-content')) {
|
|
2399
|
-
state.monthDropdownOpen = false;
|
|
2400
|
-
state.yearDropdownOpen = false;
|
|
2401
|
-
}
|
|
2402
|
-
},
|
|
2403
|
-
}, [
|
|
2404
|
-
m(DateDisplay, { options }),
|
|
2405
|
-
m('.datepicker-calendar-container', [
|
|
2406
|
-
m('.datepicker-calendar', [
|
|
2407
|
-
m(DateControls, { options, randId: `datepicker-title-${Math.random().toString(36).slice(2)}` }),
|
|
2408
|
-
m(Calendar, { year: state.calendars[0].year, month: state.calendars[0].month, options }),
|
|
2409
|
-
]),
|
|
2410
|
-
m('.datepicker-footer', [
|
|
2411
|
-
options.showClearBtn &&
|
|
2412
|
-
m('button.btn-flat.datepicker-clear.waves-effect', {
|
|
2413
|
-
type: 'button',
|
|
2414
|
-
style: '',
|
|
2415
|
-
onclick: () => {
|
|
2416
|
-
setDate(null, false, options);
|
|
2417
|
-
state.isOpen = false;
|
|
2418
|
-
},
|
|
2419
|
-
}, options.i18n.clear),
|
|
2420
|
-
m('button.btn-flat.datepicker-cancel.waves-effect', {
|
|
2421
|
-
type: 'button',
|
|
2422
|
-
onclick: () => {
|
|
2423
|
-
state.isOpen = false;
|
|
2424
|
-
if (options.onClose)
|
|
2425
|
-
options.onClose();
|
|
2426
|
-
},
|
|
2427
|
-
}, options.i18n.cancel),
|
|
2428
|
-
m('button.btn-flat.datepicker-done.waves-effect', {
|
|
2429
|
-
type: 'button',
|
|
2430
|
-
onclick: () => {
|
|
2431
|
-
state.isOpen = false;
|
|
2432
|
-
if (options.dateRange) {
|
|
2433
|
-
// Range mode
|
|
2434
|
-
if (state.startDate && state.endDate && onchange) {
|
|
2435
|
-
const startStr = toString(state.startDate, 'yyyy-mm-dd');
|
|
2436
|
-
const endStr = toString(state.endDate, 'yyyy-mm-dd');
|
|
2437
|
-
onchange(`${startStr} - ${endStr}`);
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
else {
|
|
2441
|
-
// Single date mode
|
|
2442
|
-
if (state.date && onchange) {
|
|
2443
|
-
onchange(toString(state.date, 'yyyy-mm-dd')); // Always return ISO format
|
|
2444
|
-
}
|
|
2445
|
-
}
|
|
2446
|
-
if (options.onClose)
|
|
2447
|
-
options.onClose();
|
|
2448
|
-
},
|
|
2449
|
-
}, options.i18n.done),
|
|
2450
|
-
]),
|
|
2451
|
-
]),
|
|
2452
|
-
]),
|
|
2453
|
-
]),
|
|
2454
|
-
// Modal overlay
|
|
2455
|
-
m('.modal-overlay', {
|
|
2456
|
-
style: {
|
|
2457
|
-
zIndex: 1002,
|
|
2458
|
-
display: 'block',
|
|
2459
|
-
opacity: 0.5,
|
|
2460
|
-
},
|
|
2461
|
-
onclick: () => {
|
|
2462
|
-
state.isOpen = false;
|
|
2463
|
-
if (options.onClose)
|
|
2464
|
-
options.onClose();
|
|
2465
|
-
},
|
|
2466
|
-
}),
|
|
2467
|
-
],
|
|
2591
|
+
// Modal is now rendered via portal in onupdate hook
|
|
2468
2592
|
]);
|
|
2469
2593
|
},
|
|
2470
2594
|
};
|
|
@@ -5673,6 +5797,66 @@
|
|
|
5673
5797
|
},
|
|
5674
5798
|
};
|
|
5675
5799
|
};
|
|
5800
|
+
const handleKeyDown = (e) => {
|
|
5801
|
+
if (e.key === 'Escape' && state.isOpen) {
|
|
5802
|
+
close();
|
|
5803
|
+
clearPortal(state.portalContainerId);
|
|
5804
|
+
m.redraw();
|
|
5805
|
+
}
|
|
5806
|
+
};
|
|
5807
|
+
const renderPickerToPortal = (attrs) => {
|
|
5808
|
+
const { showClearBtn = false, clearLabel = 'Clear', closeLabel = 'Cancel' } = attrs;
|
|
5809
|
+
const pickerModal = m('.timepicker-modal-wrapper', {
|
|
5810
|
+
style: {
|
|
5811
|
+
position: 'fixed',
|
|
5812
|
+
top: '0',
|
|
5813
|
+
left: '0',
|
|
5814
|
+
width: '100%',
|
|
5815
|
+
height: '100%',
|
|
5816
|
+
pointerEvents: 'auto',
|
|
5817
|
+
display: 'flex',
|
|
5818
|
+
alignItems: 'center',
|
|
5819
|
+
justifyContent: 'center',
|
|
5820
|
+
},
|
|
5821
|
+
}, [
|
|
5822
|
+
// Modal overlay
|
|
5823
|
+
m('.modal-overlay', {
|
|
5824
|
+
style: {
|
|
5825
|
+
position: 'absolute',
|
|
5826
|
+
top: '0',
|
|
5827
|
+
left: '0',
|
|
5828
|
+
width: '100%',
|
|
5829
|
+
height: '100%',
|
|
5830
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
5831
|
+
zIndex: '1002',
|
|
5832
|
+
},
|
|
5833
|
+
onclick: () => {
|
|
5834
|
+
close();
|
|
5835
|
+
m.redraw();
|
|
5836
|
+
},
|
|
5837
|
+
}),
|
|
5838
|
+
// Modal content
|
|
5839
|
+
m('.modal.timepicker-modal.open', {
|
|
5840
|
+
style: {
|
|
5841
|
+
position: 'relative',
|
|
5842
|
+
zIndex: '1003',
|
|
5843
|
+
display: 'block',
|
|
5844
|
+
opacity: 1,
|
|
5845
|
+
top: 'auto',
|
|
5846
|
+
transform: 'scaleX(1) scaleY(1)',
|
|
5847
|
+
margin: '0 auto',
|
|
5848
|
+
},
|
|
5849
|
+
}, [
|
|
5850
|
+
m(TimepickerModal, {
|
|
5851
|
+
showClearBtn,
|
|
5852
|
+
clearLabel,
|
|
5853
|
+
closeLabel,
|
|
5854
|
+
doneLabel: 'OK',
|
|
5855
|
+
}),
|
|
5856
|
+
]),
|
|
5857
|
+
]);
|
|
5858
|
+
renderToPortal(state.portalContainerId, pickerModal, 1004);
|
|
5859
|
+
};
|
|
5676
5860
|
return {
|
|
5677
5861
|
oninit: (vnode) => {
|
|
5678
5862
|
const attrs = vnode.attrs;
|
|
@@ -5689,11 +5873,14 @@
|
|
|
5689
5873
|
y0: 0,
|
|
5690
5874
|
dx: 0,
|
|
5691
5875
|
dy: 0,
|
|
5876
|
+
portalContainerId: `timepicker-portal-${uniqueId()}`,
|
|
5692
5877
|
};
|
|
5693
5878
|
// Handle value after options are set
|
|
5694
5879
|
if (attrs.defaultValue) {
|
|
5695
5880
|
updateTimeFromInput(attrs.defaultValue);
|
|
5696
5881
|
}
|
|
5882
|
+
// Add ESC key listener
|
|
5883
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
5697
5884
|
},
|
|
5698
5885
|
onremove: () => {
|
|
5699
5886
|
// Cleanup
|
|
@@ -5707,6 +5894,21 @@
|
|
|
5707
5894
|
document.removeEventListener('touchmove', handleDocumentClickMove);
|
|
5708
5895
|
document.removeEventListener('mouseup', handleDocumentClickEnd);
|
|
5709
5896
|
document.removeEventListener('touchend', handleDocumentClickEnd);
|
|
5897
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
5898
|
+
// Clean up portal if picker was open
|
|
5899
|
+
if (state.isOpen) {
|
|
5900
|
+
clearPortal(state.portalContainerId);
|
|
5901
|
+
}
|
|
5902
|
+
},
|
|
5903
|
+
onupdate: (vnode) => {
|
|
5904
|
+
const { useModal = true } = vnode.attrs;
|
|
5905
|
+
// Only render to portal when using modal mode
|
|
5906
|
+
if (useModal && state.isOpen) {
|
|
5907
|
+
renderPickerToPortal(vnode.attrs);
|
|
5908
|
+
}
|
|
5909
|
+
else {
|
|
5910
|
+
clearPortal(state.portalContainerId);
|
|
5911
|
+
}
|
|
5710
5912
|
},
|
|
5711
5913
|
view: ({ attrs }) => {
|
|
5712
5914
|
const { id = state.id, label, placeholder, disabled, readonly, required, iconName, helperText, onchange, oninput, useModal = true, showClearBtn = false, clearLabel = 'Clear', closeLabel = 'Cancel', twelveHour, className: cn1, class: cn2, } = attrs;
|
|
@@ -5803,29 +6005,7 @@
|
|
|
5803
6005
|
}, label),
|
|
5804
6006
|
// Helper text
|
|
5805
6007
|
helperText && m('span.helper-text', helperText),
|
|
5806
|
-
// Modal
|
|
5807
|
-
useModal &&
|
|
5808
|
-
state.isOpen && [
|
|
5809
|
-
// Modal overlay
|
|
5810
|
-
m('.modal-overlay', {
|
|
5811
|
-
style: {
|
|
5812
|
-
zIndex: 1002,
|
|
5813
|
-
display: 'block',
|
|
5814
|
-
opacity: 0.5,
|
|
5815
|
-
},
|
|
5816
|
-
onclick: () => close(),
|
|
5817
|
-
}),
|
|
5818
|
-
// Modal content
|
|
5819
|
-
m('.modal.timepicker-modal.open', {
|
|
5820
|
-
style: {
|
|
5821
|
-
zIndex: 1003,
|
|
5822
|
-
display: 'block',
|
|
5823
|
-
opacity: 1,
|
|
5824
|
-
top: '10%',
|
|
5825
|
-
transform: 'scaleX(1) scaleY(1)',
|
|
5826
|
-
},
|
|
5827
|
-
}, m(TimepickerModal, { showClearBtn, clearLabel, closeLabel, doneLabel: 'OK' })),
|
|
5828
|
-
],
|
|
6008
|
+
// Modal is now rendered via portal in onupdate hook
|
|
5829
6009
|
]);
|
|
5830
6010
|
},
|
|
5831
6011
|
};
|
|
@@ -9624,8 +9804,10 @@
|
|
|
9624
9804
|
exports.TreeView = TreeView;
|
|
9625
9805
|
exports.UrlInput = UrlInput;
|
|
9626
9806
|
exports.Wizard = Wizard;
|
|
9807
|
+
exports.clearPortal = clearPortal;
|
|
9627
9808
|
exports.createBreadcrumb = createBreadcrumb;
|
|
9628
9809
|
exports.getDropdownStyles = getDropdownStyles;
|
|
9810
|
+
exports.getPortalContainer = getPortalContainer;
|
|
9629
9811
|
exports.initPushpins = initPushpins;
|
|
9630
9812
|
exports.initTooltips = initTooltips;
|
|
9631
9813
|
exports.isNumeric = isNumeric;
|
|
@@ -9633,6 +9815,8 @@
|
|
|
9633
9815
|
exports.isValidationSuccess = isValidationSuccess;
|
|
9634
9816
|
exports.padLeft = padLeft;
|
|
9635
9817
|
exports.range = range;
|
|
9818
|
+
exports.releasePortalContainer = releasePortalContainer;
|
|
9819
|
+
exports.renderToPortal = renderToPortal;
|
|
9636
9820
|
exports.toast = toast;
|
|
9637
9821
|
exports.uniqueId = uniqueId;
|
|
9638
9822
|
exports.uuid4 = uuid4;
|
package/dist/utils.d.ts
CHANGED
|
@@ -41,3 +41,35 @@ export declare const getDropdownStyles: (inputRef?: HTMLElement | null, overlap?
|
|
|
41
41
|
* @example: console.log(range(5, 10)); // [5, 6, 7, 8, 9, 10]
|
|
42
42
|
*/
|
|
43
43
|
export declare const range: (a: number, b: number) => number[];
|
|
44
|
+
/**
|
|
45
|
+
* Creates or retrieves a portal container appended to document.body.
|
|
46
|
+
* Uses reference counting to manage container lifecycle.
|
|
47
|
+
*
|
|
48
|
+
* @param id - Unique identifier for the portal container
|
|
49
|
+
* @param zIndex - Z-index for the portal container (default: 1004, above modals at 1003)
|
|
50
|
+
* @returns The portal container element
|
|
51
|
+
*/
|
|
52
|
+
export declare const getPortalContainer: (id: string, zIndex?: number) => HTMLElement;
|
|
53
|
+
/**
|
|
54
|
+
* Decrements reference count and removes portal container if no longer needed.
|
|
55
|
+
*
|
|
56
|
+
* @param id - Portal container identifier
|
|
57
|
+
*/
|
|
58
|
+
export declare const releasePortalContainer: (id: string) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Renders a Mithril vnode into a portal container using m.render().
|
|
61
|
+
* This allows components to render outside their parent DOM hierarchy,
|
|
62
|
+
* useful for modals and pickers that need to escape stacking contexts.
|
|
63
|
+
*
|
|
64
|
+
* @param containerId - Portal container identifier
|
|
65
|
+
* @param vnode - Mithril vnode to render
|
|
66
|
+
* @param zIndex - Z-index for portal container (default: 1004)
|
|
67
|
+
*/
|
|
68
|
+
export declare const renderToPortal: (containerId: string, vnode: any, zIndex?: number) => void;
|
|
69
|
+
/**
|
|
70
|
+
* Clears portal content and releases container reference.
|
|
71
|
+
* If this is the last reference, the container will be removed from the DOM.
|
|
72
|
+
*
|
|
73
|
+
* @param containerId - Portal container identifier
|
|
74
|
+
*/
|
|
75
|
+
export declare const clearPortal: (containerId: string) => void;
|