@cahyo-dimas/freeday 1.54.0 → 2.1.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 +713 -545
- package/COMPONENTS.md +417 -139
- package/README.id.md +46 -45
- package/README.md +46 -43
- package/USAGE.md +34 -34
- package/adapters/blazor/FdyAppShell.razor +2 -2
- package/adapters/blazor/FdyAppShell.razor.cs +6 -6
- package/adapters/blazor/FdyCfl.razor.cs +1 -1
- package/adapters/blazor/FdyChart.razor +1 -1
- package/adapters/blazor/FdyChart.razor.cs +3 -3
- package/adapters/blazor/FdyChartSeries.cs +1 -1
- package/adapters/blazor/FdyCombo.razor.cs +2 -2
- package/adapters/blazor/FdyModal.razor +1 -1
- package/adapters/blazor/FdyTable.razor.cs +7 -7
- package/adapters/blazor/FdyTableFilter.razor +1 -1
- package/adapters/blazor/FdyTableFooter.razor +1 -1
- package/adapters/blazor/FdyTableFooter.razor.cs +4 -4
- package/adapters/blazor/Freeday.Blazor.csproj +1 -1
- package/adapters/blazor/FreedayComponentBase.cs +1 -1
- package/adapters/blazor/TableModel.cs +3 -3
- package/adapters/blazor/TableTypes.cs +3 -3
- package/adapters/blazor/freeday-blazor.js +5 -5
- package/adapters/core/app-shell.d.ts +1 -1
- package/adapters/core/app-shell.js +6 -6
- package/adapters/core/cfl-value.d.ts +11 -0
- package/adapters/core/cfl-value.js +31 -0
- package/adapters/core/table-model.d.ts +2 -2
- package/adapters/core/table-model.js +8 -8
- package/adapters/react/components/FdyAppShell.tsx +5 -5
- package/adapters/react/components/FdyAutocomplete.tsx +1 -1
- package/adapters/react/components/FdyCascade.tsx +1 -1
- package/adapters/react/components/FdyCfl.tsx +11 -11
- package/adapters/react/components/FdyDateRange.tsx +2 -2
- package/adapters/react/components/FdyDatepicker.tsx +5 -5
- package/adapters/react/components/FdyDrawer.tsx +1 -1
- package/adapters/react/components/FdyModal.tsx +2 -2
- package/adapters/react/components/FdyTable.tsx +7 -7
- package/adapters/react/components/FdyTableFilter.tsx +1 -1
- package/adapters/react/components/FdyTableFooter.tsx +5 -5
- package/adapters/react/index.d.ts +4 -1
- package/adapters/react/index.js +1 -0
- package/adapters/react/useFreeday.js +3 -3
- package/adapters/vue/components/FdyAppShell.vue +5 -5
- package/adapters/vue/components/FdyAutocomplete.vue +1 -1
- package/adapters/vue/components/FdyCascade.vue +1 -1
- package/adapters/vue/components/FdyCfl.vue +8 -8
- package/adapters/vue/components/FdyChart.vue +2 -2
- package/adapters/vue/components/FdyCombo.vue +1 -1
- package/adapters/vue/components/FdyDateRange.vue +2 -2
- package/adapters/vue/components/FdyDatepicker.vue +5 -5
- package/adapters/vue/components/FdyDrawer.vue +3 -3
- package/adapters/vue/components/FdyModal.vue +3 -3
- package/adapters/vue/components/FdyTable.vue +7 -7
- package/adapters/vue/components/FdyTableFilter.vue +1 -1
- package/adapters/vue/components/FdyTableFooter.vue +5 -5
- package/adapters/vue/index.d.ts +5 -2
- package/adapters/vue/index.js +1 -0
- package/adapters/vue/useFreeday.js +3 -3
- package/dist/asset.d.ts +3 -3
- package/dist/freeday-app-shell.js +9 -9
- package/dist/freeday-autocomplete.js +2 -2
- package/dist/freeday-breakpoint.js +1 -1
- package/dist/freeday-carousel.js +8 -7
- package/dist/freeday-cascade.js +10 -9
- package/dist/freeday-cfl.js +12 -11
- package/dist/freeday-chart.js +11 -11
- package/dist/freeday-chip.js +3 -3
- package/dist/freeday-datepicker.js +11 -7
- package/dist/freeday-datetime.js +5 -5
- package/dist/freeday-drawer.js +1 -1
- package/dist/freeday-form.js +17 -16
- package/dist/freeday-mask.js +9 -8
- package/dist/freeday-menu.js +1 -1
- package/dist/freeday-number.js +3 -3
- package/dist/freeday-popover.js +3 -3
- package/dist/freeday-rating.js +2 -2
- package/dist/freeday-select.js +5 -5
- package/dist/freeday-slider.js +2 -2
- package/dist/freeday-stepper.js +10 -9
- package/dist/freeday-table.js +18 -17
- package/dist/freeday-tabs.js +1 -1
- package/dist/freeday-timepicker.js +2 -2
- package/dist/freeday-toast.js +11 -10
- package/dist/freeday-tree.js +3 -3
- package/dist/freeday-upload.js +28 -27
- package/dist/freeday.bundle.css +176 -176
- package/dist/freeday.css +170 -170
- package/dist/freeday.d.ts +2 -2
- package/dist/freeday.js +189 -176
- package/dist/freeday.tokens.css +5 -5
- package/docs/agent-onboarding.md +49 -46
- package/docs/getting-started.md +49 -40
- package/docs/integrations.md +18 -18
- package/docs/reference-screen.html +14 -14
- package/package.json +4 -3
- package/src/base.css +6 -6
- package/src/components/accordion.css +4 -4
- package/src/components/alert.css +1 -1
- package/src/components/app-shell.css +10 -10
- package/src/components/appbar.css +3 -3
- package/src/components/autocomplete.css +1 -1
- package/src/components/avatar.css +3 -3
- package/src/components/badge.css +5 -5
- package/src/components/breadcrumb.css +1 -1
- package/src/components/breakpoints.css +4 -4
- package/src/components/button.css +13 -13
- package/src/components/card.css +8 -8
- package/src/components/carousel.css +2 -2
- package/src/components/cascade.css +2 -2
- package/src/components/cfl.css +4 -4
- package/src/components/chart.css +3 -3
- package/src/components/chip.css +2 -2
- package/src/components/combo.css +3 -3
- package/src/components/composition.css +7 -7
- package/src/components/datepicker.css +6 -6
- package/src/components/datetimepicker.css +1 -1
- package/src/components/description-list.css +1 -1
- package/src/components/divider.css +1 -1
- package/src/components/drawer.css +1 -1
- package/src/components/file-upload.css +5 -5
- package/src/components/filterbar.css +7 -7
- package/src/components/form-grid.css +2 -2
- package/src/components/input-group.css +6 -6
- package/src/components/input.css +6 -6
- package/src/components/kbd.css +1 -1
- package/src/components/list.css +6 -6
- package/src/components/menu.css +3 -3
- package/src/components/modal.css +1 -1
- package/src/components/pagination.css +1 -1
- package/src/components/progress.css +1 -1
- package/src/components/rating.css +2 -2
- package/src/components/selection.css +4 -4
- package/src/components/skeleton.css +1 -1
- package/src/components/slider.css +1 -1
- package/src/components/spinner.css +1 -1
- package/src/components/states.css +1 -1
- package/src/components/stepper.css +2 -2
- package/src/components/table.css +15 -15
- package/src/components/tabs.css +3 -3
- package/src/components/timeline.css +1 -1
- package/src/components/timepicker.css +1 -1
- package/src/components/toast.css +3 -3
- package/src/components/tooltip.css +1 -1
- package/src/components/tree.css +2 -2
- package/tokens/breakpoints.d.ts +2 -2
- package/tokens/breakpoints.mjs +3 -3
- package/tokens/tokens.json +1 -1
package/dist/freeday.tokens.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Freeday tokens
|
|
1
|
+
/* Freeday tokens. GENERATED by tokens/build.mjs. Do not edit by hand. */
|
|
2
2
|
:root {
|
|
3
3
|
--azure-50: #eff4ff;
|
|
4
4
|
--azure-100: #dbe6fe;
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
--focus-ring-width: 2px;
|
|
179
179
|
}
|
|
180
180
|
/* The SYSTEM default stays root-scoped: it is a statement about the document, and dropping :root
|
|
181
|
-
* here would match every element that is not itself [data-theme="light"]
|
|
181
|
+
* here would match every element that is not itself [data-theme="light"], which would re-darken
|
|
182
182
|
* the children of a light panel, since they carry no attribute of their own. */
|
|
183
183
|
@media (prefers-color-scheme: dark) {
|
|
184
184
|
:root:not([data-theme="light"]) {
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
}
|
|
241
241
|
/* The two EXPLICIT opt-ins are deliberately NOT scoped to :root, for the same reason as density
|
|
242
242
|
* below: these are inheriting custom properties, so data-theme on any ancestor re-themes just that
|
|
243
|
-
* subtree
|
|
243
|
+
* subtree, a dark brand panel beside a light form is an ordinary layout, and it should not require
|
|
244
244
|
* re-colouring each component by hand. The root still matches, so data-theme on <html> is unchanged.
|
|
245
245
|
* Both keep the same specificity (0,1,0) as :root and come after it, so they still win there; and
|
|
246
246
|
* --light after --dark means a light island inside a dark region wins in turn. */
|
|
@@ -356,7 +356,7 @@
|
|
|
356
356
|
--chart-tick: var(--slate-400);
|
|
357
357
|
--focus-ring: var(--azure-600);
|
|
358
358
|
}
|
|
359
|
-
/* Density is deliberately NOT scoped to :root. These are custom properties, so they inherit
|
|
359
|
+
/* Density is deliberately NOT scoped to :root. These are custom properties, so they inherit,
|
|
360
360
|
* putting the attribute on any ancestor (a route wrapper, one section) densifies just that
|
|
361
361
|
* subtree, which is how density is actually decided: per screen, not per app. The root still
|
|
362
362
|
* matches, so setting data-density on the html element keeps working exactly as before. */
|
|
@@ -368,7 +368,7 @@
|
|
|
368
368
|
--control-h: 2rem;
|
|
369
369
|
}
|
|
370
370
|
/* ...and the way back out. Inheritance only runs downhill: once the root is compact every subtree is
|
|
371
|
-
* compact, and before this rule existed a data-density="comfortable" wrapper matched nothing
|
|
371
|
+
* compact, and before this rule existed a data-density="comfortable" wrapper matched nothing, so the
|
|
372
372
|
* comment above was true in one direction only. An app that is dense overall and carries one region
|
|
373
373
|
* of shared chrome (a header, a toolbar, a footer shared with a sibling product) had to restate the
|
|
374
374
|
* defaults by hand, which is exactly the local copy that goes stale when the kit retunes them. */
|
package/docs/agent-onboarding.md
CHANGED
|
@@ -5,7 +5,7 @@ Copilot…). No model has Freeday in its training data, so an agent that is mere
|
|
|
5
5
|
will invent class names or silently fall back to Bootstrap/Tailwind conventions. This file is the
|
|
6
6
|
fix: paste the block below into the consuming project's agent instruction file, once.
|
|
7
7
|
|
|
8
|
-
> Working on **the kit itself**, not a consuming app? That's [`../CLAUDE.md`](../CLAUDE.md)
|
|
8
|
+
> Working on **the kit itself**, not a consuming app? That's [`../CLAUDE.md`](../CLAUDE.md). This
|
|
9
9
|
> file is about *using* the published package.
|
|
10
10
|
|
|
11
11
|
---
|
|
@@ -20,49 +20,49 @@ the **root of the consuming project**:
|
|
|
20
20
|
|
|
21
21
|
All UI in this project is built from Freeday: a **token-driven CSS kit** (`fdy-*` classes on plain
|
|
22
22
|
markup) with **typed components for Vue, React and Blazor** layered on top. Most of the kit is
|
|
23
|
-
markup + classes;
|
|
23
|
+
markup + classes; eleven interactive components also ship a typed wrapper, and in those three stacks
|
|
24
24
|
the wrapper is the correct way to use them.
|
|
25
25
|
|
|
26
|
-
**0. First decide which entry point this project uses. This is not an optimisation
|
|
26
|
+
**0. First decide which entry point this project uses. This is not an optimisation. Get it wrong
|
|
27
27
|
and the code looks correct and fails later.**
|
|
28
28
|
|
|
29
|
-
| This project's stack | Import the
|
|
29
|
+
| This project's stack | Import the eleven components from | Binding |
|
|
30
30
|
|---|---|---|
|
|
31
31
|
| Vue 3 | `@cahyo-dimas/freeday/vue` | `v-model` |
|
|
32
32
|
| React 18/19 | `@cahyo-dimas/freeday/react` | `value` + `onChange` |
|
|
33
33
|
| Blazor (net8.0) | `@using Freeday.Blazor` (RCL) | `@bind-Value` |
|
|
34
|
-
| Static HTML, Svelte, server-rendered templates… | no wrapper
|
|
34
|
+
| Static HTML, Svelte, server-rendered templates… | no wrapper: raw markup + the enhancer script | `fdy-*` DOM events |
|
|
35
35
|
|
|
36
|
-
The
|
|
37
|
-
FdyChart · FdyTable · FdyModal · FdyDrawer**. In Vue/React/Blazor, **never hand-write the raw
|
|
38
|
-
markup + enhancer for these
|
|
39
|
-
once on `DOMContentLoaded` and the first render is correct
|
|
36
|
+
The eleven: **FdyCombo · FdyDatepicker · FdyDateRange · FdyAutocomplete · FdyCascade · FdyCfl ·
|
|
37
|
+
FdyChart · FdyTable · FdyModal · FdyDrawer · FdyAppShell**. In Vue/React/Blazor, **never hand-write the raw
|
|
38
|
+
markup + enhancer for these eleven.** The raw path *appears* to work: the enhancer auto-initialises
|
|
39
|
+
once on `DOMContentLoaded` and the first render is correct. Then it fails quietly: DOM your framework
|
|
40
40
|
renders later is never hydrated, and the widget's state lives in the DOM instead of in your
|
|
41
41
|
framework's state.
|
|
42
42
|
|
|
43
43
|
Everything else is the same in every stack: plain `fdy-*` markup (button, card, badge, alert,
|
|
44
44
|
table markup, layout…). For the *other* interactive components (chips, stepper, input mask, file
|
|
45
45
|
upload, tree, tabs, menu, rating, slider, form validation, carousel, timepicker) there is no
|
|
46
|
-
wrapper
|
|
46
|
+
wrapper, use the raw markup and hydrate it:
|
|
47
47
|
|
|
48
|
-
- **Vue / React
|
|
48
|
+
- **Vue / React:** `useFreeday(rootRef)` from the same import path, plus `import '@cahyo-dimas/freeday'`
|
|
49
49
|
once at app entry to register the enhancers. (The eleven typed components do **not** need this: they
|
|
50
50
|
are native Vue/React implementations of the same markup, not wrappers over the enhancer.)
|
|
51
|
-
- **Blazor
|
|
51
|
+
- **Blazor:** `FreedayBlazor.initAll` interop. (Here the typed components *are* thin wrappers over
|
|
52
52
|
the enhancers, so the enhancer script is always required.)
|
|
53
53
|
|
|
54
54
|
**Before writing or editing any markup/CSS, read these (they ship inside the package):**
|
|
55
|
-
- `node_modules/@cahyo-dimas/freeday/COMPONENTS.md`
|
|
55
|
+
- `node_modules/@cahyo-dimas/freeday/COMPONENTS.md` lists every class that exists, with minimal markup
|
|
56
56
|
skeletons, enhancer hooks and the a11y contract per component. **The class list is closed:
|
|
57
|
-
if a class is not in that file, it does not exist
|
|
58
|
-
- `node_modules/@cahyo-dimas/freeday/USAGE.md`
|
|
59
|
-
- `node_modules/@cahyo-dimas/freeday/docs/reference-screen.html`
|
|
57
|
+
if a class is not in that file, it does not exist. Do not invent one.**
|
|
58
|
+
- `node_modules/@cahyo-dimas/freeday/USAGE.md` is the doctrine: which token/role/shadow to use when.
|
|
59
|
+
- `node_modules/@cahyo-dimas/freeday/docs/reference-screen.html` is one complete screen, assembled
|
|
60
60
|
the intended way. Copy this structure for a new screen.
|
|
61
61
|
|
|
62
62
|
**Non-negotiables:**
|
|
63
63
|
1. No raw hex or px in app CSS. Use tokens: `var(--color-primary)`, `var(--space-4)` (4px scale),
|
|
64
64
|
`var(--radius-md)`, `var(--shadow-1)`, `var(--dur-2)`.
|
|
65
|
-
2. Components only touch semantic tokens (`--color-*`)
|
|
65
|
+
2. Components only touch semantic tokens (`--color-*`), never the primitive ramp (`--azure-600`).
|
|
66
66
|
3. `.fdy-btn` is already the primary action (there is no `--primary`). One per screen; everything
|
|
67
67
|
else is `--ghost` or `--text`.
|
|
68
68
|
4. Three title roles only: `.fdy-title-page` (one `<h1>`) / `.fdy-title-section` / `.fdy-title-card`.
|
|
@@ -72,40 +72,43 @@ wrapper — use the raw markup and hydrate it:
|
|
|
72
72
|
Icon-only buttons need `aria-label`. Status is never colour-only.
|
|
73
73
|
7. Interactive components need their enhancer script loaded (see the table in COMPONENTS.md); in an
|
|
74
74
|
SPA, re-hydrate dynamic DOM with `useFreeday` / `FreedayBlazor.initAll`. This applies to the
|
|
75
|
-
components **without** a typed wrapper
|
|
75
|
+
components **without** a typed wrapper. For the eleven in step 0, use the wrapper instead.
|
|
76
76
|
8. Freeday owns components + tokens, **not layout**. Grids/stacks/one-off gaps come from our own
|
|
77
|
-
layout layer
|
|
77
|
+
layout layer. Build its theme on `var(--space-N)` so both systems stay in step.
|
|
78
|
+
9. The enhancers render their own English UI strings (pager, filter dialog, validation). Never
|
|
79
|
+
hand-translate one by rewriting the enhancer's nodes — set `data-fdy-text-<key>` on the
|
|
80
|
+
component root, and `<html lang>` for date names. Keys are in COMPONENTS.md.
|
|
78
81
|
```
|
|
79
82
|
|
|
80
83
|
Adjust the paths if the package lives somewhere else (a workspace, a vendored copy, `wwwroot/` for
|
|
81
|
-
Blazor). Then verify the agent can actually read those files
|
|
84
|
+
Blazor). Then verify the agent can actually read those files. An agent that can't open
|
|
82
85
|
`node_modules` will keep guessing.
|
|
83
86
|
|
|
84
87
|
## 2. What ships in the package
|
|
85
88
|
|
|
86
89
|
| File | What it answers |
|
|
87
90
|
|---|---|
|
|
88
|
-
| `COMPONENTS.md` | The complete class surface
|
|
89
|
-
| `USAGE.md` | The doctrine
|
|
91
|
+
| `COMPONENTS.md` | The complete class surface: what exists, its modifiers, minimal markup, a11y. Also the typed wrappers' props — one `### Props — <FdyX>` table each, and the `FdyTableColumn` fields. |
|
|
92
|
+
| `USAGE.md` | The doctrine: which token/role/shadow/emphasis to use when. |
|
|
90
93
|
| `docs/getting-started.md` | Install + import + theme, per stack (Static HTML · Vue · React · Blazor). |
|
|
91
94
|
| `docs/integrations.md` | How to bridge third-party libraries (validation, charts, dates, i18n…). |
|
|
92
95
|
| `docs/reference-screen.html` | A full screen assembled from the shell down. Open it in a browser. |
|
|
93
96
|
| `docs/agent-onboarding.md` | This file. |
|
|
94
|
-
| `CHANGELOG.md` | **What changed between the version this project had and the one it has now
|
|
95
|
-
| `dist/` | Built CSS + enhancers. **`freeday.bundle.css` = tokens + components** (what `@cahyo-dimas/freeday/css` resolves to); `freeday.css` is components **only**, `freeday.tokens.css` tokens only
|
|
97
|
+
| `CHANGELOG.md` | **What changed between the version this project had and the one it has now.** Read it after every upgrade; each entry says what broke, what is new, and why. |
|
|
98
|
+
| `dist/` | Built CSS + enhancers. **`freeday.bundle.css` = tokens + components** (what `@cahyo-dimas/freeday/css` resolves to); `freeday.css` is components **only**, `freeday.tokens.css` tokens only, so linking `freeday.css` alone leaves every `var(--…)` unresolved. Plus `freeday-*.js` and the `.d.ts` files. |
|
|
96
99
|
| `src/components/*.css` | The authoritative source for every class, when a doc is ambiguous. |
|
|
97
|
-
| `tokens/tokens.json` | Every token in W3C DTCG format
|
|
98
|
-
| `adapters/vue` · `adapters/react` · `adapters/blazor` | Typed wrappers,
|
|
100
|
+
| `tokens/tokens.json` | Every token in W3C DTCG format, machine-readable. |
|
|
101
|
+
| `adapters/vue` · `adapters/react` · `adapters/blazor` | Typed wrappers, 11 components each (plus `FdyTableFooter`). |
|
|
99
102
|
|
|
100
103
|
The live docs (with an interactive playground) are at
|
|
101
|
-
<https://cahyo-dimas.github.io/freeday-ui-kit/>, and the repo
|
|
102
|
-
apps under `examples/` (Vue, React, Blazor) that are **not** in the npm tarball
|
|
104
|
+
<https://cahyo-dimas.github.io/freeday-ui-kit/>, and the repo (including three complete example
|
|
105
|
+
apps under `examples/` (Vue, React, Blazor) that are **not** in the npm tarball) is at
|
|
103
106
|
<https://github.com/cahyo-dimas/freeday-ui-kit>.
|
|
104
107
|
|
|
105
108
|
### After an upgrade, read the changelog first
|
|
106
109
|
|
|
107
110
|
`npm i @cahyo-dimas/freeday@latest` does not tell you what you gained. Read
|
|
108
|
-
`node_modules/@cahyo-dimas/freeday/CHANGELOG.md` down to the version this project was on before
|
|
111
|
+
`node_modules/@cahyo-dimas/freeday/CHANGELOG.md` down to the version this project was on before,
|
|
109
112
|
it is written for exactly this moment, and it is the difference between adopting a new affordance
|
|
110
113
|
and re-implementing it locally.
|
|
111
114
|
|
|
@@ -130,31 +133,31 @@ Recent additions most likely to replace something an app hand-rolled (all detail
|
|
|
130
133
|
|
|
131
134
|
The order matters; skipping to components is what produces flat, identical-card screens.
|
|
132
135
|
|
|
133
|
-
0. **Pick the screen shape first.** Which archetype is this
|
|
136
|
+
0. **Pick the screen shape first.** Which archetype is this: dashboard, master-detail, kanban,
|
|
134
137
|
wizard, POS…? The repo's
|
|
135
138
|
[`reference/README.md`](https://github.com/cahyo-dimas/freeday-ui-kit/blob/main/reference/README.md)
|
|
136
139
|
maps 15 archetypes to the exact primitives that compose each one, and says plainly which shapes
|
|
137
140
|
the kit has **no** component for (kanban columns, calendar month grid, chat bubbles, canvas) so
|
|
138
|
-
you build the frame instead of inventing a class. Not in the npm package
|
|
139
|
-
1. **Shell
|
|
141
|
+
you build the frame instead of inventing a class. Not in the npm package, so read it on GitHub.
|
|
142
|
+
1. **Shell:** is `.fdy-app` already in place (usually once, in the app layout)? If not, copy it
|
|
140
143
|
from `docs/getting-started.md` §The app shell.
|
|
141
|
-
2. **Theme
|
|
144
|
+
2. **Theme:** `data-theme="light|dark"` + `data-density="comfortable|compact"`, normally on
|
|
142
145
|
`<html>`, set once at the root. Use `compact` for table-heavy back-office screens. Both attributes
|
|
143
146
|
also work on **any ancestor**: `<section data-theme="dark">` inverts that region and every
|
|
144
147
|
component inside it follows, so never hand-colour an inverted panel.
|
|
145
|
-
3. **Fonts
|
|
148
|
+
3. **Fonts:** the package ships **no** `@font-face`. Load Sora / IBM Plex Sans / JetBrains Mono
|
|
146
149
|
yourself, or override `--font-display`/`--font-body`/`--font-mono`. Skipping this reads as
|
|
147
150
|
"unfinished design", not "missing dependency".
|
|
148
|
-
4. **Page frame
|
|
151
|
+
4. **Page frame:** `.fdy-page` + `.fdy-page__header` (eyebrow + `.fdy-title-page` + desc on the
|
|
149
152
|
left, **one** primary action on the right).
|
|
150
|
-
5. **Sections
|
|
151
|
-
6. **Components
|
|
152
|
-
7. **Verify
|
|
153
|
+
5. **Sections:** one `.fdy-page-section` per region, each with a `.fdy-title-section`.
|
|
154
|
+
6. **Components:** from `COMPONENTS.md`, inside the sections.
|
|
155
|
+
7. **Verify:** the checklist in §5.
|
|
153
156
|
|
|
154
157
|
## 4. Migrating an existing UI to Freeday
|
|
155
158
|
|
|
156
159
|
Migration is a **class-and-structure swap**, not a rewrite. Keep the app's DOM semantics; replace
|
|
157
|
-
the styling layer. Rough equivalents
|
|
160
|
+
the styling layer. Rough equivalents, but always confirm the target class in `COMPONENTS.md`, and note
|
|
158
161
|
that Freeday deliberately has **no** layout/spacing utilities, so grid/flex/margin classes stay with
|
|
159
162
|
your own layout layer:
|
|
160
163
|
|
|
@@ -174,19 +177,19 @@ your own layout layer:
|
|
|
174
177
|
| `table table-striped` / `MudTable` | `fdy-table` in `fdy-table-wrap`; interactive → `fdy-datatable` |
|
|
175
178
|
| `badge bg-success` / `MudChip` (status) | `fdy-badge fdy-badge--success` |
|
|
176
179
|
| `alert alert-danger` | `fdy-alert fdy-alert--danger` + `role="alert"` |
|
|
177
|
-
| `modal` / `MudDialog` | `<dialog class="fdy-modal">` (native
|
|
180
|
+
| `modal` / `MudDialog` | `<dialog class="fdy-modal">` (native, so drop the JS backdrop plumbing) |
|
|
178
181
|
| `offcanvas` / `MudDrawer` | `<dialog class="fdy-drawer">` + `data-fdy-drawer` |
|
|
179
182
|
| `nav nav-tabs` | `fdy-tabs` + `data-fdy-tabs` |
|
|
180
183
|
| `breadcrumb` / `pagination` | `fdy-breadcrumb` / `fdy-pagination` (same `<nav><ol>` structure) |
|
|
181
184
|
| `spinner-border` / `progress` | `fdy-spinner` / `fdy-progress` + `__bar` |
|
|
182
|
-
| `toast` container + JS | `Freeday.toast({…})
|
|
185
|
+
| `toast` container + JS | `Freeday.toast({…})`, imperative, no markup to author |
|
|
183
186
|
| `text-muted` | `fdy-text-muted` |
|
|
184
187
|
| `d-none` / `visually-hidden` | `fdy-hidden` / `fdy-visually-hidden` |
|
|
185
|
-
| `container` / `row` / `col-*` / `mb-3` / `gap-2` | **stays yours
|
|
188
|
+
| `container` / `row` / `col-*` / `mb-3` / `gap-2` | **stays yours**: Freeday ships no layout utilities |
|
|
186
189
|
|
|
187
190
|
Order of work that avoids a half-migrated mess:
|
|
188
191
|
|
|
189
|
-
1. Load Freeday's CSS and **turn off the old framework's reset/preflight
|
|
192
|
+
1. Load Freeday's CSS and **turn off the old framework's reset/preflight**, because `base.css` is the
|
|
190
193
|
reset now. Two resets fighting is the usual source of "everything looks slightly off".
|
|
191
194
|
2. Shell + theme attributes first, so tokens resolve everywhere.
|
|
192
195
|
3. Then screen by screen: page frame → sections → controls. Convert a whole screen at a time;
|
|
@@ -194,15 +197,15 @@ Order of work that avoids a half-migrated mess:
|
|
|
194
197
|
4. Delete the old framework's CSS only when no screen references it, then grep for leftover class
|
|
195
198
|
prefixes.
|
|
196
199
|
5. Replace hand-rolled modal/drawer/dropdown JS with the native-`<dialog>` components and the
|
|
197
|
-
enhancers
|
|
200
|
+
enhancers, which is usually where the most code disappears.
|
|
198
201
|
|
|
199
202
|
## 5. Verification checklist (before claiming a screen is done)
|
|
200
203
|
|
|
201
204
|
- Every `fdy-*` class used appears in `COMPONENTS.md`. Grep the diff for `fdy-` and check.
|
|
202
205
|
- No raw hex/rgb/px in the diff's CSS. Grep for `#` and `px`.
|
|
203
206
|
- Exactly one `.fdy-btn` without a variant modifier on the screen; one `.fdy-title-page`.
|
|
204
|
-
- Toggle `data-theme="dark"` on `<html
|
|
205
|
-
- Toggle `data-density="compact"
|
|
207
|
+
- Toggle `data-theme="dark"` on `<html>`: nothing becomes unreadable, no hard-coded white/black.
|
|
208
|
+
- Toggle `data-density="compact"`: the layout still holds.
|
|
206
209
|
- Keyboard: Tab reaches every control, focus is always visible, Esc closes overlays.
|
|
207
210
|
- Form errors carry `aria-invalid` + a linked message; icon-only buttons have `aria-label`.
|
|
208
211
|
- The interactive components on the screen have their enhancer loaded, and SPA-rendered DOM is
|
package/docs/getting-started.md
CHANGED
|
@@ -15,43 +15,43 @@ A step-by-step guide to adopting Freeday in **your new project**. Pick your stac
|
|
|
15
15
|
Freeday = **CSS** (semantic tokens + `fdy-*` classes) + **zero-dependency JS enhancers** (optional).
|
|
16
16
|
|
|
17
17
|
1. **Static vs interactive.** Static components (button, card, badge, plain input, layout) need
|
|
18
|
-
only the **`fdy-*` classes
|
|
18
|
+
only the **`fdy-*` classes**, no JS. Interactive components (select/combo, cascade, date/time
|
|
19
19
|
picker, table, dropzone, form validation, input mask, chip) need the **JS enhancers**.
|
|
20
|
-
2. **The enhancer is the source of truth
|
|
20
|
+
2. **The enhancer is the source of truth, *on the raw path*.** You don't re-implement components;
|
|
21
21
|
the enhancer owns the widget's DOM. You **listen for `fdy-*` events** (all bubbling
|
|
22
22
|
`CustomEvent`s, data in `event.detail`) → store them in your framework state. Event/API contract
|
|
23
23
|
table: [`integrations.md` §Event & API contract](integrations.md).
|
|
24
|
-
**On Vue, React or Blazor this is not the path to take for
|
|
24
|
+
**On Vue, React or Blazor this is not the path to take for eleven of the components.** `FdyCombo`,
|
|
25
25
|
`FdyDatepicker`, `FdyDateRange`, `FdyAutocomplete`, `FdyCascade`, `FdyCfl`, `FdyChart`,
|
|
26
|
-
`FdyTable`, `FdyModal`, `FdyDrawer` ship typed wrappers that own the state properly (Vue and
|
|
26
|
+
`FdyTable`, `FdyModal`, `FdyDrawer`, `FdyAppShell` ship typed wrappers that own the state properly (Vue and
|
|
27
27
|
React re-implement the interaction natively; Blazor wraps the enhancer over interop). Use them;
|
|
28
28
|
the raw path is for the components without a wrapper, and for stacks without an adapter.
|
|
29
29
|
3. **Hydrate dynamic DOM.** Enhancers auto-init once on `DOMContentLoaded`. DOM an SPA renders
|
|
30
30
|
**after** that must be re-hydrated: `window.Freeday<X>.initAll(el)` (idempotent, safe to repeat).
|
|
31
|
-
Each framework's adapter wraps this
|
|
31
|
+
Each framework's adapter wraps this, so you don't call it manually.
|
|
32
32
|
4. **Theme via `data-*`.** `data-theme="light|dark"` (all semantic tokens switch) +
|
|
33
33
|
`data-density="comfortable|compact"` (control height, for data-dense screens). Normally on
|
|
34
34
|
`<html>`; change at runtime with `document.documentElement.dataset.theme = 'dark'`. Both also
|
|
35
|
-
work on **any ancestor
|
|
35
|
+
work on **any ancestor**, because these are inheriting custom properties, so `<section data-theme="dark">`
|
|
36
36
|
inverts just that region and every component inside it follows. See [`USAGE.md`](../USAGE.md) §5b.
|
|
37
37
|
5. **3-tier token rule.** Components only touch **Tier 2/3** (`var(--color-primary)`,
|
|
38
38
|
`var(--space-4)`, `var(--radius-md)`…). **Never** write raw hex/px.
|
|
39
39
|
6. **Scope: components + tokens, deliberately *not* layout.** Freeday ships components and tokens;
|
|
40
40
|
the only layout helpers are `.fdy-hidden` / `.fdy-visually-hidden`. Stacks, grids, gaps and sizing
|
|
41
|
-
come from **your** layout layer
|
|
41
|
+
come from **your** layout layer. Pair Freeday with a utility framework (Tailwind, UnoCSS…) run
|
|
42
42
|
**utilities-only, preflight OFF** (Freeday's `base.css` is your reset). Two consequences worth
|
|
43
43
|
knowing up front:
|
|
44
|
-
- **base.css is a *light* reset
|
|
44
|
+
- **base.css is a *light* reset.** It does not strip `ul`/`ol`/`p` margins. With preflight off, a
|
|
45
45
|
semantic `<ul>` keeps native bullets + a 40px indent; add **`.fdy-list-reset`** (or use a Freeday
|
|
46
46
|
list component) on such lists.
|
|
47
47
|
- **The spacing scale is public.** `--space-0`…`--space-24`, `--radius-*`, `--dur-*` etc. are real
|
|
48
|
-
custom properties in `dist/freeday.tokens.css
|
|
48
|
+
custom properties in `dist/freeday.tokens.css`, so **define your utility theme in terms of them**
|
|
49
49
|
(`spacing: { 4: 'var(--space-4)' }`) so both systems stay in step. `data-density="compact"` steps
|
|
50
50
|
`--control-h` **and** the mid-range spacing scale (`--space-3`…`--space-6`), so Freeday components
|
|
51
|
-
densify
|
|
52
|
-
7. **Load the fonts
|
|
51
|
+
densify, and if your utility theme is built on `var(--space-N)`, density reaches your utilities too.
|
|
52
|
+
7. **Load the fonts yourself. The package does not.** The type tokens *name* **Sora** (display), **IBM Plex
|
|
53
53
|
Sans** (body) and **JetBrains Mono** (data), but Freeday bundles no `@font-face` and no font files.
|
|
54
|
-
Load them yourself, or the kit renders in the system fallback
|
|
54
|
+
Load them yourself, or the kit renders in the system fallback, which reads as "unfinished design",
|
|
55
55
|
not "missing dependency". One line with [Fontsource](https://fontsource.org):
|
|
56
56
|
```css
|
|
57
57
|
@import '@fontsource/sora/600.css'; @import '@fontsource/sora/700.css';
|
|
@@ -59,23 +59,30 @@ Freeday = **CSS** (semantic tokens + `fdy-*` classes) + **zero-dependency JS enh
|
|
|
59
59
|
```
|
|
60
60
|
(Or a `<link>` to your own self-hosted copies, or override `--font-display`/`--font-body`/`--font-mono`
|
|
61
61
|
to faces you already ship. If you keep a system-sans fallback, consider softening
|
|
62
|
-
`--tracking-tighter` on headings
|
|
62
|
+
`--tracking-tighter` on headings, since it's tuned for Sora's proportions.)
|
|
63
63
|
8. **Start from the shell, then compose.** Every application goes inside **`.fdy-app`** (see below);
|
|
64
|
-
inside it, assemble screens from the composition primitives
|
|
65
|
-
`.fdy-page-section`, `.fdy-toolbar`, `.fdy-stats`/`.fdy-stat`
|
|
64
|
+
inside it, assemble screens from the composition primitives (`.fdy-page`, `.fdy-page__header`,
|
|
65
|
+
`.fdy-page-section`, `.fdy-toolbar`, `.fdy-stats`/`.fdy-stat`) and the type roles (`.fdy-title-page`
|
|
66
66
|
/ `-section` / `-card`), not by re-using `.fdy-card__title` for everything. **Which token/role/shadow
|
|
67
|
-
to use when lives in [`USAGE.md`](../USAGE.md)
|
|
67
|
+
to use when lives in [`USAGE.md`](../USAGE.md)**. Read it once; it's what makes screens cohere.
|
|
68
|
+
9. **The enhancers' UI strings are English, and replaceable per element.** Pager labels, column
|
|
69
|
+
filter dialogs, upload and validation messages come from the enhancer, not from your markup.
|
|
70
|
+
Override any of them with **`data-fdy-text-<key>`** on the component's root — key list and the
|
|
71
|
+
`{n}`/`{from}`/`{total}` placeholders are in [`COMPONENTS.md`](../COMPONENTS.md) §Data table.
|
|
72
|
+
Dates need no attribute: the pickers format through `Intl` from the page's `<html lang>`, so
|
|
73
|
+
`lang="id"` gives Indonesian month and weekday names. **Coming from 1.x**, where those defaults
|
|
74
|
+
were Indonesian: 2.0.0 flipped them to English, and this attribute is the whole migration.
|
|
68
75
|
|
|
69
76
|
---
|
|
70
77
|
|
|
71
78
|
## The app shell (start here)
|
|
72
79
|
|
|
73
|
-
Every Freeday application goes inside **`.fdy-app
|
|
80
|
+
Every Freeday application goes inside **`.fdy-app`**, the frame that holds a top bar, a sidebar, and
|
|
74
81
|
the scrolling content. Don't hand-roll one from flexbox; the responsive sidebar + backdrop are built in.
|
|
75
82
|
The nav toggle is one line: toggle `.fdy-app--nav-open` (mobile drawer) / `.fdy-app--nav-collapsed`
|
|
76
83
|
(desktop) on the `.fdy-app` element from the `__navtoggle` button's click.
|
|
77
84
|
|
|
78
|
-
The nesting is not free-form
|
|
85
|
+
The nesting is not free-form: `.fdy-app` is a flex **row** of `[sidebar | content]`, and `__content`
|
|
79
86
|
is the column that holds the topbar and the main area (it gives the sticky topbar a tall containing
|
|
80
87
|
block to travel in). The brand belongs in the **sidebar**, sized to match the topbar's height:
|
|
81
88
|
|
|
@@ -109,11 +116,11 @@ block to travel in). The brand belongs in the **sidebar**, sized to match the to
|
|
|
109
116
|
</div>
|
|
110
117
|
```
|
|
111
118
|
|
|
112
|
-
`.fdy-app__main` already carries the page padding (`--space-8`, `--space-5` on mobile)
|
|
119
|
+
`.fdy-app__main` already carries the page padding (`--space-8`, `--space-5` on mobile), so don't wrap
|
|
113
120
|
your screen in another padded box. The toggle's two states split at **720px**: above it,
|
|
114
121
|
`.fdy-app--nav-collapsed` collapses the sidebar to zero width; at or below it,
|
|
115
122
|
`.fdy-app--nav-open` slides the sidebar in as an off-canvas drawer over the backdrop. A complete,
|
|
116
|
-
working version of all of this
|
|
123
|
+
working version of all of this, including the toggle script, is
|
|
117
124
|
[`reference-screen.html`](reference-screen.html).
|
|
118
125
|
|
|
119
126
|
Then compose the screen inside `__main` with `.fdy-page` / `.fdy-page__header` / `.fdy-page-section`
|
|
@@ -125,10 +132,10 @@ token to use where.
|
|
|
125
132
|
|
|
126
133
|
## Static HTML (no build)
|
|
127
134
|
|
|
128
|
-
Good for plain `.html` pages / templates
|
|
135
|
+
Good for plain `.html` pages / templates, with no bundler and no npm.
|
|
129
136
|
|
|
130
137
|
### 1. Get the dist files into your project
|
|
131
|
-
`dist/` is committed, so there's no build step. Easiest way
|
|
138
|
+
`dist/` is committed, so there's no build step. Easiest way: use npm once just to download, then
|
|
132
139
|
copy the files (vendor them):
|
|
133
140
|
```bash
|
|
134
141
|
npm i @cahyo-dimas/freeday
|
|
@@ -184,7 +191,7 @@ live docs also have a copy button per component.
|
|
|
184
191
|
```bash
|
|
185
192
|
npm i @cahyo-dimas/freeday
|
|
186
193
|
```
|
|
187
|
-
Lands in `package.json` as `"@cahyo-dimas/freeday": "^1.
|
|
194
|
+
Lands in `package.json` as `"@cahyo-dimas/freeday": "^2.1.0"` (public npm package). `dist/` is
|
|
188
195
|
committed and published → no build step; `npm ci` runs without auth.
|
|
189
196
|
|
|
190
197
|
### 2. Import the CSS + enhancers **once** in your entry (`src/main.ts`)
|
|
@@ -229,7 +236,7 @@ const onDate = (e: Event) => { form.dueDate = (e as CustomEvent<FdyDatepicke
|
|
|
229
236
|
```
|
|
230
237
|
|
|
231
238
|
**Gotcha:** if TypeScript complains about `import '@cahyo-dimas/freeday/css'`, make sure `env.d.ts`
|
|
232
|
-
has `/// <reference types="vite/client" />`. For **Nuxt/SSR**, enhancers are client-only
|
|
239
|
+
has `/// <reference types="vite/client" />`. For **Nuxt/SSR**, enhancers are client-only, so wrap them
|
|
233
240
|
in `onMounted`/`<ClientOnly>`.
|
|
234
241
|
|
|
235
242
|
Full working example: [`examples/vue-faktur/`](../examples/vue-faktur/).
|
|
@@ -296,14 +303,15 @@ export function Panel() {
|
|
|
296
303
|
}
|
|
297
304
|
```
|
|
298
305
|
|
|
299
|
-
**Gotcha:** because the enhancer owns the widget DOM, don't double-control it from React
|
|
306
|
+
**Gotcha:** because the enhancer owns the widget DOM, don't double-control it from React. Store the
|
|
300
307
|
value from `event.detail` in state/ref; don't set the DOM `value` back. `StrictMode` mounts twice in
|
|
301
308
|
dev; `useFreeday` is idempotent, so it's safe.
|
|
302
309
|
|
|
303
|
-
### 5. Alternative: typed controlled components
|
|
310
|
+
### 5. Alternative: typed controlled components
|
|
304
311
|
For fields you'd normally write as a native `<select>`/`<input type="date">`,
|
|
305
|
-
`@cahyo-dimas/freeday/react` also exports typed **controlled** components
|
|
306
|
-
no manual event bubbling
|
|
312
|
+
`@cahyo-dimas/freeday/react` also exports typed **controlled** components with plain `value`/`onChange`,
|
|
313
|
+
no manual event bubbling — the same eleven listed in §Core concepts #2, at parity with the Vue
|
|
314
|
+
`v-model` components above:
|
|
307
315
|
```tsx
|
|
308
316
|
import { FdyCombo } from '@cahyo-dimas/freeday/react';
|
|
309
317
|
import type { FdyComboOption } from '@cahyo-dimas/freeday/react';
|
|
@@ -320,7 +328,7 @@ function StatusField({ value, onChange }: { value: Status; onChange: (v: Status)
|
|
|
320
328
|
}
|
|
321
329
|
```
|
|
322
330
|
`FdyDatepicker`, `FdyCfl` (async choose-from-list), and `FdyChart` share the same shape (typed
|
|
323
|
-
`value`/`onChange`, or `series`/`values` for `FdyChart`)
|
|
331
|
+
`value`/`onChange`, or `series`/`values` for `FdyChart`). See [`integrations.md`](integrations.md)
|
|
324
332
|
and `examples/react-faktur/src/App.tsx` for the full patterns. **Vite works with no extra config**
|
|
325
333
|
(esbuild transpiles the `.tsx` source directly); **Next.js** consumers may need
|
|
326
334
|
`transpilePackages: ['@cahyo-dimas/freeday']` in `next.config.js`.
|
|
@@ -331,9 +339,9 @@ Full working example: [`examples/react-faktur/`](../examples/react-faktur/).
|
|
|
331
339
|
|
|
332
340
|
## Blazor (WASM)
|
|
333
341
|
|
|
334
|
-
Blazor doesn't use npm
|
|
342
|
+
Blazor doesn't use npm. Freeday is served as **static files** in `wwwroot/`.
|
|
335
343
|
|
|
336
|
-
> **Prefer the native components?** Jump to [§4
|
|
344
|
+
> **Prefer the native components?** Jump to [§4, the `Freeday.Blazor` RCL](#4-recommended-native-typed-components-freedayblazor-rcl):
|
|
337
345
|
> typed `<FdyX>` with `@bind`, no manual JS interop. Steps 1–2 (assets + scripts) still apply; step 3
|
|
338
346
|
> below (the raw enhancer + event bridge) is the underlying mechanism and the fallback for markup the
|
|
339
347
|
> RCL doesn't cover.
|
|
@@ -365,7 +373,7 @@ Load `freeday.js` then `freeday-blazor.js` **before** `blazor.webassembly.js`:
|
|
|
365
373
|
<script src="_framework/blazor.webassembly.js"></script>
|
|
366
374
|
</body>
|
|
367
375
|
```
|
|
368
|
-
> Use the global IIFE (`window.FreedayBlazor`), **not** an ES module
|
|
376
|
+
> Use the global IIFE (`window.FreedayBlazor`), **not** an ES module, so it passes strict-MIME on static hosts.
|
|
369
377
|
|
|
370
378
|
### 3. Hydrate + bridge events in code-behind (`.razor.cs`)
|
|
371
379
|
In `OnAfterRenderAsync(firstRender)`: `initAll`, then `on(...)` per event → `[JSInvokable]` methods.
|
|
@@ -402,7 +410,7 @@ public partial class Panel : ComponentBase, IAsyncDisposable
|
|
|
402
410
|
}
|
|
403
411
|
```
|
|
404
412
|
```razor
|
|
405
|
-
@* Panel.razor
|
|
413
|
+
@* Panel.razor: @ref on the subtree container, fdy-* classes + data-fdy-* hooks in the markup *@
|
|
406
414
|
<div @ref="_root">
|
|
407
415
|
<button class="fdy-btn fdy-btn--primary" type="button">Save</button>
|
|
408
416
|
<div data-fdy-cascade></div>
|
|
@@ -415,7 +423,7 @@ to flip the theme. Event DTOs are deserialized case-insensitively by Blazor.
|
|
|
415
423
|
### 4. Recommended: native typed components (`Freeday.Blazor` RCL)
|
|
416
424
|
|
|
417
425
|
Instead of hand-writing `fdy-*` markup + the interop above, reference the **Razor Class Library** and
|
|
418
|
-
use typed `<FdyX>` components with `@bind
|
|
426
|
+
use typed `<FdyX>` components with `@bind`, the Blazor equivalent of the Vue `v-model` / React
|
|
419
427
|
`value`/`onChange` adapters. Place the Freeday repo near your solution and add a project reference:
|
|
420
428
|
```xml
|
|
421
429
|
<!-- YourApp.csproj -->
|
|
@@ -428,7 +436,7 @@ use typed `<FdyX>` components with `@bind` — the Blazor equivalent of the Vue
|
|
|
428
436
|
Load `freeday.js` + `freeday-blazor.js` exactly as in step 2 (the components still hydrate over the
|
|
429
437
|
kit's CSS/enhancers), then bind:
|
|
430
438
|
```razor
|
|
431
|
-
@* Invoice.razor
|
|
439
|
+
@* Invoice.razor: no @ref, no manual JS interop, no [JSInvokable] *@
|
|
432
440
|
<FdyCombo TValue="string" @bind-Value="_status" Options="_statusOptions" AriaLabelledby="lbl-status" />
|
|
433
441
|
<FdyDatepicker @bind-Value="_dueDate" Label="Due date" />
|
|
434
442
|
<FdyTable TRow="Invoice" Columns="_cols" Rows="_rows" RowKey="@(i => i.Code)"
|
|
@@ -436,15 +444,16 @@ kit's CSS/enhancers), then bind:
|
|
|
436
444
|
<FdyChart Type="donut" Values="_byCity" Labels="_cityLabels" AriaLabel="Revenue by city" />
|
|
437
445
|
<FdyDrawer @bind-Open="_drawerOpen" Title="Detail" Side="right">…</FdyDrawer>
|
|
438
446
|
```
|
|
439
|
-
|
|
447
|
+
Eleven components at parity with the Vue/React adapters: **`FdyModal`** · **`FdyDrawer`** (`@bind-Open`,
|
|
440
448
|
`Title`, `Size`/`Side`, `Dismissible`) · **`FdyCombo<TValue>`** · **`FdyDatepicker`** ·
|
|
441
449
|
**`FdyAutocomplete`** · **`FdyCascade`** · **`FdyDateRange`** (`@bind-From`/`@bind-To`) ·
|
|
442
450
|
**`FdyCfl<TRow>`** (async `LoadPage`) · **`FdyChart`** · **`FdyTable<TRow>`** (client sort/filter/page,
|
|
443
|
-
or controlled `Sort`/`Filters`/`Page` for a server-paged table; `RowActivatable`, `RowDetail`)
|
|
451
|
+
or controlled `Sort`/`Filters`/`Page` for a server-paged table; `RowActivatable`, `RowDetail`) ·
|
|
452
|
+
**`FdyAppShell`** (`@bind-NavOpen`). Each
|
|
444
453
|
`select`-type control also takes `Disabled`/`Readonly`/`Invalid`. The RCL targets **net8.0** and is
|
|
445
454
|
consumed as source (`<ProjectReference>`); `.NET bin/obj` never ships in the npm tarball.
|
|
446
455
|
|
|
447
|
-
Full working example
|
|
456
|
+
Full working example: [`examples/blazor-faktur/`](../examples/blazor-faktur/),
|
|
448
457
|
`Pages/ComponentsDemo.razor`.
|
|
449
458
|
|
|
450
459
|
---
|
|
@@ -452,8 +461,8 @@ Full working example (all ten): [`examples/blazor-faktur/`](../examples/blazor-f
|
|
|
452
461
|
## Verify (every stack)
|
|
453
462
|
|
|
454
463
|
Run the project → check two things:
|
|
455
|
-
1. **CSS connected
|
|
456
|
-
2. **Enhancers connected
|
|
464
|
+
1. **CSS connected:** buttons/cards are styled (not plain HTML).
|
|
465
|
+
2. **Enhancers connected:** interactive components come alive (e.g. datepicker/combo open on
|
|
457
466
|
click), and `event.detail` reaches your state.
|
|
458
467
|
|
|
459
468
|
If the visuals are plain → the CSS didn't load. If visuals are fine but widgets are dead → the
|