@mostajs/crud-ui 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  Format [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) · [SemVer](https://semver.org/lang/fr/).
4
4
  Auteur : Dr Hamid MADANI <drmdh@msn.com>
5
5
 
6
+ ## [0.2.1] — 2026-10-09
7
+
8
+ ### Fixed
9
+ - `detailLink` n'accepte qu'un chemin du site (`/`, `?`, `#`) ou une adresse http(s) : `javascript:` et `data:` deviennent `#`
10
+ (audit du 09/10/2026). Essai T-STY-5.
11
+
12
+ ## [0.2.0] — 2026-10-08
13
+
14
+ ### Added
15
+ - `panel({ labels })` : `{ fiche, actions, ajouter, creer }` fournis par l'app — « Actions » et « 📋 Fiche »
16
+ restaient en français dans une page anglaise ou arabe.
17
+ - `panel({ style: 'classes' })` : aucun style en ligne, panneau enveloppé dans `.cu-panel` ; `detailLink(href, label, { style })`.
18
+ - `CU_CSS` : feuille du mode `classes` sur les jetons de Palette Studio (`--brand`, `--link`, `--ink`, `--line`,
19
+ `--surface`, `--surface-alt`), avec replis ; couvre le balisage d'`@mostajs/app-shell-ui` (table, h1, .sub, .back, .act).
20
+ - `panel({ cell })` : rendu d'une cellule délégué à l'app (transmis à `table`).
21
+
22
+ ### Fixed
23
+ - Dépendances `workspace:^` remplacées par des plages publiables (`npm publish` ne les réécrit pas).
24
+
25
+ ### Tests
26
+ - `test-scripts/unit/style.test.mjs` (T-STY-1 à 4).
27
+
6
28
  ## [0.1.0] — 2026-06-20
7
29
 
8
30
  ### Added
package/README.md CHANGED
@@ -44,6 +44,11 @@ Génère : formulaire `POST /m/companies/create`, table avec lien détail `GET /
44
44
 
45
45
  > **Sécurité** : valeurs/route/labels échappés (via `app-shell-ui`). `note`/`extra`/`create.extra` = HTML brut (responsabilité de l'appelant).
46
46
 
47
+ ## Habillage et langue (0.2.0)
48
+ `panel({ labels: { fiche, actions, ajouter, creer }, style: 'classes', cell })` : libellés fournis par l'app
49
+ (défauts français), aucun style en ligne en mode `classes` (poser `CU_CSS`, sur les jetons de Palette Studio),
50
+ rendu de cellule délégué.
51
+
47
52
  ## Tests & exemple
48
53
 
49
54
  ```bash
package/llms.txt CHANGED
@@ -13,11 +13,16 @@ PRINCIPE
13
13
  COMPOSE
14
14
  @mostajs/app-shell-ui OBLIGATOIRE (dep). Fournit table/form/pageTitle/back/esc + thème.
15
15
 
16
+ HABILLAGE ET LANGUE (0.2.0)
17
+ panel({ …, labels:{fiche,actions,ajouter,creer}, style:'inline'|'classes', cell?(row,col) }) ; détails :
18
+ style 'classes' → aucun style en ligne, enveloppe .cu-panel ; poser CU_CSS (jetons Palette Studio) ou sa feuille.
19
+ Sans labels, les libellés par défaut sont FRANÇAIS : une app multilingue les fournit toujours.
20
+
16
21
  EXPORTS (".", "./html")
17
22
  panel({ title?, sub?, back?={href,label}, note?, rows, cols?, hidden?=['id','_status'], routeBase='',
18
23
  detail?=false|(row)=>href, actions?=[{id,label,show?(row)}], create?={fields,title?,submit?,enctype?,extra?},
19
24
  extra?, empty? }) -> htmlString // CORPS du panneau (à enrober via app-shell-ui.page())
20
- detailLink(href, label?='📋 Fiche') ; actionForm(routeBase, action, row) ; actionsCell(routeBase, actions, row)
25
+ detailLink(href, label?='📋 Fiche', {style}?) ; CU_CSS ; actionForm(routeBase, action, row) ; actionsCell(routeBase, actions, row)
21
26
 
22
27
  DÉTAILS
23
28
  - create.fields = format app-shell-ui `form` ({name,label,type?,value?,required?,options?,list?}) ; l'app résout les
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/crud-ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Panneau CRUD générique (rendu HTML-string, zéro dépendance) : spec déclaratif + lignes → formulaire de création + table (lien détail + actions POST). Compose @mostajs/app-shell-ui. Membre de mosta-ui-html-stack.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
@@ -16,6 +16,11 @@
16
16
  ".": "./src/html/index.js",
17
17
  "./html": "./src/html/index.js"
18
18
  },
