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