@cahyo-dimas/freeday 1.18.0 → 1.20.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +162 -0
  2. package/COMPONENTS.md +748 -0
  3. package/README.id.md +9 -1
  4. package/README.md +16 -2
  5. package/USAGE.md +34 -11
  6. package/adapters/blazor/FdyTable.razor.cs +66 -7
  7. package/adapters/blazor/TableTypes.cs +6 -0
  8. package/adapters/react/components/FdyTable.tsx +32 -8
  9. package/adapters/vue/components/FdyTable.vue +30 -6
  10. package/dist/freeday.bundle.css +35 -1
  11. package/dist/freeday.css +30 -0
  12. package/dist/freeday.tokens.css +5 -1
  13. package/docs/agent-onboarding.md +151 -0
  14. package/docs/getting-started.md +454 -0
  15. package/docs/integrations.md +321 -0
  16. package/docs/reference-screen.html +461 -0
  17. package/package.json +9 -3
  18. package/src/components/list.css +29 -0
  19. package/tokens/breakpoints.d.ts +3 -0
  20. package/tokens/breakpoints.mjs +8 -1
  21. package/src/components/.gitkeep +0 -0
  22. package/src/freeday-autocomplete.js +0 -135
  23. package/src/freeday-breakpoint.js +0 -51
  24. package/src/freeday-carousel.js +0 -111
  25. package/src/freeday-cascade.js +0 -256
  26. package/src/freeday-cfl.js +0 -213
  27. package/src/freeday-chart.js +0 -429
  28. package/src/freeday-chip.js +0 -83
  29. package/src/freeday-datepicker.js +0 -321
  30. package/src/freeday-datetime.js +0 -83
  31. package/src/freeday-drawer.js +0 -43
  32. package/src/freeday-form.js +0 -181
  33. package/src/freeday-mask.js +0 -114
  34. package/src/freeday-menu.js +0 -93
  35. package/src/freeday-popover.js +0 -69
  36. package/src/freeday-rating.js +0 -50
  37. package/src/freeday-select.js +0 -218
  38. package/src/freeday-slider.js +0 -34
  39. package/src/freeday-stepper.js +0 -90
  40. package/src/freeday-table.js +0 -475
  41. package/src/freeday-tabs.js +0 -68
  42. package/src/freeday-timepicker.js +0 -180
  43. package/src/freeday-toast.js +0 -105
  44. package/src/freeday-tree.js +0 -94
  45. package/src/freeday-upload.js +0 -206
