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.
- package/README.md +4 -4
- package/components/air-datepicker/_air-datepicker.scss +137 -0
- package/components/air-datepicker/air-datepicker.ts +192 -0
- package/components/alert/_alerts.scss +130 -0
- package/components/alert/alert.ts +73 -0
- package/components/appbar/appbar.css +301 -4
- package/components/button/_buttons.scss +39 -1
- package/components/card/_cards.scss +9 -1
- package/components/checkbox/_checkboxes.scss +120 -229
- package/components/collapsible/_collapsible.scss +50 -0
- package/components/color-input/_color-input.scss +124 -0
- package/components/color-input/color-input.ts +203 -0
- package/components/dropdown/dropdown.ts +1 -1
- package/components/file-input/_file-input-enhanced.scss +61 -0
- package/components/file-input/file-input.ts +203 -0
- package/components/kanban/_kanban.scss +148 -0
- package/components/kanban/kanban.ts +133 -0
- package/components/list/_collection.scss +10 -2
- package/components/number-input/number-input.ts +103 -0
- package/components/password-input/password-input.ts +72 -0
- package/components/slider/_range.scss +5 -1
- package/components/switch/_switches.scss +5 -0
- package/components/textfield/_input-fields.scss +4 -4
- package/components/textfield/_select.scss +54 -0
- package/components/tom-select/_tom-select-field.scss +256 -0
- package/components/tom-select/tom-select-field.ts +175 -0
- package/components/toolbar/_toolbar.scss +324 -0
- package/components/toolbar/toolbar.ts +152 -0
- package/dist/css/materialize.colors.min.css +2 -2
- package/dist/css/materialize.css +10575 -711
- package/dist/css/materialize.min.css +2 -2
- package/dist/css/materialize.min.css.map +1 -1
- package/dist/js/materialize.cjs.js +1136 -45
- package/dist/js/materialize.d.ts +227 -2
- package/dist/js/materialize.js +1136 -45
- package/dist/js/materialize.min.js +2 -2
- package/dist/js/materialize.mjs +1128 -46
- package/package.json +45 -1
- package/sass/_colors.scss +191 -5
- package/sass/_global.scss +240 -1
- package/sass/materialize.scss +14 -1
- package/sass/mixins.module.scss +6 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Materialize v2.3.3-1.0.
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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.
|
|
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
|
-
|
|
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;
|