@cahyo-dimas/freeday 3.12.1 → 3.14.0
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/CHANGELOG.md +133 -9
- package/COMPONENTS.md +76 -1
- package/README.id.md +1 -1
- package/README.md +1 -1
- package/adapters/react/components/FdyDrawer.tsx +4 -0
- package/adapters/react/index.d.ts +2 -0
- package/adapters/vue/components/FdyDrawer.vue +4 -0
- package/adapters/vue/index.d.ts +2 -0
- package/dist/freeday-app-shell.js +1 -0
- package/dist/freeday-autocomplete.js +1 -0
- package/dist/freeday-breakpoint.js +12 -2
- package/dist/freeday-carousel.js +1 -0
- package/dist/freeday-cascade.js +1 -0
- package/dist/freeday-cfl.js +5 -1
- package/dist/freeday-chart.js +1 -0
- package/dist/freeday-chip.js +12 -4
- package/dist/freeday-datepicker.js +2 -0
- package/dist/freeday-datetime.js +1 -0
- package/dist/freeday-drawer.js +2 -0
- package/dist/freeday-form.js +1 -0
- package/dist/freeday-mask.js +2 -0
- package/dist/freeday-menu.js +1 -0
- package/dist/freeday-number.js +1 -0
- package/dist/freeday-rating.js +1 -0
- package/dist/freeday-search.js +1 -0
- package/dist/freeday-select.js +1 -0
- package/dist/freeday-slider.js +1 -0
- package/dist/freeday-sortable.js +222 -0
- package/dist/freeday-stepper.js +1 -0
- package/dist/freeday-table.js +1 -0
- package/dist/freeday-tabs.js +1 -0
- package/dist/freeday-timepicker.js +1 -0
- package/dist/freeday-tree.js +1 -0
- package/dist/freeday-unhydrated.js +83 -0
- package/dist/freeday-upload.js +6 -3
- package/dist/freeday.bundle.css +20 -1
- package/dist/freeday.css +20 -1
- package/dist/freeday.js +366 -10
- package/docs/agent-onboarding.md +4 -1
- package/docs/getting-started.md +1 -1
- package/docs/integrations.md +3 -2
- package/package.json +2 -2
- package/src/components/input.css +2 -1
- package/src/components/sortable.css +17 -0
package/dist/freeday.js
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
function initShell(app) {
|
|
50
50
|
if (app.dataset.fdyAppShellReady === '1') return;
|
|
51
|
+
if (app.closest('[data-fdy-ignore]')) return;
|
|
51
52
|
app.dataset.fdyAppShellReady = '1';
|
|
52
53
|
|
|
53
54
|
var toggle = app.querySelector('.fdy-app__navtoggle');
|
|
@@ -246,6 +247,7 @@
|
|
|
246
247
|
|
|
247
248
|
function initAutocomplete(root) {
|
|
248
249
|
if (root.dataset.fdyAcReady === '1') return;
|
|
250
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
249
251
|
root.dataset.fdyAcReady = '1';
|
|
250
252
|
|
|
251
253
|
var input = root.querySelector('input[role="combobox"]') || root.querySelector('input');
|
|
@@ -409,10 +411,19 @@
|
|
|
409
411
|
if (bp === last) return;
|
|
410
412
|
last = bp;
|
|
411
413
|
root.setAttribute('data-breakpoint', bp);
|
|
412
|
-
|
|
414
|
+
fillLabels(document);
|
|
415
|
+
root.dispatchEvent(new CustomEvent('fdy-breakpoint-change', { bubbles: true, detail: { breakpoint: bp } }));
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* Also run over late-mounted markup by the stack helpers, which find it through initAll: a label
|
|
419
|
+
rendered after load otherwise stayed empty until the next breakpoint change. */
|
|
420
|
+
function fillLabels(context) {
|
|
421
|
+
var ctx = context || document;
|
|
422
|
+
var bp = last || current();
|
|
423
|
+
if (ctx.matches && ctx.matches('[data-fdy-breakpoint-label]')) ctx.textContent = bp;
|
|
424
|
+
Array.prototype.forEach.call(ctx.querySelectorAll('[data-fdy-breakpoint-label]'), function (el) {
|
|
413
425
|
el.textContent = bp;
|
|
414
426
|
});
|
|
415
|
-
root.dispatchEvent(new CustomEvent('fdy-breakpoint-change', { bubbles: true, detail: { breakpoint: bp } }));
|
|
416
427
|
}
|
|
417
428
|
|
|
418
429
|
window.addEventListener('resize', update, { passive: true });
|
|
@@ -423,6 +434,7 @@
|
|
|
423
434
|
}
|
|
424
435
|
|
|
425
436
|
window.FreedayBreakpoint = {
|
|
437
|
+
initAll: fillLabels,
|
|
426
438
|
get: function () { return last || current(); },
|
|
427
439
|
current: current,
|
|
428
440
|
// true if the current breakpoint is `name` or wider (e.g. is('md') → md, lg, or xl)
|
|
@@ -650,6 +662,7 @@
|
|
|
650
662
|
|
|
651
663
|
function initCarousel(root) {
|
|
652
664
|
if (root.dataset.fdyCarouselReady === '1') return;
|
|
665
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
653
666
|
root.dataset.fdyCarouselReady = '1';
|
|
654
667
|
|
|
655
668
|
var viewport = root.querySelector('.fdy-carousel__viewport');
|
|
@@ -830,6 +843,7 @@
|
|
|
830
843
|
|
|
831
844
|
function initCascade(wrap) {
|
|
832
845
|
if (wrap.dataset.fdyCascadeReady === '1') return;
|
|
846
|
+
if (wrap.closest('[data-fdy-ignore]')) return;
|
|
833
847
|
wrap.dataset.fdyCascadeReady = '1';
|
|
834
848
|
wrap.classList.add('fdy-cascade');
|
|
835
849
|
|
|
@@ -1295,6 +1309,7 @@
|
|
|
1295
1309
|
|
|
1296
1310
|
function bindGroup(group) {
|
|
1297
1311
|
if (group.dataset.fdyCflBound === '1') return;
|
|
1312
|
+
if (group.closest('[data-fdy-ignore]')) return;
|
|
1298
1313
|
var dialog = document.getElementById(group.getAttribute('data-fdy-cfl'));
|
|
1299
1314
|
if (!dialog) return;
|
|
1300
1315
|
initDialog(dialog);
|
|
@@ -1306,6 +1321,7 @@
|
|
|
1306
1321
|
|
|
1307
1322
|
function bindOpener(opener) {
|
|
1308
1323
|
if (opener.dataset.fdyCflBound === '1') return;
|
|
1324
|
+
if (opener.closest('[data-fdy-ignore]')) return;
|
|
1309
1325
|
var dialog = document.getElementById(opener.getAttribute('data-fdy-cfl-open'));
|
|
1310
1326
|
if (!dialog) return;
|
|
1311
1327
|
initDialog(dialog);
|
|
@@ -1328,7 +1344,9 @@
|
|
|
1328
1344
|
initTriggers();
|
|
1329
1345
|
}
|
|
1330
1346
|
|
|
1331
|
-
|
|
1347
|
+
/* initAll is what every stack helper looks for (useFreeday in Vue and React, FreedayBlazor.initAll):
|
|
1348
|
+
without it they skipped this enhancer, and raw CFL markup rendered by a framework never opened. */
|
|
1349
|
+
window.FreedayCfl = { init: initTriggers, initAll: initTriggers };
|
|
1332
1350
|
})();
|
|
1333
1351
|
|
|
1334
1352
|
/* Freeday, chart renderer (optional, zero-dependency, no external chart lib).
|
|
@@ -1822,6 +1840,7 @@
|
|
|
1822
1840
|
// Auto-init renders once; explicit update() re-renders after data changes.
|
|
1823
1841
|
function initChart(el) {
|
|
1824
1842
|
if (el.dataset.fdyChartReady === '1') return;
|
|
1843
|
+
if (el.closest('[data-fdy-ignore]')) return;
|
|
1825
1844
|
el.dataset.fdyChartReady = '1';
|
|
1826
1845
|
renderChart(el);
|
|
1827
1846
|
}
|
|
@@ -1845,8 +1864,10 @@
|
|
|
1845
1864
|
/* Freeday, chip enhancer (optional, zero-dependency).
|
|
1846
1865
|
* Two behaviours, both progressive enhancement:
|
|
1847
1866
|
*
|
|
1848
|
-
* 1. Removable chips, any .fdy-chip__remove button
|
|
1849
|
-
*
|
|
1867
|
+
* 1. Removable chips, any .fdy-chip__remove button emits a bubbling, CANCELABLE
|
|
1868
|
+
* "fdy-chip-remove" (detail {value}) and then removes its chip, unless a listener called
|
|
1869
|
+
* preventDefault(). Cancel it whenever the app owns the removal: a confirm step, or a chip
|
|
1870
|
+
* rendered from framework state, which should leave the DOM when the state does.
|
|
1850
1871
|
* 2. Choice / filter groups, a [data-fdy-chips] container of interactive chips
|
|
1851
1872
|
* (.fdy-chip--choice / .fdy-chip--filter, each a <button>) toggles aria-pressed
|
|
1852
1873
|
* on click. Add data-single for one-at-a-time (radio-like) selection; filter
|
|
@@ -1860,6 +1881,7 @@
|
|
|
1860
1881
|
|
|
1861
1882
|
function initRemove(btn) {
|
|
1862
1883
|
if (btn.dataset.fdyChipRmReady === '1') return;
|
|
1884
|
+
if (btn.closest('[data-fdy-ignore]')) return;
|
|
1863
1885
|
btn.dataset.fdyChipRmReady = '1';
|
|
1864
1886
|
btn.addEventListener('click', function () {
|
|
1865
1887
|
var chip = btn.closest('.fdy-chip');
|
|
@@ -1872,13 +1894,18 @@
|
|
|
1872
1894
|
if (rm) rm.remove();
|
|
1873
1895
|
value = (clone.textContent || '').trim();
|
|
1874
1896
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1897
|
+
/* Cancelable, because the kit cannot know whether this removal needs asking first. Removing
|
|
1898
|
+
unconditionally made a chip vanish while the app's own confirm dialog was still open, and
|
|
1899
|
+
stay gone after Cancel, with the data intact and the screen wrong (CATATAN-FREEDAY §9). */
|
|
1900
|
+
var ev = new CustomEvent('fdy-chip-remove', { bubbles: true, cancelable: true, detail: { value: value } });
|
|
1901
|
+
chip.dispatchEvent(ev);
|
|
1902
|
+
if (!ev.defaultPrevented) chip.remove();
|
|
1877
1903
|
});
|
|
1878
1904
|
}
|
|
1879
1905
|
|
|
1880
1906
|
function initGroup(group) {
|
|
1881
1907
|
if (group.dataset.fdyChipsReady === '1') return;
|
|
1908
|
+
if (group.closest('[data-fdy-ignore]')) return;
|
|
1882
1909
|
group.dataset.fdyChipsReady = '1';
|
|
1883
1910
|
var single = group.hasAttribute('data-single');
|
|
1884
1911
|
if (!group.getAttribute('role')) group.setAttribute('role', 'group');
|
|
@@ -2210,6 +2237,7 @@
|
|
|
2210
2237
|
|
|
2211
2238
|
function initPicker(wrap) {
|
|
2212
2239
|
if (wrap.dataset.fdyDpReady === '1') return wrap._fdyDp || null;
|
|
2240
|
+
if (wrap.closest('[data-fdy-ignore]')) return null;
|
|
2213
2241
|
wrap.dataset.fdyDpReady = '1';
|
|
2214
2242
|
wrap.classList.add('fdy-datepicker');
|
|
2215
2243
|
|
|
@@ -2739,6 +2767,7 @@
|
|
|
2739
2767
|
|
|
2740
2768
|
function initRange(root) {
|
|
2741
2769
|
if (root.dataset.fdyDrReady === '1') return;
|
|
2770
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
2742
2771
|
root.dataset.fdyDrReady = '1';
|
|
2743
2772
|
var fromEl = root.querySelector('[data-fdy-datepicker][data-role="from"]');
|
|
2744
2773
|
var toEl = root.querySelector('[data-fdy-datepicker][data-role="to"]');
|
|
@@ -2828,6 +2857,7 @@
|
|
|
2828
2857
|
|
|
2829
2858
|
function initDatetime(wrap) {
|
|
2830
2859
|
if (wrap.dataset.fdyDtReady === '1') return;
|
|
2860
|
+
if (wrap.closest('[data-fdy-ignore]')) return;
|
|
2831
2861
|
wrap.dataset.fdyDtReady = '1';
|
|
2832
2862
|
wrap.classList.add('fdy-datetimepicker');
|
|
2833
2863
|
|
|
@@ -2906,6 +2936,7 @@
|
|
|
2906
2936
|
|
|
2907
2937
|
function initDrawer(dialog) {
|
|
2908
2938
|
if (dialog.dataset.fdyDrawerReady === '1') return;
|
|
2939
|
+
if (dialog.closest('[data-fdy-ignore]')) return;
|
|
2909
2940
|
dialog.dataset.fdyDrawerReady = '1';
|
|
2910
2941
|
// Click on the backdrop (target is the dialog box itself) closes it.
|
|
2911
2942
|
dialog.addEventListener('click', function (e) { if (e.target === dialog) dialog.close(); });
|
|
@@ -2916,6 +2947,7 @@
|
|
|
2916
2947
|
|
|
2917
2948
|
function bindTrigger(btn) {
|
|
2918
2949
|
if (btn.dataset.fdyDrawerBound === '1') return;
|
|
2950
|
+
if (btn.closest('[data-fdy-ignore]')) return;
|
|
2919
2951
|
var dialog = document.getElementById(btn.getAttribute('data-fdy-drawer'));
|
|
2920
2952
|
if (!dialog) return;
|
|
2921
2953
|
initDrawer(dialog);
|
|
@@ -3133,6 +3165,7 @@
|
|
|
3133
3165
|
|
|
3134
3166
|
function initForm(form) {
|
|
3135
3167
|
if (form.dataset.fdyFormReady === '1') return;
|
|
3168
|
+
if (form.closest('[data-fdy-ignore]')) return;
|
|
3136
3169
|
form.dataset.fdyFormReady = '1';
|
|
3137
3170
|
form.setAttribute('novalidate', '');
|
|
3138
3171
|
var eager = form.hasAttribute('data-fdy-eager');
|
|
@@ -3317,6 +3350,7 @@
|
|
|
3317
3350
|
|
|
3318
3351
|
function initMask(el) {
|
|
3319
3352
|
if (el.dataset.fdyMaskReady === '1') return;
|
|
3353
|
+
if (el.closest('[data-fdy-ignore]')) return;
|
|
3320
3354
|
el.dataset.fdyMaskReady = '1';
|
|
3321
3355
|
var pattern = el.getAttribute('data-fdy-mask') || '';
|
|
3322
3356
|
if (!pattern) return;
|
|
@@ -3339,6 +3373,7 @@
|
|
|
3339
3373
|
|
|
3340
3374
|
function initReveal(input) {
|
|
3341
3375
|
if (input.dataset.fdyPwReady === '1') return;
|
|
3376
|
+
if (input.closest('[data-fdy-ignore]')) return;
|
|
3342
3377
|
input.dataset.fdyPwReady = '1';
|
|
3343
3378
|
|
|
3344
3379
|
var group = document.createElement('span');
|
|
@@ -3402,6 +3437,7 @@
|
|
|
3402
3437
|
|
|
3403
3438
|
function initMenu(wrap) {
|
|
3404
3439
|
if (wrap.dataset.fdyMenuReady === '1') return;
|
|
3440
|
+
if (wrap.closest('[data-fdy-ignore]')) return;
|
|
3405
3441
|
wrap.dataset.fdyMenuReady = '1';
|
|
3406
3442
|
var trigger = wrap.querySelector('[aria-haspopup="menu"]');
|
|
3407
3443
|
var menu = wrap.querySelector('.fdy-menu, [role="menu"]');
|
|
@@ -3521,6 +3557,7 @@
|
|
|
3521
3557
|
|
|
3522
3558
|
function initNumber(root) {
|
|
3523
3559
|
if (root.dataset.fdyNumberReady === '1') return;
|
|
3560
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
3524
3561
|
|
|
3525
3562
|
var input = root.querySelector('input[type="number"]');
|
|
3526
3563
|
var buttons = Array.prototype.slice.call(root.querySelectorAll('[data-fdy-number-step]'));
|
|
@@ -3699,6 +3736,7 @@
|
|
|
3699
3736
|
|
|
3700
3737
|
function initRating(root) {
|
|
3701
3738
|
if (root.dataset.fdyRatingReady === '1') return;
|
|
3739
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
3702
3740
|
root.dataset.fdyRatingReady = '1';
|
|
3703
3741
|
|
|
3704
3742
|
var stars = Array.prototype.slice.call(root.querySelectorAll('.fdy-rating__star'));
|
|
@@ -3769,6 +3807,7 @@
|
|
|
3769
3807
|
|
|
3770
3808
|
function initSearch(root) {
|
|
3771
3809
|
if (root.dataset.fdySearchReady === '1') return;
|
|
3810
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
3772
3811
|
var input = root.querySelector('input');
|
|
3773
3812
|
if (!input) return;
|
|
3774
3813
|
root.dataset.fdySearchReady = '1';
|
|
@@ -3855,6 +3894,7 @@
|
|
|
3855
3894
|
|
|
3856
3895
|
function initCombo(root) {
|
|
3857
3896
|
if (root.dataset.fdyComboReady === '1') return; // idempotent
|
|
3897
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
3858
3898
|
var button = root.querySelector('.fdy-combo__button');
|
|
3859
3899
|
var listbox = root.querySelector('.fdy-combo__listbox');
|
|
3860
3900
|
var valueEl = root.querySelector('.fdy-combo__value');
|
|
@@ -4067,6 +4107,7 @@
|
|
|
4067
4107
|
|
|
4068
4108
|
function initSlider(input) {
|
|
4069
4109
|
if (input.dataset.fdySliderReady === '1') return;
|
|
4110
|
+
if (input.closest('[data-fdy-ignore]')) return;
|
|
4070
4111
|
input.dataset.fdySliderReady = '1';
|
|
4071
4112
|
var out = input.id ? document.querySelector('output[for="' + input.id + '"]') : null;
|
|
4072
4113
|
if (!out) return;
|
|
@@ -4091,6 +4132,229 @@
|
|
|
4091
4132
|
window.FreedaySlider = { init: initSlider, initAll: initAll };
|
|
4092
4133
|
})();
|
|
4093
4134
|
|
|
4135
|
+
/* Freeday, sortable list enhancer (optional, zero-dependency).
|
|
4136
|
+
* Reorder the children of a list by dragging a handle, or by focusing it and pressing ↑ / ↓. The
|
|
4137
|
+
* keyboard path is not an extra: drag-only reordering locks out every keyboard and screen-reader
|
|
4138
|
+
* user from a settings screen, and that path is the part each app used to write for itself
|
|
4139
|
+
* (CATATAN-FREEDAY §15).
|
|
4140
|
+
*
|
|
4141
|
+
* Markup contract:
|
|
4142
|
+
* <ul class="fdy-sortable" data-fdy-sortable> (or a <tbody>, or a <div>)
|
|
4143
|
+
* <li data-key="ketua" data-label="Ketua">
|
|
4144
|
+
* <button class="fdy-sortable__handle" type="button">…icon…</button> Ketua
|
|
4145
|
+
* </li>
|
|
4146
|
+
* <li data-key="sistem" data-fdy-sort-fixed>…</li> (never moves, and nothing passes it)
|
|
4147
|
+
* </ul>
|
|
4148
|
+
* The items are the container's element children. `data-key` names each in the event; `data-label`
|
|
4149
|
+
* is what the handle's default aria-label and the announcement call it (the item text otherwise).
|
|
4150
|
+
* `data-disabled` on the container switches reordering off, e.g. while the list is filtered, and
|
|
4151
|
+
* the handles follow it through aria-disabled.
|
|
4152
|
+
*
|
|
4153
|
+
* Emits a bubbling, CANCELABLE "fdy-sort-change" on the container, detail {key, from, to, order},
|
|
4154
|
+
* `order` being every item's key in the new order. Not cancelled, the kit moves the element, which
|
|
4155
|
+
* is the whole job on a static page. A framework that renders the list from state cancels it and
|
|
4156
|
+
* reorders the state instead, because the DOM is the framework's and an element moved behind its
|
|
4157
|
+
* back leaves the two disagreeing about where each row is. Either way the kit announces the move
|
|
4158
|
+
* and, after a keyboard step, puts focus back on the moved item's handle (looked up by data-key,
|
|
4159
|
+
* since a framework re-render may have replaced the element).
|
|
4160
|
+
*
|
|
4161
|
+
* The drag shows where the item will land (is-drop-before / is-drop-after on the item it lands
|
|
4162
|
+
* against) and moves nothing until the pointer is released; Escape cancels it. Exposes
|
|
4163
|
+
* window.FreedaySortable.
|
|
4164
|
+
*/
|
|
4165
|
+
(function () {
|
|
4166
|
+
'use strict';
|
|
4167
|
+
|
|
4168
|
+
var TEXT = {
|
|
4169
|
+
handle: 'Move {label}. Drag, or press the up and down arrow keys.',
|
|
4170
|
+
moved: '{label} moved to position {position} of {total}.'
|
|
4171
|
+
};
|
|
4172
|
+
/* Kebab-cased for the lookup, see the note in freeday-upload.js. */
|
|
4173
|
+
function textAttr(root, key) {
|
|
4174
|
+
if (!root || !root.getAttribute) return null;
|
|
4175
|
+
var kebab = root.getAttribute('data-fdy-text-' + key.replace(/[A-Z]/g, function (c) { return '-' + c.toLowerCase(); }));
|
|
4176
|
+
return kebab != null && kebab !== '' ? kebab : root.getAttribute('data-fdy-text-' + key);
|
|
4177
|
+
}
|
|
4178
|
+
function textOf(root, key, vars) {
|
|
4179
|
+
var custom = textAttr(root, key);
|
|
4180
|
+
var s = custom != null && custom !== '' ? custom : TEXT[key];
|
|
4181
|
+
for (var k in vars) if (Object.prototype.hasOwnProperty.call(vars, k)) s = s.split('{' + k + '}').join(vars[k]);
|
|
4182
|
+
return s;
|
|
4183
|
+
}
|
|
4184
|
+
|
|
4185
|
+
var HANDLE = '.fdy-sortable__handle';
|
|
4186
|
+
|
|
4187
|
+
var live = null;
|
|
4188
|
+
function announce(message) {
|
|
4189
|
+
if (live === null) {
|
|
4190
|
+
live = document.createElement('div');
|
|
4191
|
+
live.className = 'fdy-visually-hidden';
|
|
4192
|
+
live.setAttribute('aria-live', 'polite');
|
|
4193
|
+
document.body.appendChild(live);
|
|
4194
|
+
}
|
|
4195
|
+
/* The same sentence twice in a row is no change, and a live region announces changes. */
|
|
4196
|
+
live.textContent = live.textContent === message ? message + ' ' : message;
|
|
4197
|
+
}
|
|
4198
|
+
|
|
4199
|
+
function items(root) {
|
|
4200
|
+
return Array.prototype.slice.call(root.children);
|
|
4201
|
+
}
|
|
4202
|
+
function keyOf(item, index) {
|
|
4203
|
+
var key = item.getAttribute('data-key');
|
|
4204
|
+
return key !== null ? key : String(index);
|
|
4205
|
+
}
|
|
4206
|
+
function labelOf(item) {
|
|
4207
|
+
var label = item.getAttribute('data-label');
|
|
4208
|
+
return label !== null ? label : (item.textContent || '').replace(/\s+/g, ' ').trim();
|
|
4209
|
+
}
|
|
4210
|
+
function disabled(root) {
|
|
4211
|
+
return root.hasAttribute('data-disabled');
|
|
4212
|
+
}
|
|
4213
|
+
function itemOf(root, node) {
|
|
4214
|
+
for (var n = node; n && n !== root; n = n.parentElement) {
|
|
4215
|
+
if (n.parentElement === root) return n;
|
|
4216
|
+
}
|
|
4217
|
+
return null;
|
|
4218
|
+
}
|
|
4219
|
+
|
|
4220
|
+
/* A move is allowed only if it shifts no fixed item, which is the same as saying the item does
|
|
4221
|
+
not start fixed and does not cross one on its way. */
|
|
4222
|
+
function allowed(list, from, to) {
|
|
4223
|
+
if (from === to || to < 0 || to >= list.length) return false;
|
|
4224
|
+
var lo = Math.min(from, to), hi = Math.max(from, to);
|
|
4225
|
+
for (var i = lo; i <= hi; i++) if (list[i].hasAttribute('data-fdy-sort-fixed')) return false;
|
|
4226
|
+
return true;
|
|
4227
|
+
}
|
|
4228
|
+
|
|
4229
|
+
function syncHandles(root) {
|
|
4230
|
+
var off = disabled(root) ? 'true' : 'false';
|
|
4231
|
+
items(root).forEach(function (item) {
|
|
4232
|
+
var handle = item.querySelector(HANDLE);
|
|
4233
|
+
if (!handle) return;
|
|
4234
|
+
if (handle.getAttribute('aria-disabled') !== off) handle.setAttribute('aria-disabled', off);
|
|
4235
|
+
if (!handle.hasAttribute('aria-label')) handle.setAttribute('aria-label', textOf(root, 'handle', { label: labelOf(item) }));
|
|
4236
|
+
});
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
function commit(root, from, to, refocus) {
|
|
4240
|
+
var list = items(root);
|
|
4241
|
+
var item = list[from];
|
|
4242
|
+
var key = keyOf(item, from);
|
|
4243
|
+
var keys = list.map(keyOf);
|
|
4244
|
+
keys.splice(to, 0, keys.splice(from, 1)[0]);
|
|
4245
|
+
var ev = new CustomEvent('fdy-sort-change', {
|
|
4246
|
+
bubbles: true,
|
|
4247
|
+
cancelable: true,
|
|
4248
|
+
detail: { key: key, from: from, to: to, order: keys }
|
|
4249
|
+
});
|
|
4250
|
+
root.dispatchEvent(ev);
|
|
4251
|
+
if (!ev.defaultPrevented) root.insertBefore(item, to > from ? list[to].nextSibling : list[to]);
|
|
4252
|
+
announce(textOf(root, 'moved', { label: labelOf(item), position: String(to + 1), total: String(list.length) }));
|
|
4253
|
+
if (!refocus) return;
|
|
4254
|
+
/* After the app's own render, which a framework runs after this handler returns. Moving a focused
|
|
4255
|
+
element drops its focus, and a keyed re-render may have replaced the element outright. */
|
|
4256
|
+
setTimeout(function () {
|
|
4257
|
+
var now = items(root);
|
|
4258
|
+
var moved = item.parentElement === root ? item : now.filter(function (el, i) { return keyOf(el, i) === key; })[0];
|
|
4259
|
+
var handle = moved ? moved.querySelector(HANDLE) : null;
|
|
4260
|
+
if (handle && document.activeElement !== handle) handle.focus();
|
|
4261
|
+
}, 0);
|
|
4262
|
+
}
|
|
4263
|
+
|
|
4264
|
+
function initSortable(root) {
|
|
4265
|
+
if (root.dataset.fdySortableReady === '1') return;
|
|
4266
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
4267
|
+
root.dataset.fdySortableReady = '1';
|
|
4268
|
+
syncHandles(root);
|
|
4269
|
+
/* Rows a framework adds later get their aria-label, and data-disabled reaches every handle. */
|
|
4270
|
+
new MutationObserver(function () { syncHandles(root); })
|
|
4271
|
+
.observe(root, { childList: true, attributes: true, attributeFilter: ['data-disabled'] });
|
|
4272
|
+
|
|
4273
|
+
root.addEventListener('keydown', function (e) {
|
|
4274
|
+
var handle = e.target.closest ? e.target.closest(HANDLE) : null;
|
|
4275
|
+
if (!handle || !root.contains(handle) || disabled(root)) return;
|
|
4276
|
+
if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return;
|
|
4277
|
+
e.preventDefault();
|
|
4278
|
+
var list = items(root);
|
|
4279
|
+
var from = list.indexOf(itemOf(root, handle));
|
|
4280
|
+
var to = from + (e.key === 'ArrowUp' ? -1 : 1);
|
|
4281
|
+
if (from !== -1 && allowed(list, from, to)) commit(root, from, to, true);
|
|
4282
|
+
});
|
|
4283
|
+
|
|
4284
|
+
var drag = null;
|
|
4285
|
+
|
|
4286
|
+
function clearMarks() {
|
|
4287
|
+
items(root).forEach(function (el) { el.classList.remove('is-drop-before', 'is-drop-after'); });
|
|
4288
|
+
}
|
|
4289
|
+
function end(apply) {
|
|
4290
|
+
if (drag === null) return;
|
|
4291
|
+
var d = drag;
|
|
4292
|
+
drag = null;
|
|
4293
|
+
document.removeEventListener('keydown', onEscape, true);
|
|
4294
|
+
clearMarks();
|
|
4295
|
+
d.item.classList.remove('is-dragging');
|
|
4296
|
+
root.classList.remove('is-sorting');
|
|
4297
|
+
if (apply && d.started && d.to !== null) commit(root, d.from, d.to, false);
|
|
4298
|
+
}
|
|
4299
|
+
function onEscape(e) {
|
|
4300
|
+
if (e.key === 'Escape') { e.preventDefault(); end(false); }
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4303
|
+
root.addEventListener('pointerdown', function (e) {
|
|
4304
|
+
var handle = e.target.closest ? e.target.closest(HANDLE) : null;
|
|
4305
|
+
if (!handle || !root.contains(handle) || disabled(root) || e.button !== 0) return;
|
|
4306
|
+
var item = itemOf(root, handle);
|
|
4307
|
+
if (!item) return;
|
|
4308
|
+
e.preventDefault();
|
|
4309
|
+
handle.focus();
|
|
4310
|
+
handle.setPointerCapture(e.pointerId);
|
|
4311
|
+
drag = { item: item, from: items(root).indexOf(item), started: false, to: null };
|
|
4312
|
+
document.addEventListener('keydown', onEscape, true);
|
|
4313
|
+
});
|
|
4314
|
+
|
|
4315
|
+
root.addEventListener('pointermove', function (e) {
|
|
4316
|
+
if (drag === null) return;
|
|
4317
|
+
/* No travel threshold: a press that never leaves its own row resolves to to === from, which
|
|
4318
|
+
allowed() refuses, so a click on the handle cannot reorder anything. */
|
|
4319
|
+
if (!drag.started) {
|
|
4320
|
+
drag.started = true;
|
|
4321
|
+
drag.item.classList.add('is-dragging');
|
|
4322
|
+
root.classList.add('is-sorting');
|
|
4323
|
+
}
|
|
4324
|
+
clearMarks();
|
|
4325
|
+
drag.to = null;
|
|
4326
|
+
var list = items(root);
|
|
4327
|
+
var over = itemOf(root, document.elementFromPoint(e.clientX, e.clientY));
|
|
4328
|
+
if (!over) return;
|
|
4329
|
+
var rect = over.getBoundingClientRect();
|
|
4330
|
+
var after = e.clientY > rect.top + rect.height / 2;
|
|
4331
|
+
var slot = list.indexOf(over) + (after ? 1 : 0);
|
|
4332
|
+
var to = slot > drag.from ? slot - 1 : slot;
|
|
4333
|
+
if (!allowed(list, drag.from, to)) return;
|
|
4334
|
+
drag.to = to;
|
|
4335
|
+
over.classList.add(after ? 'is-drop-after' : 'is-drop-before');
|
|
4336
|
+
});
|
|
4337
|
+
|
|
4338
|
+
root.addEventListener('pointerup', function () { end(true); });
|
|
4339
|
+
root.addEventListener('pointercancel', function () { end(false); });
|
|
4340
|
+
}
|
|
4341
|
+
|
|
4342
|
+
function initAll(context) {
|
|
4343
|
+
var root = context || document;
|
|
4344
|
+
/* root included: querySelectorAll never matches its own root, and a framework ref often sits ON the widget. */
|
|
4345
|
+
if (root.matches && root.matches('[data-fdy-sortable]')) initSortable(root);
|
|
4346
|
+
Array.prototype.forEach.call(root.querySelectorAll('[data-fdy-sortable]'), initSortable);
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4349
|
+
if (document.readyState === 'loading') {
|
|
4350
|
+
document.addEventListener('DOMContentLoaded', function () { initAll(); });
|
|
4351
|
+
} else {
|
|
4352
|
+
initAll();
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4355
|
+
window.FreedaySortable = { init: initSortable, initAll: initAll };
|
|
4356
|
+
})();
|
|
4357
|
+
|
|
4094
4358
|
/* Freeday, stepper/wizard enhancer (optional, zero-dependency).
|
|
4095
4359
|
* Drives a step header + panels: prev/next navigation, completed/active state, and
|
|
4096
4360
|
* clicking a reached step to revisit it (linear, can't skip ahead). Auto-inits
|
|
@@ -4142,6 +4406,7 @@
|
|
|
4142
4406
|
|
|
4143
4407
|
function initStepper(root) {
|
|
4144
4408
|
if (root.dataset.fdyStepperReady === '1') return;
|
|
4409
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
4145
4410
|
root.dataset.fdyStepperReady = '1';
|
|
4146
4411
|
|
|
4147
4412
|
var steps = Array.prototype.slice.call(root.querySelectorAll('.fdy-step'));
|
|
@@ -4341,6 +4606,7 @@
|
|
|
4341
4606
|
|
|
4342
4607
|
function initTable(root) {
|
|
4343
4608
|
if (root.dataset.fdyTableReady === '1') return;
|
|
4609
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
4344
4610
|
var table = root.querySelector('table.fdy-table');
|
|
4345
4611
|
var tbody = table && table.querySelector('tbody');
|
|
4346
4612
|
if (!table || !tbody) return;
|
|
@@ -4884,6 +5150,7 @@
|
|
|
4884
5150
|
|
|
4885
5151
|
function initTabs(root) {
|
|
4886
5152
|
if (root.dataset.fdyTabsReady === '1') return;
|
|
5153
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
4887
5154
|
var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
|
|
4888
5155
|
if (tabs.length === 0) return;
|
|
4889
5156
|
root.dataset.fdyTabsReady = '1';
|
|
@@ -4999,6 +5266,7 @@
|
|
|
4999
5266
|
|
|
5000
5267
|
function initTime(wrap) {
|
|
5001
5268
|
if (wrap.dataset.fdyTpReady === '1') return;
|
|
5269
|
+
if (wrap.closest('[data-fdy-ignore]')) return;
|
|
5002
5270
|
wrap.dataset.fdyTpReady = '1';
|
|
5003
5271
|
wrap.classList.add('fdy-timepicker');
|
|
5004
5272
|
|
|
@@ -5435,6 +5703,7 @@
|
|
|
5435
5703
|
|
|
5436
5704
|
function initTree(tree) {
|
|
5437
5705
|
if (tree.dataset.fdyTreeReady === '1') return;
|
|
5706
|
+
if (tree.closest('[data-fdy-ignore]')) return;
|
|
5438
5707
|
tree.dataset.fdyTreeReady = '1';
|
|
5439
5708
|
Array.prototype.forEach.call(tree.querySelectorAll('input[type="checkbox"]'), function (box) {
|
|
5440
5709
|
// A branch checkbox lives inside <summary>; keep its click from toggling the branch.
|
|
@@ -5465,6 +5734,90 @@
|
|
|
5465
5734
|
window.FreedayTree = { init: initTree, initAll: initAll };
|
|
5466
5735
|
})();
|
|
5467
5736
|
|
|
5737
|
+
/* Freeday, un-hydrated hook warning (optional, zero-dependency, no markup of its own).
|
|
5738
|
+
* Every enhancer marks the element it took over (`data-fdy-*-ready`). Markup that no initAll()
|
|
5739
|
+
* ever reached carries the hook and not the mark, and it fails in the worst way available: it
|
|
5740
|
+
* renders, looks finished, and does nothing, with no error anywhere. A `data-fdy-validate` form
|
|
5741
|
+
* outside the subtree handed to useFreeday() neither paints a message nor fires fdy-form-valid,
|
|
5742
|
+
* so its save button reads as dead (CATATAN-FREEDAY §10). The enhancer knows the attribute is
|
|
5743
|
+
* there; the person who wrote it does not.
|
|
5744
|
+
*
|
|
5745
|
+
* So on the first click, focus or submit inside such an element this logs ONE console.warn per
|
|
5746
|
+
* element, naming the hook, with the element itself as the second argument so devtools links it.
|
|
5747
|
+
* Interaction, not load, is the trigger on purpose: a framework mounts and hydrates in between,
|
|
5748
|
+
* and only once a person is touching the widget is "not enhanced yet" the same as "never".
|
|
5749
|
+
*
|
|
5750
|
+
* HOOKS pairs each hook selector with the ready flag its enhancer stamps on THAT element and the
|
|
5751
|
+
* namespace that owns it. A hook whose enhancer is not loaded is skipped: that is a different
|
|
5752
|
+
* mistake, and this message would misname it. test/docs.test.mjs fails if an enhancer gains a
|
|
5753
|
+
* ready flag this table does not list.
|
|
5754
|
+
*
|
|
5755
|
+
* `data-fdy-ignore` on an element or any ancestor is the sanctioned way out: every enhancer skips
|
|
5756
|
+
* that subtree, and this stays quiet about it. It is for markup whose behaviour something else
|
|
5757
|
+
* owns: the kit's own Vue/React FdyDrawer, and kit classes an app uses for their look
|
|
5758
|
+
* alone (CATATAN-FREEDAY §14: a chip matrix the app drives itself).
|
|
5759
|
+
*/
|
|
5760
|
+
(function () {
|
|
5761
|
+
'use strict';
|
|
5762
|
+
|
|
5763
|
+
var HOOKS = [
|
|
5764
|
+
['[data-fdy-app]', 'fdyAppShellReady', 'FreedayAppShell'],
|
|
5765
|
+
['[data-fdy-autocomplete]', 'fdyAcReady', 'FreedayAutocomplete'],
|
|
5766
|
+
['[data-fdy-carousel]', 'fdyCarouselReady', 'FreedayCarousel'],
|
|
5767
|
+
['[data-fdy-cascade]', 'fdyCascadeReady', 'FreedayCascade'],
|
|
5768
|
+
['[data-fdy-cfl]', 'fdyCflBound', 'FreedayCfl'],
|
|
5769
|
+
['[data-fdy-cfl-open]', 'fdyCflBound', 'FreedayCfl'],
|
|
5770
|
+
['[data-fdy-chart]', 'fdyChartReady', 'FreedayChart'],
|
|
5771
|
+
['[data-fdy-chips]', 'fdyChipsReady', 'FreedayChip'],
|
|
5772
|
+
['.fdy-chip__remove', 'fdyChipRmReady', 'FreedayChip'],
|
|
5773
|
+
['[data-fdy-datepicker]', 'fdyDpReady', 'FreedayDatepicker'],
|
|
5774
|
+
['[data-fdy-daterange]', 'fdyDrReady', 'FreedayDatepicker'],
|
|
5775
|
+
['[data-fdy-datetimepicker]', 'fdyDtReady', 'FreedayDatetime'],
|
|
5776
|
+
['[data-fdy-drawer]', 'fdyDrawerBound', 'FreedayDrawer'],
|
|
5777
|
+
['.fdy-drawer', 'fdyDrawerReady', 'FreedayDrawer'],
|
|
5778
|
+
['[data-fdy-validate]', 'fdyFormReady', 'FreedayForm'],
|
|
5779
|
+
['[data-fdy-mask]', 'fdyMaskReady', 'FreedayMask'],
|
|
5780
|
+
['[data-fdy-password]', 'fdyPwReady', 'FreedayMask'],
|
|
5781
|
+
['[data-fdy-menu]', 'fdyMenuReady', 'FreedayMenu'],
|
|
5782
|
+
['[data-fdy-number]', 'fdyNumberReady', 'FreedayNumber'],
|
|
5783
|
+
['[data-fdy-rating]', 'fdyRatingReady', 'FreedayRating'],
|
|
5784
|
+
['[data-fdy-search]', 'fdySearchReady', 'FreedaySearch'],
|
|
5785
|
+
['[data-fdy-combo]', 'fdyComboReady', 'FreedayCombo'],
|
|
5786
|
+
['[data-fdy-slider]', 'fdySliderReady', 'FreedaySlider'],
|
|
5787
|
+
['[data-fdy-sortable]', 'fdySortableReady', 'FreedaySortable'],
|
|
5788
|
+
['[data-fdy-stepper]', 'fdyStepperReady', 'FreedayStepper'],
|
|
5789
|
+
['[data-fdy-table]', 'fdyTableReady', 'FreedayTable'],
|
|
5790
|
+
['[data-fdy-tabs]', 'fdyTabsReady', 'FreedayTabs'],
|
|
5791
|
+
['[data-fdy-timepicker]', 'fdyTpReady', 'FreedayTimepicker'],
|
|
5792
|
+
['[data-fdy-tree]', 'fdyTreeReady', 'FreedayTree'],
|
|
5793
|
+
['[data-fdy-dropzone]', 'fdyUploadReady', 'FreedayUpload']
|
|
5794
|
+
];
|
|
5795
|
+
|
|
5796
|
+
var warned = typeof WeakSet === 'function' ? new WeakSet() : null;
|
|
5797
|
+
|
|
5798
|
+
function check(e) {
|
|
5799
|
+
if (!warned || !e.target || !e.target.closest) return;
|
|
5800
|
+
for (var i = 0; i < HOOKS.length; i++) {
|
|
5801
|
+
var hook = HOOKS[i];
|
|
5802
|
+
if (!window[hook[2]]) continue;
|
|
5803
|
+
var el = e.target.closest(hook[0]);
|
|
5804
|
+
if (!el || el.dataset[hook[1]] === '1' || warned.has(el) || el.closest('[data-fdy-ignore]')) continue;
|
|
5805
|
+
warned.add(el);
|
|
5806
|
+
console.warn('Freeday: this ' + hook[0] + ' was never enhanced, so it does nothing. Either it is '
|
|
5807
|
+
+ 'outside every initAll() scope (Vue/React: inside the element given to useFreeday(); Blazor: '
|
|
5808
|
+
+ 'FreedayBlazor.initAll after render; anything else: ' + hook[2] + '.initAll(el) once it is in '
|
|
5809
|
+
+ 'the DOM), or its markup lacks a part the enhancer needs (see COMPONENTS.md). If the app '
|
|
5810
|
+
+ 'drives this element itself on purpose, mark it or an ancestor data-fdy-ignore.', el);
|
|
5811
|
+
}
|
|
5812
|
+
}
|
|
5813
|
+
|
|
5814
|
+
['click', 'focusin', 'submit'].forEach(function (type) {
|
|
5815
|
+
document.addEventListener(type, check, true);
|
|
5816
|
+
});
|
|
5817
|
+
|
|
5818
|
+
window.FreedayUnhydrated = { hooks: HOOKS };
|
|
5819
|
+
})();
|
|
5820
|
+
|
|
5468
5821
|
/* Freeday, file-upload enhancer (optional, zero-dependency).
|
|
5469
5822
|
* A drop target that also opens the file dialog on click / Enter / Space, validates each file
|
|
5470
5823
|
* (accept + max size), and renders a per-file row with explicit state. Actual upload is the
|
|
@@ -5485,7 +5838,8 @@
|
|
|
5485
5838
|
* Emits bubbling CustomEvents. BOTH on the dropzone element, which is the one target a consumer
|
|
5486
5839
|
* needs to listen on:
|
|
5487
5840
|
* "fdy-upload-add" {file, rejected, reason, row}
|
|
5488
|
-
* "fdy-upload-remove" {file}
|
|
5841
|
+
* "fdy-upload-remove" {file}, cancelable: preventDefault() keeps the row (e.g. to confirm
|
|
5842
|
+
* removing a file the server already holds, then call row.el.remove())
|
|
5489
5843
|
* `row` is the state machine over the rendered .fdy-file:
|
|
5490
5844
|
* .ready() (rest, where a dropped file starts) / .uploading() / .setProgress(pct) /
|
|
5491
5845
|
* .waiting(label) (sent, awaiting the server) / .done() / .fail(msg) / .el
|
|
@@ -5578,8 +5932,9 @@
|
|
|
5578
5932
|
Firing on both would look safer, but it makes the pair asymmetric, one `add` and, for
|
|
5579
5933
|
anyone delegating on a common ancestor, two `remove`s, which is its own silent bug. It
|
|
5580
5934
|
also fixes the listless case: a row that was never attached bubbles to nothing at all. */
|
|
5581
|
-
|
|
5582
|
-
|
|
5935
|
+
var ev = new CustomEvent('fdy-upload-remove', { bubbles: true, cancelable: true, detail: { file: file } });
|
|
5936
|
+
zone.dispatchEvent(ev);
|
|
5937
|
+
if (!ev.defaultPrevented) el.remove();
|
|
5583
5938
|
});
|
|
5584
5939
|
el.appendChild(icon);
|
|
5585
5940
|
el.appendChild(meta);
|
|
@@ -5693,6 +6048,7 @@
|
|
|
5693
6048
|
|
|
5694
6049
|
function initDropzone(zone) {
|
|
5695
6050
|
if (zone.dataset.fdyUploadReady === '1') return;
|
|
6051
|
+
if (zone.closest('[data-fdy-ignore]')) return;
|
|
5696
6052
|
zone.dataset.fdyUploadReady = '1';
|
|
5697
6053
|
|
|
5698
6054
|
var input = zone.querySelector('input[type="file"]');
|
package/docs/agent-onboarding.md
CHANGED
|
@@ -118,6 +118,8 @@ Recent additions most likely to replace something an app hand-rolled (all detail
|
|
|
118
118
|
|
|
119
119
|
| Reach for | Instead of |
|
|
120
120
|
|---|---|
|
|
121
|
+
| `data-fdy-sortable` + `.fdy-sortable__handle` | SortableJS plus a hand-written arrow-key path, or a number box for an `order` column |
|
|
122
|
+
| `data-fdy-ignore` | narrowing `useFreeday()` to dodge kit markup the app drives itself, which leaves every form outside the scope dead |
|
|
121
123
|
| `.fdy-btn--stretch` | a hand-rolled overlay to make a card or list row clickable |
|
|
122
124
|
| `[data-fdy-number]` | a bare `<input type="number">` with the browser's own spin buttons |
|
|
123
125
|
| `clearable` on `FdyCfl` / `FdyDatepicker` | a value that can be set but never unset |
|
|
@@ -229,4 +231,5 @@ Order of work that avoids a half-migrated mess:
|
|
|
229
231
|
- Keyboard: Tab reaches every control, focus is always visible, Esc closes overlays.
|
|
230
232
|
- Form errors carry `aria-invalid` + a linked message; icon-only buttons have `aria-label`.
|
|
231
233
|
- The interactive components on the screen have their enhancer loaded, and SPA-rendered DOM is
|
|
232
|
-
re-hydrated.
|
|
234
|
+
re-hydrated. Click each one once with devtools open: a `Freeday: this [data-fdy-…] was never
|
|
235
|
+
enhanced` warning means it sits outside every `initAll()` scope.
|
package/docs/getting-started.md
CHANGED
|
@@ -198,7 +198,7 @@ live docs also have a copy button per component.
|
|
|
198
198
|
```bash
|
|
199
199
|
npm i @cahyo-dimas/freeday
|
|
200
200
|
```
|
|
201
|
-
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.
|
|
201
|
+
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.14.0"` (public npm package). `dist/` is
|
|
202
202
|
committed and published → no build step; `npm ci` runs without auth.
|
|
203
203
|
|
|
204
204
|
### 2. Import the CSS + enhancers **once** in your entry (`src/main.ts`)
|
package/docs/integrations.md
CHANGED
|
@@ -40,8 +40,9 @@ Every integration comes down to one of these:
|
|
|
40
40
|
| `freeday-mask` | `fdy-mask` `{value,raw}` | `FreedayMask` |
|
|
41
41
|
| `freeday-form` | `fdy-form-invalid` `{invalid}` / `fdy-form-valid` | `FreedayForm` |
|
|
42
42
|
| `freeday-table` | `fdy-table-change` · `fdy-row-select` | `FreedayTable` |
|
|
43
|
-
| `freeday-chip` | `fdy-chip-change` `{value,pressed,selected}` · `fdy-chip-remove` `{value}
|
|
44
|
-
| `freeday-upload` | `fdy-upload-add` / `fdy-upload-remove` | `FreedayUpload` |
|
|
43
|
+
| `freeday-chip` | `fdy-chip-change` `{value,pressed,selected}` · `fdy-chip-remove` `{value}`, cancelable | `FreedayChip` |
|
|
44
|
+
| `freeday-upload` | `fdy-upload-add` / `fdy-upload-remove` (cancelable) | `FreedayUpload` |
|
|
45
|
+
| `freeday-sortable` | `fdy-sort-change` `{key,from,to,order}`, cancelable | `FreedaySortable` |
|
|
45
46
|
| `freeday-stepper` | `fdy-step-change` | `FreedayStepper` |
|
|
46
47
|
| `freeday-carousel` | `fdy-carousel-change` | `FreedayCarousel` |
|
|
47
48
|
| `freeday-breakpoint` | `fdy-breakpoint-change` | `FreedayBreakpoint` |
|