@@ -1,218 +0,0 @@
1
- /* Freeday — combobox enhancer (optional, zero-dependency).
2
- * Implements the WAI-ARIA APG "select-only combobox" pattern for every
3
- * [data-fdy-combo] on the page. Progressive enhancement: the markup is the
4
- * component, this script wires behavior. In a Vue/React/Blazor app you would
5
- * bind your own state instead — this is the framework-agnostic reference.
6
- *
7
- * Expected markup:
8
- * <div class="fdy-combo" data-fdy-combo data-value="x">
9
- * <button type="button" class="fdy-combo__button" role="combobox"
10
- * aria-haspopup="listbox" aria-expanded="false"
11
- * aria-labelledby="LBL VAL">
12
- * <span class="fdy-combo__value" id="VAL">Label</span>
13
- * </button>
14
- * <ul class="fdy-combo__listbox" role="listbox" hidden>
15
- * <li class="fdy-combo__option" role="option" data-value="x"
16
- * aria-selected="true"><span class="fdy-combo__check">✓</span>Label</li>
17
- * </ul>
18
- * </div>
19
- *
20
- * Emits a bubbling "fdy-change" CustomEvent on the root with detail.value.
21
- */
22
- (function () {
23
- 'use strict';
24
-
25
- var seq = 0;
26
- var openClose = null; // close() of the currently-open combo, or null
27
-
28
- function optionLabel(opt) {
29
- var check = opt.querySelector('.fdy-combo__check');
30
- var node = check && check.nextSibling ? check.nextSibling.textContent : opt.textContent;
31
- return (node || '').trim();
32
- }
33
-
34
- function initCombo(root) {
35
- if (root.dataset.fdyComboReady === '1') return; // idempotent
36
- var button = root.querySelector('.fdy-combo__button');
37
- var listbox = root.querySelector('.fdy-combo__listbox');
38
- var valueEl = root.querySelector('.fdy-combo__value');
39
- var options = Array.prototype.slice.call(root.querySelectorAll('.fdy-combo__option'));
40
- if (!button || !listbox || !valueEl || options.length === 0) return;
41
- root.dataset.fdyComboReady = '1';
42
-
43
- seq += 1;
44
- if (!listbox.id) listbox.id = 'fdy-combo-list-' + seq;
45
- button.setAttribute('aria-controls', listbox.id);
46
- options.forEach(function (opt, i) {
47
- if (!opt.id) opt.id = listbox.id + '-opt-' + i;
48
- });
49
-
50
- var typed = '';
51
- var typedTimer = null;
52
-
53
- function highlightedIndex() {
54
- for (var i = 0; i < options.length; i++) {
55
- if (options[i].classList.contains('is-highlighted')) return i;
56
- }
57
- return -1;
58
- }
59
- function setHighlight(i) {
60
- options.forEach(function (opt, idx) {
61
- opt.classList.toggle('is-highlighted', idx === i);
62
- });
63
- if (i >= 0) {
64
- button.setAttribute('aria-activedescendant', options[i].id);
65
- options[i].scrollIntoView({ block: 'nearest' });
66
- } else {
67
- button.removeAttribute('aria-activedescendant');
68
- }
69
- }
70
- function isOpen() {
71
- return !listbox.hidden;
72
- }
73
- var _pop = null;
74
- function popCtl() { if (_pop === null && window.FreedayPopover) _pop = window.FreedayPopover.attach(listbox, button); return _pop; }
75
- function open() {
76
- if (openClose && openClose !== close) openClose();
77
- var p = popCtl(); if (p) p.show(); else listbox.hidden = false;
78
- button.classList.add('is-open');
79
- button.setAttribute('aria-expanded', 'true');
80
- var selected = options.findIndex(function (opt) {
81
- return opt.getAttribute('aria-selected') === 'true';
82
- });
83
- setHighlight(selected < 0 ? 0 : selected);
84
- openClose = close;
85
- }
86
- function close() {
87
- var p = popCtl(); if (p) p.hide(); else listbox.hidden = true;
88
- button.classList.remove('is-open');
89
- button.setAttribute('aria-expanded', 'false');
90
- button.removeAttribute('aria-activedescendant');
91
- setHighlight(-1);
92
- if (openClose === close) openClose = null;
93
- }
94
- // Mark an option selected + reflect it in the button. `silent` skips the change
95
- // event, close, and focus — used by the programmatic setValue() below so a host
96
- // (e.g. a Blazor/framework wrapper) can push a value in without echoing an event
97
- // back to itself or stealing focus. User-driven picks go through choose() (loud).
98
- function select(opt, silent) {
99
- options.forEach(function (other) {
100
- var on = other === opt;
101
- other.setAttribute('aria-selected', on ? 'true' : 'false');
102
- var check = other.querySelector('.fdy-combo__check');
103
- if (check) check.textContent = on ? '✓' : '';
104
- });
105
- root.setAttribute('data-value', opt.getAttribute('data-value') || '');
106
- valueEl.textContent = optionLabel(opt);
107
- valueEl.classList.remove('fdy-combo__value--placeholder');
108
- if (!silent) {
109
- root.dispatchEvent(new CustomEvent('fdy-change', {
110
- bubbles: true,
111
- detail: { value: opt.getAttribute('data-value') }
112
- }));
113
- close();
114
- button.focus();
115
- }
116
- }
117
- function choose(opt) { select(opt, false); }
118
- // Programmatic set (no event, no focus change). No-op if no option matches.
119
- function setValue(value) {
120
- for (var i = 0; i < options.length; i++) {
121
- if ((options[i].getAttribute('data-value') || '') === String(value)) {
122
- select(options[i], true);
123
- return;
124
- }
125
- }
126
- }
127
-
128
- button.addEventListener('click', function () {
129
- isOpen() ? close() : open();
130
- });
131
- // Pressing an option must not blur the button: a blur fires the focusout
132
- // handler below, which closes the listbox before the option's click lands —
133
- // so the pick is lost (real mouse only; synthetic .click() never blurs).
134
- // preventDefault on mousedown keeps focus on the button without blocking click.
135
- listbox.addEventListener('mousedown', function (e) { e.preventDefault(); });
136
- options.forEach(function (opt, i) {
137
- opt.addEventListener('click', function () { choose(opt); });
138
- opt.addEventListener('mousemove', function () { setHighlight(i); });
139
- });
140
-
141
- root.addEventListener('keydown', function (e) {
142
- var hi = highlightedIndex();
143
- switch (e.key) {
144
- case 'ArrowDown':
145
- e.preventDefault();
146
- isOpen() ? setHighlight((hi + 1) % options.length) : open();
147
- break;
148
- case 'ArrowUp':
149
- e.preventDefault();
150
- isOpen() ? setHighlight((hi - 1 + options.length) % options.length) : open();
151
- break;
152
- case 'Home':
153
- if (isOpen()) { e.preventDefault(); setHighlight(0); }
154
- break;
155
- case 'End':
156
- if (isOpen()) { e.preventDefault(); setHighlight(options.length - 1); }
157
- break;
158
- case 'Enter':
159
- case ' ':
160
- e.preventDefault();
161
- if (isOpen() && hi >= 0) choose(options[hi]); else open();
162
- break;
163
- case 'Escape':
164
- if (isOpen()) { e.preventDefault(); close(); button.focus(); }
165
- break;
166
- case 'Tab':
167
- if (isOpen()) close();
168
- break;
169
- default:
170
- if (e.key.length === 1 && /\S/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {
171
- typed += e.key.toLowerCase();
172
- clearTimeout(typedTimer);
173
- typedTimer = setTimeout(function () { typed = ''; }, 500);
174
- var match = options.findIndex(function (opt) {
175
- return optionLabel(opt).toLowerCase().indexOf(typed) === 0;
176
- });
177
- if (match >= 0) { if (!isOpen()) open(); setHighlight(match); }
178
- }
179
- }
180
- });
181
-
182
- // Close when focus leaves the whole combo (e.g. Shift+Tab off the button).
183
- root.addEventListener('focusout', function (e) {
184
- if (!root.contains(e.relatedTarget)) close();
185
- });
186
-
187
- // Per-instance API for programmatic control (host wrappers / two-way binding).
188
- root._fdyCombo = { setValue: setValue };
189
- }
190
-
191
- function initAll(context) {
192
- var scope = context || document;
193
- Array.prototype.forEach.call(
194
- scope.querySelectorAll('[data-fdy-combo]'),
195
- initCombo
196
- );
197
- }
198
-
199
- // One global handler closes the open combo on an outside click.
200
- document.addEventListener('click', function (e) {
201
- if (openClose && !(e.target.closest && e.target.closest('.fdy-combo'))) {
202
- openClose();
203
- }
204
- });
205
-
206
- if (document.readyState === 'loading') {
207
- document.addEventListener('DOMContentLoaded', function () { initAll(); });
208
- } else {
209
- initAll();
210
- }
211
-
212
- // Programmatic set on an already-initialised combo root (no fdy-change dispatched).
213
- function setValue(root, value) {
214
- if (root && root._fdyCombo) root._fdyCombo.setValue(value);
215
- }
216
-
217
- window.FreedayCombo = { init: initCombo, initAll: initAll, setValue: setValue };
218
- })();
@@ -1,34 +0,0 @@
1
- /* Freeday — slider value binding (optional, zero-dependency).
2
- * Mirrors a [data-fdy-slider] range input's value into <output for="inputId">, with an
3
- * optional prefix/suffix on the output (data-fdy-prefix / data-fdy-suffix). The range itself
4
- * is a native input — keyboard and ARIA are built in; this only updates the visible readout.
5
- */
6
- (function () {
7
- 'use strict';
8
-
9
- function formatted(out, value) {
10
- return (out.getAttribute('data-fdy-prefix') || '') + value + (out.getAttribute('data-fdy-suffix') || '');
11
- }
12
-
13
- function initSlider(input) {
14
- if (input.dataset.fdySliderReady === '1') return;
15
- input.dataset.fdySliderReady = '1';
16
- var out = input.id ? document.querySelector('output[for="' + input.id + '"]') : null;
17
- if (!out) return;
18
- function sync() { out.textContent = formatted(out, input.value); }
19
- input.addEventListener('input', sync);
20
- sync();
21
- }
22
-
23
- function initAll(context) {
24
- Array.prototype.forEach.call((context || document).querySelectorAll('[data-fdy-slider]'), initSlider);
25
- }
26
-
27
- if (document.readyState === 'loading') {
28
- document.addEventListener('DOMContentLoaded', function () { initAll(); });
29
- } else {
30
- initAll();
31
- }
32
-
33
- window.FreedaySlider = { init: initSlider, initAll: initAll };
34
- })();
@@ -1,90 +0,0 @@
1
- /* Freeday — stepper/wizard enhancer (optional, zero-dependency).
2
- * Drives a step header + panels: prev/next navigation, completed/active state, and
3
- * clicking a reached step to revisit it (linear — can't skip ahead). Auto-inits
4
- * [data-fdy-stepper].
5
- *
6
- * Markup: <div data-fdy-stepper>
7
- * <ol class="fdy-stepper">
8
- * <li class="fdy-step"><button class="fdy-step__btn"><span class="fdy-step__marker">1</span>
9
- * <span class="fdy-step__label">…</span></button></li>… </ol>
10
- * <div class="fdy-step-panels">
11
- * <div class="fdy-step-panel">…</div>… </div>
12
- * <div class="fdy-step-nav"><button data-fdy-step-prev>…</button>
13
- * <button data-fdy-step-next>…</button></div></div>
14
- * Emits bubbling "fdy-step-change" {index} and "fdy-step-finish" (Next on the last step).
15
- */
16
- (function () {
17
- 'use strict';
18
-
19
- var CHECK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"></path></svg>';
20
-
21
- function initStepper(root) {
22
- if (root.dataset.fdyStepperReady === '1') return;
23
- root.dataset.fdyStepperReady = '1';
24
-
25
- var steps = Array.prototype.slice.call(root.querySelectorAll('.fdy-step'));
26
- var panels = Array.prototype.slice.call(root.querySelectorAll('.fdy-step-panel'));
27
- var prevBtn = root.querySelector('[data-fdy-step-prev]');
28
- var nextBtn = root.querySelector('[data-fdy-step-next]');
29
- if (!steps.length) return;
30
-
31
- var active = 0;
32
- for (var i = 0; i < steps.length; i++) {
33
- if (steps[i].classList.contains('is-active')) { active = i; break; }
34
- }
35
- var maxReached = active;
36
- var nextLabel = nextBtn ? nextBtn.textContent : '';
37
-
38
- steps.forEach(function (s) {
39
- var marker = s.querySelector('.fdy-step__marker');
40
- if (marker && marker.dataset.num == null) marker.dataset.num = marker.textContent.trim();
41
- });
42
-
43
- function render() {
44
- steps.forEach(function (s, i) {
45
- s.classList.toggle('is-active', i === active);
46
- s.classList.toggle('is-complete', i < active);
47
- if (i === active) s.setAttribute('aria-current', 'step'); else s.removeAttribute('aria-current');
48
- var marker = s.querySelector('.fdy-step__marker');
49
- if (marker) marker.innerHTML = i < active ? CHECK : (marker.dataset.num || String(i + 1));
50
- var btn = s.querySelector('.fdy-step__btn');
51
- if (btn) btn.disabled = i > maxReached;
52
- });
53
- panels.forEach(function (p, i) { p.hidden = i !== active; });
54
- if (prevBtn) prevBtn.disabled = active === 0;
55
- if (nextBtn) nextBtn.textContent = active === steps.length - 1 ? 'Selesai' : (nextLabel || 'Lanjut');
56
- root.dispatchEvent(new CustomEvent('fdy-step-change', { bubbles: true, detail: { index: active } }));
57
- }
58
-
59
- function go(i) {
60
- if (i < 0 || i >= steps.length) return;
61
- active = i;
62
- if (active > maxReached) maxReached = active;
63
- render();
64
- }
65
-
66
- if (prevBtn) prevBtn.addEventListener('click', function () { go(active - 1); });
67
- if (nextBtn) nextBtn.addEventListener('click', function () {
68
- if (active < steps.length - 1) go(active + 1);
69
- else root.dispatchEvent(new CustomEvent('fdy-step-finish', { bubbles: true }));
70
- });
71
- steps.forEach(function (s, i) {
72
- var btn = s.querySelector('.fdy-step__btn');
73
- if (btn) btn.addEventListener('click', function () { if (i <= maxReached) go(i); });
74
- });
75
-
76
- render();
77
- }
78
-
79
- function initAll(context) {
80
- Array.prototype.forEach.call((context || document).querySelectorAll('[data-fdy-stepper]'), initStepper);
81
- }
82
-
83
- if (document.readyState === 'loading') {
84
- document.addEventListener('DOMContentLoaded', function () { initAll(); });
85
- } else {
86
- initAll();
87
- }
88
-
89
- window.FreedayStepper = { init: initStepper, initAll: initAll };
90
- })();