kmaterialize 2.3.3-1.0.2 → 2.3.3-1.0.21

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.
Files changed (42) hide show
  1. package/README.md +4 -4
  2. package/components/air-datepicker/_air-datepicker.scss +137 -0
  3. package/components/air-datepicker/air-datepicker.ts +192 -0
  4. package/components/alert/_alerts.scss +130 -0
  5. package/components/alert/alert.ts +73 -0
  6. package/components/appbar/appbar.css +301 -4
  7. package/components/button/_buttons.scss +39 -1
  8. package/components/card/_cards.scss +9 -1
  9. package/components/checkbox/_checkboxes.scss +120 -229
  10. package/components/collapsible/_collapsible.scss +50 -0
  11. package/components/color-input/_color-input.scss +124 -0
  12. package/components/color-input/color-input.ts +203 -0
  13. package/components/dropdown/dropdown.ts +1 -1
  14. package/components/file-input/_file-input-enhanced.scss +61 -0
  15. package/components/file-input/file-input.ts +203 -0
  16. package/components/kanban/_kanban.scss +148 -0
  17. package/components/kanban/kanban.ts +133 -0
  18. package/components/list/_collection.scss +10 -2
  19. package/components/number-input/number-input.ts +103 -0
  20. package/components/password-input/password-input.ts +72 -0
  21. package/components/slider/_range.scss +5 -1
  22. package/components/switch/_switches.scss +5 -0
  23. package/components/textfield/_input-fields.scss +4 -4
  24. package/components/textfield/_select.scss +54 -0
  25. package/components/tom-select/_tom-select-field.scss +256 -0
  26. package/components/tom-select/tom-select-field.ts +175 -0
  27. package/components/toolbar/_toolbar.scss +324 -0
  28. package/components/toolbar/toolbar.ts +152 -0
  29. package/dist/css/materialize.colors.min.css +2 -2
  30. package/dist/css/materialize.css +10575 -711
  31. package/dist/css/materialize.min.css +2 -2
  32. package/dist/css/materialize.min.css.map +1 -1
  33. package/dist/js/materialize.cjs.js +1136 -45
  34. package/dist/js/materialize.d.ts +227 -2
  35. package/dist/js/materialize.js +1136 -45
  36. package/dist/js/materialize.min.js +2 -2
  37. package/dist/js/materialize.mjs +1128 -46
  38. package/package.json +45 -1
  39. package/sass/_colors.scss +191 -5
  40. package/sass/_global.scss +240 -1
  41. package/sass/materialize.scss +14 -1
  42. package/sass/mixins.module.scss +6 -6
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Materialize v2.3.3-1.0.2 (https://materializeweb.com)
2
+ * Materialize v2.3.3-1.0.21 (https://materializeweb.com)
3
3
  * Copyright 2014-2026 Materialize
4
4
  * MIT License (https://raw.githubusercontent.com/materializecss/materialize/master/LICENSE)
5
5
  */
@@ -399,7 +399,7 @@ class Component {
399
399
  }
400
400
  }
401
401
 
402
- const _defaults$o = {
402
+ const _defaults$x = {
403
403
  alignment: 'left',
404
404
  autoFocus: true,
405
405
  constrainWidth: true,
@@ -452,7 +452,7 @@ class Dropdown extends Component {
452
452
  this._setupEventHandlers();
453
453
  }
454
454
  static get defaults() {
455
- return _defaults$o;
455
+ return _defaults$x;
456
456
  }
457
457
  /**
458
458
  * Initializes instances of Dropdown.
@@ -544,7 +544,7 @@ class Dropdown extends Component {
544
544
  // isTouchMoving to check if scrolling on mobile.
545
545
  this.close();
546
546
  }
547
- else if (!target.closest('.dropdown-content')) {
547
+ else if (!target.closest('.dropdown-content') && !target.closest('.dropdown-trigger')) {
548
548
  // Do this one frame later so that if the element clicked also triggers _handleClick
549
549
  // For example, if a label for a select was clicked, that we don't close/open the dropdown
550
550
  setTimeout(() => {
@@ -903,7 +903,7 @@ class Dropdown extends Component {
903
903
  };
904
904
  }
905
905
 
906
- const _defaults$n = {
906
+ const _defaults$w = {
907
907
  data: [], // Autocomplete data set
908
908
  onAutocomplete: null, // Callback for when autocompleted
909
909
  dropdownOptions: {
@@ -963,7 +963,7 @@ class Autocomplete extends Component {
963
963
  this._setupEventHandlers();
964
964
  }
965
965
  static get defaults() {
966
- return _defaults$n;
966
+ return _defaults$w;
967
967
  }
968
968
  /**
969
969
  * Initializes instances of Autocomplete.
@@ -1371,7 +1371,177 @@ class Autocomplete extends Component {
1371
1371
  }
1372
1372
  }
1373
1373
 
1374
- const _defaults$m = {
1374
+ const _defaults$v = {
1375
+ dismissible: true
1376
+ };
1377
+ /** A persistent, contextual feedback banner. */
1378
+ class Alert extends Component {
1379
+ _closeButton = null;
1380
+ _onClose = () => this.dismiss();
1381
+ constructor(el, options) {
1382
+ super(el, options, Alert);
1383
+ this.options = { ...Alert.defaults, ...options };
1384
+ this.el['M_Alert'] = this;
1385
+ this._bindCloseButton();
1386
+ }
1387
+ static get defaults() {
1388
+ return _defaults$v;
1389
+ }
1390
+ static init(els, options = {}) {
1391
+ return super.init(els, options, Alert);
1392
+ }
1393
+ static getInstance(el) {
1394
+ return el['M_Alert'];
1395
+ }
1396
+ _bindCloseButton() {
1397
+ this._closeButton = this.el.querySelector('.alert-close');
1398
+ if (this.options.dismissible && this._closeButton) {
1399
+ this._closeButton.addEventListener('click', this._onClose);
1400
+ }
1401
+ }
1402
+ /** Hide and remove the alert from the document. */
1403
+ dismiss() {
1404
+ if (!this.el.isConnected)
1405
+ return;
1406
+ this.el.classList.add('alert-dismissing');
1407
+ const remove = () => {
1408
+ this.el.removeEventListener('transitionend', remove);
1409
+ this.el.hidden = true;
1410
+ this.options.onDismiss?.(this);
1411
+ };
1412
+ if (getComputedStyle(this.el).transitionDuration === '0s')
1413
+ remove();
1414
+ else
1415
+ this.el.addEventListener('transitionend', remove, { once: true });
1416
+ }
1417
+ /** Show an alert that was previously dismissed. */
1418
+ open() {
1419
+ this.el.hidden = false;
1420
+ this.el.classList.remove('alert-dismissing');
1421
+ }
1422
+ destroy() {
1423
+ this._closeButton?.removeEventListener('click', this._onClose);
1424
+ delete this.el['M_Alert'];
1425
+ }
1426
+ }
1427
+
1428
+ const _defaults$u = {
1429
+ draggable: true
1430
+ };
1431
+ /** A lightweight, dependency-free board for columns of draggable cards. */
1432
+ class Kanban extends Component {
1433
+ _draggedCard = null;
1434
+ _dragSourceColumn = null;
1435
+ _onDragStart = (event) => {
1436
+ const card = event.target?.closest('.kanban-card');
1437
+ if (!card || !this.options.draggable)
1438
+ return;
1439
+ this._draggedCard = card;
1440
+ this._dragSourceColumn = card.closest('.kanban-column');
1441
+ card.classList.add('is-dragging');
1442
+ event.dataTransfer?.setData('text/plain', card.dataset.kanbanCard || '');
1443
+ if (event.dataTransfer)
1444
+ event.dataTransfer.effectAllowed = 'move';
1445
+ };
1446
+ _onDragOver = (event) => {
1447
+ if (!this._draggedCard)
1448
+ return;
1449
+ const column = event.target?.closest('.kanban-column');
1450
+ if (!column || !this.el.contains(column))
1451
+ return;
1452
+ event.preventDefault();
1453
+ if (event.dataTransfer)
1454
+ event.dataTransfer.dropEffect = 'move';
1455
+ this.el.querySelectorAll('.kanban-column.is-drag-over').forEach((item) => item.classList.remove('is-drag-over'));
1456
+ column.classList.add('is-drag-over');
1457
+ };
1458
+ _onDrop = (event) => {
1459
+ if (!this._draggedCard)
1460
+ return;
1461
+ const column = event.target?.closest('.kanban-column');
1462
+ if (!column || !this.el.contains(column))
1463
+ return;
1464
+ event.preventDefault();
1465
+ const body = column.querySelector('.kanban-column-body') || column;
1466
+ const targetCard = event.target?.closest('.kanban-card');
1467
+ const source = this._dragSourceColumn;
1468
+ if (targetCard && targetCard !== this._draggedCard && targetCard.parentElement === body) {
1469
+ const box = targetCard.getBoundingClientRect();
1470
+ body.insertBefore(this._draggedCard, event.clientY < box.top + box.height / 2 ? targetCard : targetCard.nextSibling);
1471
+ }
1472
+ else {
1473
+ body.appendChild(this._draggedCard);
1474
+ }
1475
+ this._clearDragState();
1476
+ this._updateCounts();
1477
+ if (source && source !== column)
1478
+ this.options.onMove?.({ card: this._draggedCard, from: source, to: column });
1479
+ };
1480
+ _onDragEnd = () => this._clearDragState();
1481
+ constructor(el, options) {
1482
+ super(el, options, Kanban);
1483
+ this.options = { ...Kanban.defaults, ...options };
1484
+ this.el['M_Kanban'] = this;
1485
+ this._prepareMarkup();
1486
+ if (this.options.draggable)
1487
+ this._bindEvents();
1488
+ }
1489
+ static get defaults() {
1490
+ return _defaults$u;
1491
+ }
1492
+ static init(els, options = {}) {
1493
+ return super.init(els, options, Kanban);
1494
+ }
1495
+ static getInstance(el) {
1496
+ return el['M_Kanban'];
1497
+ }
1498
+ _prepareMarkup() {
1499
+ this.el.setAttribute('role', 'region');
1500
+ this.el.querySelectorAll('.kanban-column').forEach((column) => {
1501
+ column.setAttribute('role', 'group');
1502
+ const body = column.querySelector('.kanban-column-body');
1503
+ if (body)
1504
+ body.setAttribute('role', 'list');
1505
+ column.querySelectorAll('.kanban-card').forEach((card) => {
1506
+ card.setAttribute('role', 'listitem');
1507
+ card.setAttribute('tabindex', '0');
1508
+ if (this.options.draggable)
1509
+ card.draggable = true;
1510
+ });
1511
+ });
1512
+ this._updateCounts();
1513
+ }
1514
+ _bindEvents() {
1515
+ this.el.addEventListener('dragstart', this._onDragStart);
1516
+ this.el.addEventListener('dragover', this._onDragOver);
1517
+ this.el.addEventListener('drop', this._onDrop);
1518
+ this.el.addEventListener('dragend', this._onDragEnd);
1519
+ }
1520
+ _clearDragState() {
1521
+ this._draggedCard?.classList.remove('is-dragging');
1522
+ this.el.querySelectorAll('.kanban-column.is-drag-over').forEach((item) => item.classList.remove('is-drag-over'));
1523
+ this._draggedCard = null;
1524
+ this._dragSourceColumn = null;
1525
+ }
1526
+ _updateCounts() {
1527
+ this.el.querySelectorAll('.kanban-column').forEach((column) => {
1528
+ const count = column.querySelector('.kanban-column-count');
1529
+ const body = column.querySelector('.kanban-column-body');
1530
+ if (count && body)
1531
+ count.textContent = String(body.querySelectorAll(':scope > .kanban-card').length);
1532
+ });
1533
+ }
1534
+ destroy() {
1535
+ this._clearDragState();
1536
+ this.el.removeEventListener('dragstart', this._onDragStart);
1537
+ this.el.removeEventListener('dragover', this._onDragOver);
1538
+ this.el.removeEventListener('drop', this._onDrop);
1539
+ this.el.removeEventListener('dragend', this._onDragEnd);
1540
+ delete this.el['M_Kanban'];
1541
+ }
1542
+ }
1543
+
1544
+ const _defaults$t = {
1375
1545
  direction: 'top',
1376
1546
  hoverEnabled: true,
1377
1547
  toolbarEnabled: false
@@ -1418,7 +1588,7 @@ class FloatingActionButton extends Component {
1418
1588
  this.#setupEventHandlers();
1419
1589
  }
1420
1590
  static get defaults() {
1421
- return _defaults$m;
1591
+ return _defaults$t;
1422
1592
  }
1423
1593
  /**
1424
1594
  * Initializes instances of FloatingActionButton.
@@ -1589,7 +1759,7 @@ class FloatingActionButton extends Component {
1589
1759
  }
1590
1760
  }
1591
1761
 
1592
- const _defaults$l = {
1762
+ const _defaults$s = {
1593
1763
  onOpen: null,
1594
1764
  onClose: null,
1595
1765
  inDuration: 225,
@@ -1625,7 +1795,7 @@ class Cards extends Component {
1625
1795
  }
1626
1796
  }
1627
1797
  static get defaults() {
1628
- return _defaults$l;
1798
+ return _defaults$s;
1629
1799
  }
1630
1800
  /**
1631
1801
  * Initializes instances of Cards.
@@ -1736,7 +1906,7 @@ class Cards extends Component {
1736
1906
  }
1737
1907
  }
1738
1908
 
1739
- const _defaults$k = {
1909
+ const _defaults$r = {
1740
1910
  duration: 200, // ms
1741
1911
  dist: -100, // zoom scale TODO: make this more intuitive as an option
1742
1912
  shift: 0, // spacing for center image
@@ -1838,7 +2008,7 @@ class Carousel extends Component {
1838
2008
  this._scroll(this.offset);
1839
2009
  }
1840
2010
  static get defaults() {
1841
- return _defaults$k;
2011
+ return _defaults$r;
1842
2012
  }
1843
2013
  /**
1844
2014
  * Initializes instances of Carousel.
@@ -2310,7 +2480,7 @@ class Carousel extends Component {
2310
2480
  }
2311
2481
 
2312
2482
  var _a;
2313
- const _defaults$j = {
2483
+ const _defaults$q = {
2314
2484
  data: [],
2315
2485
  placeholder: '',
2316
2486
  secondaryPlaceholder: '',
@@ -2364,7 +2534,7 @@ class Chips extends Component {
2364
2534
  }
2365
2535
  }
2366
2536
  static get defaults() {
2367
- return _defaults$j;
2537
+ return _defaults$q;
2368
2538
  }
2369
2539
  /**
2370
2540
  * Initializes instances of Chips.
@@ -2647,7 +2817,7 @@ class Chips extends Component {
2647
2817
  }
2648
2818
  _a = Chips;
2649
2819
 
2650
- const _defaults$i = {
2820
+ const _defaults$p = {
2651
2821
  accordion: true,
2652
2822
  onOpenStart: null,
2653
2823
  onOpenEnd: null,
@@ -2683,7 +2853,7 @@ class Collapsible extends Component {
2683
2853
  }
2684
2854
  }
2685
2855
  static get defaults() {
2686
- return _defaults$i;
2856
+ return _defaults$p;
2687
2857
  }
2688
2858
  /**
2689
2859
  * Initializes instances of Collapsible.
@@ -2802,7 +2972,7 @@ class Collapsible extends Component {
2802
2972
  };
2803
2973
  }
2804
2974
 
2805
- const _defaults$h = {
2975
+ const _defaults$o = {
2806
2976
  classes: '',
2807
2977
  dropdownOptions: {}
2808
2978
  };
@@ -2842,7 +3012,7 @@ class FormSelect extends Component {
2842
3012
  this._setupEventHandlers();
2843
3013
  }
2844
3014
  static get defaults() {
2845
- return _defaults$h;
3015
+ return _defaults$o;
2846
3016
  }
2847
3017
  /**
2848
3018
  * Initializes instances of FormSelect.
@@ -3185,7 +3355,7 @@ class FormSelect extends Component {
3185
3355
  }
3186
3356
  }
3187
3357
 
3188
- const _defaults$g = {
3358
+ const _defaults$n = {
3189
3359
  margin: 5,
3190
3360
  transition: 10,
3191
3361
  duration: 250,
@@ -3202,7 +3372,7 @@ class DockedDisplayPlugin {
3202
3372
  constructor(el, container, options) {
3203
3373
  this.el = el;
3204
3374
  this.options = {
3205
- ..._defaults$g,
3375
+ ..._defaults$n,
3206
3376
  ...options
3207
3377
  };
3208
3378
  this.container = document.createElement('div');
@@ -3264,7 +3434,7 @@ class DockedDisplayPlugin {
3264
3434
  };
3265
3435
  }
3266
3436
 
3267
- const _defaults$f = {
3437
+ const _defaults$m = {
3268
3438
  classList: ['modal'],
3269
3439
  title: null,
3270
3440
  onOpen: null,
@@ -3279,7 +3449,7 @@ class ModalDisplayPlugin {
3279
3449
  constructor(el, container, options) {
3280
3450
  this.el = el;
3281
3451
  this.options = {
3282
- ..._defaults$f,
3452
+ ..._defaults$m,
3283
3453
  ...options,
3284
3454
  };
3285
3455
  this.container = document.createElement('dialog');
@@ -3337,7 +3507,7 @@ class ModalDisplayPlugin {
3337
3507
  };
3338
3508
  }
3339
3509
 
3340
- const _defaults$e = {
3510
+ const _defaults$l = {
3341
3511
  // the default output format for the input field value
3342
3512
  format: 'mmm dd, yyyy',
3343
3513
  // Used to create date object from current input string
@@ -3487,7 +3657,7 @@ class Datepicker extends Component {
3487
3657
  this._pickerSetup();
3488
3658
  }
3489
3659
  static get defaults() {
3490
- return _defaults$e;
3660
+ return _defaults$l;
3491
3661
  }
3492
3662
  /**
3493
3663
  * Initializes instances of Datepicker.
@@ -4540,7 +4710,7 @@ class Forms {
4540
4710
  }
4541
4711
  }
4542
4712
 
4543
- const _defaults$d = {
4713
+ const _defaults$k = {
4544
4714
  inDuration: 275,
4545
4715
  outDuration: 200,
4546
4716
  onOpenStart: null,
@@ -4592,7 +4762,7 @@ class Materialbox extends Component {
4592
4762
  this._setupEventHandlers();
4593
4763
  }
4594
4764
  static get defaults() {
4595
- return _defaults$d;
4765
+ return _defaults$k;
4596
4766
  }
4597
4767
  /**
4598
4768
  * Initializes instances of MaterialBox.
@@ -4916,7 +5086,7 @@ class Materialbox extends Component {
4916
5086
  };
4917
5087
  }
4918
5088
 
4919
- const _defaults$c = {
5089
+ const _defaults$j = {
4920
5090
  opacity: 0.5,
4921
5091
  inDuration: 250,
4922
5092
  outDuration: 250,
@@ -4941,7 +5111,7 @@ class Modal extends Component {
4941
5111
  this._setupEventHandlers();
4942
5112
  }
4943
5113
  static get defaults() {
4944
- return _defaults$c;
5114
+ return _defaults$j;
4945
5115
  }
4946
5116
  static init(els, options = {}) {
4947
5117
  return super.init(els, options, Modal);
@@ -4984,7 +5154,7 @@ class Modal extends Component {
4984
5154
  static { }
4985
5155
  }
4986
5156
 
4987
- const _defaults$b = {
5157
+ const _defaults$i = {
4988
5158
  edge: 'left',
4989
5159
  draggable: true,
4990
5160
  dragTargetWidth: '10px',
@@ -5040,7 +5210,7 @@ class Sidenav extends Component {
5040
5210
  Sidenav._sidenavs.push(this);
5041
5211
  }
5042
5212
  static get defaults() {
5043
- return _defaults$b;
5213
+ return _defaults$i;
5044
5214
  }
5045
5215
  /**
5046
5216
  * Initializes instances of Sidenav.
@@ -5437,7 +5607,7 @@ class Sidenav extends Component {
5437
5607
  }
5438
5608
  }
5439
5609
 
5440
- const _defaults$a = {
5610
+ const _defaults$h = {
5441
5611
  indicators: true,
5442
5612
  height: 400,
5443
5613
  duration: 500,
@@ -5529,7 +5699,7 @@ class Slider extends Component {
5529
5699
  this.start();
5530
5700
  }
5531
5701
  static get defaults() {
5532
- return _defaults$a;
5702
+ return _defaults$h;
5533
5703
  }
5534
5704
  /**
5535
5705
  * Initializes instances of Slider.
@@ -5776,7 +5946,7 @@ class Slider extends Component {
5776
5946
  };
5777
5947
  }
5778
5948
 
5779
- const _defaults$9 = {
5949
+ const _defaults$g = {
5780
5950
  duration: 300,
5781
5951
  onShow: null,
5782
5952
  swipeable: false,
@@ -5813,7 +5983,7 @@ class Tabs extends Component {
5813
5983
  this._setupEventHandlers();
5814
5984
  }
5815
5985
  static get defaults() {
5816
- return _defaults$9;
5986
+ return _defaults$g;
5817
5987
  }
5818
5988
  /**
5819
5989
  * Initializes instances of Tabs.
@@ -6064,7 +6234,7 @@ class Tabs extends Component {
6064
6234
  }
6065
6235
  }
6066
6236
 
6067
- const _defaults$8 = {
6237
+ const _defaults$f = {
6068
6238
  dialRadius: 135,
6069
6239
  outerRadius: 105,
6070
6240
  innerRadius: 70,
@@ -6151,7 +6321,7 @@ class Timepicker extends Component {
6151
6321
  this._pickerSetup();
6152
6322
  }
6153
6323
  static get defaults() {
6154
- return _defaults$8;
6324
+ return _defaults$f;
6155
6325
  }
6156
6326
  /**
6157
6327
  * Initializes instances of Timepicker.
@@ -6757,7 +6927,7 @@ class Timepicker extends Component {
6757
6927
  }
6758
6928
  }
6759
6929
 
6760
- const _defaults$7 = {
6930
+ const _defaults$e = {
6761
6931
  text: '',
6762
6932
  displayLength: 4000,
6763
6933
  inDuration: 300,
@@ -6810,7 +6980,7 @@ class Toast {
6810
6980
  this._setTimer();
6811
6981
  }
6812
6982
  static get defaults() {
6813
- return _defaults$7;
6983
+ return _defaults$e;
6814
6984
  }
6815
6985
  static getInstance(el) {
6816
6986
  return el['M_Toast'];
@@ -7002,7 +7172,7 @@ class Toast {
7002
7172
  }
7003
7173
  }
7004
7174
 
7005
- const _defaults$6 = {
7175
+ const _defaults$d = {
7006
7176
  exitDelay: 200,
7007
7177
  enterDelay: 0,
7008
7178
  text: '',
@@ -7046,7 +7216,7 @@ class Tooltip extends Component {
7046
7216
  this._setupEventHandlers();
7047
7217
  }
7048
7218
  static get defaults() {
7049
- return _defaults$6;
7219
+ return _defaults$d;
7050
7220
  }
7051
7221
  /**
7052
7222
  * Initializes instances of Tooltip.
@@ -7271,7 +7441,7 @@ class Tooltip extends Component {
7271
7441
  }
7272
7442
  }
7273
7443
 
7274
- const _defaults$5 = {};
7444
+ const _defaults$c = {};
7275
7445
  // TODO: !!!!!
7276
7446
  class Range extends Component {
7277
7447
  _mousedown;
@@ -7289,7 +7459,7 @@ class Range extends Component {
7289
7459
  this._setupEventHandlers();
7290
7460
  }
7291
7461
  static get defaults() {
7292
- return _defaults$5;
7462
+ return _defaults$c;
7293
7463
  }
7294
7464
  /**
7295
7465
  * Initializes instances of Range.
@@ -7440,6 +7610,896 @@ class Range extends Component {
7440
7610
  }
7441
7611
  }
7442
7612
 
7613
+ const _defaults$b = {};
7614
+ // @implement /Users/kzarshenas/Sites/RodeoFx/rodeo_toolkit_2/app/Environment/Partials/PlanningToolbar.ts
7615
+ // Generic version of that file's track-indicator sliding and expandable
7616
+ // search behavior, decoupled from the page-specific filter/state-binding
7617
+ // system (UtilityFilter) the source used - here it's just plain DOM state.
7618
+ class Toolbar extends Component {
7619
+ _tracks;
7620
+ constructor(el, options) {
7621
+ super(el, options, Toolbar);
7622
+ this.el.M_Toolbar = this;
7623
+ this.options = {
7624
+ ...Toolbar.defaults,
7625
+ ...options
7626
+ };
7627
+ this._tracks = Array.from(this.el.querySelectorAll('.toolbar-track'));
7628
+ this._setupEventHandlers();
7629
+ this._tracks.forEach((track) => this._moveIndicator(track, false));
7630
+ // A custom/web font can still be loading at construction time; its
7631
+ // metrics landing after this first measurement would leave the
7632
+ // indicator very slightly offset from the (now differently-sized)
7633
+ // text it's supposed to sit behind. Re-measure once fonts are ready.
7634
+ if (typeof document !== 'undefined' && document.fonts) {
7635
+ document.fonts.ready.then(() => {
7636
+ this._tracks.forEach((track) => this._moveIndicator(track, false));
7637
+ });
7638
+ }
7639
+ }
7640
+ static get defaults() {
7641
+ return _defaults$b;
7642
+ }
7643
+ static init(els, options = {}) {
7644
+ return super.init(els, options, Toolbar);
7645
+ }
7646
+ static getInstance(el) {
7647
+ return el.M_Toolbar;
7648
+ }
7649
+ destroy() {
7650
+ this._removeEventHandlers();
7651
+ this.el.M_Toolbar = undefined;
7652
+ }
7653
+ /**
7654
+ * Re-measure and reposition every track's sliding indicator - call this
7655
+ * after changing which .toolbar-track-item is active from your own code,
7656
+ * or after anything that could have changed the toolbar's layout/width.
7657
+ */
7658
+ updateIndicators() {
7659
+ this._tracks.forEach((track) => this._moveIndicator(track, true));
7660
+ }
7661
+ _setupEventHandlers() {
7662
+ this.el.addEventListener('click', this._handleTrackClick);
7663
+ this.el.addEventListener('focusin', this._handleSearchFocusIn);
7664
+ this.el.addEventListener('focusout', this._handleSearchFocusOut);
7665
+ this.el.addEventListener('input', this._handleSearchInput);
7666
+ this.el.addEventListener('keydown', this._handleSearchKeydown);
7667
+ window.addEventListener('resize', this._handleWindowResize);
7668
+ }
7669
+ _removeEventHandlers() {
7670
+ this.el.removeEventListener('click', this._handleTrackClick);
7671
+ this.el.removeEventListener('focusin', this._handleSearchFocusIn);
7672
+ this.el.removeEventListener('focusout', this._handleSearchFocusOut);
7673
+ this.el.removeEventListener('input', this._handleSearchInput);
7674
+ this.el.removeEventListener('keydown', this._handleSearchKeydown);
7675
+ window.removeEventListener('resize', this._handleWindowResize);
7676
+ }
7677
+ _handleTrackClick = (e) => {
7678
+ const item = e.target.closest('.toolbar-track-item');
7679
+ if (!item)
7680
+ return;
7681
+ const track = item.closest('.toolbar-track');
7682
+ if (!track || !this._tracks.includes(track))
7683
+ return;
7684
+ track.querySelectorAll('.toolbar-track-item.is-active').forEach((el) => el.classList.remove('is-active'));
7685
+ item.classList.add('is-active');
7686
+ this._moveIndicator(track, true);
7687
+ };
7688
+ _handleSearchFocusIn = (e) => {
7689
+ const search = e.target.closest('.toolbar-search');
7690
+ if (search)
7691
+ search.classList.add('is-expanded');
7692
+ };
7693
+ _handleSearchFocusOut = (e) => {
7694
+ const search = e.target.closest('.toolbar-search');
7695
+ if (!search)
7696
+ return;
7697
+ const input = search.querySelector('.toolbar-search-input');
7698
+ if (input && input.value === '')
7699
+ search.classList.remove('is-expanded');
7700
+ };
7701
+ _handleSearchInput = (e) => {
7702
+ const input = e.target;
7703
+ if (!input.classList.contains('toolbar-search-input'))
7704
+ return;
7705
+ const search = input.closest('.toolbar-search');
7706
+ if (search)
7707
+ search.classList.toggle('is-expanded', input.value !== '' || document.activeElement === input);
7708
+ };
7709
+ _handleSearchKeydown = (e) => {
7710
+ if (e.key !== 'Escape')
7711
+ return;
7712
+ const input = e.target.closest('.toolbar-search')?.querySelector('.toolbar-search-input');
7713
+ if (!input)
7714
+ return;
7715
+ input.value = '';
7716
+ input.blur();
7717
+ };
7718
+ _handleWindowResize = () => {
7719
+ this._tracks.forEach((track) => this._moveIndicator(track, false));
7720
+ };
7721
+ _moveIndicator(track, animate) {
7722
+ const indicator = track.querySelector('.toolbar-track-indicator');
7723
+ const active = track.querySelector('.toolbar-track-item.is-active');
7724
+ if (!indicator || !active)
7725
+ return;
7726
+ if (!animate)
7727
+ indicator.style.transition = 'none';
7728
+ // No "- track.clientLeft" here: offsetLeft is already relative to the
7729
+ // offsetParent's padding edge, same origin as the indicator's own
7730
+ // `left: 0` (an absolutely positioned element's containing block is
7731
+ // its ancestor's padding box) - subtracting the border width again
7732
+ // was double-counting it, nudging the indicator a px too far left.
7733
+ indicator.style.transform = `translateX(${active.offsetLeft}px)`;
7734
+ indicator.style.width = `${active.offsetWidth}px`;
7735
+ track.classList.add('is-armed');
7736
+ if (!animate) {
7737
+ // Force layout so the transition-less move above actually applies
7738
+ // before re-enabling transitions on the next frame.
7739
+ void indicator.offsetWidth;
7740
+ requestAnimationFrame(() => {
7741
+ indicator.style.transition = '';
7742
+ });
7743
+ }
7744
+ }
7745
+ }
7746
+
7747
+ const _defaults$a = {};
7748
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Password.ts
7749
+ // Show/hide toggle for a password input - no third-party dependency, just
7750
+ // Materialize's own .prefix/.suffix icon-slot convention (see
7751
+ // components/textfield/_input-fields.scss), so unlike the other new form
7752
+ // enhancements in this batch this one needs no peer-loader/dynamic import.
7753
+ class PasswordInput extends Component {
7754
+ _suffixEl;
7755
+ constructor(el, options) {
7756
+ super(el, options, PasswordInput);
7757
+ this.el.M_PasswordInput = this;
7758
+ this.options = {
7759
+ ...PasswordInput.defaults,
7760
+ ...options
7761
+ };
7762
+ this._suffixEl = this.el.parentElement?.querySelector('[data-password-toggle-icon]') ?? null;
7763
+ if (!this.el.dataset.passwordVisible)
7764
+ this.el.dataset.passwordVisible = '0';
7765
+ this._setupEventHandlers();
7766
+ }
7767
+ static get defaults() {
7768
+ return _defaults$a;
7769
+ }
7770
+ static init(els, options = {}) {
7771
+ return super.init(els, options, PasswordInput);
7772
+ }
7773
+ static getInstance(el) {
7774
+ return el.M_PasswordInput;
7775
+ }
7776
+ destroy() {
7777
+ this._removeEventHandlers();
7778
+ this.el.M_PasswordInput = undefined;
7779
+ }
7780
+ _setupEventHandlers() {
7781
+ this._suffixEl?.addEventListener('click', this._handleToggleClick);
7782
+ }
7783
+ _removeEventHandlers() {
7784
+ this._suffixEl?.removeEventListener('click', this._handleToggleClick);
7785
+ }
7786
+ _handleToggleClick = () => {
7787
+ const visible = this.el.dataset.passwordVisible === '1';
7788
+ this.el.type = visible ? 'password' : 'text';
7789
+ this.el.dataset.passwordVisible = visible ? '0' : '1';
7790
+ const iconEl = this._suffixEl?.querySelector('i');
7791
+ if (iconEl)
7792
+ iconEl.textContent = visible ? 'visibility' : 'visibility_off';
7793
+ };
7794
+ }
7795
+
7796
+ const _cache = new Map();
7797
+ async function loadPeer(spec, importer) {
7798
+ if (_cache.has(spec.specifier))
7799
+ return _cache.get(spec.specifier);
7800
+ try {
7801
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7802
+ const mod = await importer();
7803
+ const resolved = mod?.default ?? mod;
7804
+ _cache.set(spec.specifier, resolved);
7805
+ return resolved;
7806
+ }
7807
+ catch {
7808
+ // fall through to the global-scope lookup below
7809
+ }
7810
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7811
+ const globalScope = typeof window !== 'undefined' ? window : undefined;
7812
+ if (globalScope && globalScope[spec.globalName]) {
7813
+ const resolved = globalScope[spec.globalName];
7814
+ _cache.set(spec.specifier, resolved);
7815
+ return resolved;
7816
+ }
7817
+ throw new Error(`kmaterialize's ${spec.feature} requires "${spec.specifier}", which isn't installed/loaded.\n` +
7818
+ `- If you're using a bundler: npm/pnpm/yarn install "${spec.specifier}".\n` +
7819
+ `- If you're using the plain <script> (no-bundler) build: add\n` +
7820
+ ` ${spec.cdnHint}\n` +
7821
+ ` before initializing this component, so window.${spec.globalName} is defined.`);
7822
+ }
7823
+
7824
+ const _defaults$9 = {
7825
+ thousandsSeparator: ' ',
7826
+ radix: '.',
7827
+ mapToRadix: [',']
7828
+ };
7829
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Number.ts
7830
+ // Masked/formatted numeric input via IMask (thousands separator, decimal
7831
+ // scale, min/max) - deliberately opts in on `type="text" data-type="number"`
7832
+ // rather than `type="number"`, so IMask can format the display value
7833
+ // (thousands separators etc.) that a native number input wouldn't allow.
7834
+ //
7835
+ // IMask is an optional peerDependency, loaded on demand via peer-loader -
7836
+ // see that file for the bundler/no-bundler resolution strategy.
7837
+ class NumberInput extends Component {
7838
+ mask;
7839
+ ready;
7840
+ constructor(el, options) {
7841
+ super(el, options, NumberInput);
7842
+ this.el.M_NumberInput = this;
7843
+ this.options = {
7844
+ ...NumberInput.defaults,
7845
+ ...options
7846
+ };
7847
+ this.ready = this._setup();
7848
+ }
7849
+ static get defaults() {
7850
+ return _defaults$9;
7851
+ }
7852
+ static init(els, options = {}) {
7853
+ return super.init(els, options, NumberInput);
7854
+ }
7855
+ static getInstance(el) {
7856
+ return el.M_NumberInput;
7857
+ }
7858
+ destroy() {
7859
+ this.mask?.destroy();
7860
+ this.el.M_NumberInput = undefined;
7861
+ }
7862
+ async _setup() {
7863
+ const IMask = await loadPeer({
7864
+ specifier: 'imask',
7865
+ globalName: 'IMask',
7866
+ feature: 'Number input (IMask) enhancement',
7867
+ cdnHint: '<script src="path/to/imask.min.js"></script> (self-hosted - copy from node_modules/imask/dist/imask.min.js, or a CDN of your choice)'
7868
+ }, () => import('imask'));
7869
+ const maskOptions = {
7870
+ mask: Number,
7871
+ skipInvalid: true,
7872
+ thousandsSeparator: this.options.thousandsSeparator,
7873
+ radix: this.options.radix,
7874
+ mapToRadix: this.options.mapToRadix,
7875
+ autofix: true
7876
+ };
7877
+ const max = this.options.max ?? (this.el.hasAttribute('max') ? Number(this.el.getAttribute('max')) : undefined);
7878
+ if (max !== undefined && !Number.isNaN(max))
7879
+ maskOptions.max = max;
7880
+ const min = this.options.min ?? (this.el.hasAttribute('min') ? Number(this.el.getAttribute('min')) : undefined);
7881
+ if (min !== undefined && !Number.isNaN(min))
7882
+ maskOptions.min = min;
7883
+ const step = this.el.getAttribute('step');
7884
+ const scale = this.options.scale ?? (step?.includes('.') ? step.split('.').at(-1)?.length : undefined);
7885
+ if (scale !== undefined)
7886
+ maskOptions.scale = scale;
7887
+ this.mask = IMask(this.el, maskOptions);
7888
+ }
7889
+ }
7890
+
7891
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Color.ts
7892
+ // Built-in French translation for Pickr's UI strings, activated by
7893
+ // `data-color-locale="fr-fr"` alone - no separate options object required
7894
+ // from the consumer, unlike a fully custom `options.locale` override.
7895
+ const FR_FR = {
7896
+ 'ui:dialog': 'boîte de dialogue du sélecteur de couleur',
7897
+ 'btn:toggle': 'basculer la boîte de dialogue du sélecteur de couleur',
7898
+ 'btn:swatch': 'échantillon de couleur',
7899
+ 'btn:last-color': 'utiliser la couleur précédente',
7900
+ 'btn:save': 'Enregistrer',
7901
+ 'btn:cancel': 'Annuler',
7902
+ 'btn:clear': 'Effacer',
7903
+ 'aria:btn:save': 'enregistrer et fermer',
7904
+ 'aria:btn:cancel': 'annuler et fermer',
7905
+ 'aria:btn:clear': 'effacer et fermer',
7906
+ 'aria:input': 'champ de saisie de couleur',
7907
+ 'aria:palette': 'zone de sélection des couleurs',
7908
+ 'aria:hue': 'curseur de sélection de teinte',
7909
+ 'aria:opacity': "curseur de sélection d'opacité"
7910
+ };
7911
+ const _defaults$8 = {
7912
+ theme: 'classic',
7913
+ opacity: true,
7914
+ swatches: [
7915
+ 'rgba(244, 67, 54, 1)',
7916
+ 'rgba(233, 30, 99, 0.95)',
7917
+ 'rgba(156, 39, 176, 0.9)',
7918
+ 'rgba(103, 58, 183, 0.85)',
7919
+ 'rgba(63, 81, 181, 0.8)',
7920
+ 'rgba(33, 150, 243, 0.75)',
7921
+ 'rgba(3, 169, 244, 0.7)',
7922
+ 'rgba(0, 188, 212, 0.7)',
7923
+ 'rgba(0, 150, 136, 0.75)',
7924
+ 'rgba(76, 175, 80, 0.8)',
7925
+ 'rgba(139, 195, 74, 0.85)',
7926
+ 'rgba(205, 220, 57, 0.9)',
7927
+ 'rgba(255, 235, 59, 0.95)',
7928
+ 'rgba(255, 193, 7, 1)'
7929
+ ]
7930
+ };
7931
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Color.ts
7932
+ // Enhances a native `<input type="color" data-color-picker="pickr">` with a
7933
+ // full Pickr popup (palette, hue/opacity sliders, swatches, hex/rgba/hsla).
7934
+ // If `data-color-picker` is absent the input is left completely untouched -
7935
+ // still a plain native color swatch, matching CrazyPHP's own fallback.
7936
+ //
7937
+ // Pickr remains an optional peerDependency and is loaded on demand via peer-loader.
7938
+ class ColorInput extends Component {
7939
+ pickr;
7940
+ ready;
7941
+ _swatchEl;
7942
+ _labels;
7943
+ constructor(el, options) {
7944
+ super(el, options, ColorInput);
7945
+ this.el.M_ColorInput = this;
7946
+ this.options = {
7947
+ ...ColorInput.defaults,
7948
+ ...options
7949
+ };
7950
+ this._swatchEl = document.createElement('div');
7951
+ this.el.after(this._swatchEl);
7952
+ this.el.classList.add('hide');
7953
+ this.el.addEventListener('change', this._handleInputChange);
7954
+ this._labels = Array.from(document.querySelectorAll('label')).filter(label => label.htmlFor === this.el.id);
7955
+ this._labels.forEach(label => label.addEventListener('click', this._handleLabelClick));
7956
+ this.ready = this._setup();
7957
+ }
7958
+ static get defaults() {
7959
+ return _defaults$8;
7960
+ }
7961
+ static init(els, options = {}) {
7962
+ return super.init(els, options, ColorInput);
7963
+ }
7964
+ static getInstance(el) {
7965
+ return el.M_ColorInput;
7966
+ }
7967
+ destroy() {
7968
+ this.el.removeEventListener('change', this._handleInputChange);
7969
+ this._labels.forEach(label => label.removeEventListener('click', this._handleLabelClick));
7970
+ this.pickr?.destroyAndRemove();
7971
+ this._swatchEl.remove();
7972
+ this.el.classList.remove('hide');
7973
+ this.el.M_ColorInput = undefined;
7974
+ }
7975
+ _handleInputChange = () => {
7976
+ this.pickr?.setColor(this.el.value);
7977
+ };
7978
+ _handleLabelClick = (event) => {
7979
+ // A label associated with a hidden input[type=color] otherwise opens
7980
+ // the browser's native picker (notably in Firefox). Route the same
7981
+ // accessible label activation to Pickr instead.
7982
+ event.preventDefault();
7983
+ void this.ready.then(() => this.pickr?.show());
7984
+ };
7985
+ async _setup() {
7986
+ const Pickr = await loadPeer({
7987
+ specifier: '@simonwep/pickr',
7988
+ globalName: 'Pickr',
7989
+ feature: 'Color input (Pickr) enhancement',
7990
+ cdnHint: '<link rel="stylesheet" href="path/to/pickr-classic.min.css">\n' +
7991
+ ' <script src="path/to/pickr.min.js"></script>\n' +
7992
+ ' (self-hosted - copy from node_modules/@simonwep/pickr/dist/, or a CDN of your choice)'
7993
+ }, () => import('@simonwep/pickr'));
7994
+ const dataset = this.el.dataset;
7995
+ const theme = (['classic', 'monolith', 'nano'].includes(dataset.colorTheme ?? '')
7996
+ ? dataset.colorTheme
7997
+ : this.options.theme);
7998
+ const lockOpacity = dataset.colorOpacity !== undefined
7999
+ ? ['false', '0', '', 'null'].includes(dataset.colorOpacity)
8000
+ : !this.options.opacity;
8001
+ const pickrOptions = {
8002
+ el: this._swatchEl,
8003
+ theme,
8004
+ lockOpacity,
8005
+ swatches: this.options.swatches,
8006
+ components: {
8007
+ preview: true,
8008
+ opacity: true,
8009
+ hue: true,
8010
+ interaction: {
8011
+ hex: true,
8012
+ rgba: true,
8013
+ hsla: true,
8014
+ hsva: true,
8015
+ cmyk: true,
8016
+ input: true,
8017
+ clear: true,
8018
+ save: true
8019
+ }
8020
+ }
8021
+ };
8022
+ if (this.options.locale) {
8023
+ pickrOptions.i18n = this.options.locale;
8024
+ }
8025
+ else if (dataset.colorLocale === 'fr-fr') {
8026
+ pickrOptions.i18n = FR_FR;
8027
+ }
8028
+ const currentValue = this.el.getAttribute('value');
8029
+ if (currentValue && currentValue !== 'randomHex()') {
8030
+ pickrOptions.default = currentValue;
8031
+ }
8032
+ else if (this.el.hasAttribute('default')) {
8033
+ const currentDefault = this.el.getAttribute('default');
8034
+ if (currentDefault === 'randomHex()') {
8035
+ const randomColor = Math.floor(Math.random() * 16777216);
8036
+ pickrOptions.default = `#${randomColor.toString(16).padStart(6, '0')}`;
8037
+ }
8038
+ else if (currentDefault) {
8039
+ pickrOptions.default = currentDefault;
8040
+ }
8041
+ }
8042
+ this.pickr = Pickr.create(pickrOptions);
8043
+ if (this.el.disabled)
8044
+ this.pickr.disable();
8045
+ this.pickr.on('save', (color, instance) => {
8046
+ const hexa = color?.toHEXA().toString();
8047
+ if (hexa) {
8048
+ this.el.value = hexa;
8049
+ this.el.dispatchEvent(new Event('change', { bubbles: true }));
8050
+ }
8051
+ instance.hide();
8052
+ });
8053
+ }
8054
+ }
8055
+
8056
+ const _defaults$7 = {};
8057
+ let activeAirDatepickerField;
8058
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Date.ts
8059
+ // Enhances `<input type="text" data-type="date" data-date-picker="air-datepicker">`
8060
+ // with the air-datepicker calendar/range picker - deliberately separate from
8061
+ // kmaterialize's own native `components/datepicker/` (a different, already
8062
+ // existing class-based component); this one is opted into per-input via the
8063
+ // `data-date-picker` attribute so it never collides with `.datepicker`
8064
+ // elements. The `multiple` attribute switches the picker into range mode,
8065
+ // `data-date-format`/`data-date-lang` (only "fr-FR" ported so far) mirror
8066
+ // CrazyPHP's own dataset convention.
8067
+ //
8068
+ // air-datepicker is an optional peerDependency, loaded on demand via
8069
+ // peer-loader. Its own base stylesheet (air-datepicker/air-datepicker.css)
8070
+ // must be imported separately by the consumer - see the docs page.
8071
+ class AirDatepickerField extends Component {
8072
+ picker;
8073
+ ready;
8074
+ _triggers;
8075
+ _handleOutsideClick = (e) => {
8076
+ const calendarEl = document.querySelector('.air-datepicker');
8077
+ const clickedTrigger = this._triggers.some(trigger => trigger.contains(e.target));
8078
+ if (calendarEl instanceof HTMLElement &&
8079
+ !calendarEl.contains(e.target) &&
8080
+ !this.el.contains(e.target) &&
8081
+ !clickedTrigger) {
8082
+ this.picker?.hide();
8083
+ }
8084
+ };
8085
+ constructor(el, options) {
8086
+ super(el, options, AirDatepickerField);
8087
+ this.el.M_AirDatepickerField = this;
8088
+ this.options = {
8089
+ ...AirDatepickerField.defaults,
8090
+ ...options
8091
+ };
8092
+ const labels = Array.from(document.querySelectorAll('label')).filter(label => label.htmlFor === this.el.id);
8093
+ const icons = Array.from(this.el.parentElement?.querySelectorAll('.prefix, .suffix') ?? []);
8094
+ this._triggers = [...labels, ...icons];
8095
+ this._triggers.forEach(trigger => trigger.addEventListener('click', this._handleTriggerClick));
8096
+ this.ready = this._setup();
8097
+ }
8098
+ static get defaults() {
8099
+ return _defaults$7;
8100
+ }
8101
+ static init(els, options = {}) {
8102
+ return super.init(els, options, AirDatepickerField);
8103
+ }
8104
+ static getInstance(el) {
8105
+ return el.M_AirDatepickerField;
8106
+ }
8107
+ destroy() {
8108
+ document.removeEventListener('click', this._handleOutsideClick);
8109
+ this._triggers.forEach(trigger => trigger.removeEventListener('click', this._handleTriggerClick));
8110
+ this.picker?.destroy();
8111
+ if (activeAirDatepickerField === this)
8112
+ activeAirDatepickerField = undefined;
8113
+ this.el.M_AirDatepickerField = undefined;
8114
+ }
8115
+ _handleTriggerClick = (event) => {
8116
+ event.preventDefault();
8117
+ event.stopPropagation();
8118
+ void this.ready.then(() => this.picker?.show());
8119
+ };
8120
+ async _setup() {
8121
+ const AirDatepicker = await loadPeer({
8122
+ specifier: 'air-datepicker',
8123
+ globalName: 'AirDatepicker',
8124
+ feature: 'Date input (air-datepicker) enhancement',
8125
+ cdnHint: '<link rel="stylesheet" href="path/to/air-datepicker.css">\n' +
8126
+ ' <script src="path/to/air-datepicker.js"></script>\n' +
8127
+ ' (self-hosted - copy from node_modules/air-datepicker/, or a CDN of your choice)'
8128
+ }, () => import('air-datepicker'));
8129
+ const dataset = this.el.dataset;
8130
+ const builtInLocale = dataset.dateLang === 'fr-FR'
8131
+ ? (await import('air-datepicker/locale/fr')).default
8132
+ : (await import('air-datepicker/locale/en')).default;
8133
+ const pickerOptions = {
8134
+ dateFormat: dataset.dateFormat || 'yyyy-MM-dd',
8135
+ autoClose: dataset.dateAutoClose !== 'false',
8136
+ locale: (this.options.locale ?? builtInLocale),
8137
+ onShow: isAnimationComplete => {
8138
+ if (isAnimationComplete)
8139
+ return;
8140
+ if (activeAirDatepickerField && activeAirDatepickerField !== this) {
8141
+ activeAirDatepickerField.picker?.hide();
8142
+ }
8143
+ activeAirDatepickerField = this;
8144
+ },
8145
+ onHide: isAnimationComplete => {
8146
+ if (isAnimationComplete && activeAirDatepickerField === this) {
8147
+ activeAirDatepickerField = undefined;
8148
+ }
8149
+ }
8150
+ };
8151
+ let multiple = false;
8152
+ if (this.el.multiple || dataset.dateRange === 'true') {
8153
+ pickerOptions.range = true;
8154
+ pickerOptions.multipleDatesSeparator = ' - ';
8155
+ multiple = true;
8156
+ }
8157
+ const initialValue = this.el.getAttribute('value')?.trim();
8158
+ if (initialValue) {
8159
+ pickerOptions.selectedDates = multiple
8160
+ ? initialValue.split(' - ').map(value => value.trim())
8161
+ : [initialValue];
8162
+ }
8163
+ if (dataset.dateTimepicker === 'true') {
8164
+ pickerOptions.timepicker = true;
8165
+ if (dataset.dateTimeFormat)
8166
+ pickerOptions.timeFormat = dataset.dateTimeFormat;
8167
+ }
8168
+ const supportedViews = ['days', 'months', 'years'];
8169
+ if (supportedViews.includes(dataset.dateView ?? '')) {
8170
+ pickerOptions.view = dataset.dateView;
8171
+ }
8172
+ if (supportedViews.includes(dataset.dateMinView ?? '')) {
8173
+ pickerOptions.minView = dataset.dateMinView;
8174
+ }
8175
+ if (dataset.dateMobile === 'true')
8176
+ pickerOptions.isMobile = true;
8177
+ if (dataset.datePosition) {
8178
+ pickerOptions.position = dataset.datePosition;
8179
+ }
8180
+ if (dataset.dateButtons) {
8181
+ const supportedButtons = ['today', 'clear'];
8182
+ pickerOptions.buttons = dataset.dateButtons
8183
+ .split(',')
8184
+ .map(button => button.trim())
8185
+ .filter(button => supportedButtons.includes(button));
8186
+ }
8187
+ if (this.el.hasAttribute('min') && this.el.getAttribute('min')) {
8188
+ pickerOptions.minDate = new Date(this.el.getAttribute('min'));
8189
+ }
8190
+ if (this.el.hasAttribute('max') && this.el.getAttribute('max')) {
8191
+ pickerOptions.maxDate = new Date(this.el.getAttribute('max'));
8192
+ }
8193
+ if (!this.el.required && !pickerOptions.buttons) {
8194
+ pickerOptions.buttons = ['clear'];
8195
+ }
8196
+ pickerOptions.onSelect = ({ date }) => {
8197
+ if (multiple && Array.isArray(date) && date.length === 1)
8198
+ return;
8199
+ this.el.dispatchEvent(new Event('input', { bubbles: true }));
8200
+ this.el.dispatchEvent(new Event('change', { bubbles: true }));
8201
+ };
8202
+ this.picker = new AirDatepicker(this.el, pickerOptions);
8203
+ document.addEventListener('click', this._handleOutsideClick);
8204
+ }
8205
+ }
8206
+
8207
+ const _defaults$6 = {
8208
+ plugins: []
8209
+ };
8210
+ // Each plugin needs its own literal `import('literal-string')` call (see
8211
+ // peer-loader.ts) so Vite/webpack/Rollup can statically discover it - a
8212
+ // generic specifier-driven loop can't produce that, hence one entry per
8213
+ // plugin instead of building the import call from PLUGIN_SPECS's string.
8214
+ const PLUGIN_LOADERS = {
8215
+ 'image-preview': {
8216
+ specifier: 'filepond-plugin-image-preview',
8217
+ globalName: 'FilePondPluginImagePreview',
8218
+ importer: () => import('filepond-plugin-image-preview')
8219
+ },
8220
+ 'file-validate-type': {
8221
+ specifier: 'filepond-plugin-file-validate-type',
8222
+ globalName: 'FilePondPluginFileValidateType',
8223
+ importer: () => import('filepond-plugin-file-validate-type')
8224
+ },
8225
+ 'image-exif-orientation': {
8226
+ specifier: 'filepond-plugin-image-exif-orientation',
8227
+ globalName: 'FilePondPluginImageExifOrientation',
8228
+ importer: () => import('filepond-plugin-image-exif-orientation')
8229
+ }
8230
+ };
8231
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/File.ts
8232
+ // Enhances the EXISTING `.file-field` structure in place - add
8233
+ // `data-file-picker="filepond"` (+ optional `data-file-plugins="a,b,c"`) to
8234
+ // an otherwise completely stock `.file-field`, nothing else about the
8235
+ // markup changes. FilePond.create() hides the native `<input type=file>`
8236
+ // and injects its own root as a *sibling*, it never removes anything from
8237
+ // the DOM, so the surrounding button/label/file-path-wrapper stay intact
8238
+ // at rest - only the interactive drop area swaps in visually.
8239
+ //
8240
+ // FilePond and its plugins are optional peerDependencies, loaded on demand
8241
+ // via peer-loader.
8242
+ class FileInput extends Component {
8243
+ pond;
8244
+ ready;
8245
+ _fileEl;
8246
+ _pathEl;
8247
+ constructor(el, options) {
8248
+ super(el, options, FileInput);
8249
+ this.el.M_FileInput = this;
8250
+ const pluginsAttr = this.el.dataset.filePlugins;
8251
+ this.options = {
8252
+ ...FileInput.defaults,
8253
+ plugins: pluginsAttr
8254
+ ? pluginsAttr.split(',').map((p) => p.trim())
8255
+ : FileInput.defaults.plugins,
8256
+ ...options
8257
+ };
8258
+ this._fileEl = this.el.querySelector('input[type="file"]');
8259
+ this._pathEl = this.el.querySelector('.file-path');
8260
+ this.ready = this._setup();
8261
+ }
8262
+ static get defaults() {
8263
+ return _defaults$6;
8264
+ }
8265
+ static init(els, options = {}) {
8266
+ return super.init(els, options, FileInput);
8267
+ }
8268
+ static getInstance(el) {
8269
+ return el.M_FileInput;
8270
+ }
8271
+ destroy() {
8272
+ this.el.classList.remove('file-field-enhanced');
8273
+ this.el.querySelector('.btn')?.classList.remove('hide');
8274
+ this.el.querySelector('.file-path-wrapper')?.classList.remove('hide');
8275
+ this.pond?.destroy();
8276
+ this.el.M_FileInput = undefined;
8277
+ }
8278
+ /** Convenience wrapper over the underlying FilePond instance's own getFiles(). */
8279
+ getFiles() {
8280
+ return this.pond?.getFiles() ?? [];
8281
+ }
8282
+ async _setup() {
8283
+ if (!this._fileEl) {
8284
+ console.error(Error('.file-field enhanced with data-file-picker="filepond" needs an input[type=file]'));
8285
+ return;
8286
+ }
8287
+ const FilePond = await loadPeer({
8288
+ specifier: 'filepond',
8289
+ globalName: 'FilePond',
8290
+ feature: 'File input (FilePond) enhancement',
8291
+ cdnHint: '<link rel="stylesheet" href="path/to/filepond.min.css">\n' +
8292
+ ' <script src="path/to/filepond.min.js"></script>\n' +
8293
+ ' (self-hosted - copy from node_modules/filepond/dist/, or a CDN of your choice)'
8294
+ }, () => import('filepond'));
8295
+ const pluginNames = new Set(this.options.plugins);
8296
+ // file-validate-type is auto-registered whenever the input restricts
8297
+ // `accept`, matching CrazyPHP's own convention, even if the consumer
8298
+ // didn't list it explicitly in data-file-plugins.
8299
+ if (this._fileEl.accept)
8300
+ pluginNames.add('file-validate-type');
8301
+ for (const name of pluginNames) {
8302
+ const loader = PLUGIN_LOADERS[name];
8303
+ if (!loader)
8304
+ continue;
8305
+ const plugin = await loadPeer({
8306
+ specifier: loader.specifier,
8307
+ globalName: loader.globalName,
8308
+ feature: `File input FilePond plugin "${name}"`,
8309
+ cdnHint: `<script src="path/to/${loader.specifier}.min.js"></script> (self-hosted - copy from node_modules/${loader.specifier}/dist/, or a CDN of your choice)`
8310
+ }, loader.importer);
8311
+ FilePond.registerPlugin(plugin);
8312
+ }
8313
+ const pondOptions = {};
8314
+ const { dataset } = this._fileEl;
8315
+ const readBoolean = (value) => value !== 'false';
8316
+ pondOptions.allowMultiple = this._fileEl.multiple;
8317
+ pondOptions.disabled = this._fileEl.disabled;
8318
+ if (dataset.defaultFile)
8319
+ pondOptions.files = [dataset.defaultFile];
8320
+ if (dataset.maxFiles)
8321
+ pondOptions.maxFiles = Number(dataset.maxFiles);
8322
+ if (this._fileEl.multiple)
8323
+ pondOptions.allowReorder = readBoolean(dataset.allowReorder);
8324
+ if (dataset.labelIdle)
8325
+ pondOptions.labelIdle = dataset.labelIdle;
8326
+ if (dataset.instantUpload !== undefined)
8327
+ pondOptions.instantUpload = readBoolean(dataset.instantUpload);
8328
+ if (dataset.dropValidation !== undefined)
8329
+ pondOptions.dropValidation = readBoolean(dataset.dropValidation);
8330
+ if (dataset.imagePreviewHeight)
8331
+ pondOptions.imagePreviewHeight = Number(dataset.imagePreviewHeight);
8332
+ if (dataset.stylePanelLayout) {
8333
+ pondOptions.stylePanelLayout = dataset.stylePanelLayout;
8334
+ }
8335
+ if (dataset.stylePanelAspectRatio)
8336
+ pondOptions.stylePanelAspectRatio = dataset.stylePanelAspectRatio;
8337
+ this.pond = FilePond.create(this._fileEl, pondOptions);
8338
+ // FilePond inserts its own root as a *sibling* of the input it was
8339
+ // given - but that input lives inside .btn (stock .file-field markup
8340
+ // is `.btn > input[type=file]`), so the fresh FilePond root lands
8341
+ // inside .btn too. Move it back out to be a direct child of .file-field
8342
+ // itself before hiding .btn, or hiding .btn would take the whole
8343
+ // FilePond widget down with it.
8344
+ const pondRoot = this.pond.element;
8345
+ if (pondRoot) {
8346
+ this.el.appendChild(pondRoot);
8347
+ const fileHeight = Number(dataset.fileHeight);
8348
+ if (Number.isFinite(fileHeight) && fileHeight > 0) {
8349
+ pondRoot.style.height = `${fileHeight}px`;
8350
+ }
8351
+ // Matches CrazyPHP's own File.ts behavior - FilePond's free-tier
8352
+ // "Powered by FilePond" credit link doesn't fit a themed, branded UI.
8353
+ pondRoot.querySelectorAll('.filepond--credits').forEach((el) => el.remove());
8354
+ }
8355
+ // Everything from the stock .file-field is now redundant - FilePond's
8356
+ // own drop zone is the entire upload affordance. Hidden, not removed,
8357
+ // so the .file-field structure this component promises to preserve is
8358
+ // still there, just not shown alongside FilePond's widget.
8359
+ this.el.classList.add('file-field-enhanced');
8360
+ this.el.querySelector('.btn')?.classList.add('hide');
8361
+ this.el.querySelector('.file-path-wrapper')?.classList.add('hide');
8362
+ this._syncPathInput();
8363
+ this.pond.on('updatefiles', this._syncPathInput);
8364
+ }
8365
+ _syncPathInput = () => {
8366
+ if (!this._pathEl || !this.pond)
8367
+ return;
8368
+ this._pathEl.value = this.pond
8369
+ .getFiles()
8370
+ .map((f) => f.filename)
8371
+ .join(', ');
8372
+ };
8373
+ }
8374
+
8375
+ const _defaults$5 = {};
8376
+ function readRemoteSpec(el) {
8377
+ const raw = el.dataset.selectRemote;
8378
+ if (!raw)
8379
+ return undefined;
8380
+ try {
8381
+ return JSON.parse(raw);
8382
+ }
8383
+ catch {
8384
+ return undefined;
8385
+ }
8386
+ }
8387
+ // @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Select.ts
8388
+ // Enhances an EXISTING native `<select class="tomselected">` with Tom
8389
+ // Select - searchable, taggable, remote-loading, dependent-field wiring,
8390
+ // clear button, drag-drop reorder. Ported in a somewhat scoped form: the
8391
+ // CrazyPHP source's remote-loading path goes through its own app-specific
8392
+ // Crazyrequest/Crazyurl HTTP-client and query-param helpers, which have no
8393
+ // equivalent in a standalone UI library - this version uses a plain
8394
+ // `fetch()` instead, keeping the same `data-select-remote` JSON shape
8395
+ // (url/value/label/search/dataKey) and the same `{{field}}` render-template
8396
+ // convention.
8397
+ //
8398
+ // Coexistence with FormSelect: `.tomselected` is a recognized exclusion
8399
+ // marker in FormSelect's own AutoInit selector (see src/index.ts), so a
8400
+ // `.tomselected` select is never picked up by FormSelect regardless of
8401
+ // init ordering. This constructor still defensively tears down any
8402
+ // FormSelect instance found on the same element, belt-and-suspenders, in
8403
+ // case that selector rule is ever violated by hand.
8404
+ //
8405
+ // Tom Select is an optional peerDependency, loaded on demand via
8406
+ // peer-loader.
8407
+ class TomSelectField extends Component {
8408
+ tomSelect;
8409
+ ready;
8410
+ _dependsOnEl = null;
8411
+ constructor(el, options) {
8412
+ super(el, options, TomSelectField);
8413
+ this.el.M_TomSelectField = this;
8414
+ FormSelect.getInstance(this.el)?.destroy();
8415
+ this.options = {
8416
+ remote: readRemoteSpec(this.el),
8417
+ ...TomSelectField.defaults,
8418
+ ...options
8419
+ };
8420
+ this.ready = this._setup();
8421
+ }
8422
+ static get defaults() {
8423
+ return _defaults$5;
8424
+ }
8425
+ static init(els, options = {}) {
8426
+ return super.init(els, options, TomSelectField);
8427
+ }
8428
+ static getInstance(el) {
8429
+ return el.M_TomSelectField;
8430
+ }
8431
+ destroy() {
8432
+ if (this._dependsOnEl)
8433
+ this._dependsOnEl.removeEventListener('change', this._handleDependencyChange);
8434
+ this.tomSelect?.destroy();
8435
+ this.el.M_TomSelectField = undefined;
8436
+ }
8437
+ _handleDependencyChange = () => {
8438
+ this.tomSelect?.clear();
8439
+ this.tomSelect?.clearOptions();
8440
+ this.tomSelect?.load?.('');
8441
+ };
8442
+ async _setup() {
8443
+ const TomSelect = await loadPeer({
8444
+ specifier: 'tom-select',
8445
+ globalName: 'TomSelect',
8446
+ feature: 'Select (Tom Select) enhancement',
8447
+ cdnHint: '<script src="path/to/tom-select.complete.min.js"></script> (self-hosted - copy from node_modules/tom-select/dist/js/, or a CDN of your choice)'
8448
+ }, () => import('tom-select'));
8449
+ const dataset = this.el.dataset;
8450
+ const settings = {
8451
+ persist: false,
8452
+ createOnBlur: true,
8453
+ create: 'selectTag' in dataset,
8454
+ plugins: {},
8455
+ ...this.options.settings
8456
+ };
8457
+ if ('selectClear' in dataset) {
8458
+ settings.plugins.clear_button = { title: dataset.selectClear || 'Clear' };
8459
+ }
8460
+ if ('selectTag' in dataset || this.el.multiple) {
8461
+ settings.plugins.caret_position = {};
8462
+ settings.plugins.drag_drop = {};
8463
+ }
8464
+ if (this.el.classList.contains('icons')) {
8465
+ const renderWithIcon = (data, escape) => {
8466
+ const icon = data.icon ? `<img src="${escape(String(data.icon))}" alt="" />` : '';
8467
+ return `<div class="ts-option-content">${icon}<span>${escape(String(data.text ?? ''))}</span></div>`;
8468
+ };
8469
+ settings.render = { ...settings.render, option: renderWithIcon, item: renderWithIcon };
8470
+ }
8471
+ const remote = this.options.remote;
8472
+ if (remote) {
8473
+ settings.valueField = remote.value;
8474
+ if (remote.search)
8475
+ settings.searchField = [remote.search];
8476
+ if (remote.label && remote.label.includes('{{') && remote.label.includes('}}')) {
8477
+ const renderTemplate = (data, escape) => `<div>${remote.label.replace(/\{\{(.*?)\}\}/g, (_m, key) => escape(String(data[key] ?? '')))}</div>`;
8478
+ settings.render = { option: renderTemplate, item: renderTemplate };
8479
+ }
8480
+ else {
8481
+ settings.labelField = remote.label;
8482
+ }
8483
+ settings.load = (query, callback) => {
8484
+ fetch(remote.url)
8485
+ .then((r) => r.json())
8486
+ .then((value) => {
8487
+ const results = remote.dataKey
8488
+ ? remote.dataKey.split('.').reduce((acc, key) => acc && acc[key], value)
8489
+ : value?.results ?? value;
8490
+ callback(Array.isArray(results) ? results : []);
8491
+ })
8492
+ .catch(() => callback([]));
8493
+ };
8494
+ }
8495
+ this.tomSelect = new TomSelect(this.el, settings);
8496
+ if (dataset.depends) {
8497
+ this._dependsOnEl = document.querySelector(dataset.depends);
8498
+ this._dependsOnEl?.addEventListener('change', this._handleDependencyChange);
8499
+ }
8500
+ }
8501
+ }
8502
+
7443
8503
  const _defaults$4 = {
7444
8504
  onOpen: null,
7445
8505
  onClose: null
@@ -8320,7 +9380,7 @@ class Waves {
8320
9380
  }
8321
9381
 
8322
9382
  /* eslint-disable @typescript-eslint/no-unused-vars */
8323
- const version = '2.3.3-1.0.2';
9383
+ const version = '2.3.3-1.0.21';
8324
9384
  /**
8325
9385
  * Convenience helper matching v1's `M.toast({...})` call, since Toast is a
8326
9386
  * class in v2 with no bare functional equivalent of its own.
@@ -8335,6 +9395,8 @@ function toast(options) {
8335
9395
  */
8336
9396
  function AutoInit(context = document.body, options) {
8337
9397
  const registry = {
9398
+ Alert: context.querySelectorAll('.alert:not(.no-autoinit)'),
9399
+ Kanban: context.querySelectorAll('.kanban-board:not(.no-autoinit)'),
8338
9400
  Autocomplete: context.querySelectorAll('.autocomplete:not(.no-autoinit)'),
8339
9401
  Cards: context.querySelectorAll('.cards:not(.no-autoinit)'),
8340
9402
  Carousel: context.querySelectorAll('.carousel:not(.no-autoinit)'),
@@ -8347,15 +9409,28 @@ function AutoInit(context = document.body, options) {
8347
9409
  Parallax: context.querySelectorAll('.parallax:not(.no-autoinit)'),
8348
9410
  Pushpin: context.querySelectorAll('.pushpin:not(.no-autoinit)'),
8349
9411
  ScrollSpy: context.querySelectorAll('.scrollspy:not(.no-autoinit)'),
8350
- FormSelect: context.querySelectorAll('select:not(.no-autoinit)'),
9412
+ // Excludes .tomselected - a select opted into TomSelectField instead
9413
+ // (see below), never eligible for FormSelect regardless of ordering.
9414
+ FormSelect: context.querySelectorAll('select:not(.no-autoinit):not(.tomselected)'),
8351
9415
  Sidenav: context.querySelectorAll('.sidenav:not(.no-autoinit)'),
8352
9416
  Tabs: context.querySelectorAll('.tabs:not(.no-autoinit)'),
8353
9417
  TapTarget: context.querySelectorAll('.tap-target:not(.no-autoinit)'),
8354
9418
  Timepicker: context.querySelectorAll('.timepicker:not(.no-autoinit)'),
8355
9419
  Tooltip: context.querySelectorAll('.tooltipped:not(.no-autoinit)'),
8356
- FloatingActionButton: context.querySelectorAll('.fixed-action-btn:not(.no-autoinit)')
9420
+ FloatingActionButton: context.querySelectorAll('.fixed-action-btn:not(.no-autoinit)'),
9421
+ // Excludes .fixed-action-btn.toolbar - that's an unrelated FAB display
9422
+ // mode reusing the same class name, not this component.
9423
+ Toolbar: context.querySelectorAll('.toolbar:not(.fixed-action-btn):not(.no-autoinit)'),
9424
+ PasswordInput: context.querySelectorAll('input[data-password-toggle]:not(.no-autoinit)'),
9425
+ NumberInput: context.querySelectorAll('input[data-type="number"]:not(.no-autoinit)'),
9426
+ ColorInput: context.querySelectorAll('input[type="color"][data-color-picker="pickr"]:not(.no-autoinit)'),
9427
+ AirDatepickerField: context.querySelectorAll('input[data-date-picker="air-datepicker"]:not(.no-autoinit)'),
9428
+ FileInput: context.querySelectorAll('.file-field[data-file-picker="filepond"]:not(.no-autoinit)'),
9429
+ TomSelectField: context.querySelectorAll('select.tomselected:not(.no-autoinit)')
8357
9430
  };
8358
9431
  Autocomplete.init(registry.Autocomplete, options?.Autocomplete ?? {});
9432
+ Alert.init(registry.Alert, options?.Alert ?? {});
9433
+ Kanban.init(registry.Kanban, options?.Kanban ?? {});
8359
9434
  Cards.init(registry.Cards, options?.Cards ?? {});
8360
9435
  Carousel.init(registry.Carousel, options?.Carousel ?? {});
8361
9436
  Chips.init(registry.Chips, options?.Chips ?? {});
@@ -8374,6 +9449,13 @@ function AutoInit(context = document.body, options) {
8374
9449
  Timepicker.init(registry.Timepicker, options?.Timepicker ?? {});
8375
9450
  Tooltip.init(registry.Tooltip, options?.Tooltip ?? {});
8376
9451
  FloatingActionButton.init(registry.FloatingActionButton, options?.FloatingActionButton ?? {});
9452
+ Toolbar.init(registry.Toolbar, options?.Toolbar ?? {});
9453
+ PasswordInput.init(registry.PasswordInput, options?.PasswordInput ?? {});
9454
+ NumberInput.init(registry.NumberInput, options?.NumberInput ?? {});
9455
+ ColorInput.init(registry.ColorInput, options?.ColorInput ?? {});
9456
+ AirDatepickerField.init(registry.AirDatepickerField, options?.AirDatepickerField ?? {});
9457
+ FileInput.init(registry.FileInput, options?.FileInput ?? {});
9458
+ TomSelectField.init(registry.TomSelectField, options?.TomSelectField ?? {});
8377
9459
  }
8378
9460
  // Init
8379
9461
  if (typeof document !== 'undefined') {
@@ -8388,6 +9470,8 @@ Waves.Init();
8388
9470
  Range.Init();
8389
9471
  Cards.Init();
8390
9472
 
9473
+ exports.AirDatepickerField = AirDatepickerField;
9474
+ exports.Alert = Alert;
8391
9475
  exports.AutoInit = AutoInit;
8392
9476
  exports.Autocomplete = Autocomplete;
8393
9477
  exports.Cards = Cards;
@@ -8395,14 +9479,19 @@ exports.Carousel = Carousel;
8395
9479
  exports.CharacterCounter = CharacterCounter;
8396
9480
  exports.Chips = Chips;
8397
9481
  exports.Collapsible = Collapsible;
9482
+ exports.ColorInput = ColorInput;
8398
9483
  exports.Datepicker = Datepicker;
8399
9484
  exports.Dropdown = Dropdown;
9485
+ exports.FileInput = FileInput;
8400
9486
  exports.FloatingActionButton = FloatingActionButton;
8401
9487
  exports.FormSelect = FormSelect;
8402
9488
  exports.Forms = Forms;
9489
+ exports.Kanban = Kanban;
8403
9490
  exports.Materialbox = Materialbox;
8404
9491
  exports.Modal = Modal;
9492
+ exports.NumberInput = NumberInput;
8405
9493
  exports.Parallax = Parallax;
9494
+ exports.PasswordInput = PasswordInput;
8406
9495
  exports.Pushpin = Pushpin;
8407
9496
  exports.Range = Range;
8408
9497
  exports.ScrollSpy = ScrollSpy;
@@ -8412,6 +9501,8 @@ exports.Tabs = Tabs;
8412
9501
  exports.TapTarget = TapTarget;
8413
9502
  exports.Timepicker = Timepicker;
8414
9503
  exports.Toast = Toast;
9504
+ exports.TomSelectField = TomSelectField;
9505
+ exports.Toolbar = Toolbar;
8415
9506
  exports.Tooltip = Tooltip;
8416
9507
  exports.Waves = Waves;
8417
9508
  exports.toast = toast;