declarative-forms 2.0.0-alpha.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 ADDED
@@ -0,0 +1,115 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - A second stylesheet, `declarative-forms/theme.css`: a modern redesign with
13
+ automatic light and dark mode (`prefers-color-scheme`, overridable with
14
+ `data-dl-theme`), focus rings, fluid widths and a fuller token set. It is a
15
+ standalone alternative to `styles.css`, renders the identical DOM, and mirrors
16
+ the default stylesheet's selectors and specificity so existing overrides keep
17
+ winning. The default stylesheet is unchanged.
18
+ - Under the modern theme, checkboxes are **keyboard-reachable**: the input is
19
+ styled directly with `appearance: none` rather than hidden behind a
20
+ pseudo-element. The default stylesheet keeps its existing behaviour.
21
+ - Two wrapper classes for stacked dialogs: `dl-modal-stacked` on a dialog opened
22
+ on top of another, and `dl-modal-restored` on one revealed again after being
23
+ covered. Both mark a backdrop that is already on screen, so a theme can skip
24
+ its entrance animation. A stacked wrapper also carries `--dl-stack-depth`, the
25
+ number of dialogs underneath it.
26
+ - Under the modern theme, a stacked dialog now **shows the stack**: the dialogs
27
+ below it, which are hidden, are drawn as card edges peeking out above the
28
+ dialog on top — one edge for a single dialog below, two for more. Sized with
29
+ `--dl-stack-peek` and `--dl-stack-inset`. The default stylesheet is unchanged.
30
+
31
+ ### Fixed
32
+
33
+ - Opening or closing a stacked dialog no longer flashes the page under the
34
+ backdrop. The covered dialog was hidden in the same frame the new one started
35
+ fading in, leaving nothing over the page for the length of the animation; the
36
+ modern theme now skips that animation for stacked and restored dialogs. The
37
+ default stylesheet was never affected — it has no animations.
38
+
39
+ ## [2.0.0-alpha.0]
40
+
41
+ Complete rewrite in TypeScript with an object-oriented design.
42
+
43
+ **The JavaScript API is a clean break; the rendered DOM is deliberately
44
+ unchanged.** Stylesheets and DOM-based end-to-end selectors written against v1
45
+ keep working. See the [migration guide](https://wolfoo2931.github.io/declarative-forms/migration-v1).
46
+
47
+ ### Added
48
+
49
+ - Discriminated `kind` on field descriptors, making them fully typable.
50
+ - `form.field(name)` — a typed handle with `getValue`, `setValue`, `focus`,
51
+ `setLoading`, `element` and `wrapper`.
52
+ - `FieldRegistry`, so applications can register their own field kinds.
53
+ - Pluggable `TooltipProvider`, with a native zero-dependency default.
54
+ - `html()` / `escapeHtml()` for explicit, opt-in markup.
55
+ - `whenReady()`, `destroy()`, and an unsubscribe return from
56
+ `subscribeOnInput()`.
57
+ - `dl-error` event on file-upload failure.
58
+ - A `--dl-*` design-token layer and a dark theme.
59
+ - Documentation site, and a live example playground under `examples/`.
60
+
61
+ ### Changed
62
+
63
+ - Package renamed to `declarative-forms`; the export is now named
64
+ (`import { DeclarativeForm }`).
65
+ - Constructor takes a single options object instead of five positional
66
+ arguments.
67
+ - Descriptor callbacks receive one context object instead of per-callback
68
+ positional argument lists.
69
+ - Renamed: `mapFiledsOnEdit` → `mapFieldsOnEdit`,
70
+ `onValuesCalculationFailedMessage` → `onOptionsError`,
71
+ `closeModalIfOpen` → `close`, `updateCalculatedFields` →
72
+ `updateComputedFields`, `mulitple-allowed` → `multiple`.
73
+ - `descriptor.domElement` replaced by `form.field(name)`; the library no longer
74
+ mutates caller-supplied descriptors.
75
+ - Dialog buttons are `<button type="button">` rather than `<div>`, keeping the
76
+ `.btn` class.
77
+ - Content is rendered as text by default; markup requires `html()`.
78
+ - `message` fields no longer appear in `getValues()`.
79
+ - `buttons` and `onConfirm` are independent — a single-button map no longer
80
+ silently replaces `onConfirm`.
81
+ - Test tooling replaced with Vitest, Playwright and tsup.
82
+
83
+ ### Removed
84
+
85
+ - All runtime dependencies: `tippy.js`, `@popperjs/core`,
86
+ `@react-hookz/deep-equal`, and the unused `uuid`.
87
+ - The v1 Karma/Jasmine/wdio/Browserify setup, which could not run — its
88
+ packages were referenced by scripts but absent from `devDependencies`.
89
+
90
+ ### Fixed
91
+
92
+ - `<label for>` pointed at a field name that was never an element id, so no
93
+ field was ever labelled for assistive technology.
94
+ - Checkbox ids collided between a parent form and its array sub-form.
95
+ - `getValues()` could not represent `''`, `0` or `false`.
96
+ - The internal promise list grew without bound and was never cleared.
97
+ - Tabs and tooltips were resolved with `document.querySelector`, so two open
98
+ forms fought over each other's state.
99
+ - A slow options load could overwrite a newer one; loads are now
100
+ generation-guarded.
101
+ - Caller data was interpolated as HTML in 21 places.
102
+ - Option values containing a quote threw a `DOMException`.
103
+ - A keydown listener and a stylesheet were installed as import side effects,
104
+ breaking server-side rendering.
105
+ - `class DlSelect extends HTMLElement` was evaluated at module load, so simply
106
+ importing the package threw `HTMLElement is not defined` in Node and broke
107
+ any server-rendered or prerendered app.
108
+ - `classList.remove` was written as `Element.remove()`, deleting the confirm
109
+ button whenever it showed its loading state.
110
+ - `<dl-option>` was never registered as a custom element.
111
+ - Buttons flashed disabled on every keystroke, and a well-timed click could be
112
+ dropped.
113
+
114
+ [Unreleased]: https://github.com/wolfoo2931/declarative-forms/compare/v2.0.0-alpha.0...HEAD
115
+ [2.0.0-alpha.0]: https://github.com/wolfoo2931/declarative-forms/releases/tag/v2.0.0-alpha.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Wolf Oliver
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # declarative-forms
2
+
3
+ Declarative forms for the web that make front-end development less front-end development.
4
+
5
+ Whenever you need input from a user, you describe the data you need and the rules around it. `declarative-forms` takes care of the front-end work to ask for that information: rendering the fields, wiring updates, loading async option sets, managing nested structures, handling modal stacks, tabs, and keeping the UI in sync as values change.
6
+
7
+ 📖 **[Read the documentation](https://wolfoo2931.github.io/declarative-forms/)**
8
+
9
+ You do not have to build the front-end plumbing by hand just to collect structured input. Instead, you provide a schema-like description of the form and the library handles the rest.
10
+
11
+ This is especially useful for complex forms, complex data structures, and workflows where the interface is mostly there to collect and validate user input rather than to render bespoke product UI.
12
+
13
+ ## What it is
14
+
15
+ At its core, `declarative-forms` is a framework-agnostic form engine.
16
+
17
+ You define a form like this:
18
+
19
+ ```ts
20
+ import 'declarative-forms/styles.css';
21
+ import { DeclarativeForm } from 'declarative-forms';
22
+
23
+ const form = new DeclarativeForm({
24
+ fields: [
25
+ { name: 'title', displayName: 'Title' },
26
+ {
27
+ name: 'language',
28
+ kind: 'select',
29
+ displayName: 'Language',
30
+ options: [
31
+ { value: 'en', label: 'English' },
32
+ { value: 'de', label: 'German' },
33
+ ],
34
+ defaultValue: 'en',
35
+ },
36
+ {
37
+ name: 'repo',
38
+ kind: 'select',
39
+ displayName: 'Repository',
40
+ reloadOnChangeOf: ['language'],
41
+ options: async ({ data }) => {
42
+ const lang = String(data['language'] ?? 'en');
43
+ return [{ value: `repo-${lang}`, label: `Repo (${lang})` }];
44
+ },
45
+ },
46
+ ],
47
+ onConfirm: (values) => console.log(values),
48
+ onCancel: () => {},
49
+ });
50
+
51
+ form.openInModal();
52
+ ```
53
+
54
+ This is not a generated UI package or a full application framework. It is a runtime for declarative form behavior: you describe the data model and form rules, and it turns that into a working user flow with the UI concerns handled for you.
55
+
56
+ ## What makes it different
57
+
58
+ The library is built around a few real strengths that show up in the codebase:
59
+
60
+ - Data-first form definitions instead of manual DOM creation
61
+ - Cross-field reactivity via `reloadOnChangeOf`, `isActive`, `defaultValue`, and `onFormChange`
62
+ - Async option loading and async button predicates
63
+ - Built-in modal stack support for nested dialogs and wizards
64
+ - Tabbed forms and array-of-record editing
65
+ - Automatic handling of many front-end concerns: layout, state sync, stacking, dialog behavior, and reusable field logic
66
+ - Zero runtime dependencies
67
+ - Works in plain JavaScript or TypeScript, not just React/Vue/Svelte
68
+
69
+ The library also includes a few opinionated features that are especially useful for interactive tools:
70
+
71
+ - computed fields that recalculate before confirmation
72
+ - file fields that require a `persistFile` callback to convert a local file into a stored URL
73
+ - custom render fields for embedding arbitrary DOM or widget logic inside a form
74
+ - message, cards, and custom field types for dynamic UI without a separate component library
75
+
76
+ ## When to use this library
77
+
78
+ Use `declarative-forms` when the form is more like an application workflow than a static input form.
79
+
80
+ It fits especially well for:
81
+
82
+ - admin panels and settings dialogs
83
+ - configuration flows with conditions and dependencies
84
+ - modal-based wizards with step logic
85
+ - forms whose options depend on other fields
86
+ - array/list editing with nested record forms
87
+ - internal tools that need compact, data-driven UI without a UI framework dependency
88
+
89
+ ## Core ideas in the codebase
90
+
91
+ The library is centered on a few runtime concepts:
92
+
93
+ - `DeclarativeForm`: the main runtime that owns rendering, values, tabs, and modal behavior
94
+ - `FieldDescriptor`: a plain object describing each field (`name`, `kind`, `options`, `tab`, `isActive`, etc.)
95
+ - `FormValues`: the current data dictionary keyed by field name
96
+ - `subscribeOnInput`: a way to observe form updates without wiring lots of DOM listeners
97
+ - `ButtonDescriptor`: supports async enable/disable logic and “do not close” actions for wizards
98
+
99
+ This is why the project feels more like a small “form engine” than a typical form component library.
100
+
101
+ ## Install
102
+
103
+ ```bash
104
+ npm install declarative-forms
105
+ ```
106
+
107
+ And include the default CSS:
108
+
109
+ ```ts
110
+ import 'declarative-forms/styles.css';
111
+ ```
112
+
113
+ ## Example: modal form
114
+
115
+ ```ts
116
+ import { DeclarativeForm } from 'declarative-forms';
117
+
118
+ const form = new DeclarativeForm({
119
+ fields: [
120
+ { name: 'name', displayName: 'Name' },
121
+ {
122
+ name: 'role',
123
+ kind: 'select',
124
+ displayName: 'Role',
125
+ options: ['Admin', 'Editor', 'Viewer'],
126
+ defaultValue: 'Editor',
127
+ },
128
+ ],
129
+ onConfirm: (values) => {
130
+ console.log('submitted', values);
131
+ },
132
+ onCancel: () => {
133
+ console.log('cancelled');
134
+ },
135
+ });
136
+
137
+ form.openInModal();
138
+ ```
139
+
140
+ ## Example: reactive field logic
141
+
142
+ ```ts
143
+ const form = new DeclarativeForm({
144
+ fields: [
145
+ {
146
+ name: 'source',
147
+ kind: 'select',
148
+ displayName: 'Source',
149
+ options: ['GitHub', 'GitLab'],
150
+ defaultValue: 'GitHub',
151
+ },
152
+ {
153
+ name: 'token',
154
+ displayName: 'Token',
155
+ type: 'password',
156
+ isActive: ({ data }) => data['source'] === 'GitLab',
157
+ },
158
+ {
159
+ name: 'repo',
160
+ kind: 'select',
161
+ displayName: 'Repository',
162
+ reloadOnChangeOf: ['source'],
163
+ options: async ({ data }) => {
164
+ const source = String(data['source'] ?? 'GitHub');
165
+ return [{ value: `${source}-repo`, label: `${source} repo` }];
166
+ },
167
+ },
168
+ ],
169
+ onConfirm: (values) => console.log(values),
170
+ });
171
+ ```
172
+
173
+ This is the sort of behavior the library is designed to make practical without building a lot of custom event wiring.
174
+
175
+ ## Documentation
176
+
177
+ Full documentation is at **[wolfoo2931.github.io/declarative-forms](https://wolfoo2931.github.io/declarative-forms/)**:
178
+
179
+ - [Getting started](https://wolfoo2931.github.io/declarative-forms/guide/getting-started)
180
+ - [Field kinds](https://wolfoo2931.github.io/declarative-forms/guide/fields/) — the ten built-in kinds
181
+ - [Reactivity](https://wolfoo2931.github.io/declarative-forms/guide/reactivity) — `isActive`, `reloadOnChangeOf`, computed fields
182
+ - [API reference](https://wolfoo2931.github.io/declarative-forms/reference/api)
183
+ - [Migrating from v1](https://wolfoo2931.github.io/declarative-forms/migration-v1)
184
+
185
+ ## Status and limitations
186
+
187
+ Worth knowing before you adopt it:
188
+
189
+ - **Accessibility is a work in progress.** Labels, ids and focusable buttons are correct; dialog semantics, combobox ARIA and keyboard-reachable checkboxes are not there yet. The [accessibility page](https://wolfoo2931.github.io/declarative-forms/accessibility) lists every known gap.
190
+ - **There is no validation framework.** `isActive` handles conditional fields and button predicates gate submission, but there is no rule engine or error-message system.
191
+ - **The rendered DOM is a frozen contract.** Class names, ids and structure are stable across the v1 → v2 rewrite, so existing stylesheets keep working. See the [DOM contract](https://wolfoo2931.github.io/declarative-forms/dom-contract).
192
+
193
+ ## Summary
194
+
195
+ `declarative-forms` is best thought of as a declarative form runtime for web dialogs and tool-like workflows.
196
+
197
+ It is for the cases where the main job is not “build another UI component,” but “ask the user for structured data.” You define what needs to be collected, and the library handles the front-end work to gather it: field rendering, behavior, defaults, dynamic changes, nested records, modal stacking, and workflow handling.
198
+
199
+ That is the core difference: instead of writing front-end code for every form interaction, you describe the data and rules, and the runtime takes care of the responsibilities that usually consume most of the work in form-heavy interfaces.