19
+ "scripts": {
20
+ "test": "bash test-scripts/run-tests.sh",
21
+ "example": "node examples/run.mjs",
22
+ "clean": "rm -f examples/out.html test-report.html"
23
+ },
19
24
  "keywords": [
20
25
  "mostajs",
21
26
  "ui",
@@ -30,11 +35,14 @@
30
35
  "@mostajs/app-shell-ui": "^0.1.0"
31
36
  },
32
37
  "devDependencies": {
33
- "@mostajs/mjs-unit": "^0.3.0"
38
+ "@mostajs/mjs-unit": "^0.7.0"
34
39
  },
35
- "scripts": {
36
- "test": "bash test-scripts/run-tests.sh",
37
- "example": "node examples/run.mjs",
38
- "clean": "rm -f examples/out.html test-report.html"
40
+ "mostajs": {
41
+ "niveau": "N2",
42
+ "nature": "compose",
43
+ "reutilisabilite": "multi-domaine",
44
+ "depend_de": [
45
+ "@mostajs/app-shell-ui"
46
+ ]
39
47
  }
40
- }
48
+ }
package/src/html/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @mostajs/crud-ui — barrel ./html. Author: Dr Hamid MADANI <drmdh@msn.com>
2
- export { panel, detailLink, actionForm, actionsCell } from './panel.js';
2
+ export { panel, detailLink, actionForm, actionsCell, CU_CSS } from './panel.js';
package/src/html/panel.js CHANGED
@@ -3,9 +3,38 @@
3
3
  // COMPOSE @mostajs/app-shell-ui (table/form/pageTitle/back/esc) — aucune primitive bas-niveau ni accès données ici.
4
4
  import { esc, table, form, pageTitle, back as backLink } from '@mostajs/app-shell-ui';
5
5
 
6
+ /**
7
+ * 0.2.0 — DEUX HABILLAGES. `inline` (défaut, inchangé) : le lien porte son style. `classes` : aucun style en ligne,
8
+ * la page habille par les classes `cu-*` (avec `CU_CSS` ou sa propre feuille). Demande du fondateur, 08/10/2026 :
9
+ * un style imposé en ligne ne se surcharge qu'à coups de `!important`.
10
+ */
11
+ const LIBELLES = { fiche: '📋 Fiche', actions: 'Actions', ajouter: '➕ Ajouter', creer: 'Créer' };
12
+
13
+ /**
14
+ * La feuille du mode `classes`, sur les jetons de Palette Studio (ceux que pose @mostajs/wagon-ui), avec replis.
15
+ * Elle couvre aussi le balisage d'@mostajs/app-shell-ui que le panneau compose (table, h1, .sub, .back, .act).
16
+ */
17
+ export const CU_CSS = `.cu-panel{--cu-accent:var(--brand,#1B3FA0);--cu-ink:var(--ink,var(--text,#16223f));--cu-line:var(--line,#e2e8f0);--cu-fond:var(--surface,#fff);--cu-doux:var(--surface-alt,#f8fafc);--cu-radius:1rem}
18
+ .cu-panel h1{margin:.2rem 0 .3rem;color:var(--cu-ink)}
19
+ .cu-panel .sub{margin:0 0 1rem;opacity:.7}
20
+ .cu-panel a.back{display:inline-block;margin-bottom:.6rem;color:var(--link,var(--cu-accent));text-decoration:none;font-weight:600}
21
+ .cu-panel table{width:100%;border-collapse:separate;border-spacing:0;background:var(--cu-fond);border:1px solid var(--cu-line);border-radius:var(--cu-radius);overflow:hidden}
22
+ .cu-panel th{text-align:start;font-size:.8rem;text-transform:uppercase;letter-spacing:.03em;opacity:.7;background:var(--cu-doux);padding:.65rem .8rem;border-bottom:1px solid var(--cu-line)}
23
+ .cu-panel td{padding:.65rem .8rem;border-bottom:1px solid var(--cu-line);vertical-align:middle}
24
+ .cu-panel tr:last-child td{border-bottom:0}
25
+ .cu-panel .cu-fiche{color:var(--link,var(--cu-accent));font-weight:600;text-decoration:none;white-space:nowrap}
26
+ .cu-panel button.act{background:transparent;border:1px solid var(--cu-line);border-radius:999px;padding:.25rem .8rem;cursor:pointer;font:inherit}
27
+ .cu-panel form{display:inline}`;
28
+
6
29
  /** Lien de détail (cellule de tête de ligne). */
