mithril-materialized 2.0.0-beta.11 → 2.0.0-beta.14

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.umd.js CHANGED
@@ -840,6 +840,18 @@
840
840
  'M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 0 0 5.7 7.11L10.59 12l-4.89 4.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z',
841
841
  'M0 0h24v24H0z',
842
842
  ],
843
+ chevron: [
844
+ 'M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z', // chevron down
845
+ 'M0 0h24v24H0z', // background
846
+ ],
847
+ expand: [
848
+ 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z', // plus
849
+ 'M0 0h24v24H0z', // background
850
+ ],
851
+ collapse: [
852
+ 'M19 13H5v-2h14v2z', // minus
853
+ 'M0 0h24v24H0z', // background
854
+ ],
843
855
  };
844
856
  const MaterialIcon = () => {
845
857
  return {
@@ -849,8 +861,8 @@
849
861
  const rotationMap = {
850
862
  down: 0,
851
863
  up: 180,
852
- left: -90,
853
- right: 90,
864
+ left: 90,
865
+ right: -90,
854
866
  };
855
867
  const rotation = (_a = rotationMap[direction]) !== null && _a !== void 0 ? _a : 0;
856
868
  const transform = rotation ? `rotate(${rotation}deg)` : undefined;
@@ -1159,7 +1171,7 @@
1159
1171
  const lang = language || 'lang-TypeScript';
1160
1172
  const label = lang.replace('lang-', '');
1161
1173
  const cb = code instanceof Array ? code.join('\n') : code;
1162
- const cn = [newRow ? 'clear' : '', lang, className].filter(Boolean).join(' ').trim();
1174
+ const cn = [newRow ? 'clear' : '', lang, className].filter(Boolean).join(' ').trim() || undefined;
1163
1175
  return m(`pre.codeblock${newRow ? '.clear' : ''}`, attrs, [
1164
1176
  m('div', m('label', label)),
1165
1177
  m('code', Object.assign(Object.assign({}, params), { className: cn }), cb),
@@ -2182,6 +2194,12 @@
2182
2194
  isValid: true,
2183
2195
  active: false,
2184
2196
  inputElement: null,
2197
+ // Range-specific state
2198
+ rangeMinValue: undefined,
2199
+ rangeMaxValue: undefined,
2200
+ singleValue: undefined,
2201
+ isDragging: false,
2202
+ activeThumb: null,
2185
2203
  };
2186
2204
  // let labelManager: { updateLabelState: () => void; cleanup: () => void } | null = null;
2187
2205
  // let lengthUpdateHandler: (() => void) | null = null;
@@ -2207,19 +2225,425 @@
2207
2225
  state.hasInteracted = length > 0;
2208
2226
  }
2209
2227
  };
2228
+ // Range slider helper functions
2229
+ const getPercentage = (value, min, max) => {
2230
+ return ((value - min) / (max - min)) * 100;
2231
+ };
2232
+ const updateRangeValues = (minValue, maxValue, attrs, immediate = false) => {
2233
+ // Ensure min doesn't exceed max and vice versa
2234
+ if (minValue > maxValue)
2235
+ minValue = maxValue;
2236
+ if (maxValue < minValue)
2237
+ maxValue = minValue;
2238
+ state.rangeMinValue = minValue;
2239
+ state.rangeMaxValue = maxValue;
2240
+ // Call oninput for immediate feedback or onchange for final changes
2241
+ if (immediate && attrs.oninput) {
2242
+ attrs.oninput(minValue, maxValue);
2243
+ }
2244
+ else if (!immediate && attrs.onchange) {
2245
+ attrs.onchange(minValue, maxValue);
2246
+ }
2247
+ };
2248
+ // Render function for single range slider with tooltip
2249
+ const renderSingleRangeWithTooltip = (attrs, state, cn, style, iconName, id, label, isMandatory, helperText) => {
2250
+ const { min = 0, max = 100, step = 1, initialValue, vertical = false, showValue = false, height = '200px', disabled = false, oninput, onchange, } = attrs;
2251
+ // Initialize single range value
2252
+ const currentValue = initialValue !== undefined ? initialValue : state.singleValue || min;
2253
+ if (state.singleValue === undefined) {
2254
+ state.singleValue = currentValue;
2255
+ }
2256
+ const percentage = getPercentage(state.singleValue, min, max);
2257
+ // Only keep dynamic styles as inline, use CSS classes for static styles
2258
+ const containerStyle = vertical ? { height } : {};
2259
+ const progressStyle = vertical
2260
+ ? {
2261
+ height: `${percentage}%`,
2262
+ }
2263
+ : {
2264
+ width: `${percentage}%`,
2265
+ };
2266
+ const thumbStyle = vertical
2267
+ ? {
2268
+ bottom: `${percentage}%`,
2269
+ }
2270
+ : {
2271
+ left: `${percentage}%`,
2272
+ marginLeft: '-10px', // Half of thumb size (20px)
2273
+ };
2274
+ const updateSingleValue = (newValue, immediate = false) => {
2275
+ state.singleValue = newValue;
2276
+ if (immediate && oninput) {
2277
+ oninput(newValue);
2278
+ }
2279
+ else if (!immediate && onchange) {
2280
+ onchange(newValue);
2281
+ }
2282
+ };
2283
+ const handleMouseDown = (e) => {
2284
+ if (disabled)
2285
+ return;
2286
+ e.preventDefault();
2287
+ state.isDragging = true;
2288
+ // Get container reference from the current target's parent
2289
+ const thumbElement = e.currentTarget;
2290
+ const container = thumbElement.parentElement;
2291
+ if (!container)
2292
+ return;
2293
+ const handleMouseMove = (e) => {
2294
+ if (!state.isDragging || !container)
2295
+ return;
2296
+ const rect = container.getBoundingClientRect();
2297
+ let percentage;
2298
+ if (vertical) {
2299
+ percentage = ((rect.bottom - e.clientY) / rect.height) * 100;
2300
+ }
2301
+ else {
2302
+ percentage = ((e.clientX - rect.left) / rect.width) * 100;
2303
+ }
2304
+ percentage = Math.max(0, Math.min(100, percentage));
2305
+ const value = min + (percentage / 100) * (max - min);
2306
+ const steppedValue = Math.round(value / step) * step;
2307
+ updateSingleValue(steppedValue, true);
2308
+ // Redraw to update the UI
2309
+ m.redraw();
2310
+ };
2311
+ const handleMouseUp = () => {
2312
+ state.isDragging = false;
2313
+ document.removeEventListener('mousemove', handleMouseMove);
2314
+ document.removeEventListener('mouseup', handleMouseUp);
2315
+ // Fire onchange when dragging ends
2316
+ updateSingleValue(state.singleValue, false);
2317
+ };
2318
+ document.addEventListener('mousemove', handleMouseMove);
2319
+ document.addEventListener('mouseup', handleMouseUp);
2320
+ };
2321
+ const fieldClass = vertical ? 'range-field vertical' : 'range-field';
2322
+ const orientation = vertical ? 'vertical' : 'horizontal';
2323
+ return m('.input-field', { className: cn, style }, [
2324
+ iconName ? m('i.material-icons.prefix', iconName) : undefined,
2325
+ // Hidden input for label association and accessibility
2326
+ m('input[type=range]', {
2327
+ id,
2328
+ value: state.singleValue,
2329
+ min,
2330
+ max,
2331
+ step,
2332
+ style: { display: 'none' },
2333
+ disabled,
2334
+ tabindex: -1,
2335
+ }),
2336
+ m('div', { class: fieldClass, style: containerStyle }, [
2337
+ m(`.single-range-slider.${orientation}`, {
2338
+ tabindex: disabled ? -1 : 0,
2339
+ role: 'slider',
2340
+ 'aria-valuemin': min,
2341
+ 'aria-valuemax': max,
2342
+ 'aria-valuenow': state.singleValue,
2343
+ 'aria-label': label || 'Range slider',
2344
+ onclick: (e) => {
2345
+ // Focus the slider when clicked
2346
+ e.currentTarget.focus();
2347
+ },
2348
+ onkeydown: (e) => {
2349
+ if (disabled)
2350
+ return;
2351
+ let newValue = state.singleValue;
2352
+ switch (e.key) {
2353
+ case 'ArrowLeft':
2354
+ case 'ArrowDown':
2355
+ e.preventDefault();
2356
+ newValue = Math.max(min, newValue - step);
2357
+ updateSingleValue(newValue, false);
2358
+ m.redraw();
2359
+ break;
2360
+ case 'ArrowRight':
2361
+ case 'ArrowUp':
2362
+ e.preventDefault();
2363
+ newValue = Math.min(max, newValue + step);
2364
+ updateSingleValue(newValue, false);
2365
+ m.redraw();
2366
+ break;
2367
+ case 'Home':
2368
+ e.preventDefault();
2369
+ updateSingleValue(min, false);
2370
+ m.redraw();
2371
+ break;
2372
+ case 'End':
2373
+ e.preventDefault();
2374
+ updateSingleValue(max, false);
2375
+ m.redraw();
2376
+ break;
2377
+ }
2378
+ },
2379
+ }, [
2380
+ // Track
2381
+ m(`.track.${orientation}`),
2382
+ // Progress
2383
+ m(`.range-progress.${orientation}`, { style: progressStyle }),
2384
+ // Thumb
2385
+ m(`.thumb.${orientation}`, {
2386
+ style: thumbStyle,
2387
+ onmousedown: handleMouseDown,
2388
+ }, showValue
2389
+ ? m(`.value-tooltip.${vertical ? 'right' : 'top'}`, state.singleValue.toFixed(0))
2390
+ : null),
2391
+ ]),
2392
+ ]),
2393
+ label
2394
+ ? m(Label, {
2395
+ label,
2396
+ id,
2397
+ isMandatory,
2398
+ isActive: true, // Range sliders always have active labels
2399
+ })
2400
+ : null,
2401
+ helperText ? m(HelperText, { helperText }) : null,
2402
+ ]);
2403
+ };
2404
+ // Render function for minmax range slider
2405
+ const renderMinMaxRange = (attrs, state, cn, style, iconName, id, label, isMandatory, helperText) => {
2406
+ const { min = 0, max = 100, step = 1, minValue, maxValue, vertical = false, showValue = false, height = '200px', disabled = false, } = attrs;
2407
+ // Initialize range values
2408
+ const currentMinValue = minValue !== undefined ? minValue : attrs.minValue || min;
2409
+ const currentMaxValue = maxValue !== undefined ? maxValue : attrs.maxValue || max;
2410
+ if (state.rangeMinValue === undefined || state.rangeMaxValue === undefined) {
2411
+ state.rangeMinValue = currentMinValue;
2412
+ state.rangeMaxValue = currentMaxValue;
2413
+ }
2414
+ // Initialize active thumb if not set
2415
+ if (state.activeThumb === null) {
2416
+ state.activeThumb = 'min';
2417
+ }
2418
+ const minPercentage = getPercentage(state.rangeMinValue, min, max);
2419
+ const maxPercentage = getPercentage(state.rangeMaxValue, min, max);
2420
+ // Only keep dynamic styles as inline, use CSS classes for static styles
2421
+ const containerStyle = vertical ? { height } : {};
2422
+ const rangeStyle = vertical
2423
+ ? {
2424
+ bottom: `${minPercentage}%`,
2425
+ height: `${maxPercentage - minPercentage}%`,
2426
+ }
2427
+ : {
2428
+ left: `${minPercentage}%`,
2429
+ width: `${maxPercentage - minPercentage}%`,
2430
+ };
2431
+ // Only keep dynamic positioning and z-index as inline styles
2432
+ const createThumbStyle = (percentage, isActive) => vertical
2433
+ ? {
2434
+ bottom: `${percentage}%`,
2435
+ zIndex: isActive ? 10 : 5,
2436
+ }
2437
+ : {
2438
+ left: `${percentage}%`,
2439
+ marginLeft: '-10px', // Half of thumb size (20px)
2440
+ zIndex: isActive ? 10 : 5,
2441
+ };
2442
+ const handleMouseDown = (thumb) => (e) => {
2443
+ if (disabled)
2444
+ return;
2445
+ e.preventDefault();
2446
+ state.isDragging = true;
2447
+ state.activeThumb = thumb;
2448
+ // Get container reference from the current target's parent
2449
+ const thumbElement = e.currentTarget;
2450
+ const container = thumbElement.parentElement;
2451
+ if (!container)
2452
+ return;
2453
+ const handleMouseMove = (e) => {
2454
+ if (!state.isDragging || !container)
2455
+ return;
2456
+ const rect = container.getBoundingClientRect();
2457
+ let percentage;
2458
+ if (vertical) {
2459
+ percentage = ((rect.bottom - e.clientY) / rect.height) * 100;
2460
+ }
2461
+ else {
2462
+ percentage = ((e.clientX - rect.left) / rect.width) * 100;
2463
+ }
2464
+ percentage = Math.max(0, Math.min(100, percentage));
2465
+ const value = min + (percentage / 100) * (max - min);
2466
+ const steppedValue = Math.round(value / step) * step;
2467
+ if (thumb === 'min') {
2468
+ updateRangeValues(Math.min(steppedValue, state.rangeMaxValue), state.rangeMaxValue, attrs, true);
2469
+ }
2470
+ else {
2471
+ updateRangeValues(state.rangeMinValue, Math.max(steppedValue, state.rangeMinValue), attrs, true);
2472
+ }
2473
+ // Redraw to update the UI
2474
+ m.redraw();
2475
+ };
2476
+ const handleMouseUp = () => {
2477
+ state.isDragging = false;
2478
+ state.activeThumb = null;
2479
+ document.removeEventListener('mousemove', handleMouseMove);
2480
+ document.removeEventListener('mouseup', handleMouseUp);
2481
+ // Fire onchange when dragging ends
2482
+ updateRangeValues(state.rangeMinValue, state.rangeMaxValue, attrs, false);
2483
+ };
2484
+ document.addEventListener('mousemove', handleMouseMove);
2485
+ document.addEventListener('mouseup', handleMouseUp);
2486
+ };
2487
+ const fieldClass = vertical ? 'range-field vertical' : 'range-field';
2488
+ const orientation = vertical ? 'vertical' : 'horizontal';
2489
+ return m('.input-field', { className: cn, style }, [
2490
+ iconName ? m('i.material-icons.prefix', iconName) : undefined,
2491
+ // Hidden inputs for label association and accessibility
2492
+ m('input[type=range]', {
2493
+ id,
2494
+ value: state.rangeMinValue,
2495
+ min,
2496
+ max,
2497
+ step,
2498
+ style: { display: 'none' },
2499
+ disabled,
2500
+ tabindex: -1,
2501
+ }),
2502
+ m('input[type=range]', {
2503
+ id: `${id}_max`,
2504
+ value: state.rangeMaxValue,
2505
+ min,
2506
+ max,
2507
+ step,
2508
+ style: { display: 'none' },
2509
+ disabled,
2510
+ tabindex: -1,
2511
+ }),
2512
+ m(`.${fieldClass}`, [
2513
+ m(`.double-range-slider.${orientation}`, {
2514
+ style: containerStyle,
2515
+ tabindex: disabled ? -1 : 0,
2516
+ role: 'slider',
2517
+ 'aria-valuemin': min,
2518
+ 'aria-valuemax': max,
2519
+ 'aria-valuenow': state.rangeMinValue,
2520
+ 'aria-valuetext': `${state.rangeMinValue} to ${state.rangeMaxValue}`,
2521
+ 'aria-label': label || 'Range slider',
2522
+ onclick: (e) => {
2523
+ // Focus the slider when clicked
2524
+ e.currentTarget.focus();
2525
+ },
2526
+ onkeydown: (e) => {
2527
+ if (disabled)
2528
+ return;
2529
+ let newMinValue = state.rangeMinValue;
2530
+ let newMaxValue = state.rangeMaxValue;
2531
+ const activeThumb = state.activeThumb || 'min';
2532
+ switch (e.key) {
2533
+ case 'ArrowLeft':
2534
+ case 'ArrowDown':
2535
+ e.preventDefault();
2536
+ if (activeThumb === 'min') {
2537
+ newMinValue = Math.max(min, newMinValue - step);
2538
+ updateRangeValues(newMinValue, newMaxValue, attrs, false);
2539
+ }
2540
+ else {
2541
+ newMaxValue = Math.max(newMinValue, newMaxValue - step);
2542
+ updateRangeValues(newMinValue, newMaxValue, attrs, false);
2543
+ }
2544
+ m.redraw();
2545
+ break;
2546
+ case 'ArrowRight':
2547
+ case 'ArrowUp':
2548
+ e.preventDefault();
2549
+ if (activeThumb === 'min') {
2550
+ newMinValue = Math.min(newMaxValue, newMinValue + step);
2551
+ updateRangeValues(newMinValue, newMaxValue, attrs, false);
2552
+ }
2553
+ else {
2554
+ newMaxValue = Math.min(max, newMaxValue + step);
2555
+ updateRangeValues(newMinValue, newMaxValue, attrs, false);
2556
+ }
2557
+ m.redraw();
2558
+ break;
2559
+ // Remove Tab case - let normal tab navigation work
2560
+ // Users can click on specific thumbs to activate them
2561
+ case 'Home':
2562
+ e.preventDefault();
2563
+ if (activeThumb === 'min') {
2564
+ updateRangeValues(min, newMaxValue, attrs, false);
2565
+ }
2566
+ else {
2567
+ updateRangeValues(newMinValue, newMinValue, attrs, false);
2568
+ }
2569
+ m.redraw();
2570
+ break;
2571
+ case 'End':
2572
+ e.preventDefault();
2573
+ if (activeThumb === 'min') {
2574
+ updateRangeValues(newMaxValue, newMaxValue, attrs, false);
2575
+ }
2576
+ else {
2577
+ updateRangeValues(newMinValue, max, attrs, false);
2578
+ }
2579
+ m.redraw();
2580
+ break;
2581
+ }
2582
+ },
2583
+ }, [
2584
+ // Track
2585
+ m(`.track.${orientation}`),
2586
+ // Range
2587
+ m(`.range.${orientation}`, { style: rangeStyle }),
2588
+ // Min thumb
2589
+ m(`.thumb.${orientation}.min-thumb${state.activeThumb === 'min' ? '.active' : ''}`, {
2590
+ style: createThumbStyle(minPercentage, state.activeThumb === 'min'),
2591
+ onmousedown: handleMouseDown('min'),
2592
+ onclick: () => {
2593
+ state.activeThumb = 'min';
2594
+ m.redraw();
2595
+ },
2596
+ }, showValue ? m(`.value.${orientation}`, state.rangeMinValue.toFixed(0)) : null),
2597
+ // Max thumb
2598
+ m(`.thumb.${orientation}.max-thumb${state.activeThumb === 'max' ? '.active' : ''}`, {
2599
+ style: createThumbStyle(maxPercentage, state.activeThumb === 'max'),
2600
+ onmousedown: handleMouseDown('max'),
2601
+ onclick: () => {
2602
+ state.activeThumb = 'max';
2603
+ m.redraw();
2604
+ },
2605
+ }, showValue ? m(`.value.${orientation}`, state.rangeMaxValue.toFixed(0)) : null),
2606
+ ]),
2607
+ ]),
2608
+ label
2609
+ ? m(Label, {
2610
+ label,
2611
+ id,
2612
+ isMandatory,
2613
+ isActive: true, // Range sliders always have active labels
2614
+ })
2615
+ : null,
2616
+ helperText ? m(HelperText, { helperText }) : null,
2617
+ ]);
2618
+ };
2210
2619
  return {
2211
2620
  view: ({ attrs }) => {
2212
2621
  var _a;
2213
2622
  const { className = 'col s12', dataError, dataSuccess, helperText, iconName, id = state.id, initialValue, placeholder, isMandatory, label, maxLength, newRow, oninput, onchange, onkeydown, onkeypress, onkeyup, style, validate } = attrs, params = __rest(attrs, ["className", "dataError", "dataSuccess", "helperText", "iconName", "id", "initialValue", "placeholder", "isMandatory", "label", "maxLength", "newRow", "oninput", "onchange", "onkeydown", "onkeypress", "onkeyup", "style", "validate"]);
2214
2623
  // const attributes = toAttrs(params);
2215
- const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim();
2624
+ const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
2216
2625
  const isActive = state.active || ((_a = state.inputElement) === null || _a === void 0 ? void 0 : _a.value) || placeholder || type === 'color' || type === 'range'
2217
2626
  ? true
2218
2627
  : false;
2628
+ // Special rendering for minmax range sliders
2629
+ if (type === 'range' && attrs.minmax) {
2630
+ return renderMinMaxRange(attrs, state, cn, style, iconName, id, label, isMandatory, helperText);
2631
+ }
2632
+ // Special rendering for single range sliders with tooltips
2633
+ if (type === 'range' && attrs.showValue) {
2634
+ return renderSingleRangeWithTooltip(attrs, state, cn, style, iconName, id, label, isMandatory, helperText);
2635
+ }
2219
2636
  return m('.input-field', { className: cn, style }, [
2220
2637
  iconName ? m('i.material-icons.prefix', iconName) : undefined,
2221
2638
  m('input.validate', Object.assign(Object.assign({}, params), { type, tabindex: 0, id,
2222
- placeholder,
2639
+ placeholder, class: type === 'range' && attrs.vertical ? 'range-slider vertical' : undefined, style: type === 'range' && attrs.vertical
2640
+ ? {
2641
+ height: attrs.height || '200px',
2642
+ width: '6px',
2643
+ writingMode: 'vertical-lr',
2644
+ direction: 'rtl',
2645
+ }
2646
+ : undefined,
2223
2647
  // attributes,
2224
2648
  oncreate: ({ dom }) => {
2225
2649
  const input = (state.inputElement = dom);
@@ -2235,7 +2659,7 @@
2235
2659
  state.currentLength = input.value.length; // Initial count
2236
2660
  }
2237
2661
  // Range input functionality
2238
- if (type === 'range') {
2662
+ if (type === 'range' && !attrs.minmax) {
2239
2663
  const updateThumb = () => {
2240
2664
  const value = input.value;
2241
2665
  const min = input.min || '0';
@@ -2488,7 +2912,7 @@
2488
2912
  callback(checkedIds);
2489
2913
  }
2490
2914
  : undefined;
2491
- const cn = [newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim();
2915
+ const cn = [newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim() || undefined;
2492
2916
  const optionsContent = layout === 'horizontal'
2493
2917
  ? m('div.grid-container', options.map((option) => m(InputCheckbox, {
2494
2918
  disabled: disabled || option.disabled,
@@ -3359,6 +3783,423 @@
3359
3783
  };
3360
3784
  };
3361
3785
 
3786
+ // Utility functions
3787
+ const getPercentage = (value, min, max) => {
3788
+ return ((value - min) / (max - min)) * 100;
3789
+ };
3790
+ const updateRangeValues = (minValue, maxValue, attrs, state, immediate) => {
3791
+ // Ensure min doesn't exceed max and vice versa
3792
+ if (minValue > maxValue)
3793
+ minValue = maxValue;
3794
+ if (maxValue < minValue)
3795
+ maxValue = minValue;
3796
+ state.rangeMinValue = minValue;
3797
+ state.rangeMaxValue = maxValue;
3798
+ // Call oninput for immediate feedback or onchange for final changes
3799
+ if (immediate && attrs.oninput) {
3800
+ attrs.oninput(minValue, maxValue);
3801
+ }
3802
+ else if (!immediate && attrs.onchange) {
3803
+ attrs.onchange(minValue, maxValue);
3804
+ }
3805
+ };
3806
+ // Single Range Slider with Tooltip
3807
+ const renderSingleRangeWithTooltip = (attrs, state, cn, style, iconName, id, label, isMandatory, helperText) => {
3808
+ const { min = 0, max = 100, step = 1, initialValue, vertical = false, showValue = false, height = '200px', disabled = false, tooltipPos = 'top', oninput, onchange, } = attrs;
3809
+ // Initialize single range value
3810
+ const currentValue = initialValue !== undefined ? initialValue : state.singleValue || min;
3811
+ if (state.singleValue === undefined) {
3812
+ state.singleValue = currentValue;
3813
+ }
3814
+ const percentage = getPercentage(state.singleValue, min, max);
3815
+ // Only keep dynamic styles as inline, use CSS classes for static styles
3816
+ const containerStyle = vertical ? { height } : {};
3817
+ const progressStyle = vertical
3818
+ ? {
3819
+ height: `${percentage}%`,
3820
+ }
3821
+ : {
3822
+ width: `${percentage}%`,
3823
+ };
3824
+ const thumbStyle = vertical
3825
+ ? {
3826
+ bottom: `${percentage}%`,
3827
+ }
3828
+ : {
3829
+ left: `${percentage}%`,
3830
+ marginLeft: '-10px', // Half of thumb size (20px)
3831
+ };
3832
+ const updateSingleValue = (newValue, immediate = false) => {
3833
+ state.singleValue = newValue;
3834
+ if (immediate && oninput) {
3835
+ oninput(newValue);
3836
+ }
3837
+ else if (!immediate && onchange) {
3838
+ onchange(newValue);
3839
+ }
3840
+ };
3841
+ const handleMouseDown = (e) => {
3842
+ if (disabled)
3843
+ return;
3844
+ e.preventDefault();
3845
+ state.isDragging = true;
3846
+ // Get container reference from the current target's parent
3847
+ const thumbElement = e.currentTarget;
3848
+ const container = thumbElement.parentElement;
3849
+ if (!container)
3850
+ return;
3851
+ const handleMouseMove = (e) => {
3852
+ if (!state.isDragging || !container)
3853
+ return;
3854
+ const rect = container.getBoundingClientRect();
3855
+ let percentage;
3856
+ if (vertical) {
3857
+ percentage = ((rect.bottom - e.clientY) / rect.height) * 100;
3858
+ }
3859
+ else {
3860
+ percentage = ((e.clientX - rect.left) / rect.width) * 100;
3861
+ }
3862
+ percentage = Math.max(0, Math.min(100, percentage));
3863
+ const value = min + (percentage / 100) * (max - min);
3864
+ const steppedValue = Math.round(value / step) * step;
3865
+ updateSingleValue(steppedValue, true);
3866
+ // Redraw to update the UI during drag
3867
+ m.redraw();
3868
+ };
3869
+ const handleMouseUp = () => {
3870
+ state.isDragging = false;
3871
+ document.removeEventListener('mousemove', handleMouseMove);
3872
+ document.removeEventListener('mouseup', handleMouseUp);
3873
+ // Fire onchange when dragging ends
3874
+ updateSingleValue(state.singleValue, false);
3875
+ };
3876
+ document.addEventListener('mousemove', handleMouseMove);
3877
+ document.addEventListener('mouseup', handleMouseUp);
3878
+ };
3879
+ const fieldClass = vertical ? 'range-field vertical' : 'range-field';
3880
+ const orientation = vertical ? 'vertical' : 'horizontal';
3881
+ // Determine tooltip position for vertical sliders
3882
+ const tooltipPosition = vertical ? (tooltipPos === 'top' || tooltipPos === 'bottom' ? 'right' : tooltipPos) : tooltipPos;
3883
+ return m('.input-field', { className: cn, style }, [
3884
+ iconName ? m('i.material-icons.prefix', iconName) : undefined,
3885
+ // Hidden input for label association and accessibility
3886
+ m('input[type=range]', {
3887
+ id,
3888
+ value: state.singleValue,
3889
+ min,
3890
+ max,
3891
+ step,
3892
+ style: { display: 'none' },
3893
+ disabled,
3894
+ tabindex: -1,
3895
+ }),
3896
+ m('div', { class: fieldClass, style: containerStyle }, [
3897
+ m(`.single-range-slider.${orientation}`, {
3898
+ tabindex: disabled ? -1 : 0,
3899
+ role: 'slider',
3900
+ 'aria-valuemin': min,
3901
+ 'aria-valuemax': max,
3902
+ 'aria-valuenow': state.singleValue,
3903
+ 'aria-label': label || 'Range slider',
3904
+ onclick: (e) => {
3905
+ // Focus the slider when clicked
3906
+ e.currentTarget.focus();
3907
+ },
3908
+ onkeydown: (e) => {
3909
+ if (disabled)
3910
+ return;
3911
+ let newValue = state.singleValue;
3912
+ switch (e.key) {
3913
+ case 'ArrowLeft':
3914
+ case 'ArrowDown':
3915
+ e.preventDefault();
3916
+ newValue = Math.max(min, newValue - step);
3917
+ updateSingleValue(newValue, false);
3918
+ // m.redraw();
3919
+ break;
3920
+ case 'ArrowRight':
3921
+ case 'ArrowUp':
3922
+ e.preventDefault();
3923
+ newValue = Math.min(max, newValue + step);
3924
+ updateSingleValue(newValue, false);
3925
+ // m.redraw();
3926
+ break;
3927
+ case 'Home':
3928
+ e.preventDefault();
3929
+ updateSingleValue(min, false);
3930
+ // m.redraw();
3931
+ break;
3932
+ case 'End':
3933
+ e.preventDefault();
3934
+ updateSingleValue(max, false);
3935
+ // m.redraw();
3936
+ break;
3937
+ }
3938
+ },
3939
+ }, [
3940
+ // Track
3941
+ m(`.track.${orientation}`),
3942
+ // Progress
3943
+ m(`.range-progress.${orientation}`, { style: progressStyle }),
3944
+ // Thumb
3945
+ m(`.thumb.${orientation}`, {
3946
+ style: thumbStyle,
3947
+ onmousedown: handleMouseDown,
3948
+ }, showValue
3949
+ ? m(`.value-tooltip.${tooltipPosition}`, state.singleValue.toFixed(0))
3950
+ : null),
3951
+ ]),
3952
+ ]),
3953
+ label
3954
+ ? m(Label, {
3955
+ label,
3956
+ id,
3957
+ isMandatory,
3958
+ isActive: true, // Range sliders always have active labels
3959
+ })
3960
+ : null,
3961
+ helperText ? m(HelperText, { helperText }) : null,
3962
+ ]);
3963
+ };
3964
+ // Double Range Slider (Min/Max)
3965
+ const renderMinMaxRange = (attrs, state, cn, style, iconName, id, label, isMandatory, helperText) => {
3966
+ const { min = 0, max = 100, step = 1, minValue, maxValue, vertical = false, showValue = false, height = '200px', disabled = false, } = attrs;
3967
+ // Initialize range values
3968
+ const currentMinValue = minValue !== undefined ? minValue : attrs.minValue || min;
3969
+ const currentMaxValue = maxValue !== undefined ? maxValue : attrs.maxValue || max;
3970
+ if (state.rangeMinValue === undefined || state.rangeMaxValue === undefined) {
3971
+ state.rangeMinValue = currentMinValue;
3972
+ state.rangeMaxValue = currentMaxValue;
3973
+ }
3974
+ // Initialize active thumb if not set
3975
+ if (state.activeThumb === null) {
3976
+ state.activeThumb = 'min';
3977
+ }
3978
+ const minPercentage = getPercentage(state.rangeMinValue, min, max);
3979
+ const maxPercentage = getPercentage(state.rangeMaxValue, min, max);
3980
+ // Only keep dynamic styles as inline, use CSS classes for static styles
3981
+ const containerStyle = vertical ? { height } : {};
3982
+ const rangeStyle = vertical
3983
+ ? {
3984
+ bottom: `${minPercentage}%`,
3985
+ height: `${maxPercentage - minPercentage}%`,
3986
+ }
3987
+ : {
3988
+ left: `${minPercentage}%`,
3989
+ width: `${maxPercentage - minPercentage}%`,
3990
+ };
3991
+ // Only keep dynamic positioning and z-index as inline styles
3992
+ const createThumbStyle = (percentage, isActive) => vertical
3993
+ ? {
3994
+ bottom: `${percentage}%`,
3995
+ zIndex: isActive ? 10 : 5,
3996
+ }
3997
+ : {
3998
+ left: `${percentage}%`,
3999
+ marginLeft: '-10px', // Half of thumb size (20px)
4000
+ zIndex: isActive ? 10 : 5,
4001
+ };
4002
+ const handleMouseDown = (thumb) => (e) => {
4003
+ if (disabled)
4004
+ return;
4005
+ e.preventDefault();
4006
+ state.isDragging = true;
4007
+ state.activeThumb = thumb;
4008
+ // Get container reference from the current target's parent
4009
+ const thumbElement = e.currentTarget;
4010
+ const container = thumbElement.parentElement;
4011
+ if (!container)
4012
+ return;
4013
+ const handleMouseMove = (e) => {
4014
+ if (!state.isDragging || !container)
4015
+ return;
4016
+ const rect = container.getBoundingClientRect();
4017
+ let percentage;
4018
+ if (vertical) {
4019
+ percentage = ((rect.bottom - e.clientY) / rect.height) * 100;
4020
+ }
4021
+ else {
4022
+ percentage = ((e.clientX - rect.left) / rect.width) * 100;
4023
+ }
4024
+ percentage = Math.max(0, Math.min(100, percentage));
4025
+ const value = min + (percentage / 100) * (max - min);
4026
+ const steppedValue = Math.round(value / step) * step;
4027
+ if (thumb === 'min') {
4028
+ updateRangeValues(Math.min(steppedValue, state.rangeMaxValue), state.rangeMaxValue, attrs, state, true);
4029
+ }
4030
+ else {
4031
+ updateRangeValues(state.rangeMinValue, Math.max(steppedValue, state.rangeMinValue), attrs, state, true);
4032
+ }
4033
+ // Redraw to update the UI during drag
4034
+ m.redraw();
4035
+ };
4036
+ const handleMouseUp = () => {
4037
+ state.isDragging = false;
4038
+ state.activeThumb = null;
4039
+ document.removeEventListener('mousemove', handleMouseMove);
4040
+ document.removeEventListener('mouseup', handleMouseUp);
4041
+ // Fire onchange when dragging ends
4042
+ updateRangeValues(state.rangeMinValue, state.rangeMaxValue, attrs, state, false);
4043
+ };
4044
+ document.addEventListener('mousemove', handleMouseMove);
4045
+ document.addEventListener('mouseup', handleMouseUp);
4046
+ };
4047
+ const fieldClass = vertical ? 'range-field vertical' : 'range-field';
4048
+ const orientation = vertical ? 'vertical' : 'horizontal';
4049
+ return m('.input-field', { className: cn, style }, [
4050
+ iconName ? m('i.material-icons.prefix', iconName) : undefined,
4051
+ // Hidden inputs for label association and accessibility
4052
+ m('input[type=range]', {
4053
+ id,
4054
+ value: state.rangeMinValue,
4055
+ min,
4056
+ max,
4057
+ step,
4058
+ style: { display: 'none' },
4059
+ disabled,
4060
+ tabindex: -1,
4061
+ }),
4062
+ m('input[type=range]', {
4063
+ id: `${id}_max`,
4064
+ value: state.rangeMaxValue,
4065
+ min,
4066
+ max,
4067
+ step,
4068
+ style: { display: 'none' },
4069
+ disabled,
4070
+ tabindex: -1,
4071
+ }),
4072
+ m(`div`, { className: fieldClass }, [
4073
+ m(`.double-range-slider.${orientation}`, {
4074
+ style: containerStyle,
4075
+ tabindex: disabled ? -1 : 0,
4076
+ role: 'slider',
4077
+ 'aria-valuemin': min,
4078
+ 'aria-valuemax': max,
4079
+ 'aria-valuenow': state.rangeMinValue,
4080
+ 'aria-valuetext': `${state.rangeMinValue} to ${state.rangeMaxValue}`,
4081
+ 'aria-label': label || 'Range slider',
4082
+ onclick: (e) => {
4083
+ // Focus the slider when clicked
4084
+ e.currentTarget.focus();
4085
+ },
4086
+ onkeydown: (e) => {
4087
+ if (disabled)
4088
+ return;
4089
+ let newMinValue = state.rangeMinValue;
4090
+ let newMaxValue = state.rangeMaxValue;
4091
+ const activeThumb = state.activeThumb || 'min';
4092
+ switch (e.key) {
4093
+ case 'ArrowLeft':
4094
+ case 'ArrowDown':
4095
+ e.preventDefault();
4096
+ if (activeThumb === 'min') {
4097
+ newMinValue = Math.max(min, newMinValue - step);
4098
+ updateRangeValues(newMinValue, newMaxValue, attrs, state, false);
4099
+ }
4100
+ else {
4101
+ newMaxValue = Math.max(newMinValue, newMaxValue - step);
4102
+ updateRangeValues(newMinValue, newMaxValue, attrs, state, false);
4103
+ }
4104
+ // m.redraw();
4105
+ break;
4106
+ case 'ArrowRight':
4107
+ case 'ArrowUp':
4108
+ e.preventDefault();
4109
+ if (activeThumb === 'min') {
4110
+ newMinValue = Math.min(newMaxValue, newMinValue + step);
4111
+ updateRangeValues(newMinValue, newMaxValue, attrs, state, false);
4112
+ }
4113
+ else {
4114
+ newMaxValue = Math.min(max, newMaxValue + step);
4115
+ updateRangeValues(newMinValue, newMaxValue, attrs, state, false);
4116
+ }
4117
+ // m.redraw();
4118
+ break;
4119
+ case 'Tab':
4120
+ // Handle Tab navigation properly
4121
+ if (activeThumb === 'min') {
4122
+ if (e.shiftKey) {
4123
+ // Shift+Tab from min thumb: go to previous element (let browser handle)
4124
+ return; // Don't prevent default
4125
+ }
4126
+ else {
4127
+ // Tab from min thumb: go to max thumb
4128
+ e.preventDefault();
4129
+ state.activeThumb = 'max';
4130
+ }
4131
+ }
4132
+ else { // activeThumb === 'max'
4133
+ if (e.shiftKey) {
4134
+ // Shift+Tab from max thumb: go to min thumb
4135
+ e.preventDefault();
4136
+ state.activeThumb = 'min';
4137
+ }
4138
+ else {
4139
+ // Tab from max thumb: go to next element (let browser handle)
4140
+ return; // Don't prevent default
4141
+ }
4142
+ }
4143
+ break;
4144
+ case 'Home':
4145
+ e.preventDefault();
4146
+ if (activeThumb === 'min') {
4147
+ updateRangeValues(min, newMaxValue, attrs, state, false);
4148
+ }
4149
+ else {
4150
+ updateRangeValues(newMinValue, newMinValue, attrs, state, false);
4151
+ }
4152
+ // m.redraw();
4153
+ break;
4154
+ case 'End':
4155
+ e.preventDefault();
4156
+ if (activeThumb === 'min') {
4157
+ updateRangeValues(newMaxValue, newMaxValue, attrs, state, false);
4158
+ }
4159
+ else {
4160
+ updateRangeValues(newMinValue, max, attrs, state, false);
4161
+ }
4162
+ // m.redraw();
4163
+ break;
4164
+ }
4165
+ },
4166
+ }, [
4167
+ // Track
4168
+ m(`.track.${orientation}`),
4169
+ // Range
4170
+ m(`.range.${orientation}`, { style: rangeStyle }),
4171
+ // Min thumb
4172
+ m(`.thumb.${orientation}.min-thumb${state.activeThumb === 'min' ? '.active' : ''}`, {
4173
+ style: createThumbStyle(minPercentage, state.activeThumb === 'min'),
4174
+ onmousedown: handleMouseDown('min'),
4175
+ onclick: () => {
4176
+ state.activeThumb = 'min';
4177
+ // m.redraw();
4178
+ },
4179
+ }, showValue ? m(`.value.${orientation}`, state.rangeMinValue.toFixed(0)) : null),
4180
+ // Max thumb
4181
+ m(`.thumb.${orientation}.max-thumb${state.activeThumb === 'max' ? '.active' : ''}`, {
4182
+ style: createThumbStyle(maxPercentage, state.activeThumb === 'max'),
4183
+ onmousedown: handleMouseDown('max'),
4184
+ onclick: () => {
4185
+ state.activeThumb = 'max';
4186
+ // m.redraw();
4187
+ },
4188
+ }, showValue ? m(`.value.${orientation}`, state.rangeMaxValue.toFixed(0)) : null),
4189
+ ]),
4190
+ ]),
4191
+ label
4192
+ ? m(Label, {
4193
+ label,
4194
+ id,
4195
+ isMandatory,
4196
+ isActive: true, // Range sliders always have active labels
4197
+ })
4198
+ : null,
4199
+ helperText ? m(HelperText, { helperText }) : null,
4200
+ ]);
4201
+ };
4202
+
3362
4203
  /**
3363
4204
  * Pure TypeScript MaterialBox - creates an image lightbox that fills the screen when clicked
3364
4205
  * No MaterializeCSS dependencies
@@ -3533,7 +4374,7 @@
3533
4374
  view: ({ attrs }) => {
3534
4375
  const { src, alt, width, height, caption, className, style } = attrs, otherAttrs = __rest(attrs, ["src", "alt", "width", "height", "caption", "className", "style"]);
3535
4376
  return m('img.materialboxed', Object.assign(Object.assign({}, otherAttrs), { src, alt: alt || '', width,
3536
- height, className: ['materialboxed', className].filter(Boolean).join(' '), style: Object.assign({ cursor: 'zoom-in', transition: 'opacity 200ms ease' }, style), onclick: (e) => {
4377
+ height, className: ['materialboxed', className].filter(Boolean).join(' ') || undefined, style: Object.assign({ cursor: 'zoom-in', transition: 'opacity 200ms ease' }, style), onclick: (e) => {
3537
4378
  e.preventDefault();
3538
4379
  openBox(e.target, attrs);
3539
4380
  } }));
@@ -3615,7 +4456,7 @@
3615
4456
  .filter(Boolean)
3616
4457
  .join(' ')
3617
4458
  .trim();
3618
- const overlayClasses = ['modal-overlay', state.isOpen ? 'active' : ''].filter(Boolean).join(' ').trim();
4459
+ const overlayClasses = ['modal-overlay', state.isOpen ? 'active' : ''].filter(Boolean).join(' ').trim() || undefined;
3619
4460
  return m('div', { className: 'modal-container' }, [
3620
4461
  // Modal overlay
3621
4462
  m('div', {
@@ -3640,23 +4481,25 @@
3640
4481
  role: 'dialog',
3641
4482
  'aria-labelledby': `${id}-title`,
3642
4483
  'aria-describedby': description ? `${id}-desc` : undefined,
3643
- style: Object.assign(Object.assign({ display: state.isOpen ? 'flex' : 'none', position: 'fixed' }, (bottomSheet ? {
3644
- // Bottom sheet positioning
3645
- top: 'auto',
3646
- bottom: '0',
3647
- left: '0',
3648
- right: '0',
3649
- transform: 'none',
3650
- maxWidth: '100%',
3651
- borderRadius: '8px 8px 0 0',
3652
- } : {
3653
- // Regular modal positioning
3654
- top: '50%',
3655
- left: '50%',
3656
- transform: 'translate(-50%, -50%)',
3657
- maxWidth: '75%',
3658
- borderRadius: '4px',
3659
- })), { backgroundColor: 'var(--mm-modal-background, #fff)', maxHeight: '85%', overflow: 'auto', zIndex: '1003', padding: '0', flexDirection: 'column', boxShadow: '0 24px 38px 3px rgba(0,0,0,0.14), 0 9px 46px 8px rgba(0,0,0,0.12), 0 11px 15px -7px rgba(0,0,0,0.20)' }),
4484
+ style: Object.assign(Object.assign({ display: state.isOpen ? 'flex' : 'none', position: 'fixed' }, (bottomSheet
4485
+ ? {
4486
+ // Bottom sheet positioning
4487
+ top: 'auto',
4488
+ bottom: '0',
4489
+ left: '0',
4490
+ right: '0',
4491
+ transform: 'none',
4492
+ maxWidth: '100%',
4493
+ borderRadius: '8px 8px 0 0',
4494
+ }
4495
+ : {
4496
+ // Regular modal positioning
4497
+ top: '50%',
4498
+ left: '50%',
4499
+ transform: 'translate(-50%, -50%)',
4500
+ maxWidth: '75%',
4501
+ borderRadius: '4px',
4502
+ })), { backgroundColor: 'var(--mm-modal-background, #fff)', maxHeight: '85%', overflow: 'auto', zIndex: '1003', padding: '0', flexDirection: 'column', boxShadow: '0 24px 38px 3px rgba(0,0,0,0.14), 0 9px 46px 8px rgba(0,0,0,0.12), 0 11px 15px -7px rgba(0,0,0,0.20)' }),
3660
4503
  onclick: (e) => e.stopPropagation(), // Prevent backdrop click when clicking inside modal
3661
4504
  }, [
3662
4505
  // Close button
@@ -4694,7 +5537,7 @@
4694
5537
  callback(propId);
4695
5538
  }
4696
5539
  };
4697
- const cn = [newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim();
5540
+ const cn = [newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim() || undefined;
4698
5541
  const optionsContent = layout === 'horizontal'
4699
5542
  ? m('div.grid-container', options.map((r) => m(RadioButton, Object.assign(Object.assign({}, r), { onchange,
4700
5543
  groupId, disabled: disabled || r.disabled, className: checkboxClass, checked: r.id === checkedId, inputId: `${componentId}-${r.id}` }))))
@@ -4967,7 +5810,7 @@
4967
5810
  view: ({ attrs }) => {
4968
5811
  const id = attrs.id || state.id;
4969
5812
  const { label, left, right, disabled, newRow, onchange, isMandatory, className = 'col s12' } = attrs, params = __rest(attrs, ["label", "left", "right", "disabled", "newRow", "onchange", "isMandatory", "className"]);
4970
- const cn = ['input-field', newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim();
5813
+ const cn = ['input-field', newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim() || undefined;
4971
5814
  return m('div', {
4972
5815
  className: cn,
4973
5816
  onclick: (e) => {
@@ -5118,7 +5961,7 @@
5118
5961
  },
5119
5962
  view: ({ attrs }) => {
5120
5963
  const { tabWidth, tabs, className, style, swipeable = false } = attrs;
5121
- const cn = [tabWidth === 'fill' ? 'tabs-fixed-width' : '', className].filter(Boolean).join(' ').trim();
5964
+ const cn = [tabWidth === 'fill' ? 'tabs-fixed-width' : '', className].filter(Boolean).join(' ').trim() || undefined;
5122
5965
  const anchoredTabs = tabs.map(toAnchored());
5123
5966
  const activeTab = setActiveTabId(anchoredTabs, attrs.selectedTabId);
5124
5967
  updateIndicator();
@@ -6104,8 +6947,8 @@
6104
6947
  }
6105
6948
  // Check file type
6106
6949
  if (attrs.accept) {
6107
- const acceptedTypes = attrs.accept.split(',').map(type => type.trim());
6108
- const isAccepted = acceptedTypes.some(acceptedType => {
6950
+ const acceptedTypes = attrs.accept.split(',').map((type) => type.trim());
6951
+ const isAccepted = acceptedTypes.some((acceptedType) => {
6109
6952
  if (acceptedType.startsWith('.')) {
6110
6953
  // Extension check
6111
6954
  return file.name.toLowerCase().endsWith(acceptedType.toLowerCase());
@@ -6165,11 +7008,11 @@
6165
7008
  }
6166
7009
  // Notify parent component
6167
7010
  if (attrs.onFilesSelected) {
6168
- attrs.onFilesSelected(state.files.filter(f => !f.uploadError));
7011
+ attrs.onFilesSelected(state.files.filter((f) => !f.uploadError));
6169
7012
  }
6170
7013
  };
6171
7014
  const removeFile = (fileToRemove, attrs) => {
6172
- state.files = state.files.filter(file => file !== fileToRemove);
7015
+ state.files = state.files.filter((file) => file !== fileToRemove);
6173
7016
  if (attrs.onFileRemoved) {
6174
7017
  attrs.onFileRemoved(fileToRemove);
6175
7018
  }
@@ -6188,11 +7031,11 @@
6188
7031
  id: uniqueId(),
6189
7032
  files: [],
6190
7033
  isDragOver: false,
6191
- isUploading: false
7034
+ isUploading: false,
6192
7035
  };
6193
7036
  },
6194
7037
  view: ({ attrs }) => {
6195
- const { accept, multiple = false, disabled = false, label = 'Choose files or drag them here', helperText, showPreview = true, className = '', error } = attrs;
7038
+ const { accept, multiple = false, disabled = false, label = 'Choose files or drag them here', helperText, showPreview = true, className = '', error, } = attrs;
6196
7039
  return m('.file-upload-container', { class: className }, [
6197
7040
  // Upload area
6198
7041
  m('.file-upload-area', {
@@ -6200,8 +7043,10 @@
6200
7043
  state.isDragOver ? 'drag-over' : '',
6201
7044
  disabled ? 'disabled' : '',
6202
7045
  error ? 'error' : '',
6203
- state.files.length > 0 ? 'has-files' : ''
6204
- ].filter(Boolean).join(' '),
7046
+ state.files.length > 0 ? 'has-files' : '',
7047
+ ]
7048
+ .filter(Boolean)
7049
+ .join(' ') || undefined,
6205
7050
  ondragover: (e) => {
6206
7051
  if (disabled)
6207
7052
  return;
@@ -6232,7 +7077,7 @@
6232
7077
  return;
6233
7078
  const input = document.getElementById(state.id);
6234
7079
  input === null || input === void 0 ? void 0 : input.click();
6235
- }
7080
+ },
6236
7081
  }, [
6237
7082
  m('input[type="file"]', {
6238
7083
  id: state.id,
@@ -6245,57 +7090,55 @@
6245
7090
  if (target.files) {
6246
7091
  handleFiles(target.files, attrs);
6247
7092
  }
6248
- }
7093
+ },
6249
7094
  }),
6250
7095
  m('.file-upload-content', [
6251
7096
  m('i.material-icons.file-upload-icon', 'cloud_upload'),
6252
7097
  m('p.file-upload-label', label),
6253
7098
  helperText && m('p.file-upload-helper', helperText),
6254
- accept && m('p.file-upload-types', `Accepted: ${accept}`)
6255
- ])
7099
+ accept && m('p.file-upload-types', `Accepted: ${accept}`),
7100
+ ]),
6256
7101
  ]),
6257
7102
  // Error message
6258
7103
  error && m('.file-upload-error', error),
6259
7104
  // File list
6260
- state.files.length > 0 && m('.file-upload-list', [
6261
- m('h6', 'Selected Files:'),
6262
- state.files.map(file => m('.file-upload-item', { key: file.name + file.size }, [
6263
- // Preview thumbnail
6264
- showPreview && file.preview && m('.file-preview', [
6265
- m('img', { src: file.preview, alt: file.name })
6266
- ]),
6267
- // File info
6268
- m('.file-info', [
6269
- m('.file-name', file.name),
6270
- m('.file-details', [
6271
- m('span.file-size', formatFileSize(file.size)),
6272
- file.type && m('span.file-type', file.type)
6273
- ]),
6274
- // Progress bar (if uploading)
6275
- file.uploadProgress !== undefined && m('.file-progress', [
6276
- m('.progress', [
6277
- m('.determinate', {
6278
- style: { width: `${file.uploadProgress}%` }
6279
- })
6280
- ])
7105
+ state.files.length > 0 &&
7106
+ m('.file-upload-list', [
7107
+ m('h6', 'Selected Files:'),
7108
+ state.files.map((file) => m('.file-upload-item', { key: file.name + file.size }, [
7109
+ // Preview thumbnail
7110
+ showPreview && file.preview && m('.file-preview', [m('img', { src: file.preview, alt: file.name })]),
7111
+ // File info
7112
+ m('.file-info', [
7113
+ m('.file-name', file.name),
7114
+ m('.file-details', [
7115
+ m('span.file-size', formatFileSize(file.size)),
7116
+ file.type && m('span.file-type', file.type),
7117
+ ]),
7118
+ // Progress bar (if uploading)
7119
+ file.uploadProgress !== undefined &&
7120
+ m('.file-progress', [
7121
+ m('.progress', [
7122
+ m('.determinate', {
7123
+ style: { width: `${file.uploadProgress}%` },
7124
+ }),
7125
+ ]),
7126
+ ]),
7127
+ // Error message
7128
+ file.uploadError && m('.file-error', file.uploadError),
6281
7129
  ]),
6282
- // Error message
6283
- file.uploadError && m('.file-error', file.uploadError)
6284
- ]),
6285
- // Remove button
6286
- m('button.btn-flat.file-remove', {
6287
- onclick: (e) => {
6288
- e.stopPropagation();
6289
- removeFile(file, attrs);
6290
- },
6291
- title: 'Remove file'
6292
- }, [
6293
- m('i.material-icons', 'close')
6294
- ])
6295
- ]))
6296
- ])
7130
+ // Remove button
7131
+ m('button.btn-flat.file-remove', {
7132
+ onclick: (e) => {
7133
+ e.stopPropagation();
7134
+ removeFile(file, attrs);
7135
+ },
7136
+ title: 'Remove file',
7137
+ }, [m('i.material-icons', 'close')]),
7138
+ ])),
7139
+ ]),
6297
7140
  ]);
6298
- }
7141
+ },
6299
7142
  };
6300
7143
  };
6301
7144
 
@@ -6325,7 +7168,7 @@
6325
7168
  state = {
6326
7169
  id: attrs.id || uniqueId(),
6327
7170
  isOpen: attrs.isOpen || false,
6328
- isAnimating: false
7171
+ isAnimating: false,
6329
7172
  };
6330
7173
  // Set up keyboard listener
6331
7174
  if (typeof document !== 'undefined' && attrs.closeOnEscape !== false) {
@@ -6354,34 +7197,33 @@
6354
7197
  }
6355
7198
  },
6356
7199
  view: ({ attrs, children }) => {
6357
- const { position = 'left', mode = 'overlay', width = 300, className = '', showBackdrop = true, animationDuration = 300, fixed = false } = attrs;
7200
+ const { position = 'left', mode = 'overlay', width = 300, className = '', showBackdrop = true, animationDuration = 300, fixed = false, } = attrs;
6358
7201
  const isOpen = state.isOpen;
6359
7202
  return [
6360
7203
  // Backdrop (using existing materialize class)
6361
- showBackdrop && mode === 'overlay' && m('.sidenav-overlay', {
6362
- style: {
6363
- display: isOpen ? 'block' : 'none',
6364
- opacity: isOpen ? '1' : '0'
6365
- },
6366
- onclick: () => handleBackdropClick(attrs)
6367
- }),
7204
+ showBackdrop &&
7205
+ mode === 'overlay' &&
7206
+ m('.sidenav-overlay', {
7207
+ style: {
7208
+ display: isOpen ? 'block' : 'none',
7209
+ opacity: isOpen ? '1' : '0',
7210
+ },
7211
+ onclick: () => handleBackdropClick(attrs),
7212
+ }),
6368
7213
  // Sidenav (using existing materialize structure)
6369
7214
  m('ul.sidenav', {
6370
7215
  id: state.id,
6371
- class: [
6372
- position === 'right' ? 'right-aligned' : '',
6373
- fixed ? 'sidenav-fixed' : '',
6374
- className
6375
- ].filter(Boolean).join(' '),
7216
+ class: [position === 'right' ? 'right-aligned' : '', fixed ? 'sidenav-fixed' : '', className]
7217
+ .filter(Boolean)
7218
+ .join(' ') || undefined,
6376
7219
  style: {
6377
7220
  width: `${width}px`,
6378
- transform: isOpen ? 'translateX(0)' :
6379
- position === 'left' ? 'translateX(-105%)' : 'translateX(105%)',
6380
- 'transition-duration': `${animationDuration}ms`
6381
- }
6382
- }, children)
7221
+ transform: isOpen ? 'translateX(0)' : position === 'left' ? 'translateX(-105%)' : 'translateX(105%)',
7222
+ 'transition-duration': `${animationDuration}ms`,
7223
+ },
7224
+ }, children),
6383
7225
  ];
6384
- }
7226
+ },
6385
7227
  };
6386
7228
  };
6387
7229
  /**
@@ -6391,37 +7233,30 @@
6391
7233
  const SidenavItem = () => {
6392
7234
  return {
6393
7235
  view: ({ attrs, children }) => {
6394
- const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false } = attrs;
7236
+ const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, } = attrs;
6395
7237
  if (divider) {
6396
7238
  return m('li.divider');
6397
7239
  }
6398
7240
  if (subheader) {
6399
7241
  return m('li.subheader', text || children);
6400
7242
  }
6401
- const itemClasses = [
6402
- active ? 'active' : '',
6403
- disabled ? 'disabled' : '',
6404
- className
6405
- ].filter(Boolean).join(' ');
6406
- const content = [
6407
- icon && m('i.material-icons', icon),
6408
- text || children
6409
- ];
7243
+ const itemClasses = [active ? 'active' : '', disabled ? 'disabled' : '', className].filter(Boolean).join(' ') || undefined;
7244
+ const content = [icon && m('i.material-icons', icon), text || children];
6410
7245
  if (href && !disabled) {
6411
7246
  return m('li', { class: itemClasses }, [
6412
7247
  m('a', {
6413
7248
  href,
6414
- onclick: disabled ? undefined : onclick
6415
- }, content)
7249
+ onclick: disabled ? undefined : onclick,
7250
+ }, content),
6416
7251
  ]);
6417
7252
  }
6418
7253
  return m('li', { class: itemClasses }, [
6419
7254
  m('a', {
6420
7255
  onclick: disabled ? undefined : onclick,
6421
- href: '#!'
6422
- }, content)
7256
+ href: '#!',
7257
+ }, content),
6423
7258
  ]);
6424
- }
7259
+ },
6425
7260
  };
6426
7261
  };
6427
7262
  /**
@@ -6472,7 +7307,7 @@
6472
7307
  const Breadcrumb = () => {
6473
7308
  return {
6474
7309
  view: ({ attrs }) => {
6475
- const { items = [], separator = 'chevron_right', className = '', showIcons = false, maxItems, showHome = false } = attrs;
7310
+ const { items = [], separator = 'chevron_right', className = '', showIcons = false, maxItems, showHome = false, } = attrs;
6476
7311
  if (items.length === 0) {
6477
7312
  return null;
6478
7313
  }
@@ -6481,52 +7316,46 @@
6481
7316
  if (maxItems && items.length > maxItems) {
6482
7317
  const firstItem = items[0];
6483
7318
  const lastItems = items.slice(-(maxItems - 2));
6484
- displayItems = [
6485
- firstItem,
6486
- { text: '...', disabled: true, className: 'breadcrumb-ellipsis' },
6487
- ...lastItems
6488
- ];
7319
+ displayItems = [firstItem, { text: '...', disabled: true, className: 'breadcrumb-ellipsis' }, ...lastItems];
6489
7320
  }
6490
7321
  return m('nav.breadcrumb', { class: className }, [
6491
- m('ol.breadcrumb-list', displayItems.map((item, index) => {
7322
+ m('ol.breadcrumb-list', displayItems
7323
+ .map((item, index) => {
6492
7324
  const isLast = index === displayItems.length - 1;
6493
7325
  const isFirst = index === 0;
6494
7326
  return [
6495
7327
  // Breadcrumb item
6496
7328
  m('li.breadcrumb-item', {
6497
- class: [
6498
- item.active || isLast ? 'active' : '',
6499
- item.disabled ? 'disabled' : '',
6500
- item.className || ''
6501
- ].filter(Boolean).join(' ')
7329
+ class: [item.active || isLast ? 'active' : '', item.disabled ? 'disabled' : '', item.className || '']
7330
+ .filter(Boolean)
7331
+ .join(' ') || undefined,
6502
7332
  }, [
6503
- item.href && !item.disabled && !isLast ?
6504
- // Link item
6505
- m('a.breadcrumb-link', {
6506
- href: item.href,
6507
- onclick: item.onclick
6508
- }, [
6509
- (showIcons && item.icon) && m('i.material-icons.breadcrumb-icon', item.icon),
6510
- (showHome && isFirst && !item.icon) && m('i.material-icons.breadcrumb-icon', 'home'),
6511
- m('span.breadcrumb-text', item.text)
6512
- ]) :
6513
- // Text item (active or disabled)
6514
- m('span.breadcrumb-text', {
6515
- onclick: item.disabled ? undefined : item.onclick
6516
- }, [
6517
- (showIcons && item.icon) && m('i.material-icons.breadcrumb-icon', item.icon),
6518
- (showHome && isFirst && !item.icon) && m('i.material-icons.breadcrumb-icon', 'home'),
6519
- item.text
6520
- ])
7333
+ item.href && !item.disabled && !isLast
7334
+ ? // Link item
7335
+ m('a.breadcrumb-link', {
7336
+ href: item.href,
7337
+ onclick: item.onclick,
7338
+ }, [
7339
+ showIcons && item.icon && m('i.material-icons.breadcrumb-icon', item.icon),
7340
+ showHome && isFirst && !item.icon && m('i.material-icons.breadcrumb-icon', 'home'),
7341
+ m('span.breadcrumb-text', item.text),
7342
+ ])
7343
+ : // Text item (active or disabled)
7344
+ m('span.breadcrumb-text', {
7345
+ onclick: item.disabled ? undefined : item.onclick,
7346
+ }, [
7347
+ showIcons && item.icon && m('i.material-icons.breadcrumb-icon', item.icon),
7348
+ showHome && isFirst && !item.icon && m('i.material-icons.breadcrumb-icon', 'home'),
7349
+ item.text,
7350
+ ]),
6521
7351
  ]),
6522
7352
  // Separator (except for last item)
6523
- !isLast && m('li.breadcrumb-separator', [
6524
- m('i.material-icons', separator)
6525
- ])
7353
+ !isLast && m('li.breadcrumb-separator', [m('i.material-icons', separator)]),
6526
7354
  ];
6527
- }).reduce((acc, val) => acc.concat(val), []))
7355
+ })
7356
+ .reduce((acc, val) => acc.concat(val), [])),
6528
7357
  ]);
6529
- }
7358
+ },
6530
7359
  };
6531
7360
  };
6532
7361
  /**
@@ -6539,7 +7368,7 @@
6539
7368
  items.push({
6540
7369
  text: 'Home',
6541
7370
  href: basePath,
6542
- icon: 'home'
7371
+ icon: 'home',
6543
7372
  });
6544
7373
  // Add path segments
6545
7374
  let currentPath = basePath;
@@ -6549,7 +7378,7 @@
6549
7378
  items.push({
6550
7379
  text: segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' '),
6551
7380
  href: isLast ? undefined : currentPath,
6552
- active: isLast
7381
+ active: isLast,
6553
7382
  });
6554
7383
  });
6555
7384
  return items;
@@ -6568,19 +7397,18 @@
6568
7397
  items.push({
6569
7398
  text: 'Home',
6570
7399
  href: '/',
6571
- icon: 'home'
7400
+ icon: 'home',
6572
7401
  });
6573
7402
  let currentPath = '';
6574
7403
  segments.forEach((segment, index) => {
6575
7404
  currentPath += '/' + segment;
6576
7405
  const isLast = index === segments.length - 1;
6577
7406
  // Use custom text from config or format segment
6578
- const text = routeConfig[currentPath] ||
6579
- segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' ');
7407
+ const text = routeConfig[currentPath] || segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' ');
6580
7408
  items.push({
6581
7409
  text,
6582
7410
  href: isLast ? undefined : currentPath,
6583
- active: isLast
7411
+ active: isLast,
6584
7412
  });
6585
7413
  });
6586
7414
  return items;
@@ -6592,7 +7420,7 @@
6592
7420
  return hierarchy.map((item, index) => ({
6593
7421
  text: item[textKey],
6594
7422
  href: index === hierarchy.length - 1 ? undefined : item[pathKey],
6595
- active: index === hierarchy.length - 1
7423
+ active: index === hierarchy.length - 1,
6596
7424
  }));
6597
7425
  }
6598
7426
  }
@@ -6726,7 +7554,7 @@
6726
7554
  hasError ? 'error' : '',
6727
7555
  step.disabled ? 'disabled' : '',
6728
7556
  step.optional ? 'optional' : ''
6729
- ].filter(Boolean).join(' '),
7557
+ ].filter(Boolean).join(' ') || undefined,
6730
7558
  onclick: allowHeaderNavigation && !step.disabled ?
6731
7559
  () => goToStep(index, attrs) : undefined
6732
7560
  }, [
@@ -6800,6 +7628,292 @@
6800
7628
  };
6801
7629
  };
6802
7630
 
7631
+ // Utility function to check if a node is the last in its branch
7632
+ const isNodeLastInBranch = (nodePath, rootNodes) => {
7633
+ // Navigate to the node's position and check if it's the last child at every level
7634
+ let currentNodes = rootNodes;
7635
+ for (let i = 0; i < nodePath.length; i++) {
7636
+ const index = nodePath[i];
7637
+ const isLastAtThisLevel = index === currentNodes.length - 1;
7638
+ // If this is not the last child at this level, then this node is not last in branch
7639
+ if (!isLastAtThisLevel) {
7640
+ return false;
7641
+ }
7642
+ // Move to the next level if it exists
7643
+ if (i < nodePath.length - 1) {
7644
+ const currentNode = currentNodes[index];
7645
+ if (currentNode.children) {
7646
+ currentNodes = currentNode.children;
7647
+ }
7648
+ }
7649
+ }
7650
+ return true;
7651
+ };
7652
+ const TreeNodeComponent = () => {
7653
+ return {
7654
+ view: ({ attrs }) => {
7655
+ const { node, level, isSelected, isExpanded, isFocused, showConnectors, iconType, selectionMode, onToggleExpand, onToggleSelect, onFocus, } = attrs;
7656
+ const hasChildren = node.children && node.children.length > 0;
7657
+ const indentLevel = level * 24; // 24px per level
7658
+ return m('li.tree-node', {
7659
+ class: [
7660
+ isSelected && 'selected',
7661
+ isFocused && 'focused',
7662
+ node.disabled && 'disabled',
7663
+ hasChildren && 'has-children',
7664
+ attrs.isLastInBranch && 'tree-last-in-branch',
7665
+ ]
7666
+ .filter(Boolean)
7667
+ .join(' ') || undefined,
7668
+ 'data-node-id': node.id,
7669
+ 'data-level': level,
7670
+ }, [
7671
+ // Node content
7672
+ m('.tree-node-content', {
7673
+ style: {
7674
+ paddingLeft: `${indentLevel}px`,
7675
+ },
7676
+ onclick: node.disabled
7677
+ ? undefined
7678
+ : () => {
7679
+ if (selectionMode !== 'none') {
7680
+ onToggleSelect(node.id);
7681
+ }
7682
+ onFocus(node.id);
7683
+ },
7684
+ onkeydown: (e) => {
7685
+ if (e.key === 'Enter' || e.key === ' ') {
7686
+ e.preventDefault();
7687
+ if (!node.disabled && selectionMode !== 'none') {
7688
+ onToggleSelect(node.id);
7689
+ }
7690
+ }
7691
+ },
7692
+ tabindex: node.disabled ? -1 : 0,
7693
+ role: selectionMode === 'multiple' ? 'option' : 'treeitem',
7694
+ 'aria-selected': selectionMode !== 'none' ? isSelected.toString() : undefined,
7695
+ 'aria-expanded': hasChildren ? isExpanded.toString() : undefined,
7696
+ 'aria-disabled': node.disabled ? 'true' : undefined,
7697
+ }, [
7698
+ // Connector lines
7699
+ showConnectors &&
7700
+ level > 0 &&
7701
+ m('.tree-connectors', Array.from({ length: level }, (_, i) => m('.tree-connector', {
7702
+ key: i,
7703
+ style: { left: `${i * 24 + 12}px` },
7704
+ }))),
7705
+ // Expand/collapse icon or spacer
7706
+ hasChildren
7707
+ ? m('.tree-expand-icon', {
7708
+ onclick: (e) => {
7709
+ e.stopPropagation();
7710
+ if (!node.disabled) {
7711
+ onToggleExpand(node.id);
7712
+ }
7713
+ },
7714
+ class: iconType,
7715
+ }, [
7716
+ iconType === 'plus-minus'
7717
+ ? m('span.tree-plus-minus', isExpanded ? '−' : '+')
7718
+ : iconType === 'triangle'
7719
+ ? m('span.tree-triangle', { class: isExpanded ? 'expanded' : undefined }, '▶')
7720
+ : iconType === 'chevron'
7721
+ ? m(MaterialIcon, {
7722
+ name: 'chevron',
7723
+ direction: isExpanded ? 'down' : 'right',
7724
+ class: 'tree-chevron-icon',
7725
+ })
7726
+ : m(MaterialIcon, {
7727
+ name: 'caret',
7728
+ direction: isExpanded ? 'down' : 'right',
7729
+ class: 'tree-caret-icon',
7730
+ }),
7731
+ ])
7732
+ : m('.tree-expand-spacer'), // Spacer for alignment
7733
+ // Selection indicator for multiple selection
7734
+ selectionMode === 'multiple' &&
7735
+ m('.tree-selection-indicator', [
7736
+ m('input[type=checkbox]', {
7737
+ checked: isSelected,
7738
+ disabled: node.disabled,
7739
+ onchange: () => {
7740
+ if (!node.disabled) {
7741
+ onToggleSelect(node.id);
7742
+ }
7743
+ },
7744
+ onclick: (e) => e.stopPropagation(),
7745
+ }),
7746
+ ]),
7747
+ // Node icon (optional)
7748
+ node.icon && m('i.tree-node-icon.material-icons', node.icon),
7749
+ // Node label
7750
+ m('span.tree-node-label', node.label),
7751
+ ]),
7752
+ // Children (recursive)
7753
+ hasChildren &&
7754
+ isExpanded &&
7755
+ m('ul.tree-children', {
7756
+ role: 'group',
7757
+ 'aria-expanded': 'true',
7758
+ }, node.children.map((child, childIndex) => {
7759
+ var _a, _b, _c, _d, _e, _f;
7760
+ // Calculate state for each child using treeState
7761
+ const childIsSelected = (_b = (_a = attrs.treeState) === null || _a === void 0 ? void 0 : _a.selectedIds.has(child.id)) !== null && _b !== void 0 ? _b : false;
7762
+ const childIsExpanded = (_d = (_c = attrs.treeState) === null || _c === void 0 ? void 0 : _c.expandedIds.has(child.id)) !== null && _d !== void 0 ? _d : false;
7763
+ const childIsFocused = ((_e = attrs.treeState) === null || _e === void 0 ? void 0 : _e.focusedNodeId) === child.id;
7764
+ // Calculate if this child is last in branch
7765
+ const childPath = [...(attrs.currentPath || []), childIndex];
7766
+ const childIsLastInBranch = ((_f = attrs.treeAttrs) === null || _f === void 0 ? void 0 : _f.data) ?
7767
+ isNodeLastInBranch(childPath, attrs.treeAttrs.data) : false;
7768
+ return m(TreeNodeComponent, {
7769
+ key: child.id,
7770
+ node: child,
7771
+ level: level + 1,
7772
+ isSelected: childIsSelected,
7773
+ isExpanded: childIsExpanded,
7774
+ isFocused: childIsFocused,
7775
+ showConnectors,
7776
+ iconType,
7777
+ selectionMode,
7778
+ onToggleExpand,
7779
+ onToggleSelect,
7780
+ onFocus,
7781
+ isLastInBranch: childIsLastInBranch,
7782
+ currentPath: childPath,
7783
+ treeState: attrs.treeState,
7784
+ treeAttrs: attrs.treeAttrs,
7785
+ });
7786
+ })),
7787
+ ]);
7788
+ },
7789
+ };
7790
+ };
7791
+ const TreeView = () => {
7792
+ const state = {
7793
+ selectedIds: new Set(),
7794
+ expandedIds: new Set(),
7795
+ focusedNodeId: null,
7796
+ treeMap: new Map(),
7797
+ };
7798
+ const buildTreeMap = (nodes, map) => {
7799
+ nodes.forEach((node) => {
7800
+ map.set(node.id, node);
7801
+ if (node.children) {
7802
+ buildTreeMap(node.children, map);
7803
+ }
7804
+ });
7805
+ };
7806
+ const initializeExpandedNodes = (nodes) => {
7807
+ nodes.forEach((node) => {
7808
+ if (node.expanded) {
7809
+ state.expandedIds.add(node.id);
7810
+ }
7811
+ if (node.children) {
7812
+ initializeExpandedNodes(node.children);
7813
+ }
7814
+ });
7815
+ };
7816
+ const handleToggleExpand = (nodeId, attrs) => {
7817
+ var _a;
7818
+ const isExpanded = state.expandedIds.has(nodeId);
7819
+ if (isExpanded) {
7820
+ state.expandedIds.delete(nodeId);
7821
+ }
7822
+ else {
7823
+ state.expandedIds.add(nodeId);
7824
+ }
7825
+ (_a = attrs.onexpand) === null || _a === void 0 ? void 0 : _a.call(attrs, { nodeId, expanded: !isExpanded });
7826
+ };
7827
+ const handleToggleSelect = (nodeId, attrs) => {
7828
+ var _a;
7829
+ const { selectionMode = 'single' } = attrs;
7830
+ if (selectionMode === 'single') {
7831
+ state.selectedIds.clear();
7832
+ state.selectedIds.add(nodeId);
7833
+ }
7834
+ else if (selectionMode === 'multiple') {
7835
+ if (state.selectedIds.has(nodeId)) {
7836
+ state.selectedIds.delete(nodeId);
7837
+ }
7838
+ else {
7839
+ state.selectedIds.add(nodeId);
7840
+ }
7841
+ }
7842
+ (_a = attrs.onselection) === null || _a === void 0 ? void 0 : _a.call(attrs, Array.from(state.selectedIds));
7843
+ };
7844
+ const handleFocus = (nodeId) => {
7845
+ state.focusedNodeId = nodeId;
7846
+ };
7847
+ const renderNodes = (nodes, attrs, level = 0, parentPath = []) => {
7848
+ return nodes.map((node, index) => {
7849
+ var _a, _b, _c;
7850
+ const isSelected = state.selectedIds.has(node.id);
7851
+ const isExpanded = state.expandedIds.has(node.id);
7852
+ const isFocused = state.focusedNodeId === node.id;
7853
+ const currentPath = [...parentPath, index];
7854
+ const isLastInBranch = isNodeLastInBranch(currentPath, attrs.data);
7855
+ return m(TreeNodeComponent, {
7856
+ key: node.id,
7857
+ node,
7858
+ level,
7859
+ isSelected,
7860
+ isExpanded,
7861
+ isFocused,
7862
+ showConnectors: (_a = attrs.showConnectors) !== null && _a !== void 0 ? _a : true,
7863
+ iconType: (_b = attrs.iconType) !== null && _b !== void 0 ? _b : 'caret',
7864
+ selectionMode: (_c = attrs.selectionMode) !== null && _c !== void 0 ? _c : 'single',
7865
+ onToggleExpand: (nodeId) => handleToggleExpand(nodeId, attrs),
7866
+ onToggleSelect: (nodeId) => handleToggleSelect(nodeId, attrs),
7867
+ onFocus: handleFocus,
7868
+ isLastInBranch,
7869
+ currentPath,
7870
+ // Pass state and attrs for recursive rendering
7871
+ treeState: state,
7872
+ treeAttrs: attrs,
7873
+ });
7874
+ });
7875
+ };
7876
+ return {
7877
+ oninit: ({ attrs }) => {
7878
+ // Build internal tree map for efficient lookups
7879
+ buildTreeMap(attrs.data, state.treeMap);
7880
+ // Initialize expanded nodes from data
7881
+ initializeExpandedNodes(attrs.data);
7882
+ // Initialize selected nodes from props
7883
+ if (attrs.selectedIds) {
7884
+ state.selectedIds = new Set(attrs.selectedIds);
7885
+ }
7886
+ },
7887
+ onupdate: ({ attrs }) => {
7888
+ // Sync selectedIds prop with internal state
7889
+ if (attrs.selectedIds) {
7890
+ const newSelection = new Set(attrs.selectedIds);
7891
+ if (newSelection.size !== state.selectedIds.size ||
7892
+ !Array.from(newSelection).every((id) => state.selectedIds.has(id))) {
7893
+ state.selectedIds = newSelection;
7894
+ }
7895
+ }
7896
+ },
7897
+ view: ({ attrs }) => {
7898
+ const { data, className, style, id, selectionMode = 'single', showConnectors = true } = attrs;
7899
+ return m('div.tree-view', {
7900
+ class: [
7901
+ className,
7902
+ showConnectors && 'show-connectors'
7903
+ ].filter(Boolean).join(' ') || undefined,
7904
+ style,
7905
+ id,
7906
+ role: selectionMode === 'multiple' ? 'listbox' : 'tree',
7907
+ 'aria-multiselectable': selectionMode === 'multiple' ? 'true' : 'false',
7908
+ }, [
7909
+ m('ul.tree-root', {
7910
+ role: 'group',
7911
+ }, renderNodes(data, attrs)),
7912
+ ]);
7913
+ },
7914
+ };
7915
+ };
7916
+
6803
7917
  /**
6804
7918
  * @fileoverview Core TypeScript utility types for mithril-materialized library
6805
7919
  * These types improve type safety and developer experience across all components
@@ -6851,6 +7965,7 @@
6851
7965
  exports.ListItem = ListItem;
6852
7966
  exports.Mandatory = Mandatory;
6853
7967
  exports.MaterialBox = MaterialBox;
7968
+ exports.MaterialIcon = MaterialIcon;
6854
7969
  exports.ModalPanel = ModalPanel;
6855
7970
  exports.NumberInput = NumberInput;
6856
7971
  exports.Options = Options;
@@ -6885,6 +8000,7 @@
6885
8000
  exports.ToastComponent = ToastComponent;
6886
8001
  exports.Tooltip = Tooltip;
6887
8002
  exports.TooltipComponent = TooltipComponent;
8003
+ exports.TreeView = TreeView;
6888
8004
  exports.UrlInput = UrlInput;
6889
8005
  exports.Wizard = Wizard;
6890
8006
  exports.createBreadcrumb = createBreadcrumb;
@@ -6896,6 +8012,8 @@
6896
8012
  exports.isValidationSuccess = isValidationSuccess;
6897
8013
  exports.padLeft = padLeft;
6898
8014
  exports.range = range;
8015
+ exports.renderMinMaxRange = renderMinMaxRange;
8016
+ exports.renderSingleRangeWithTooltip = renderSingleRangeWithTooltip;
6899
8017
  exports.toast = toast;
6900
8018
  exports.uniqueId = uniqueId;
6901
8019
  exports.uuid4 = uuid4;