jsswift 2.0.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/AI.md +38 -73
- package/README.md +2 -0
- package/dist/build/build-configured-runtime.d.mts +29 -0
- package/dist/build/build-configured-runtime.mjs +92 -0
- package/dist/build/runtime-layout.mjs +13 -0
- package/dist/build/select-ui.mjs +167 -0
- package/dist/build/vite-jss.d.mts +2 -0
- package/dist/build/vite-jss.mjs +73 -0
- package/dist/cms.js +3522 -0
- package/dist/documentions/AI.md +38 -73
- package/dist/documentions/README.md +4 -2
- package/dist/documentions/components/table.md +13 -0
- package/dist/documentions/configured-runtime.md +82 -0
- package/dist/documentions/examples/crud.md +18 -7
- package/dist/documentions/getting-started.md +2 -0
- package/dist/documentions/knowledge-map.json +20 -1
- package/dist/documentions/ui/data-feedback-overlays.md +2 -0
- package/dist/documentions/ui/forms.md +2 -0
- package/dist/ui-src/00-bootstrap.js +330 -0
- package/dist/ui-src/01-foundation-helpers.js +809 -0
- package/dist/ui-src/10-primitives-layout.js +5091 -0
- package/dist/ui-src/20-display-content.js +780 -0
- package/dist/ui-src/21-list-content.js +246 -0
- package/dist/ui-src/22-banner-content.js +376 -0
- package/dist/ui-src/23-tooltip.js +276 -0
- package/dist/ui-src/31-form-advanced.js +2784 -0
- package/dist/ui-src/40-navigation.js +1262 -0
- package/dist/ui-src/41-tab-panel.js +896 -0
- package/dist/ui-src/50-feedback.js +999 -0
- package/dist/ui-src/51-feedback-service.js +166 -0
- package/dist/ui-src/60-shell-app.js +1223 -0
- package/dist/ui-src/61-form-service.js +368 -0
- package/dist/ui-src/70-dialog.js +333 -0
- package/dist/ui-src/71-menu-overlays.js +1217 -0
- package/dist/ui-src/80-data.js +437 -0
- package/dist/ui-src/modules.json +212 -0
- package/dist/ui.js +12565 -0
- package/package.json +26 -2
package/dist/documentions/AI.md
CHANGED
|
@@ -16,6 +16,7 @@ The installed package exposes this same guide as `AI.md` at its root and through
|
|
|
16
16
|
| --- | --- | --- |
|
|
17
17
|
| Small page with the six components below | This guide | Implement the supported subset without opening component contracts. |
|
|
18
18
|
| Product CRUD with validation, persistence and focus | [CRUD example](examples/crud.md) | Reuse the example; do not also concatenate Input, Select, Dialog and Table contracts. |
|
|
19
|
+
| jss.config.js, selective runtime, Vite plugin or optional extras | [Configured runtime](configured-runtime.md) (`guide:configured-runtime`) | Follow the existing app configuration; do not also import the complete runtime/CSS. |
|
|
19
20
|
| One missing prop or callback | Map → exact document, or selective MCP read | Read only the needed section; do not search the runtime bundle. |
|
|
20
21
|
| Custom appearance | Supported props below, then one relevant contract | Keep component styles; add CSS for page layout and task-specific visuals. |
|
|
21
22
|
|
|
@@ -23,52 +24,34 @@ The map locates a contract; it does not replace it. Avoid reading all of `ui/com
|
|
|
23
24
|
|
|
24
25
|
## Import, create, mount
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
For an existing app, preserve its loading method. With the configured Vite plugin, import `jss:runtime` instead of the two traditional imports below: it includes the configured JavaScript, CSS and extras. Read [configured-runtime.md](configured-runtime.md) for setup and package availability; older installed releases may not expose this tooling.
|
|
28
|
+
|
|
29
|
+
With Vite, provide `<div id="app"></div>` and a module entrypoint:
|
|
27
30
|
|
|
28
31
|
```js
|
|
29
32
|
import 'jsswift';
|
|
30
33
|
import 'jsswift/css/ui-light.css';
|
|
31
34
|
const _ = window._;
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!name.value.trim()) {
|
|
48
|
-
errors.replaceChildren(_.p('Il nome è obbligatorio.'));
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
errors.replaceChildren();
|
|
52
|
-
console.log({ name: name.value, category: category.value });
|
|
53
|
-
dialog.close();
|
|
54
|
-
}}, 'Salva');
|
|
55
|
-
dialog.update({ actions: [
|
|
56
|
-
_.Button({ onClick: () => dialog.close() }, 'Annulla'), save
|
|
57
|
-
] });
|
|
58
|
-
const edit = _.Button({ onClick: () => dialog.open() }, 'Modifica');
|
|
59
|
-
const table = _.Table({
|
|
60
|
-
rows: [{ id: 1, name: 'Prodotto 01', price: 10 }], rowKey: 'id',
|
|
61
|
-
columns: [
|
|
62
|
-
{ key: 'name', label: 'Nome', render: (row, { value }) => _.strong(value) },
|
|
63
|
-
{ key: 'price', label: 'Prezzo', format: value => `${value} EUR` }
|
|
64
|
-
],
|
|
65
|
-
pagination: false, hideFooter: true, hideStatus: true, minTableWidth: 700
|
|
66
|
-
});
|
|
67
|
-
const page = _.Page({}, _.div({}, _.h1('Prodotti'), edit, table));
|
|
68
|
-
_.mount('#app', page);
|
|
35
|
+
const name = _.rod('Prodotto 01'), category = _.rod('Casa');
|
|
36
|
+
const input = _.Input({label:'Nome', required:true, model:name});
|
|
37
|
+
const select = _.Select({label:'Categoria', model:category,
|
|
38
|
+
options:[{value:'Casa',label:'Casa'},{value:'Ufficio',label:'Ufficio'}]});
|
|
39
|
+
const dialog = _.Dialog({title:'Prodotto', ariaLabel:'Prodotto',
|
|
40
|
+
content:_.div({}, input, select), trapFocus:true, closeOnEsc:true,
|
|
41
|
+
onOpen:() => input.focus()});
|
|
42
|
+
dialog.update({actions:[_.Button({onClick:() => {
|
|
43
|
+
console.log({name:name.value, category:category.value}); dialog.close();
|
|
44
|
+
}}, 'Salva')]});
|
|
45
|
+
const table = _.Table({rows:[{id:1,name:'Prodotto 01'}], rowKey:'id',
|
|
46
|
+
columns:[{key:'name',label:'Nome',sortable:false,render:(row,ctx) => _.strong(ctx.value)}],
|
|
47
|
+
pagination:false, hideFooter:true, hideStatus:true, minTableWidth:600});
|
|
48
|
+
_.mount('#app', _.div({}, _.Card({title:'Prodotti'},
|
|
49
|
+
_.Button({color:'primary',onClick:() => dialog.open()}, 'Modifica')), table));
|
|
69
50
|
```
|
|
70
51
|
|
|
71
|
-
This
|
|
52
|
+
This logs values; it does not implement validation or persistence. For product editing use [the executable CRUD example](examples/crud.md) instead of reading forms, overlays or component contracts first.
|
|
53
|
+
|
|
54
|
+
Prefer `_.rod(initial)` for bidirectional fields: read/write `model.value`. `_.signal(initial)` remains supported. Input/Select expose `focus(options?)`; avoid private `_input`/`_select`. Use `label`, `required`, `ariaLabel`, `ariaLabelledBy`, `ariaDescribedBy`, `ariaInvalid`, and `error: _.rod('')`. Input accepts `min`, `max`, `step`, `pattern`, `minLength`, `maxLength`.
|
|
72
55
|
|
|
73
56
|
## Exact callback arguments
|
|
74
57
|
|
|
@@ -87,67 +70,49 @@ Dialog returns an API object, not a node to mount: `open(overrides?)`, `close()`
|
|
|
87
70
|
|
|
88
71
|
## Existing CSS and optional assets
|
|
89
72
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
The UI stylesheet includes component styles, theme variables, and responsive rules. Start with native components. Prefer documented `color`, `dense`, `padding`, `radius`, `shadow`, and breakpoint props to overrides of internal `.jss-*` classes. Read [common props](ui/common-props.md) only for an additional inherited prop; component-specific definitions take precedence. Use custom CSS for remaining page requirements.
|
|
73
|
+
The light import includes base tokens, colors, component styles, dense/outline and unprefixed layout utilities. Add `jsswift/css/responsive.css` **after** it for tablet/pc/desktop or legacy breakpoint classes. `ui.css` is the complete alternative; do not import full and light together. Component-specific mobile rules remain in light.
|
|
93
74
|
|
|
94
|
-
|
|
75
|
+
Prefer public props to rebuilding controls: `_.Button({color:'primary',outline:true,dense:true}, 'Modifica')`. For breakpoint props use `_.Row({gap:'md',tablet:{gap:'lg'}})` with the responsive addon. Consult common props only for an additional inherited API.
|
|
95
76
|
|
|
96
|
-
|
|
77
|
+
Classes and theme variables use `jss-`; migrate old `cms-` overrides. Fonts are system defaults. Import `jsswift/css/fonts-nunito.css`, `fonts-material.css`, or `jsswift/tabler` only when required; Material Symbols downloads a remote font.
|
|
97
78
|
|
|
98
|
-
|
|
79
|
+
With `jss:runtime`, choose assets in `jss.config.js` through `extras` instead of adding these imports. `ui: {all:true}` includes the complete UI and services. For a selective build, use `ui: {components:['Button','Input','Select','Card','Table'],services:['Dialog']}` for the example above; dependencies are automatic. Services also support Notify, Loading and Form (useForm). Add every component used through dynamic lookup explicitly. `responsive:false` retains base utilities and component mobile CSS but excludes breakpoint utilities; use true for tablet/pc props. Shared and complex CSS rules are retained conservatively.
|
|
99
80
|
|
|
100
81
|
## Accessibility and verification
|
|
101
82
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Run the app's build after implementation and check values, validation, dialog keyboard behavior, and persistence when required. Start one development server on an explicit available port; with Vite use `npm run dev -- --port <port> --strictPort`. Report checks actually performed.
|
|
105
|
-
|
|
106
|
-
## Read only what the task needs
|
|
107
|
-
|
|
108
|
-
- Exact APIs: [Input](components/input.md), [Select](components/select.md), [Button](components/btn.md), [Card](components/card.md), [Table](components/table.md), [Dialog](components/dialog.md).
|
|
109
|
-
- Extra behavior: [forms](ui/forms.md), [reactivity](reactivity.md), [layout](ui/layout-and-responsive.md), [overlays](ui/data-feedback-overlays.md).
|
|
110
|
-
- Other components: [index](components/README.md). MCP: read `guide:AI`, then search only for additional features.
|
|
83
|
+
String labels name Input/Select; set Dialog `ariaLabel`. Field errors are associated automatically. Dialog preserves focus assigned in `onOpen`. If rendering replaces the trigger, restore its current replacement in `onClose`; see CRUD.
|
|
111
84
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
## Verification evidence and environment
|
|
115
|
-
|
|
116
|
-
Check whether browser tooling and server permissions are available before launching checks. Run Git commands only in a Git worktree; for example test `git rev-parse --is-inside-work-tree` before requesting a diff. Keep build, pure-logic tests and server startup results separate. An HTTP response confirms a reachable server, not that your startup command succeeded or that browser interactions work. Report environment failures separately from application failures. Test the implemented functions rather than rebuilding equivalent data inside an assertion.
|
|
117
|
-
|
|
118
|
-
Dialog autofocus preserves focus assigned inside `onOpen`; verify initial focus after the deferred autofocus has run, separately from validation focus and return focus. Record each check separately: initial field, Tab/Shift+Tab containment, Escape, and return to the current trigger. A focus-trap result does not prove initial focus. Field messages are associated with Input/Select through `aria-describedby` automatically.
|
|
119
|
-
|
|
120
|
-
## Focus CSS and targeted reads
|
|
121
|
-
|
|
122
|
-
Apply focus indicators to every selector through `:is`, rather than placing the pseudo-class on only the final selector in a comma-separated list:
|
|
85
|
+
Build is not a browser test. Verify initial focus after deferred autofocus, Tab/Shift+Tab containment, Escape, return focus, validation, persistence, mobile overflow and borders separately. Report unverified checks. Use this custom focus CSS:
|
|
123
86
|
|
|
124
87
|
```css
|
|
125
|
-
:is(button,
|
|
88
|
+
:is(button,a,input,select,[tabindex]):focus-visible {
|
|
126
89
|
outline: 3px solid #2563eb;
|
|
127
90
|
outline-offset: 3px;
|
|
128
91
|
}
|
|
129
92
|
```
|
|
130
93
|
|
|
131
|
-
|
|
94
|
+
Keep build, logic assertions and server startup in separate commands. Check tooling/permissions first; use an explicit Vite port with `--strictPort`. Environment failures are not application failures; HTTP alone does not verify interactions.
|
|
95
|
+
|
|
96
|
+
## Additional APIs only
|
|
132
97
|
|
|
98
|
+
Use the map for the missing API, then read its focused contract. Button is `components/btn.md` (`button.md` redirects). With configured MCP: `jsswift_read({id:"component:table",section:"props",keys:["pagination","hideFooter"]})`; sections include props/events/methods/slots and resolve inherited props. No MCP setup is required for local documentation.
|
|
133
99
|
|
|
134
100
|
## Catalogue surfaces and field styling
|
|
135
101
|
|
|
136
|
-
|
|
102
|
+
`_.Kpi({title:'Disponibili',value:9,note:'Con quantità maggiore di zero'})` supplies dashboard metrics. Update KPI when inventory changes, not on each filter; see CRUD. Read the Kpi contract only for additional options.
|
|
137
103
|
|
|
138
|
-
Table
|
|
104
|
+
Table returns a Card; use a structural container. Card props include `shadow:'none'`, `radius:'12px'`, and `padding`. For a fixed light surface: `style:{background:'#fff'}`, `tableStyle:{background:'#fff','--set-color-1':'#fff'}`. This does not provide automatic dark theming.
|
|
139
105
|
|
|
140
|
-
|
|
106
|
+
For external pagination use `pagination:false`, `hideFooter:true`, `hideStatus:true`, `emptyText:'Nessun prodotto trovato'`, `minTableWidth:600`. Set each data column's `sortable:false`: built-in sorting sees only the supplied page. Sort the full filtered dataset before slicing if needed.
|
|
141
107
|
|
|
142
|
-
|
|
108
|
+
Input's native input is transparent; preserve that background to keep the outer curved border visible. Set height on an application container:
|
|
143
109
|
|
|
144
110
|
```css
|
|
145
111
|
.catalogue-filters {
|
|
146
112
|
--jss-input-height-default: 40px;
|
|
147
113
|
}
|
|
148
114
|
```
|
|
149
|
-
|
|
150
|
-
Check the border, floating label, error message and keyboard focus at desktop and mobile sizes. A passing CRUD test does not verify these visual states. Keep failed server startup, retry incidents, cached input and uncached input separate when comparing repeated benchmark runs.
|
|
115
|
+
Use the field's `radius` prop if it should not inherit a surface radius. Avoid clipping controls/focus indicators with overflow:hidden. Check borders, labels, errors and focus at desktop/mobile sizes.
|
|
151
116
|
|
|
152
117
|
## Theme and lifecycle essentials
|
|
153
118
|
|
|
@@ -7,11 +7,13 @@ Build applications with JSswift by reading only the smallest focused guide. Exac
|
|
|
7
7
|
| Need | Read |
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| AI discovery, portable Skill, local MCP | [ai-development.md](ai-development.md), [knowledge-map.json](knowledge-map.json) |
|
|
10
|
-
| First app or screen | [getting-started.md](getting-started.md) |
|
|
10
|
+
| First app or screen | [AI.md](AI.md) alone; [getting-started.md](getting-started.md) only for additional setup |
|
|
11
|
+
| Experimental configured runtime build | [configured-runtime.md](configured-runtime.md) |
|
|
11
12
|
| Component choice and composition | [application-rules.md](application-rules.md), [components/README.md](components/README.md) |
|
|
12
13
|
| State and controlled inputs | [reactivity.md](reactivity.md) |
|
|
13
14
|
| Layout and breakpoints | [ui/layout-and-responsive.md](ui/layout-and-responsive.md) |
|
|
14
|
-
|
|
|
15
|
+
| Product CRUD | [examples/crud.md](examples/crud.md), without pre-reading forms or overlay contracts |
|
|
16
|
+
| Additional form APIs | [ui/forms.md](ui/forms.md) |
|
|
15
17
|
| Base CSS, theme tokens and component colors | [ui/themes.md](ui/themes.md) |
|
|
16
18
|
| Router, store, HTTP, auth, themes | [platform.md](platform.md) |
|
|
17
19
|
| Tables, feedback, dialogs, menus | [ui/data-feedback-overlays.md](ui/data-feedback-overlays.md) |
|
|
@@ -116,3 +116,16 @@ _.mount('#app', _.div({style: {minWidth: 0}}, table));
|
|
|
116
116
|
For external paging, the status count describes the supplied page (for example, “5 righe”); an external total describes all filtered results. Choose whether both pieces of information are useful. `status` adds content; it does not replace or hide the built-in count. `hideFooter` only hides the footer. Do not use `hideHeader` to remove the status row. Use `hideStatus: true` to hide that row when the application supplies its own summary. It does not hide the toolbar, column headings or footer.
|
|
117
117
|
|
|
118
118
|
A grey surface or gradient is not a focus indicator. Inspect the Card/theme surface separately from `:focus-visible`; do not remove keyboard indicators to change a background. Custom table-cell styling is application CSS, and should remain scoped to an application class.
|
|
119
|
+
|
|
120
|
+
## Fixed white catalogue surface
|
|
121
|
+
|
|
122
|
+
Use public `style` for the outer Card and `tableStyle` for the HTML table:
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
_.Table({rows:products, columns:[{key:'name',label:'Nome'}],
|
|
126
|
+
shadow:'none', radius:'12px',
|
|
127
|
+
style:{background:'#fff'},
|
|
128
|
+
tableStyle:{background:'#fff', '--set-color-1':'#fff'}});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`radius`, `padding` and `shadow` act on the Card; `tableStyle` acts on the table, and `--set-color-1` supplies its header background. The inner scroll frame remains. This explicitly fixes a light surface; for theme switching use theme-dependent values instead. Do not remove focus outlines to change a surface.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Configured application runtime (experimental)
|
|
2
|
+
|
|
3
|
+
`jss.config.js` selects UI components, services and optional assets at build time. The complete runtime remains compatible with existing imports and script bundles. The package build includes the tooling under jsswift/vite and jsswift/build, plus the jss-build command. These additions are included starting with jsswift 2.1.0; older installed releases do not expose them. Build tooling requires Node.js 20.19.x or >=22.12.0.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
export default {
|
|
9
|
+
ui: { all: true, responsive: true },
|
|
10
|
+
extras: ['material-symbols-outlined'],
|
|
11
|
+
};
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
For a selective application:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
export default {
|
|
18
|
+
ui: {
|
|
19
|
+
components: ['Button', 'Input', 'Table'],
|
|
20
|
+
services: ['Dialog', 'Notify'],
|
|
21
|
+
responsive: false,
|
|
22
|
+
},
|
|
23
|
+
extras: ['material-symbols-outlined'],
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`ui.all` defaults to true when neither components nor services is specified. Providing either list enables selective mode unless all is explicitly true. Use all:true alone; combining it with nonempty selection lists is rejected. `ui: {all:false}` without lists builds core-only JavaScript and base CSS. Unknown component, service, extra and configuration names fail the build.
|
|
28
|
+
|
|
29
|
+
Component names match the public API, including Button/Btn and cardHeader/cardBody/cardFooter. Supported services are Dialog (component plus alert/confirm/prompt shortcuts), Notify (component plus toast service), Loading (loading overlay), and Form (useForm). Dependencies are resolved from source statements; Button includes Icon, Tooltip and Spinner, while Table also includes Card. Referenced optional branches are included conservatively. Applications using dynamic component lookup must explicitly request every possible component.
|
|
30
|
+
|
|
31
|
+
`ui.responsive` defaults to true. False retains base layout utilities and component mobile CSS, but excludes breakpoint utilities. In selective mode, component-owned CSS selectors are pruned; shared tokens, native rules, utilities, animations, unknown selectors and complex functional selectors are retained conservatively. The core is always included completely.
|
|
32
|
+
|
|
33
|
+
Supported extras are `material-symbols-outlined`, `nunito-font`, and `tabler`; the default is an empty array. Material Symbols uses a remote Google font. Nunito font files and the Tabler sprite are local assets. Extra assets are included only when configured; separate application CSS/imports can still load additional assets independently.
|
|
34
|
+
|
|
35
|
+
## Vite
|
|
36
|
+
|
|
37
|
+
Install jsswift and Vite in your application, then register the plugin:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { defineConfig } from 'vite';
|
|
41
|
+
import { jssRuntime } from 'jsswift/vite';
|
|
42
|
+
|
|
43
|
+
export default defineConfig({ plugins: [jssRuntime()] });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Import the configured runtime from your application module:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import 'jss:runtime';
|
|
50
|
+
_.mount('#app', _.Button({ label: 'Save' }));
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The plugin includes JavaScript, CSS and extras together, emits jss-build-report.json in production, and restarts the development server when configuration changes. An alternative config path can be passed as `jssRuntime({config:'./other.config.js'})`. The repository ui.html demo now uses this integration; it requires Vite rather than opening the source HTML directly as a local file. The demo calls many components, so retain all:true unless its example code is reduced to the selected components.
|
|
54
|
+
|
|
55
|
+
## Standalone output
|
|
56
|
+
|
|
57
|
+
With jsswift installed, run the packaged CLI from your project:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npx jss-build jss.config.js dist-runtime
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
You can also put `"build:runtime": "jss-build"` in your application package.json scripts. `jss-build --help` prints the arguments. For programmatic builds, import buildConfiguredRuntime or validateConfig from `jsswift/build`. The plugin and CLI use the package's own runtime, CSS, source modules and assets; no framework checkout is needed. Vite is an optional peer dependency and is not required for standalone builds.
|
|
64
|
+
|
|
65
|
+
In the framework checkout, first run `npm run build:runtime`, then:
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
npm run build:configured -- jss.config.js dist-runtime
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This generates runtime.js, css/runtime.css, selected extra assets and build-report.json. The report lists selected components/services, dependency reasons, inputs, removed CSS selectors and JavaScript/CSS byte counts. The output directory must be empty to avoid stale optional assets; use a fresh destination for subsequent standalone builds. Vite builds manage their own output normally.
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
<link rel="stylesheet" href="./dist-runtime/css/runtime.css">
|
|
76
|
+
<script type="module">
|
|
77
|
+
import './dist-runtime/runtime.js';
|
|
78
|
+
_.mount('#app', _.Button({label:'Save'}));
|
|
79
|
+
</script>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Continue using the single public `_` application namespace.
|
|
@@ -37,32 +37,42 @@ save = _.Button({id:'save-product', onClick:() => {
|
|
|
37
37
|
const record = {id:editing ?? Math.max(0,...rows.map(r => r.id))+1,...value};
|
|
38
38
|
const next = editing == null ? [...rows,record] : rows.map(r => r.id === editing ? record : r);
|
|
39
39
|
try { localStorage.setItem(key, JSON.stringify(next)); } catch { notice.textContent = 'Salvataggio non riuscito'; return; }
|
|
40
|
-
rows = next; render(); dialog.close(); notice.textContent = 'Salvato';
|
|
40
|
+
rows = next; renderStats(); render(); dialog.close(); notice.textContent = 'Salvato';
|
|
41
41
|
}}, 'Salva');
|
|
42
42
|
dialog.update({actions:[_.Button({onClick:() => dialog.close()},'Annulla'),save]});
|
|
43
43
|
for (const k of Object.keys(models)) models[k].value = String(record?.[k] ?? '');
|
|
44
44
|
dialog.open();
|
|
45
45
|
}
|
|
46
|
-
const host = _.div({style:{maxWidth:'100%',overflowX:'auto'}}), pager = _.div();
|
|
46
|
+
const host = _.div({style:{maxWidth:'100%',overflowX:'auto'}}), pager = _.div(), stats = _.div();
|
|
47
|
+
function renderStats() {
|
|
48
|
+
const available = rows.filter(r => r.quantity > 0).length;
|
|
49
|
+
_.mount(stats, [_.Kpi({title:'Prodotti totali',value:rows.length}), _.Kpi({title:'Disponibili',value:available}), _.Kpi({title:'Esauriti',value:rows.length-available}), _.Kpi({title:'Valore magazzino',value:priceFormat.format(rows.reduce((sum,r) => sum+r.price*r.quantity,0))})]);
|
|
50
|
+
}
|
|
51
|
+
function changePage(delta, trigger) {
|
|
52
|
+
page += delta; render();
|
|
53
|
+
const button = document.getElementById(trigger);
|
|
54
|
+
(button.disabled ? pager : button).focus();
|
|
55
|
+
}
|
|
56
|
+
pager.tabIndex = -1;
|
|
47
57
|
const add = _.Button({id:'add-product',onClick:() => edit()},'Nuovo prodotto');
|
|
48
58
|
const search = _.Input({label:'Cerca',onInput:value => {query=value;page=1;render();}});
|
|
49
59
|
const filter = _.Select({label:'Filtro categoria',options:[{value:'',label:'Tutte'},...categories.map(value => ({value,label:value}))],onChange:value => {category=value;page=1;render();}});
|
|
50
60
|
function render() {
|
|
51
61
|
const found = rows.filter(r => r.name.toLowerCase().includes(query.trim().toLowerCase()) && (!category || r.category === category));
|
|
52
62
|
const pages = Math.max(1,Math.ceil(found.length/5)); page = Math.min(page,pages);
|
|
53
|
-
_.mount(host, _.Table({rows:found.slice((page-1)*5,page*5),rowKey:'id',pagination:false,hideFooter:true,hideStatus:true,minTableWidth:600,emptyText:'Nessun prodotto trovato',
|
|
63
|
+
_.mount(host, _.Table({rows:found.slice((page-1)*5,page*5),rowKey:'id',pagination:false,hideFooter:true,hideStatus:true,minTableWidth:600,shadow:'none',radius:'12px',style:{background:'#fff'},tableStyle:{background:'#fff','--set-color-1':'#fff'},emptyText:'Nessun prodotto trovato',
|
|
54
64
|
columns:[{key:'name',sortable:false,label:'Nome'},{key:'category',sortable:false,label:'Categoria'},{key:'price',sortable:false,label:'Prezzo',format:value => priceFormat.format(value)},{key:'quantity',sortable:false,label:'Quantità'},
|
|
55
65
|
{key:'actions',label:'Azioni',render:r => _.Button({id:`edit-${r.id}`,onClick:() => edit(r)},'Modifica')}] }));
|
|
56
66
|
_.mount(pager, [_.span(`${found.length} prodotti — pagina ${page}/${pages}`),
|
|
57
|
-
_.Button({id:'previous',disabled:page===1,onClick:() =>
|
|
58
|
-
_.Button({id:'next',disabled:page===pages,onClick:() =>
|
|
67
|
+
_.Button({id:'previous',disabled:page===1,onClick:() => changePage(-1,'previous')},'Precedente'),
|
|
68
|
+
_.Button({id:'next',disabled:page===pages,onClick:() => changePage(1,'next')},'Successiva')]);
|
|
59
69
|
}
|
|
60
|
-
_.mount('#app', _.div({style:{minWidth:0}}, add, search, filter, host, pager, notice)); render();
|
|
70
|
+
_.mount('#app', _.div({style:{minWidth:0}}, add, stats, search, filter, host, pager, notice)); renderStats(); render();
|
|
61
71
|
```
|
|
62
72
|
|
|
63
73
|
Application validation remains explicit. `error` marks the control invalid; rendered field messages are associated automatically. Use `ariaDescribedBy` for additional application-owned descriptions. This example does not provide delete, server synchronization or a complete visual design.
|
|
64
74
|
|
|
65
|
-
Performance: the currency formatter is reused. This small example rebuilds its table for clarity; profile larger datasets before changing rendering strategy. `onOpen` focuses the name field and automatic focus respects that choice.
|
|
75
|
+
Performance: the currency formatter is reused; KPI update only when inventory changes, not on search or pagination. This small example rebuilds its table for clarity; profile larger datasets before changing rendering strategy. `onOpen` focuses the name field and automatic focus respects that choice.
|
|
66
76
|
|
|
67
77
|
## Verification checklist
|
|
68
78
|
|
|
@@ -73,6 +83,7 @@ Build success alone does not verify this flow. In a browser, record these result
|
|
|
73
83
|
- Reject blank fields, negative price and fractional quantity; check `aria-invalid` and the field error referenced by `aria-describedby`.
|
|
74
84
|
- Use Tab and Shift+Tab at both dialog boundaries, Escape to close, and check focus returns to the current trigger after rendering.
|
|
75
85
|
- Add and edit, reload, then search, filter and paginate; check persistence and page reset.
|
|
86
|
+
- Reach both pagination boundaries with the keyboard: focus moves to the pager when the clicked button becomes disabled.
|
|
76
87
|
- At a narrow viewport, check page overflow and table scrolling. Measure contrast separately; screenshots alone do not establish contrast compliance.
|
|
77
88
|
|
|
78
89
|
The example uses public field APIs and rod values. If a browser is unavailable, report these interactions as unverified rather than deriving them from pure-logic assertions.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Getting started with JSswift
|
|
2
2
|
|
|
3
|
+
For a first page, read [AI quick start](AI.md) alone. For product editing, use its CRUD route; this guide is for additional APIs.
|
|
4
|
+
|
|
3
5
|
- Application namespace: `window._`, written `_` in application code.
|
|
4
6
|
- `_` exposes both UI components and core APIs directly: `_.Toggle`, `_.mount`, `_.signal`.
|
|
5
7
|
- The runtime also exposes `window.JSswift`; application examples and generated code use `_`.
|
|
@@ -241,6 +241,25 @@
|
|
|
241
241
|
"paths": [
|
|
242
242
|
"ui/themes.md"
|
|
243
243
|
]
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"id": "configured-runtime",
|
|
247
|
+
"title": "Configured runtime and selective application builds",
|
|
248
|
+
"keywords": [
|
|
249
|
+
"jss.config.js",
|
|
250
|
+
"jss:runtime",
|
|
251
|
+
"jsswift/vite",
|
|
252
|
+
"jsswift/build",
|
|
253
|
+
"jss-build",
|
|
254
|
+
"selective runtime",
|
|
255
|
+
"componenti selettivi",
|
|
256
|
+
"extras",
|
|
257
|
+
"ui.all",
|
|
258
|
+
"runtime configurabile"
|
|
259
|
+
],
|
|
260
|
+
"paths": [
|
|
261
|
+
"configured-runtime.md"
|
|
262
|
+
]
|
|
244
263
|
}
|
|
245
264
|
],
|
|
246
265
|
"components": [
|
|
@@ -1004,5 +1023,5 @@
|
|
|
1004
1023
|
"documentAliases": {
|
|
1005
1024
|
"components/button.md": "components/btn.md"
|
|
1006
1025
|
},
|
|
1007
|
-
"packageVersion": "2.
|
|
1026
|
+
"packageVersion": "2.1.0"
|
|
1008
1027
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Data, feedback, and overlays
|
|
2
2
|
|
|
3
|
+
For a first page, read [AI quick start](../AI.md) alone. For product editing, use its CRUD route; this guide is for additional APIs.
|
|
4
|
+
|
|
3
5
|
Use Table for operational data. Use Spinner, Progress, LoadingBar, Notify, Alert, Banner, and EmptyState for the matching state. Use Dialog for focused flows and Menu, Popover, ContextMenu, or Tooltip for anchored interactions.
|
|
4
6
|
|
|
5
7
|
Overlay behavior and imperative APIs differ. Before implementing triggers, focus, outside clicks, escape behavior, or return values, read the exact component file. Do not assume overlays share props.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Forms
|
|
2
2
|
|
|
3
|
+
For a first page, read [AI quick start](../AI.md) alone. For product editing, use its CRUD route; this guide is for additional APIs.
|
|
4
|
+
|
|
3
5
|
Use _.useForm for values, validation, touched/dirty flags, and submissions. Bind fields through form.model("field").
|
|
4
6
|
|
|
5
7
|
const form = _.useForm({ values: { email: "" } });
|