@cahyo-dimas/freeday 1.15.0 → 1.17.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 +52 -0
- package/README.id.md +18 -8
- package/README.md +18 -8
- package/adapters/blazor/CflTypes.cs +11 -0
- package/adapters/blazor/FdyAutocomplete.razor +19 -0
- package/adapters/blazor/FdyAutocomplete.razor.cs +40 -0
- package/adapters/blazor/FdyCascade.razor +33 -0
- package/adapters/blazor/FdyCascade.razor.cs +38 -0
- package/adapters/blazor/FdyCascadeNode.cs +8 -0
- package/adapters/blazor/FdyCfl.razor +93 -0
- package/adapters/blazor/FdyCfl.razor.cs +146 -0
- package/adapters/blazor/FdyChart.razor +25 -0
- package/adapters/blazor/FdyChart.razor.cs +90 -0
- package/adapters/blazor/FdyChartSeries.cs +10 -0
- package/adapters/blazor/FdyCombo.razor +28 -0
- package/adapters/blazor/FdyCombo.razor.cs +86 -0
- package/adapters/blazor/FdyComboOption.cs +7 -0
- package/adapters/blazor/FdyDateRange.razor +16 -0
- package/adapters/blazor/FdyDateRange.razor.cs +58 -0
- package/adapters/blazor/FdyDatepicker.razor +13 -0
- package/adapters/blazor/FdyDatepicker.razor.cs +39 -0
- package/adapters/blazor/FdyDrawer.razor +36 -0
- package/adapters/blazor/FdyDrawer.razor.cs +88 -0
- package/adapters/blazor/FdyModal.razor +36 -0
- package/adapters/blazor/FdyModal.razor.cs +88 -0
- package/adapters/blazor/FdyTable.razor +140 -0
- package/adapters/blazor/FdyTable.razor.cs +200 -0
- package/adapters/blazor/FdyTableFilter.razor +77 -0
- package/adapters/blazor/FdyTableFilter.razor.cs +117 -0
- package/adapters/blazor/Freeday.Blazor.csproj +27 -0
- package/adapters/blazor/FreedayComponentBase.cs +73 -0
- package/adapters/blazor/TableModel.cs +196 -0
- package/adapters/blazor/TableTypes.cs +69 -0
- package/adapters/blazor/_Imports.razor +5 -0
- package/adapters/blazor/freeday-blazor.js +101 -3
- package/dist/freeday-select.js +32 -8
- package/dist/freeday-toast.js +22 -1
- package/dist/freeday.bundle.css +27 -0
- package/dist/freeday.css +27 -0
- package/dist/freeday.d.ts +5 -0
- package/dist/freeday.js +54 -9
- package/package.json +1 -1
- package/src/base.css +5 -0
- package/src/components/avatar.css +13 -0
- package/src/components/card.css +4 -0
- package/src/components/skeleton.css +5 -0
- package/src/freeday-select.js +32 -8
- package/src/freeday-toast.js +22 -1
package/dist/freeday.js
CHANGED
|
@@ -2340,7 +2340,11 @@
|
|
|
2340
2340
|
setHighlight(-1);
|
|
2341
2341
|
if (openClose === close) openClose = null;
|
|
2342
2342
|
}
|
|
2343
|
-
|
|
2343
|
+
// Mark an option selected + reflect it in the button. `silent` skips the change
|
|
2344
|
+
// event, close, and focus — used by the programmatic setValue() below so a host
|
|
2345
|
+
// (e.g. a Blazor/framework wrapper) can push a value in without echoing an event
|
|
2346
|
+
// back to itself or stealing focus. User-driven picks go through choose() (loud).
|
|
2347
|
+
function select(opt, silent) {
|
|
2344
2348
|
options.forEach(function (other) {
|
|
2345
2349
|
var on = other === opt;
|
|
2346
2350
|
other.setAttribute('aria-selected', on ? 'true' : 'false');
|
|
@@ -2350,12 +2354,24 @@
|
|
|
2350
2354
|
root.setAttribute('data-value', opt.getAttribute('data-value') || '');
|
|
2351
2355
|
valueEl.textContent = optionLabel(opt);
|
|
2352
2356
|
valueEl.classList.remove('fdy-combo__value--placeholder');
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2357
|
+
if (!silent) {
|
|
2358
|
+
root.dispatchEvent(new CustomEvent('fdy-change', {
|
|
2359
|
+
bubbles: true,
|
|
2360
|
+
detail: { value: opt.getAttribute('data-value') }
|
|
2361
|
+
}));
|
|
2362
|
+
close();
|
|
2363
|
+
button.focus();
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
function choose(opt) { select(opt, false); }
|
|
2367
|
+
// Programmatic set (no event, no focus change). No-op if no option matches.
|
|
2368
|
+
function setValue(value) {
|
|
2369
|
+
for (var i = 0; i < options.length; i++) {
|
|
2370
|
+
if ((options[i].getAttribute('data-value') || '') === String(value)) {
|
|
2371
|
+
select(options[i], true);
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2359
2375
|
}
|
|
2360
2376
|
|
|
2361
2377
|
button.addEventListener('click', function () {
|
|
@@ -2416,6 +2432,9 @@
|
|
|
2416
2432
|
root.addEventListener('focusout', function (e) {
|
|
2417
2433
|
if (!root.contains(e.relatedTarget)) close();
|
|
2418
2434
|
});
|
|
2435
|
+
|
|
2436
|
+
// Per-instance API for programmatic control (host wrappers / two-way binding).
|
|
2437
|
+
root._fdyCombo = { setValue: setValue };
|
|
2419
2438
|
}
|
|
2420
2439
|
|
|
2421
2440
|
function initAll(context) {
|
|
@@ -2439,7 +2458,12 @@
|
|
|
2439
2458
|
initAll();
|
|
2440
2459
|
}
|
|
2441
2460
|
|
|
2442
|
-
|
|
2461
|
+
// Programmatic set on an already-initialised combo root (no fdy-change dispatched).
|
|
2462
|
+
function setValue(root, value) {
|
|
2463
|
+
if (root && root._fdyCombo) root._fdyCombo.setValue(value);
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
window.FreedayCombo = { init: initCombo, initAll: initAll, setValue: setValue };
|
|
2443
2467
|
})();
|
|
2444
2468
|
|
|
2445
2469
|
/* Freeday — slider value binding (optional, zero-dependency).
|
|
@@ -3295,16 +3319,26 @@
|
|
|
3295
3319
|
})();
|
|
3296
3320
|
|
|
3297
3321
|
/* Freeday — toast API (optional, zero-dependency).
|
|
3298
|
-
* Freeday.toast({ variant, title, message, timeout }) shows a transient
|
|
3322
|
+
* Freeday.toast({ variant, title, message, timeout, key }) shows a transient
|
|
3299
3323
|
* notification in a live region (created on first use). Returns the element.
|
|
3300
3324
|
* variant: 'success' | 'warning' | 'danger' | 'info' (default: neutral)
|
|
3301
3325
|
* timeout: ms before auto-dismiss (default 4000; 0 = sticky)
|
|
3326
|
+
* key: optional stable id — a new toast with the same key REPLACES the
|
|
3327
|
+
* existing one in place instead of stacking a duplicate (e.g. a burst
|
|
3328
|
+
* of identical failures shows one toast, refreshed).
|
|
3329
|
+
* Freeday.dismiss(nodeOrKey) closes a toast early (pass the returned element or its key).
|
|
3302
3330
|
* Danger toasts use role="alert"; others role="status".
|
|
3303
3331
|
*/
|
|
3304
3332
|
(function () {
|
|
3305
3333
|
'use strict';
|
|
3306
3334
|
|
|
3307
3335
|
var region = null;
|
|
3336
|
+
var keyed = {}; // key -> current node, for replace-in-place + dismiss-by-key
|
|
3337
|
+
|
|
3338
|
+
function forget(node) {
|
|
3339
|
+
var k = node && node._fdyKey;
|
|
3340
|
+
if (k != null && keyed[k] === node) delete keyed[k];
|
|
3341
|
+
}
|
|
3308
3342
|
|
|
3309
3343
|
function ensureRegion() {
|
|
3310
3344
|
if (region && document.body.contains(region)) return region;
|
|
@@ -3320,7 +3354,9 @@
|
|
|
3320
3354
|
}
|
|
3321
3355
|
|
|
3322
3356
|
function dismiss(toast) {
|
|
3357
|
+
if (typeof toast === 'string') toast = keyed[toast]; // dismiss by key
|
|
3323
3358
|
if (!toast || toast.dataset.leaving === '1') return;
|
|
3359
|
+
forget(toast);
|
|
3324
3360
|
toast.dataset.leaving = '1';
|
|
3325
3361
|
toast.classList.add('is-leaving');
|
|
3326
3362
|
var remove = function () { if (toast.parentNode) toast.parentNode.removeChild(toast); };
|
|
@@ -3360,6 +3396,14 @@
|
|
|
3360
3396
|
node.appendChild(accent);
|
|
3361
3397
|
node.appendChild(body);
|
|
3362
3398
|
node.appendChild(close);
|
|
3399
|
+
|
|
3400
|
+
// Replace-in-place: a same-key toast removes the previous one so bursts don't stack.
|
|
3401
|
+
if (opts.key != null) {
|
|
3402
|
+
var prev = keyed[opts.key];
|
|
3403
|
+
if (prev && prev.parentNode) prev.parentNode.removeChild(prev);
|
|
3404
|
+
node._fdyKey = opts.key;
|
|
3405
|
+
keyed[opts.key] = node;
|
|
3406
|
+
}
|
|
3363
3407
|
region.appendChild(node);
|
|
3364
3408
|
|
|
3365
3409
|
var timeout = opts.timeout == null ? 4000 : opts.timeout;
|
|
@@ -3377,6 +3421,7 @@
|
|
|
3377
3421
|
|
|
3378
3422
|
window.Freeday = window.Freeday || {};
|
|
3379
3423
|
window.Freeday.toast = toast;
|
|
3424
|
+
window.Freeday.dismiss = dismiss; // dismiss(nodeOrKey)
|
|
3380
3425
|
})();
|
|
3381
3426
|
|
|
3382
3427
|
/* Freeday — tree checkbox cascade (optional, zero-dependency).
|
package/package.json
CHANGED
package/src/base.css
CHANGED
|
@@ -15,6 +15,11 @@ a { color: var(--color-primary); }
|
|
|
15
15
|
:focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring); outline-offset: var(--focus-ring-width); border-radius: var(--radius-xs); }
|
|
16
16
|
:where(button, input, select, textarea) { font: inherit; }
|
|
17
17
|
.fdy-visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
18
|
+
/* Opt-in list reset. base.css is intentionally a *light* reset — it does NOT strip list/paragraph
|
|
19
|
+
* margins (see the kit's own list components, which each reset themselves). If you run a utility
|
|
20
|
+
* framework with its preflight OFF (the recommended pairing), a semantic <ul>/<ol> keeps native
|
|
21
|
+
* bullets + a 40px indent; add this class (or a Freeday list component) to normalise it. */
|
|
22
|
+
.fdy-list-reset { list-style: none; margin: 0; padding: 0; }
|
|
18
23
|
@media (prefers-reduced-motion: reduce) {
|
|
19
24
|
*, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
|
|
20
25
|
}
|
|
@@ -6,3 +6,16 @@
|
|
|
6
6
|
.fdy-avatar-group{display:inline-flex;}
|
|
7
7
|
.fdy-avatar-group .fdy-avatar{border:2px solid var(--color-surface);margin-left:calc(var(--space-2)*-1);}
|
|
8
8
|
.fdy-avatar-group .fdy-avatar:first-child{margin-left:0;}
|
|
9
|
+
/* Decorative identity tones — a soft tint of a categorical chart colour with a theme-aware,
|
|
10
|
+
* text-leaning foreground so initials keep WCAG AA (verified >=4.5:1 in light & dark by
|
|
11
|
+
* test/contrast.test.mjs). Use to disambiguate same-initial avatars (e.g. many "PT …" names):
|
|
12
|
+
* hash a stable 1..8 index off the FULL name in your app, then apply .fdy-avatar--tone-<n>. */
|
|
13
|
+
.fdy-avatar--tone-1,.fdy-avatar--tone-2,.fdy-avatar--tone-3,.fdy-avatar--tone-4,.fdy-avatar--tone-5,.fdy-avatar--tone-6,.fdy-avatar--tone-7,.fdy-avatar--tone-8{background:color-mix(in srgb,var(--_fdy-avatar-tone) 18%,var(--color-surface));color:color-mix(in srgb,var(--_fdy-avatar-tone) 50%,var(--color-text));}
|
|
14
|
+
.fdy-avatar--tone-1{--_fdy-avatar-tone:var(--chart-1);}
|
|
15
|
+
.fdy-avatar--tone-2{--_fdy-avatar-tone:var(--chart-2);}
|
|
16
|
+
.fdy-avatar--tone-3{--_fdy-avatar-tone:var(--chart-3);}
|
|
17
|
+
.fdy-avatar--tone-4{--_fdy-avatar-tone:var(--chart-4);}
|
|
18
|
+
.fdy-avatar--tone-5{--_fdy-avatar-tone:var(--chart-5);}
|
|
19
|
+
.fdy-avatar--tone-6{--_fdy-avatar-tone:var(--chart-6);}
|
|
20
|
+
.fdy-avatar--tone-7{--_fdy-avatar-tone:var(--chart-7);}
|
|
21
|
+
.fdy-avatar--tone-8{--_fdy-avatar-tone:var(--chart-8);}
|
package/src/components/card.css
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
.fdy-card--elevated{box-shadow:var(--shadow-lift-hover);}
|
|
4
4
|
.fdy-card--interactive{cursor:pointer;}
|
|
5
5
|
.fdy-card--interactive:hover{box-shadow:var(--shadow-lift-hover);transform:translateY(-3px);}
|
|
6
|
+
/* When the whole card IS the control — a real <button> so the row is keyboard-reachable and
|
|
7
|
+
* announced — reset the UA button box. Note: it does NOT reset background/border, because
|
|
8
|
+
* .fdy-card already sets its own surface + border (resetting them here would strip the card). */
|
|
9
|
+
.fdy-card--button{display:block;width:100%;text-align:inherit;color:inherit;appearance:none;-webkit-appearance:none;}
|
|
6
10
|
.fdy-card__body{padding:var(--space-5);}
|
|
7
11
|
.fdy-card__title{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-tight);color:var(--color-text);margin:0 0 var(--space-1);}
|
|
8
12
|
.fdy-card__desc{font-size:var(--text-sm);color:var(--color-text-muted);margin:0;line-height:var(--leading-normal);}
|
|
@@ -3,5 +3,10 @@
|
|
|
3
3
|
.fdy-skeleton--text{height:.8rem;margin:.3rem 0;}
|
|
4
4
|
.fdy-skeleton--title{height:1.2rem;width:40%;}
|
|
5
5
|
.fdy-skeleton--circle{border-radius:var(--radius-full);}
|
|
6
|
+
/* Size-matched to .fdy-avatar (2.5rem) and its --sm/--lg, so a skeleton reserves the exact avatar
|
|
7
|
+
* box and data landing causes no layout shift (a plain --circle has no dimensions of its own). */
|
|
8
|
+
.fdy-skeleton--avatar{width:2.5rem;height:2.5rem;border-radius:var(--radius-full);}
|
|
9
|
+
.fdy-skeleton--avatar-sm{width:2rem;height:2rem;border-radius:var(--radius-full);}
|
|
10
|
+
.fdy-skeleton--avatar-lg{width:3.5rem;height:3.5rem;border-radius:var(--radius-full);}
|
|
6
11
|
@keyframes fdy-skeleton{to{background-position:-200% 0;}}
|
|
7
12
|
@media (prefers-reduced-motion:reduce){.fdy-skeleton{animation:none;}}
|
package/src/freeday-select.js
CHANGED
|
@@ -91,7 +91,11 @@
|
|
|
91
91
|
setHighlight(-1);
|
|
92
92
|
if (openClose === close) openClose = null;
|
|
93
93
|
}
|
|
94
|
-
|
|
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) {
|
|
95
99
|
options.forEach(function (other) {
|
|
96
100
|
var on = other === opt;
|
|
97
101
|
other.setAttribute('aria-selected', on ? 'true' : 'false');
|
|
@@ -101,12 +105,24 @@
|
|
|
101
105
|
root.setAttribute('data-value', opt.getAttribute('data-value') || '');
|
|
102
106
|
valueEl.textContent = optionLabel(opt);
|
|
103
107
|
valueEl.classList.remove('fdy-combo__value--placeholder');
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
+
}
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
button.addEventListener('click', function () {
|
|
@@ -167,6 +183,9 @@
|
|
|
167
183
|
root.addEventListener('focusout', function (e) {
|
|
168
184
|
if (!root.contains(e.relatedTarget)) close();
|
|
169
185
|
});
|
|
186
|
+
|
|
187
|
+
// Per-instance API for programmatic control (host wrappers / two-way binding).
|
|
188
|
+
root._fdyCombo = { setValue: setValue };
|
|
170
189
|
}
|
|
171
190
|
|
|
172
191
|
function initAll(context) {
|
|
@@ -190,5 +209,10 @@
|
|
|
190
209
|
initAll();
|
|
191
210
|
}
|
|
192
211
|
|
|
193
|
-
|
|
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 };
|
|
194
218
|
})();
|
package/src/freeday-toast.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
/* Freeday — toast API (optional, zero-dependency).
|
|
2
|
-
* Freeday.toast({ variant, title, message, timeout }) shows a transient
|
|
2
|
+
* Freeday.toast({ variant, title, message, timeout, key }) shows a transient
|
|
3
3
|
* notification in a live region (created on first use). Returns the element.
|
|
4
4
|
* variant: 'success' | 'warning' | 'danger' | 'info' (default: neutral)
|
|
5
5
|
* timeout: ms before auto-dismiss (default 4000; 0 = sticky)
|
|
6
|
+
* key: optional stable id — a new toast with the same key REPLACES the
|
|
7
|
+
* existing one in place instead of stacking a duplicate (e.g. a burst
|
|
8
|
+
* of identical failures shows one toast, refreshed).
|
|
9
|
+
* Freeday.dismiss(nodeOrKey) closes a toast early (pass the returned element or its key).
|
|
6
10
|
* Danger toasts use role="alert"; others role="status".
|
|
7
11
|
*/
|
|
8
12
|
(function () {
|
|
9
13
|
'use strict';
|
|
10
14
|
|
|
11
15
|
var region = null;
|
|
16
|
+
var keyed = {}; // key -> current node, for replace-in-place + dismiss-by-key
|
|
17
|
+
|
|
18
|
+
function forget(node) {
|
|
19
|
+
var k = node && node._fdyKey;
|
|
20
|
+
if (k != null && keyed[k] === node) delete keyed[k];
|
|
21
|
+
}
|
|
12
22
|
|
|
13
23
|
function ensureRegion() {
|
|
14
24
|
if (region && document.body.contains(region)) return region;
|
|
@@ -24,7 +34,9 @@
|
|
|
24
34
|
}
|
|
25
35
|
|
|
26
36
|
function dismiss(toast) {
|
|
37
|
+
if (typeof toast === 'string') toast = keyed[toast]; // dismiss by key
|
|
27
38
|
if (!toast || toast.dataset.leaving === '1') return;
|
|
39
|
+
forget(toast);
|
|
28
40
|
toast.dataset.leaving = '1';
|
|
29
41
|
toast.classList.add('is-leaving');
|
|
30
42
|
var remove = function () { if (toast.parentNode) toast.parentNode.removeChild(toast); };
|
|
@@ -64,6 +76,14 @@
|
|
|
64
76
|
node.appendChild(accent);
|
|
65
77
|
node.appendChild(body);
|
|
66
78
|
node.appendChild(close);
|
|
79
|
+
|
|
80
|
+
// Replace-in-place: a same-key toast removes the previous one so bursts don't stack.
|
|
81
|
+
if (opts.key != null) {
|
|
82
|
+
var prev = keyed[opts.key];
|
|
83
|
+
if (prev && prev.parentNode) prev.parentNode.removeChild(prev);
|
|
84
|
+
node._fdyKey = opts.key;
|
|
85
|
+
keyed[opts.key] = node;
|
|
86
|
+
}
|
|
67
87
|
region.appendChild(node);
|
|
68
88
|
|
|
69
89
|
var timeout = opts.timeout == null ? 4000 : opts.timeout;
|
|
@@ -81,4 +101,5 @@
|
|
|
81
101
|
|
|
82
102
|
window.Freeday = window.Freeday || {};
|
|
83
103
|
window.Freeday.toast = toast;
|
|
104
|
+
window.Freeday.dismiss = dismiss; // dismiss(nodeOrKey)
|
|
84
105
|
})();
|