jsswift 1.0.54 → 2.0.1
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 +40 -72
- package/README.md +2 -2
- package/dist/css/animation.css +36 -36
- package/dist/css/base.css +374 -374
- package/dist/css/docs.css +54 -54
- package/dist/css/fonts-nunito.css +2 -2
- package/dist/css/min-ui.css +1 -1
- package/dist/css/responsive-base.css +549 -549
- package/dist/css/responsive.css +3225 -3225
- package/dist/css/ui-components.css +2902 -2930
- package/dist/css/ui-light.css +3853 -3881
- package/dist/css/ui-light.min.css +1 -1
- package/dist/css/ui.css +6530 -6558
- package/dist/css/ui.min.css +1 -1
- package/dist/documentions/AI.md +40 -72
- package/dist/documentions/README.md +4 -2
- package/dist/documentions/application-rules.md +2 -2
- package/dist/documentions/components/table.md +13 -0
- package/dist/documentions/components/toolbar.md +1 -1
- package/dist/documentions/examples/crud.md +21 -8
- package/dist/documentions/getting-started.md +6 -0
- package/dist/documentions/knowledge-map.json +22 -1
- package/dist/documentions/ui/data-feedback-overlays.md +2 -0
- package/dist/documentions/ui/forms.md +2 -0
- package/dist/documentions/ui/themes.md +39 -0
- package/dist/jsswift.js +5685 -12485
- package/dist/jsswift.min.js +12 -12
- package/dist/min-jsswift.js +12 -12
- package/package.json +2 -2
package/dist/documentions/AI.md
CHANGED
|
@@ -23,52 +23,32 @@ The map locates a contract; it does not replace it. Avoid reading all of `ui/com
|
|
|
23
23
|
|
|
24
24
|
## Import, create, mount
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
With Vite, provide `<div id="app"></div>` and a module entrypoint:
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
29
|
import 'jsswift';
|
|
30
30
|
import 'jsswift/css/ui-light.css';
|
|
31
31
|
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);
|
|
32
|
+
const name = _.rod('Prodotto 01'), category = _.rod('Casa');
|
|
33
|
+
const input = _.Input({label:'Nome', required:true, model:name});
|
|
34
|
+
const select = _.Select({label:'Categoria', model:category,
|
|
35
|
+
options:[{value:'Casa',label:'Casa'},{value:'Ufficio',label:'Ufficio'}]});
|
|
36
|
+
const dialog = _.Dialog({title:'Prodotto', ariaLabel:'Prodotto',
|
|
37
|
+
content:_.div({}, input, select), trapFocus:true, closeOnEsc:true,
|
|
38
|
+
onOpen:() => input.focus()});
|
|
39
|
+
dialog.update({actions:[_.Button({onClick:() => {
|
|
40
|
+
console.log({name:name.value, category:category.value}); dialog.close();
|
|
41
|
+
}}, 'Salva')]});
|
|
42
|
+
const table = _.Table({rows:[{id:1,name:'Prodotto 01'}], rowKey:'id',
|
|
43
|
+
columns:[{key:'name',label:'Nome',sortable:false,render:(row,ctx) => _.strong(ctx.value)}],
|
|
44
|
+
pagination:false, hideFooter:true, hideStatus:true, minTableWidth:600});
|
|
45
|
+
_.mount('#app', _.div({}, _.Card({title:'Prodotti'},
|
|
46
|
+
_.Button({color:'primary',onClick:() => dialog.open()}, 'Modifica')), table));
|
|
69
47
|
```
|
|
70
48
|
|
|
71
|
-
This
|
|
49
|
+
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.
|
|
50
|
+
|
|
51
|
+
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
52
|
|
|
73
53
|
## Exact callback arguments
|
|
74
54
|
|
|
@@ -87,62 +67,50 @@ Dialog returns an API object, not a node to mount: `open(overrides?)`, `close()`
|
|
|
87
67
|
|
|
88
68
|
## Existing CSS and optional assets
|
|
89
69
|
|
|
90
|
-
The
|
|
70
|
+
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.
|
|
91
71
|
|
|
92
|
-
|
|
72
|
+
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.
|
|
93
73
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
System fonts are the default. Import `jsswift/css/fonts-nunito.css`, `jsswift/css/fonts-material.css`, or `jsswift/tabler` only when required; Material Symbols loads a remote Google font. See [setup](getting-started.md).
|
|
74
|
+
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
75
|
|
|
98
76
|
## Accessibility and verification
|
|
99
77
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
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.
|
|
103
|
-
|
|
104
|
-
## Read only what the task needs
|
|
105
|
-
|
|
106
|
-
- 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).
|
|
107
|
-
- Extra behavior: [forms](ui/forms.md), [reactivity](reactivity.md), [layout](ui/layout-and-responsive.md), [overlays](ui/data-feedback-overlays.md).
|
|
108
|
-
- Other components: [index](components/README.md). MCP: read `guide:AI`, then search only for additional features.
|
|
109
|
-
|
|
110
|
-
For a complete application flow, read [the compact CRUD example](examples/crud.md) only when the task needs editing, validation, persistence and focus restoration together.
|
|
78
|
+
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
79
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
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.
|
|
115
|
-
|
|
116
|
-
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.
|
|
117
|
-
|
|
118
|
-
## Focus CSS and targeted reads
|
|
119
|
-
|
|
120
|
-
Apply focus indicators to every selector through `:is`, rather than placing the pseudo-class on only the final selector in a comma-separated list:
|
|
80
|
+
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:
|
|
121
81
|
|
|
122
82
|
```css
|
|
123
|
-
:is(button,
|
|
83
|
+
:is(button,a,input,select,[tabindex]):focus-visible {
|
|
124
84
|
outline: 3px solid #2563eb;
|
|
125
85
|
outline-offset: 3px;
|
|
126
86
|
}
|
|
127
87
|
```
|
|
128
88
|
|
|
129
|
-
|
|
89
|
+
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.
|
|
130
90
|
|
|
91
|
+
## Additional APIs only
|
|
92
|
+
|
|
93
|
+
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.
|
|
131
94
|
|
|
132
95
|
## Catalogue surfaces and field styling
|
|
133
96
|
|
|
134
|
-
|
|
97
|
+
`_.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.
|
|
135
98
|
|
|
136
|
-
Table
|
|
99
|
+
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.
|
|
137
100
|
|
|
138
|
-
|
|
101
|
+
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.
|
|
139
102
|
|
|
140
|
-
|
|
103
|
+
Input's native input is transparent; preserve that background to keep the outer curved border visible. Set height on an application container:
|
|
141
104
|
|
|
142
105
|
```css
|
|
143
106
|
.catalogue-filters {
|
|
144
|
-
--
|
|
107
|
+
--jss-input-height-default: 40px;
|
|
145
108
|
}
|
|
146
109
|
```
|
|
110
|
+
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.
|
|
111
|
+
|
|
112
|
+
## Theme and lifecycle essentials
|
|
113
|
+
|
|
114
|
+
base.css is already included. Use `_.setTheme('dark')` or `_.setTheme('light')`; persistence defaults to `jsswift:theme`. At startup restore with `_.setTheme(_.getTheme())`. Customize the existing `--jss-primary-600`/`--jss-primary-700` palette values after the UI import. See [base CSS and themes](ui/themes.md) only for additional theme requirements.
|
|
147
115
|
|
|
148
|
-
|
|
116
|
+
Replace component subtrees with `_.mount(host, nextContent)` (default clear:true), which cleans up previous effects and subscriptions. Native `replaceChildren`/`innerHTML` alone do not run JSswift cleanup. Keep shared models owned by the application alive.
|
|
@@ -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
11
|
| Component choice and composition | [application-rules.md](application-rules.md), [components/README.md](components/README.md) |
|
|
12
12
|
| State and controlled inputs | [reactivity.md](reactivity.md) |
|
|
13
13
|
| Layout and breakpoints | [ui/layout-and-responsive.md](ui/layout-and-responsive.md) |
|
|
14
|
-
|
|
|
14
|
+
| Product CRUD | [examples/crud.md](examples/crud.md), without pre-reading forms or overlay contracts |
|
|
15
|
+
| Additional form APIs | [ui/forms.md](ui/forms.md) |
|
|
16
|
+
| Base CSS, theme tokens and component colors | [ui/themes.md](ui/themes.md) |
|
|
15
17
|
| Router, store, HTTP, auth, themes | [platform.md](platform.md) |
|
|
16
18
|
| Tables, feedback, dialogs, menus | [ui/data-feedback-overlays.md](ui/data-feedback-overlays.md) |
|
|
17
19
|
| Exact component API | components/<component>.md only |
|
|
@@ -8,12 +8,12 @@ Open [components/README.md](components/README.md) to choose a family, then open
|
|
|
8
8
|
|
|
9
9
|
## Use the existing CSS first
|
|
10
10
|
|
|
11
|
-
Import `jsswift/css/ui.css` once. JSswift already supplies component styles, theme variables, and responsive layout rules. Start with the native appearance. Use documented props such as `color`, `dense`, `padding`, `radius`, `shadow`, and responsive overrides before writing custom CSS. Prefer theme variables from the installed stylesheet for shared colors and typography.
|
|
11
|
+
Import `jsswift/css/ui-light.css` once; add `responsive.css` for breakpoint props, or choose complete `ui.css`. JSswift already supplies component styles, theme variables, and responsive layout rules. Start with the native appearance. Use documented props such as `color`, `dense`, `padding`, `radius`, `shadow`, and responsive overrides before writing custom CSS. Prefer theme variables from the installed stylesheet for shared colors and typography.
|
|
12
12
|
|
|
13
13
|
Custom CSS is appropriate for page-specific visuals or requirements the documented props do not cover. Keep it scoped to application classes; avoid recreating buttons, fields, cards, table cells, pagination, or dialog internals. Read the exact component contract before choosing a prop.
|
|
14
14
|
|
|
15
15
|
## Keep discovery focused
|
|
16
16
|
|
|
17
|
-
Read
|
|
17
|
+
Read AI.md alone first. Use its supported subset directly; read a contract only for an API absent from that guide. Batch independent file reads; do not concatenate the whole catalog, extract it with Python, or search the framework source when the documented contract already answers the question. When a contract is missing or ambiguous, inspect only the relevant implementation and report the gap. Build after the first complete implementation, then correct concrete failures.
|
|
18
18
|
|
|
19
19
|
Run comparative benchmarks in an isolated workspace, with equivalent instructions for every stack.
|
|
@@ -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.
|
|
@@ -27,7 +27,7 @@ Exact JSswift UI contract. Shared definitions listed in `commonProps` are in [co
|
|
|
27
27
|
"wrap": {"type": "boolean|string", "description": "Allows children to wrap to new lines.", "default": null, "values": null, "category": "general"},
|
|
28
28
|
"align": {"type": "stretch|flex-start|center|flex-end|baseline", "description": "Alignment of content along the cross axis (e.g. left/center/right).", "default": null, "values": ["left", "center", "right"], "category": "general"},
|
|
29
29
|
"justify": {"type": "flex-start|center|flex-end|space-between|space-around|space-evenly", "description": "Justification of items along the main axis.", "default": null, "values": ["start", "center", "end", "space-between", "space-around", "space-evenly"], "category": "general"},
|
|
30
|
-
"gap": {"type": "string|number (e.g. '8px' or 'var(--
|
|
30
|
+
"gap": {"type": "string|number (e.g. '8px' or 'var(--jss-s-md)')", "description": "Gap/spacing between child elements.", "default": null, "values": null, "category": "general"},
|
|
31
31
|
"beforeClass": {"type": "string", "description": "Component configuration for \"beforeClass\". When not handled internally, it is forwarded to the root element.", "default": null, "values": null, "category": "general"},
|
|
32
32
|
"startClass": {"type": "string", "description": "Component configuration for \"startClass\". When not handled internally, it is forwarded to the root element.", "default": null, "values": null, "category": "general"},
|
|
33
33
|
"bodyClass": {"type": "string", "description": "Component configuration for \"bodyClass\". When not handled internally, it is forwarded to the root element.", "default": null, "values": null, "category": "general"},
|
|
@@ -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
|
-
|
|
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
|
-
|
|
57
|
-
_.Button({id:'previous',disabled:page===1,onClick:() =>
|
|
58
|
-
_.Button({id:'next',disabled:page===pages,onClick:() =>
|
|
66
|
+
_.mount(pager, [_.span(`${found.length} prodotti — pagina ${page}/${pages}`),
|
|
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,8 +83,11 @@ 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.
|
|
79
90
|
|
|
80
91
|
Table supplies its own Card and empty state. This example disables column sorting because it supplies a page slice; sort the complete filtered data before slicing if global sorting is required. For dashboard counters prefer `_.Kpi({title, value, note})`. Preserve field input transparency and use the container height variable described in [AI guide](../AI.md#catalogue-surfaces-and-field-styling).
|
|
92
|
+
|
|
93
|
+
Lifecycle: `_.mount(host, nextContent)` clears the previous subtree through JSswift cleanup (default `clear:true`). Its returned function unmounts the new content. Use this for replacing component subtrees; native `replaceChildren`, `innerHTML` or `remove` alone do not invoke registered JSswift cleanup. Keep shared models alive until their application owner disposes them.
|
|
@@ -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 `_`.
|
|
@@ -59,3 +61,7 @@ import 'jsswift/css/responsive.css';
|
|
|
59
61
|
```
|
|
60
62
|
|
|
61
63
|
The light entry includes base.css, animation.css, component styles and generated unprefixed utilities. It preserves color, dense, outline, tokens, base layout and component-specific mobile styles. Breakpoint props remain in JavaScript; their generated CSS requires the responsive addon. Load the addon after the light entry. Use either full CSS or light plus optional addon, not both full and light. Both new light exports also exist under `@jsswift/ui`. This changes application CSS size, not JavaScript or npm installation size.
|
|
64
|
+
|
|
65
|
+
## CSS namespace migration
|
|
66
|
+
|
|
67
|
+
Component classes, overlay IDs and CSS custom properties now use `jss-` instead of `cms-`, without compatibility aliases. Update application selectors and theme overrides together, for example `.jss-control` and `--jss-primary`. Component APIs and npm import paths remain unchanged. Rebuild JS and CSS together; do not mix runtimes and styles from different namespace versions. This is an intentionally incompatible CSS namespace change.
|
|
@@ -220,6 +220,27 @@
|
|
|
220
220
|
"paths": [
|
|
221
221
|
"examples/crud.md"
|
|
222
222
|
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"id": "themes",
|
|
226
|
+
"title": "Base CSS, theme tokens and native component styling",
|
|
227
|
+
"keywords": [
|
|
228
|
+
"base.css",
|
|
229
|
+
"theme",
|
|
230
|
+
"themes",
|
|
231
|
+
"tema",
|
|
232
|
+
"color",
|
|
233
|
+
"colors",
|
|
234
|
+
"colori",
|
|
235
|
+
"palette",
|
|
236
|
+
"dark",
|
|
237
|
+
"light",
|
|
238
|
+
"outline",
|
|
239
|
+
"dense"
|
|
240
|
+
],
|
|
241
|
+
"paths": [
|
|
242
|
+
"ui/themes.md"
|
|
243
|
+
]
|
|
223
244
|
}
|
|
224
245
|
],
|
|
225
246
|
"components": [
|
|
@@ -983,5 +1004,5 @@
|
|
|
983
1004
|
"documentAliases": {
|
|
984
1005
|
"components/button.md": "components/btn.md"
|
|
985
1006
|
},
|
|
986
|
-
"packageVersion": "
|
|
1007
|
+
"packageVersion": "2.0.1"
|
|
987
1008
|
}
|
|
@@ -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: "" } });
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Base CSS, themes and component props
|
|
2
|
+
|
|
3
|
+
Both ui.css and ui-light.css include base.css. Do not import base.css again. It supplies shared color scales, semantic theme variables, typography and component tokens. Light CSS omits breakpoint utilities, not the default theme or color/dense/outline props.
|
|
4
|
+
|
|
5
|
+
## Shared theme
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
_.setTheme('light', {persist:false});
|
|
9
|
+
_.setTheme('dark');
|
|
10
|
+
_.toggleTheme(['light', 'dark']);
|
|
11
|
+
const current = _.getTheme();
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
setTheme writes data-theme on the document root and persists by default under jsswift:theme. Use persist:false for an ephemeral preview. Apply the restored value at startup with `_.setTheme(_.getTheme())`; theme helpers do not synthesize a palette for arbitrary theme names. base.css defines light and dark rules; custom themes need matching CSS.
|
|
15
|
+
|
|
16
|
+
For a brand color, override the existing scale after importing JSswift CSS:
|
|
17
|
+
|
|
18
|
+
```css
|
|
19
|
+
:root {
|
|
20
|
+
--jss-primary-600: #2563eb;
|
|
21
|
+
--jss-primary-700: #1d4ed8;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Semantic variables such as --jss-primary, --jss-primary-hover, --jss-bg and --jss-text connect the palette to components. Dark/brand selectors may override them; check computed values in each desired theme. Scope custom colors to an application container when they should not affect the whole page. Do not rename internal selectors to build a theme.
|
|
26
|
+
|
|
27
|
+
## Individual components
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
_.Button({color:'primary', outline:true, dense:true}, 'Modifica');
|
|
31
|
+
_.Input({label:'Nome', radius:8});
|
|
32
|
+
_.Kpi({title:'Disponibili', value:9, note:'Con scorte', radius:12, shadow:'none'});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Use documented component props before custom CSS. dense is component-specific: do not assume every component supports it. A page background belongs to an application container; preserve the transparent native Input background and its surrounding control border. Props affect the component, whereas theme variables can affect every descendant.
|
|
36
|
+
|
|
37
|
+
## Verification
|
|
38
|
+
|
|
39
|
+
Check light/dark computed colors, border/focus/error states, and mobile dimensions. Measure contrast for text/background pairs, including disabled states where appropriate. A screenshot or a valid color token alone does not establish accessibility compliance.
|