7
- export function detailLink(href, label = '📋 Fiche') {
8
- return `<a href="${esc(href)}" style="color:var(--blue);font-weight:600;text-decoration:none">${esc(label)}</a>`;
30
+ /** 0.2.1 — un lien n'est jamais `javascript:` ni `data:` : seuls un chemin du site (/…, ?…, #…) ou http(s) passent. */
31
+ const lienSur = (href) => { const h = String(href ?? ''); return /^(\/(?!\/)|\?|#|https?:\/\/)/i.test(h) ? h : '#'; };
32
+
33
+ export function detailLink(href, label = LIBELLES.fiche, { style = 'inline' } = {}) {
34
+ href = lienSur(href);
35
+ return style === 'classes'
36
+ ? `<a class="cu-fiche" href="${esc(href)}">${esc(label)}</a>`
37
+ : `<a href="${esc(href)}" style="color:var(--blue);font-weight:600;text-decoration:none">${esc(label)}</a>`;
9
38
  }
10
39
 
11
40
  /** Mini-formulaire POST pour une action de ligne → `${routeBase}/act/${action.id}`. */
@@ -24,20 +53,22 @@ export function actionsCell(routeBase, actions, row) {
24
53
  */
25
54
  export function panel({
26
55
  title, sub = '', back, note = '', rows = [], cols, hidden = ['id', '_status'],
27
- routeBase = '', detail = false, actions, create, extra = '', empty,
56
+ routeBase = '', detail = false, actions, create, extra = '', empty, cell,
57
+ labels = {}, style = 'inline',
28
58
  } = {}) {
59
+ const L = { ...LIBELLES, ...labels };
29
60
  const parts = [];
30
61
  if (back) parts.push(backLink(back.href, back.label));
31
62
  if (title) parts.push(pageTitle(title, sub));
32
63
  if (note) parts.push(note);
33
64
  if (create) parts.push(form(create.fields, {
34
65
  action: `${routeBase}/create`, method: 'post',
35
- title: create.title || '➕ Ajouter', submit: create.submit || 'Créer',
66
+ title: create.title || L.ajouter, submit: create.submit || L.creer,
36
67
  enctype: create.enctype, extra: create.extra,
37
68
  }));
38
- const lead = detail ? (r) => detailLink(typeof detail === 'function' ? detail(r) : `${routeBase}/${r.id}`) : undefined;
39
- const trail = actions ? { header: 'Actions', render: (r) => actionsCell(routeBase, actions, r) } : undefined;
40
- parts.push(table(rows, { cols, hidden, lead, trail, empty }));
69
+ const lead = detail ? (r) => detailLink(typeof detail === 'function' ? detail(r) : `${routeBase}/${r.id}`, L.fiche, { style }) : undefined;
70
+ const trail = actions ? { header: L.actions, render: (r) => actionsCell(routeBase, actions, r) } : undefined;
71
+ parts.push(table(rows, { cols, hidden, lead, trail, empty, cell }));
41
72
  if (extra) parts.push(extra);
42
- return parts.join('\n');
73
+ return style === 'classes' ? `<div class="cu-panel">${parts.join('\n')}</div>` : parts.join('\n');
43
74
  }