@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-search.js
CHANGED
package/dist/freeday-select.js
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
function initCombo(root) {
|
|
34
34
|
if (root.dataset.fdyComboReady === '1') return; // idempotent
|
|
35
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
35
36
|
var button = root.querySelector('.fdy-combo__button');
|
|
36
37
|
var listbox = root.querySelector('.fdy-combo__listbox');
|
|
37
38
|
var valueEl = root.querySelector('.fdy-combo__value');
|
package/dist/freeday-slider.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
function initSlider(input) {
|
|
14
14
|
if (input.dataset.fdySliderReady === '1') return;
|
|
15
|
+
if (input.closest('[data-fdy-ignore]')) return;
|
|
15
16
|
input.dataset.fdySliderReady = '1';
|
|
16
17
|
var out = input.id ? document.querySelector('output[for="' + input.id + '"]') : null;
|
|
17
18
|
if (!out) return;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/* Freeday, sortable list enhancer (optional, zero-dependency).
|
|
2
|
+
* Reorder the children of a list by dragging a handle, or by focusing it and pressing ↑ / ↓. The
|
|
3
|
+
* keyboard path is not an extra: drag-only reordering locks out every keyboard and screen-reader
|
|
4
|
+
* user from a settings screen, and that path is the part each app used to write for itself
|
|
5
|
+
* (CATATAN-FREEDAY §15).
|
|
6
|
+
*
|
|
7
|
+
* Markup contract:
|
|
8
|
+
* <ul class="fdy-sortable" data-fdy-sortable> (or a <tbody>, or a <div>)
|
|
9
|
+
* <li data-key="ketua" data-label="Ketua">
|
|
10
|
+
* <button class="fdy-sortable__handle" type="button">…icon…</button> Ketua
|
|
11
|
+
* </li>
|
|
12
|
+
* <li data-key="sistem" data-fdy-sort-fixed>…</li> (never moves, and nothing passes it)
|
|
13
|
+
* </ul>
|
|
14
|
+
* The items are the container's element children. `data-key` names each in the event; `data-label`
|
|
15
|
+
* is what the handle's default aria-label and the announcement call it (the item text otherwise).
|
|
16
|
+
* `data-disabled` on the container switches reordering off, e.g. while the list is filtered, and
|
|
17
|
+
* the handles follow it through aria-disabled.
|
|
18
|
+
*
|
|
19
|
+
* Emits a bubbling, CANCELABLE "fdy-sort-change" on the container, detail {key, from, to, order},
|
|
20
|
+
* `order` being every item's key in the new order. Not cancelled, the kit moves the element, which
|
|
21
|
+
* is the whole job on a static page. A framework that renders the list from state cancels it and
|
|
22
|
+
* reorders the state instead, because the DOM is the framework's and an element moved behind its
|
|
23
|
+
* back leaves the two disagreeing about where each row is. Either way the kit announces the move
|
|
24
|
+
* and, after a keyboard step, puts focus back on the moved item's handle (looked up by data-key,
|
|
25
|
+
* since a framework re-render may have replaced the element).
|
|
26
|
+
*
|
|
27
|
+
* The drag shows where the item will land (is-drop-before / is-drop-after on the item it lands
|
|
28
|
+
* against) and moves nothing until the pointer is released; Escape cancels it. Exposes
|
|
29
|
+
* window.FreedaySortable.
|
|
30
|
+
*/
|
|
31
|
+
(function () {
|
|
32
|
+
'use strict';
|
|
33
|
+
|
|
34
|
+
var TEXT = {
|
|
35
|
+
handle: 'Move {label}. Drag, or press the up and down arrow keys.',
|
|
36
|
+
moved: '{label} moved to position {position} of {total}.'
|
|
37
|
+
};
|
|
38
|
+
/* Kebab-cased for the lookup, see the note in freeday-upload.js. */
|
|
39
|
+
function textAttr(root, key) {
|
|
40
|
+
if (!root || !root.getAttribute) return null;
|
|
41
|
+
var kebab = root.getAttribute('data-fdy-text-' + key.replace(/[A-Z]/g, function (c) { return '-' + c.toLowerCase(); }));
|
|
42
|
+
return kebab != null && kebab !== '' ? kebab : root.getAttribute('data-fdy-text-' + key);
|
|
43
|
+
}
|
|
44
|
+
function textOf(root, key, vars) {
|
|
45
|
+
var custom = textAttr(root, key);
|
|
46
|
+
var s = custom != null && custom !== '' ? custom : TEXT[key];
|
|
47
|
+
for (var k in vars) if (Object.prototype.hasOwnProperty.call(vars, k)) s = s.split('{' + k + '}').join(vars[k]);
|
|
48
|
+
return s;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
var HANDLE = '.fdy-sortable__handle';
|
|
52
|
+
|
|
53
|
+
var live = null;
|
|
54
|
+
function announce(message) {
|
|
55
|
+
if (live === null) {
|
|
56
|
+
live = document.createElement('div');
|
|
57
|
+
live.className = 'fdy-visually-hidden';
|
|
58
|
+
live.setAttribute('aria-live', 'polite');
|
|
59
|
+
document.body.appendChild(live);
|
|
60
|
+
}
|
|
61
|
+
/* The same sentence twice in a row is no change, and a live region announces changes. */
|
|
62
|
+
live.textContent = live.textContent === message ? message + ' ' : message;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function items(root) {
|
|
66
|
+
return Array.prototype.slice.call(root.children);
|
|
67
|
+
}
|
|
68
|
+
function keyOf(item, index) {
|
|
69
|
+
var key = item.getAttribute('data-key');
|
|
70
|
+
return key !== null ? key : String(index);
|
|
71
|
+
}
|
|
72
|
+
function labelOf(item) {
|
|
73
|
+
var label = item.getAttribute('data-label');
|
|
74
|
+
return label !== null ? label : (item.textContent || '').replace(/\s+/g, ' ').trim();
|
|
75
|
+
}
|
|
76
|
+
function disabled(root) {
|
|
77
|
+
return root.hasAttribute('data-disabled');
|
|
78
|
+
}
|
|
79
|
+
function itemOf(root, node) {
|
|
80
|
+
for (var n = node; n && n !== root; n = n.parentElement) {
|
|
81
|
+
if (n.parentElement === root) return n;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* A move is allowed only if it shifts no fixed item, which is the same as saying the item does
|
|
87
|
+
not start fixed and does not cross one on its way. */
|
|
88
|
+
function allowed(list, from, to) {
|
|
89
|
+
if (from === to || to < 0 || to >= list.length) return false;
|
|
90
|
+
var lo = Math.min(from, to), hi = Math.max(from, to);
|
|
91
|
+
for (var i = lo; i <= hi; i++) if (list[i].hasAttribute('data-fdy-sort-fixed')) return false;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function syncHandles(root) {
|
|
96
|
+
var off = disabled(root) ? 'true' : 'false';
|
|
97
|
+
items(root).forEach(function (item) {
|
|
98
|
+
var handle = item.querySelector(HANDLE);
|
|
99
|
+
if (!handle) return;
|
|
100
|
+
if (handle.getAttribute('aria-disabled') !== off) handle.setAttribute('aria-disabled', off);
|
|
101
|
+
if (!handle.hasAttribute('aria-label')) handle.setAttribute('aria-label', textOf(root, 'handle', { label: labelOf(item) }));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function commit(root, from, to, refocus) {
|
|
106
|
+
var list = items(root);
|
|
107
|
+
var item = list[from];
|
|
108
|
+
var key = keyOf(item, from);
|
|
109
|
+
var keys = list.map(keyOf);
|
|
110
|
+
keys.splice(to, 0, keys.splice(from, 1)[0]);
|
|
111
|
+
var ev = new CustomEvent('fdy-sort-change', {
|
|
112
|
+
bubbles: true,
|
|
113
|
+
cancelable: true,
|
|
114
|
+
detail: { key: key, from: from, to: to, order: keys }
|
|
115
|
+
});
|
|
116
|
+
root.dispatchEvent(ev);
|
|
117
|
+
if (!ev.defaultPrevented) root.insertBefore(item, to > from ? list[to].nextSibling : list[to]);
|
|
118
|
+
announce(textOf(root, 'moved', { label: labelOf(item), position: String(to + 1), total: String(list.length) }));
|
|
119
|
+
if (!refocus) return;
|
|
120
|
+
/* After the app's own render, which a framework runs after this handler returns. Moving a focused
|
|
121
|
+
element drops its focus, and a keyed re-render may have replaced the element outright. */
|
|
122
|
+
setTimeout(function () {
|
|
123
|
+
var now = items(root);
|
|
124
|
+
var moved = item.parentElement === root ? item : now.filter(function (el, i) { return keyOf(el, i) === key; })[0];
|
|
125
|
+
var handle = moved ? moved.querySelector(HANDLE) : null;
|
|
126
|
+
if (handle && document.activeElement !== handle) handle.focus();
|
|
127
|
+
}, 0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function initSortable(root) {
|
|
131
|
+
if (root.dataset.fdySortableReady === '1') return;
|
|
132
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
133
|
+
root.dataset.fdySortableReady = '1';
|
|
134
|
+
syncHandles(root);
|
|
135
|
+
/* Rows a framework adds later get their aria-label, and data-disabled reaches every handle. */
|
|
136
|
+
new MutationObserver(function () { syncHandles(root); })
|
|
137
|
+
.observe(root, { childList: true, attributes: true, attributeFilter: ['data-disabled'] });
|
|
138
|
+
|
|
139
|
+
root.addEventListener('keydown', function (e) {
|
|
140
|
+
var handle = e.target.closest ? e.target.closest(HANDLE) : null;
|
|
141
|
+
if (!handle || !root.contains(handle) || disabled(root)) return;
|
|
142
|
+
if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return;
|
|
143
|
+
e.preventDefault();
|
|
144
|
+
var list = items(root);
|
|
145
|
+
var from = list.indexOf(itemOf(root, handle));
|
|
146
|
+
var to = from + (e.key === 'ArrowUp' ? -1 : 1);
|
|
147
|
+
if (from !== -1 && allowed(list, from, to)) commit(root, from, to, true);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
var drag = null;
|
|
151
|
+
|
|
152
|
+
function clearMarks() {
|
|
153
|
+
items(root).forEach(function (el) { el.classList.remove('is-drop-before', 'is-drop-after'); });
|
|
154
|
+
}
|
|
155
|
+
function end(apply) {
|
|
156
|
+
if (drag === null) return;
|
|
157
|
+
var d = drag;
|
|
158
|
+
drag = null;
|
|
159
|
+
document.removeEventListener('keydown', onEscape, true);
|
|
160
|
+
clearMarks();
|
|
161
|
+
d.item.classList.remove('is-dragging');
|
|
162
|
+
root.classList.remove('is-sorting');
|
|
163
|
+
if (apply && d.started && d.to !== null) commit(root, d.from, d.to, false);
|
|
164
|
+
}
|
|
165
|
+
function onEscape(e) {
|
|
166
|
+
if (e.key === 'Escape') { e.preventDefault(); end(false); }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
root.addEventListener('pointerdown', function (e) {
|
|
170
|
+
var handle = e.target.closest ? e.target.closest(HANDLE) : null;
|
|
171
|
+
if (!handle || !root.contains(handle) || disabled(root) || e.button !== 0) return;
|
|
172
|
+
var item = itemOf(root, handle);
|
|
173
|
+
if (!item) return;
|
|
174
|
+
e.preventDefault();
|
|
175
|
+
handle.focus();
|
|
176
|
+
handle.setPointerCapture(e.pointerId);
|
|
177
|
+
drag = { item: item, from: items(root).indexOf(item), started: false, to: null };
|
|
178
|
+
document.addEventListener('keydown', onEscape, true);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
root.addEventListener('pointermove', function (e) {
|
|
182
|
+
if (drag === null) return;
|
|
183
|
+
/* No travel threshold: a press that never leaves its own row resolves to to === from, which
|
|
184
|
+
allowed() refuses, so a click on the handle cannot reorder anything. */
|
|
185
|
+
if (!drag.started) {
|
|
186
|
+
drag.started = true;
|
|
187
|
+
drag.item.classList.add('is-dragging');
|
|
188
|
+
root.classList.add('is-sorting');
|
|
189
|
+
}
|
|
190
|
+
clearMarks();
|
|
191
|
+
drag.to = null;
|
|
192
|
+
var list = items(root);
|
|
193
|
+
var over = itemOf(root, document.elementFromPoint(e.clientX, e.clientY));
|
|
194
|
+
if (!over) return;
|
|
195
|
+
var rect = over.getBoundingClientRect();
|
|
196
|
+
var after = e.clientY > rect.top + rect.height / 2;
|
|
197
|
+
var slot = list.indexOf(over) + (after ? 1 : 0);
|
|
198
|
+
var to = slot > drag.from ? slot - 1 : slot;
|
|
199
|
+
if (!allowed(list, drag.from, to)) return;
|
|
200
|
+
drag.to = to;
|
|
201
|
+
over.classList.add(after ? 'is-drop-after' : 'is-drop-before');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
root.addEventListener('pointerup', function () { end(true); });
|
|
205
|
+
root.addEventListener('pointercancel', function () { end(false); });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function initAll(context) {
|
|
209
|
+
var root = context || document;
|
|
210
|
+
/* root included: querySelectorAll never matches its own root, and a framework ref often sits ON the widget. */
|
|
211
|
+
if (root.matches && root.matches('[data-fdy-sortable]')) initSortable(root);
|
|
212
|
+
Array.prototype.forEach.call(root.querySelectorAll('[data-fdy-sortable]'), initSortable);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (document.readyState === 'loading') {
|
|
216
|
+
document.addEventListener('DOMContentLoaded', function () { initAll(); });
|
|
217
|
+
} else {
|
|
218
|
+
initAll();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
window.FreedaySortable = { init: initSortable, initAll: initAll };
|
|
222
|
+
})();
|
package/dist/freeday-stepper.js
CHANGED
package/dist/freeday-table.js
CHANGED
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
|
|
78
78
|
function initTable(root) {
|
|
79
79
|
if (root.dataset.fdyTableReady === '1') return;
|
|
80
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
80
81
|
var table = root.querySelector('table.fdy-table');
|
|
81
82
|
var tbody = table && table.querySelector('tbody');
|
|
82
83
|
if (!table || !tbody) return;
|
package/dist/freeday-tabs.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
function initTabs(root) {
|
|
18
18
|
if (root.dataset.fdyTabsReady === '1') return;
|
|
19
|
+
if (root.closest('[data-fdy-ignore]')) return;
|
|
19
20
|
var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
|
|
20
21
|
if (tabs.length === 0) return;
|
|
21
22
|
root.dataset.fdyTabsReady = '1';
|
package/dist/freeday-tree.js
CHANGED
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
function initTree(tree) {
|
|
68
68
|
if (tree.dataset.fdyTreeReady === '1') return;
|
|
69
|
+
if (tree.closest('[data-fdy-ignore]')) return;
|
|
69
70
|
tree.dataset.fdyTreeReady = '1';
|
|
70
71
|
Array.prototype.forEach.call(tree.querySelectorAll('input[type="checkbox"]'), function (box) {
|
|
71
72
|
// A branch checkbox lives inside <summary>; keep its click from toggling the branch.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* Freeday, un-hydrated hook warning (optional, zero-dependency, no markup of its own).
|
|
2
|
+
* Every enhancer marks the element it took over (`data-fdy-*-ready`). Markup that no initAll()
|
|
3
|
+
* ever reached carries the hook and not the mark, and it fails in the worst way available: it
|
|
4
|
+
* renders, looks finished, and does nothing, with no error anywhere. A `data-fdy-validate` form
|
|
5
|
+
* outside the subtree handed to useFreeday() neither paints a message nor fires fdy-form-valid,
|
|
6
|
+
* so its save button reads as dead (CATATAN-FREEDAY §10). The enhancer knows the attribute is
|
|
7
|
+
* there; the person who wrote it does not.
|
|
8
|
+
*
|
|
9
|
+
* So on the first click, focus or submit inside such an element this logs ONE console.warn per
|
|
10
|
+
* element, naming the hook, with the element itself as the second argument so devtools links it.
|
|
11
|
+
* Interaction, not load, is the trigger on purpose: a framework mounts and hydrates in between,
|
|
12
|
+
* and only once a person is touching the widget is "not enhanced yet" the same as "never".
|
|
13
|
+
*
|
|
14
|
+
* HOOKS pairs each hook selector with the ready flag its enhancer stamps on THAT element and the
|
|
15
|
+
* namespace that owns it. A hook whose enhancer is not loaded is skipped: that is a different
|
|
16
|
+
* mistake, and this message would misname it. test/docs.test.mjs fails if an enhancer gains a
|
|
17
|
+
* ready flag this table does not list.
|
|
18
|
+
*
|
|
19
|
+
* `data-fdy-ignore` on an element or any ancestor is the sanctioned way out: every enhancer skips
|
|
20
|
+
* that subtree, and this stays quiet about it. It is for markup whose behaviour something else
|
|
21
|
+
* owns: the kit's own Vue/React FdyDrawer, and kit classes an app uses for their look
|
|
22
|
+
* alone (CATATAN-FREEDAY §14: a chip matrix the app drives itself).
|
|
23
|
+
*/
|
|
24
|
+
(function () {
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
var HOOKS = [
|
|
28
|
+
['[data-fdy-app]', 'fdyAppShellReady', 'FreedayAppShell'],
|
|
29
|
+
['[data-fdy-autocomplete]', 'fdyAcReady', 'FreedayAutocomplete'],
|
|
30
|
+
['[data-fdy-carousel]', 'fdyCarouselReady', 'FreedayCarousel'],
|
|
31
|
+
['[data-fdy-cascade]', 'fdyCascadeReady', 'FreedayCascade'],
|
|
32
|
+
['[data-fdy-cfl]', 'fdyCflBound', 'FreedayCfl'],
|
|
33
|
+
['[data-fdy-cfl-open]', 'fdyCflBound', 'FreedayCfl'],
|
|
34
|
+
['[data-fdy-chart]', 'fdyChartReady', 'FreedayChart'],
|
|
35
|
+
['[data-fdy-chips]', 'fdyChipsReady', 'FreedayChip'],
|
|
36
|
+
['.fdy-chip__remove', 'fdyChipRmReady', 'FreedayChip'],
|
|
37
|
+
['[data-fdy-datepicker]', 'fdyDpReady', 'FreedayDatepicker'],
|
|
38
|
+
['[data-fdy-daterange]', 'fdyDrReady', 'FreedayDatepicker'],
|
|
39
|
+
['[data-fdy-datetimepicker]', 'fdyDtReady', 'FreedayDatetime'],
|
|
40
|
+
['[data-fdy-drawer]', 'fdyDrawerBound', 'FreedayDrawer'],
|
|
41
|
+
['.fdy-drawer', 'fdyDrawerReady', 'FreedayDrawer'],
|
|
42
|
+
['[data-fdy-validate]', 'fdyFormReady', 'FreedayForm'],
|
|
43
|
+
['[data-fdy-mask]', 'fdyMaskReady', 'FreedayMask'],
|
|
44
|
+
['[data-fdy-password]', 'fdyPwReady', 'FreedayMask'],
|
|
45
|
+
['[data-fdy-menu]', 'fdyMenuReady', 'FreedayMenu'],
|
|
46
|
+
['[data-fdy-number]', 'fdyNumberReady', 'FreedayNumber'],
|
|
47
|
+
['[data-fdy-rating]', 'fdyRatingReady', 'FreedayRating'],
|
|
48
|
+
['[data-fdy-search]', 'fdySearchReady', 'FreedaySearch'],
|
|
49
|
+
['[data-fdy-combo]', 'fdyComboReady', 'FreedayCombo'],
|
|
50
|
+
['[data-fdy-slider]', 'fdySliderReady', 'FreedaySlider'],
|
|
51
|
+
['[data-fdy-sortable]', 'fdySortableReady', 'FreedaySortable'],
|
|
52
|
+
['[data-fdy-stepper]', 'fdyStepperReady', 'FreedayStepper'],
|
|
53
|
+
['[data-fdy-table]', 'fdyTableReady', 'FreedayTable'],
|
|
54
|
+
['[data-fdy-tabs]', 'fdyTabsReady', 'FreedayTabs'],
|
|
55
|
+
['[data-fdy-timepicker]', 'fdyTpReady', 'FreedayTimepicker'],
|
|
56
|
+
['[data-fdy-tree]', 'fdyTreeReady', 'FreedayTree'],
|
|
57
|
+
['[data-fdy-dropzone]', 'fdyUploadReady', 'FreedayUpload']
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
var warned = typeof WeakSet === 'function' ? new WeakSet() : null;
|
|
61
|
+
|
|
62
|
+
function check(e) {
|
|
63
|
+
if (!warned || !e.target || !e.target.closest) return;
|
|
64
|
+
for (var i = 0; i < HOOKS.length; i++) {
|
|
65
|
+
var hook = HOOKS[i];
|
|
66
|
+
if (!window[hook[2]]) continue;
|
|
67
|
+
var el = e.target.closest(hook[0]);
|
|
68
|
+
if (!el || el.dataset[hook[1]] === '1' || warned.has(el) || el.closest('[data-fdy-ignore]')) continue;
|
|
69
|
+
warned.add(el);
|
|
70
|
+
console.warn('Freeday: this ' + hook[0] + ' was never enhanced, so it does nothing. Either it is '
|
|
71
|
+
+ 'outside every initAll() scope (Vue/React: inside the element given to useFreeday(); Blazor: '
|
|
72
|
+
+ 'FreedayBlazor.initAll after render; anything else: ' + hook[2] + '.initAll(el) once it is in '
|
|
73
|
+
+ 'the DOM), or its markup lacks a part the enhancer needs (see COMPONENTS.md). If the app '
|
|
74
|
+
+ 'drives this element itself on purpose, mark it or an ancestor data-fdy-ignore.', el);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
['click', 'focusin', 'submit'].forEach(function (type) {
|
|
79
|
+
document.addEventListener(type, check, true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
window.FreedayUnhydrated = { hooks: HOOKS };
|
|
83
|
+
})();
|
package/dist/freeday-upload.js
CHANGED
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* Emits bubbling CustomEvents. BOTH on the dropzone element, which is the one target a consumer
|
|
19
19
|
* needs to listen on:
|
|
20
20
|
* "fdy-upload-add" {file, rejected, reason, row}
|
|
21
|
-
* "fdy-upload-remove" {file}
|
|
21
|
+
* "fdy-upload-remove" {file}, cancelable: preventDefault() keeps the row (e.g. to confirm
|
|
22
|
+
* removing a file the server already holds, then call row.el.remove())
|
|
22
23
|
* `row` is the state machine over the rendered .fdy-file:
|
|
23
24
|
* .ready() (rest, where a dropped file starts) / .uploading() / .setProgress(pct) /
|
|
24
25
|
* .waiting(label) (sent, awaiting the server) / .done() / .fail(msg) / .el
|
|
@@ -111,8 +112,9 @@
|
|
|
111
112
|
Firing on both would look safer, but it makes the pair asymmetric, one `add` and, for
|
|
112
113
|
anyone delegating on a common ancestor, two `remove`s, which is its own silent bug. It
|
|
113
114
|
also fixes the listless case: a row that was never attached bubbles to nothing at all. */
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
var ev = new CustomEvent('fdy-upload-remove', { bubbles: true, cancelable: true, detail: { file: file } });
|
|
116
|
+
zone.dispatchEvent(ev);
|
|
117
|
+
if (!ev.defaultPrevented) el.remove();
|
|
116
118
|
});
|
|
117
119
|
el.appendChild(icon);
|
|
118
120
|
el.appendChild(meta);
|
|
@@ -226,6 +228,7 @@
|
|
|
226
228
|
|
|
227
229
|
function initDropzone(zone) {
|
|
228
230
|
if (zone.dataset.fdyUploadReady === '1') return;
|
|
231
|
+
if (zone.closest('[data-fdy-ignore]')) return;
|
|
229
232
|
zone.dataset.fdyUploadReady = '1';
|
|
230
233
|
|
|
231
234
|
var input = zone.querySelector('input[type="file"]');
|
package/dist/freeday.bundle.css
CHANGED
|
@@ -2696,7 +2696,8 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
2696
2696
|
remember to mark aria-hidden, and it cannot be forgotten. */
|
|
2697
2697
|
.fdy-label--required::after{content:"*" / "";margin-left:var(--space-1);color:var(--color-danger);}
|
|
2698
2698
|
.fdy-help{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
2699
|
-
|
|
2699
|
+
/* --danger is the tone word everywhere else in the kit; help text takes either (CATATAN-FREEDAY §11). */
|
|
2700
|
+
.fdy-help--error,.fdy-help--danger{color:var(--color-danger);}
|
|
2700
2701
|
|
|
2701
2702
|
/* Freeday. Keyboard key */
|
|
2702
2703
|
.fdy-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:1.5rem;height:1.5rem;padding:0 var(--space-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text);background:var(--color-surface-2);border:var(--bw) solid var(--color-border-strong);border-bottom-width:2px;border-radius:var(--radius-sm);}
|
|
@@ -2899,6 +2900,24 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
2899
2900
|
.fdy-slider__value{font-family:var(--font-mono);font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-primary-strong);font-variant-numeric:tabular-nums;}
|
|
2900
2901
|
.fdy-slider__scale{display:flex;justify-content:space-between;font-size:var(--text-xs);color:var(--color-text-muted);font-variant-numeric:tabular-nums;}
|
|
2901
2902
|
|
|
2903
|
+
/* Freeday. Sortable list (freeday-sortable.js). The kit styles the handle and the drag states only;
|
|
2904
|
+
* the list itself is whatever it already was: .fdy-list, a table body, plain rows.
|
|
2905
|
+
*
|
|
2906
|
+
* The handle is a control-height square so a thumb can hold it on a phone, and `touch-action:none`
|
|
2907
|
+
* keeps that drag from scrolling the page. Its glyph is the only thing marking it as a control, so
|
|
2908
|
+
* it takes --color-text-muted, not --color-text-subtle: a non-text control still owes 3:1. */
|
|
2909
|
+
.fdy-sortable__handle{display:inline-flex;flex:none;align-items:center;justify-content:center;width:var(--control-h);height:var(--control-h);padding:0;border:0;border-radius:var(--radius-md);background:transparent;color:var(--color-text-muted);cursor:grab;touch-action:none;}
|
|
2910
|
+
.fdy-sortable__handle:hover{background:var(--color-surface-2);color:var(--color-text);}
|
|
2911
|
+
.fdy-sortable__handle:active{cursor:grabbing;}
|
|
2912
|
+
.fdy-sortable__handle[aria-disabled="true"]{cursor:not-allowed;opacity:.4;}
|
|
2913
|
+
.fdy-sortable__handle[aria-disabled="true"]:hover{background:transparent;color:var(--color-text-muted);}
|
|
2914
|
+
.fdy-sortable.is-sorting{-webkit-user-select:none;user-select:none;}
|
|
2915
|
+
.fdy-sortable > .is-dragging{opacity:.45;}
|
|
2916
|
+
/* The landing line. On a table row it is drawn on the cells: a box-shadow on a <tr> is not painted
|
|
2917
|
+
* by every engine the kit supports. */
|
|
2918
|
+
.fdy-sortable > :not(tr).is-drop-before,.fdy-sortable > tr.is-drop-before > *{box-shadow:inset 0 var(--focus-ring-width) 0 var(--color-primary);}
|
|
2919
|
+
.fdy-sortable > :not(tr).is-drop-after,.fdy-sortable > tr.is-drop-after > *{box-shadow:inset 0 calc(var(--focus-ring-width) * -1) 0 var(--color-primary);}
|
|
2920
|
+
|
|
2902
2921
|
/* Freeday. Spinner */
|
|
2903
2922
|
.fdy-spinner{display:inline-block;width:1.5rem;height:1.5rem;border:2.5px solid var(--color-border-strong);border-top-color:var(--color-primary);border-radius:var(--radius-full);animation:fdy-spin .7s linear infinite;}
|
|
2904
2923
|
.fdy-spinner--sm{width:1rem;height:1rem;border-width:2px;}
|
package/dist/freeday.css
CHANGED
|
@@ -1519,7 +1519,8 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1519
1519
|
remember to mark aria-hidden, and it cannot be forgotten. */
|
|
1520
1520
|
.fdy-label--required::after{content:"*" / "";margin-left:var(--space-1);color:var(--color-danger);}
|
|
1521
1521
|
.fdy-help{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
1522
|
-
|
|
1522
|
+
/* --danger is the tone word everywhere else in the kit; help text takes either (CATATAN-FREEDAY §11). */
|
|
1523
|
+
.fdy-help--error,.fdy-help--danger{color:var(--color-danger);}
|
|
1523
1524
|
|
|
1524
1525
|
/* Freeday. Keyboard key */
|
|
1525
1526
|
.fdy-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:1.5rem;height:1.5rem;padding:0 var(--space-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text);background:var(--color-surface-2);border:var(--bw) solid var(--color-border-strong);border-bottom-width:2px;border-radius:var(--radius-sm);}
|
|
@@ -1722,6 +1723,24 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1722
1723
|
.fdy-slider__value{font-family:var(--font-mono);font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-primary-strong);font-variant-numeric:tabular-nums;}
|
|
1723
1724
|
.fdy-slider__scale{display:flex;justify-content:space-between;font-size:var(--text-xs);color:var(--color-text-muted);font-variant-numeric:tabular-nums;}
|
|
1724
1725
|
|
|
1726
|
+
/* Freeday. Sortable list (freeday-sortable.js). The kit styles the handle and the drag states only;
|
|
1727
|
+
* the list itself is whatever it already was: .fdy-list, a table body, plain rows.
|
|
1728
|
+
*
|
|
1729
|
+
* The handle is a control-height square so a thumb can hold it on a phone, and `touch-action:none`
|
|
1730
|
+
* keeps that drag from scrolling the page. Its glyph is the only thing marking it as a control, so
|
|
1731
|
+
* it takes --color-text-muted, not --color-text-subtle: a non-text control still owes 3:1. */
|
|
1732
|
+
.fdy-sortable__handle{display:inline-flex;flex:none;align-items:center;justify-content:center;width:var(--control-h);height:var(--control-h);padding:0;border:0;border-radius:var(--radius-md);background:transparent;color:var(--color-text-muted);cursor:grab;touch-action:none;}
|
|
1733
|
+
.fdy-sortable__handle:hover{background:var(--color-surface-2);color:var(--color-text);}
|
|
1734
|
+
.fdy-sortable__handle:active{cursor:grabbing;}
|
|
1735
|
+
.fdy-sortable__handle[aria-disabled="true"]{cursor:not-allowed;opacity:.4;}
|
|
1736
|
+
.fdy-sortable__handle[aria-disabled="true"]:hover{background:transparent;color:var(--color-text-muted);}
|
|
1737
|
+
.fdy-sortable.is-sorting{-webkit-user-select:none;user-select:none;}
|
|
1738
|
+
.fdy-sortable > .is-dragging{opacity:.45;}
|
|
1739
|
+
/* The landing line. On a table row it is drawn on the cells: a box-shadow on a <tr> is not painted
|
|
1740
|
+
* by every engine the kit supports. */
|
|
1741
|
+
.fdy-sortable > :not(tr).is-drop-before,.fdy-sortable > tr.is-drop-before > *{box-shadow:inset 0 var(--focus-ring-width) 0 var(--color-primary);}
|
|
1742
|
+
.fdy-sortable > :not(tr).is-drop-after,.fdy-sortable > tr.is-drop-after > *{box-shadow:inset 0 calc(var(--focus-ring-width) * -1) 0 var(--color-primary);}
|
|
1743
|
+
|
|
1725
1744
|
/* Freeday. Spinner */
|
|
1726
1745
|
.fdy-spinner{display:inline-block;width:1.5rem;height:1.5rem;border:2.5px solid var(--color-border-strong);border-top-color:var(--color-primary);border-radius:var(--radius-full);animation:fdy-spin .7s linear infinite;}
|
|
1727
1746
|
.fdy-spinner--sm{width:1rem;height:1rem;border-width:2px;}
|