@klodd/ds 3.3.0 → 3.4.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.
Files changed (31) hide show
  1. package/SKILL.md +56 -0
  2. package/bin/klodd-ds.js +25 -0
  3. package/bin/precache.js +43 -0
  4. package/bin/sync.js +33 -0
  5. package/bin/verify.js +66 -0
  6. package/css/00-primitives.css +13 -4
  7. package/css/10-semantic.css +3 -3
  8. package/css/components/dropdown.css +1 -1
  9. package/css/components/setting-row.css +1 -1
  10. package/css/components/tab-bar.css +1 -1
  11. package/css/components/tooltip.css +1 -1
  12. package/css/utilities.css +101 -67
  13. package/package.json +12 -3
  14. package/references/01-tokens.md +182 -0
  15. package/references/02-components.md +260 -0
  16. package/references/03-quality-bar.md +238 -0
  17. package/references/04-locked-decisions/0001-three-layer-token-architecture.md +41 -0
  18. package/references/04-locked-decisions/0002-bem-naming.md +37 -0
  19. package/references/04-locked-decisions/0003-radix-colors-oklch.md +39 -0
  20. package/references/04-locked-decisions/0004-pixel-numeric-spacing.md +31 -0
  21. package/references/04-locked-decisions/0005-data-app-theming.md +42 -0
  22. package/references/04-locked-decisions/0006-mauve-neutral.md +40 -0
  23. package/references/04-locked-decisions/0007-font-weight-400-500.md +46 -0
  24. package/references/04-locked-decisions/0008-npm-package-distribution.md +40 -0
  25. package/references/05-open-decisions/0001-tx-row-to-list-row-migration-CLOSED.md +80 -0
  26. package/references/05-open-decisions/0002-parallel-classnames-cleanup-CLOSED.md +75 -0
  27. package/references/05-open-decisions/0003-js-duplicates-migration-CLOSED.md +79 -0
  28. package/references/05-open-decisions/0004-halsomentorn-legacy-css.md +51 -0
  29. package/references/05-open-decisions/0005-cat-class-location-CLOSED.md +37 -0
  30. package/references/05-open-decisions/0006-bar-kind-template-migration-CLOSED.md +75 -0
  31. package/references/05-open-decisions/0007-ekonom-base-import-gap-CLOSED.md +111 -0
package/SKILL.md ADDED
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: klodd-ds
3
+ description: Design memory for the @klodd/ds shared design system across all Klodd apps (Jubb, Ekonom, future apps). Use this skill whenever working on UI components, design tokens, theming, CSS class names, spacing, color, typography, accessibility, or any visual or interaction decision in an app that imports @klodd/ds. Also use when questions arise about component APIs, token architecture, BEM naming, whether to add new tokens vs reuse existing, or how to theme a new app. Contains locked architectural decisions (do not re-litigate without explicit instruction) and open migration items (still under discussion).
4
+ ---
5
+
6
+ # @klodd/ds — Design Memory
7
+
8
+ ## Vad detta är
9
+ Gemensamt designsystem på npm (`@klodd/ds@3.x`). Tre-lagers tokens,
10
+ 33+ komponenter, konsumeras av Jubb och Ekonom. Fler appar planerade.
11
+ Denna Skill fångar både reglerna ("vad") och resonemanget ("varför").
12
+
13
+ ## Läs i denna ordning
14
+ 1. `references/01-tokens.md` — token-arkitektur (primitives → semantic → per-app)
15
+ 2. `references/02-components.md` — komponentkatalog med anti-patterns
16
+ 3. `references/03-quality-bar.md` — icke-förhandlingsbara krav
17
+
18
+ <locked_rules>
19
+ - ALDRIG hårdkoda färg, spacing, radius eller font-size. Alltid semantic token.
20
+ - BEM-namngivning för alla CSS-klasser (.block__element--modifier).
21
+ - WCAG AA minimum på alla interaktiva komponenter.
22
+ - Spacing är pixel-numerisk: --space-N där N = exakt antal pixlar (4, 8, 12, 16...).
23
+ - Per-app token-lager overridar bara semantic — aldrig primitives direkt.
24
+ - Font-weight: bara --fw-regular (400) eller --fw-medium (500).
25
+ Undantag: display-siffror (hero-roll) explicit font-weight: 600.
26
+ - Komponenter refererar ALDRIG --gray-N, --blue-N, --plum-N direkt.
27
+ </locked_rules>
28
+
29
+ ## Apps och theming
30
+ - `data-app="jubb"` → Blue accent (Radix Blue Dark), Mauve neutral
31
+ - `data-app="ekonom"` → Plum accent (Radix Plum Dark), Plum-tonad bakgrund
32
+ - Ny app: lägg till ramp i 00-primitives.css + 5-raders apps/foo.css
33
+
34
+ ## Besluts-records
35
+ - `references/04-locked-decisions/` — låsta beslut. Förklara, ändra inte.
36
+ - `references/05-open-decisions/` — öppna punkter. Presentera alternativen.
37
+
38
+ ## Komponent-val
39
+ 1. Kolla `references/02-components.md` för befintlig komponent
40
+ 2. Föredra komposition över fork
41
+ 3. Saknas den genuint — föreslå var den passar i token-modellen FÖRST
42
+
43
+ ## Uppdatera paketet
44
+ ```bash
45
+ cd ~/dev/klodd-ds
46
+ npm version patch|minor|major
47
+ npm publish --access public
48
+ cd ~/dev/Jubb && npm install @klodd/ds@latest && npm run build:ds
49
+ cd ~/dev/Ekonom && npm install @klodd/ds@latest && npm run build:ds
50
+ ```
51
+
52
+ ## När du är osäker
53
+ Läs relevant ADR. Täcks frågan inte av något ADR — flagga det explicit:
54
+ "Jag ser inget beslut på detta — ska vi skapa ett i references/05-open-decisions/?"
55
+
56
+ Updated: 2026-05-07 (matchar @klodd/ds 3.2.0)
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ /* @klodd/ds CLI-dispatcher.
3
+ *
4
+ * Anvandning fran ett app-repo (Jubb, Ekonom, framtida appar):
5
+ * npx @klodd/ds sync - kopiera paketets CSS/JS till app-repots ds-mapp
6
+ * npx @klodd/ds verify - diff:a committade DS-filer mot paketet (CI-gate)
7
+ * npx @klodd/ds precache - generera PRECACHE_URLS fran main.css + base.html
8
+ *
9
+ * Konfiguration: klodd-ds.json i app-repots rot.
10
+ * { "cssTarget": "app/static/css/ds", "jsTarget": "app/static/js/ds" } */
11
+ 'use strict';
12
+
13
+ const cmd = process.argv[2];
14
+ const valid = new Set(['sync', 'verify', 'precache']);
15
+
16
+ if (!valid.has(cmd)) {
17
+ console.error('Anvandning: npx @klodd/ds <sync|verify|precache>');
18
+ console.error('');
19
+ console.error(' sync Kopiera paketets CSS/JS till app-repots ds-mapp.');
20
+ console.error(' verify Diff:a committade DS-filer mot paketet (CI-gate).');
21
+ console.error(' precache Generera PRECACHE_URLS fran main.css + base.html.');
22
+ process.exit(1);
23
+ }
24
+
25
+ require('./' + cmd + '.js');
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ /* @klodd/ds precache - genererar PRECACHE_URLS fran main.css @imports
3
+ * och base.html <link>-taggar.
4
+ * Kor: npx @klodd/ds precache
5
+ * Output: lista av URL:er att klistra in i sw.js
6
+ *
7
+ * Notera: hanterar bara direkta @import i main.css (inte nested).
8
+ * Ekonom har bundles/ekonom.css som importerar nestat - kompletterar
9
+ * manuellt vid jamforelse mot befintlig PRECACHE_URLS. */
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const cssPath = path.join(process.cwd(), 'app/static/css/main.css');
16
+ const htmlPath = path.join(process.cwd(), 'app/templates/base.html');
17
+
18
+ if (!fs.existsSync(cssPath)) {
19
+ console.error(`Saknas: ${cssPath}`);
20
+ process.exit(1);
21
+ }
22
+ if (!fs.existsSync(htmlPath)) {
23
+ console.error(`Saknas: ${htmlPath}`);
24
+ process.exit(1);
25
+ }
26
+
27
+ const mainCss = fs.readFileSync(cssPath, 'utf8');
28
+ const baseHtml = fs.readFileSync(htmlPath, 'utf8');
29
+
30
+ const cssImports = [...mainCss.matchAll(/@import url\(['"]?(.+?)['"]?\)/g)]
31
+ .map((m) => '/static/css/' + m[1].replace(/^\.\//, ''));
32
+
33
+ const htmlLinks = [...baseHtml.matchAll(/<link[^>]+rel=["']stylesheet["'][^>]+href=["']([^"'?]+)/g)]
34
+ .map((m) => m[1]);
35
+
36
+ const allUrls = [...new Set([...cssImports, ...htmlLinks])].sort();
37
+
38
+ console.log('// Auto-genererat av npx @klodd/ds precache');
39
+ console.log('// Kor kommandot igen om main.css eller base.html andras.');
40
+ console.log('// Hanterar bara direkta @imports - jamfor mot befintlig SW-lista.');
41
+ console.log('const PRECACHE_URLS = [');
42
+ allUrls.forEach((url) => console.log(` '${url}',`));
43
+ console.log('];');
package/bin/sync.js ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ /* @klodd/ds sync - kopierar paketets CSS och JS till app-repot.
3
+ * Kor: npx @klodd/ds sync
4
+ * Forutsatter att CWD ar app-repots rot.
5
+ * Laser cssTarget/jsTarget fran klodd-ds.json i CWD, eller anvander default.
6
+ *
7
+ * Cross-platform via fs.cpSync (Node 16.7+) - inte POSIX cp -r. */
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ const pkgDir = path.dirname(require.resolve('@klodd/ds/package.json'));
14
+ const cssSource = path.join(pkgDir, 'css');
15
+ const jsSource = path.join(pkgDir, 'js');
16
+
17
+ const configPath = path.join(process.cwd(), 'klodd-ds.json');
18
+ const config = fs.existsSync(configPath)
19
+ ? JSON.parse(fs.readFileSync(configPath, 'utf8'))
20
+ : { cssTarget: 'app/static/css/ds', jsTarget: 'app/static/js/ds' };
21
+
22
+ const cssTarget = path.join(process.cwd(), config.cssTarget);
23
+ const jsTarget = path.join(process.cwd(), config.jsTarget);
24
+
25
+ fs.mkdirSync(cssTarget, { recursive: true });
26
+ fs.mkdirSync(jsTarget, { recursive: true });
27
+
28
+ fs.cpSync(cssSource, cssTarget, { recursive: true });
29
+ if (fs.existsSync(jsSource)) {
30
+ fs.cpSync(jsSource, jsTarget, { recursive: true });
31
+ }
32
+
33
+ console.log(`OK @klodd/ds synkad till ${config.cssTarget} och ${config.jsTarget}`);
package/bin/verify.js ADDED
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ /* @klodd/ds verify - diff:ar committade DS-filer mot paket-kallan.
3
+ * Kor i CI: npx @klodd/ds verify
4
+ * Fail:ar med exit code 1 om drift detekteras. */
5
+ 'use strict';
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const crypto = require('crypto');
10
+
11
+ const pkgDir = path.dirname(require.resolve('@klodd/ds/package.json'));
12
+ const configPath = path.join(process.cwd(), 'klodd-ds.json');
13
+ const config = fs.existsSync(configPath)
14
+ ? JSON.parse(fs.readFileSync(configPath, 'utf8'))
15
+ : { cssTarget: 'app/static/css/ds', jsTarget: 'app/static/js/ds' };
16
+
17
+ function hashFile(filePath) {
18
+ return crypto.createHash('sha256')
19
+ .update(fs.readFileSync(filePath))
20
+ .digest('hex');
21
+ }
22
+
23
+ function listFilesRec(dir) {
24
+ const out = [];
25
+ const stack = [{ abs: dir, rel: '' }];
26
+ while (stack.length) {
27
+ const { abs, rel } = stack.pop();
28
+ for (const entry of fs.readdirSync(abs, { withFileTypes: true })) {
29
+ const childAbs = path.join(abs, entry.name);
30
+ const childRel = rel ? path.join(rel, entry.name) : entry.name;
31
+ if (entry.isDirectory()) stack.push({ abs: childAbs, rel: childRel });
32
+ else if (entry.isFile()) out.push(childRel);
33
+ }
34
+ }
35
+ return out;
36
+ }
37
+
38
+ function diffDirs(sourceDir, targetRel) {
39
+ const drifted = [];
40
+ if (!fs.existsSync(sourceDir)) return drifted;
41
+ const targetAbs = path.join(process.cwd(), targetRel);
42
+ for (const file of listFilesRec(sourceDir)) {
43
+ const src = path.join(sourceDir, file);
44
+ const tgt = path.join(targetAbs, file);
45
+ if (!fs.existsSync(tgt)) {
46
+ drifted.push(`SAKNAS: ${targetRel}/${file}`);
47
+ } else if (hashFile(src) !== hashFile(tgt)) {
48
+ drifted.push(`DRIFT: ${targetRel}/${file}`);
49
+ }
50
+ }
51
+ return drifted;
52
+ }
53
+
54
+ const cssDrift = diffDirs(path.join(pkgDir, 'css'), config.cssTarget);
55
+ const jsDrift = diffDirs(path.join(pkgDir, 'js'), config.jsTarget);
56
+ const allDrift = [...cssDrift, ...jsDrift];
57
+
58
+ if (allDrift.length > 0) {
59
+ console.error('FAIL: @klodd/ds drift detekterad:');
60
+ allDrift.forEach((d) => console.error(' ' + d));
61
+ console.error('\nKor `npm run build:ds` for att synka.');
62
+ process.exit(1);
63
+ }
64
+
65
+ console.log('OK: alla DS-filer matchar @klodd/ds-paketet.');
66
+ process.exit(0);
@@ -272,7 +272,6 @@
272
272
  "Inter", "SF Pro Display", -apple-system,
273
273
  system-ui, "Segoe UI", Roboto, "Helvetica Neue",
274
274
  Arial, sans-serif;
275
- --font-numeric: var(--font-sans);
276
275
  --font-mono:
277
276
  "SF Mono", "Geist Mono", ui-monospace,
278
277
  SFMono-Regular, Menlo, Monaco, "Cascadia Code",
@@ -350,11 +349,21 @@
350
349
 
351
350
  /* ================================================================
352
351
  ==== Z-INDEX
352
+ Hierarki (lagst forst):
353
+ - tooltip: hover-popups, ovanpa allt vanligt content
354
+ - dropdown: dropdown-menyer, autocomplete, kontextmenyer
355
+ - sticky: sticky-headers, fixed bottom-nav
356
+ - modal: overlays, sheets, modals
357
+ - spinner: upload-spinner, blockerar interaktion
353
358
  ================================================================ */
354
359
  :root {
355
- --z-nav: 100;
356
- --z-overlay: 200;
357
- --z-spinner: 9999;
360
+ --z-tooltip: 50;
361
+ --z-dropdown: 100;
362
+ --z-nav: 100; /* alias for --z-dropdown - bottom-nav-niva */
363
+ --z-sticky: 150;
364
+ --z-modal: 200;
365
+ --z-overlay: 200; /* alias for --z-modal - bibehalls bakat-kompat */
366
+ --z-spinner: 9999;
358
367
  }
359
368
 
360
369
 
@@ -208,7 +208,7 @@
208
208
  /* Danger (rod, separat fran negative). Anvand for: delete-knappar,
209
209
  destructive bekraftelser. Skiljer sig fran --negative for att markera
210
210
  IRREVERSIBEL aktion vs faktiskt negativt belopp. */
211
- --accent-danger: oklch(0.62 0.215 25);
211
+ --accent-danger: var(--red-9);
212
212
  --accent-danger-dim: color-mix(in oklch, var(--accent-danger) 8%, transparent);
213
213
  --accent-danger-border: color-mix(in oklch, var(--accent-danger) 35%, transparent);
214
214
 
@@ -473,8 +473,8 @@
473
473
  --radius-4xl: var(--radius-24);
474
474
  --radius-pill: var(--radius-full);
475
475
 
476
- /* Font-weight - --fw-semibold mappas till --fw-medium per 400/500-policy. */
477
- --fw-semibold: var(--fw-medium);
476
+ /* Font-weight: --fw-semibold borttagen 2026-05-07 per 400/500-policy.
477
+ Aktiva call-sites bytte till var(--fw-medium) explicit. Se DECISIONS.md. */
478
478
 
479
479
  /* Kategori-paletter (Ekonom-only). Behalls for shared-tokens-paritet
480
480
  med Ekonom-repot, oanvanda i Jubb. */
@@ -31,7 +31,7 @@
31
31
  border-radius: var(--radius-10);
32
32
  padding: var(--space-4) 0;
33
33
  box-shadow: 0 4px 16px color-mix(in oklch, black 40%, transparent);
34
- z-index: var(--z-dropdown, 100);
34
+ z-index: var(--z-dropdown);
35
35
  display: none;
36
36
  }
37
37
 
@@ -172,7 +172,7 @@
172
172
  background: var(--surface-page);
173
173
  border-radius: 50%;
174
174
  transition: transform var(--dur-medium) var(--ease-spring-snappy);
175
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
175
+ box-shadow: var(--shadow-card);
176
176
  }
177
177
  .setting-toggle input:checked + .setting-toggle__track {
178
178
  background: var(--accent-9);
@@ -42,7 +42,7 @@
42
42
  background: var(--surface-raised);
43
43
  color: var(--text-default);
44
44
  font-weight: var(--fw-medium);
45
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
45
+ box-shadow: var(--shadow-card);
46
46
  }
47
47
 
48
48
  @media (hover: hover) and (pointer: fine) {
@@ -35,7 +35,7 @@
35
35
  pointer-events: none;
36
36
  opacity: 0;
37
37
  transition: opacity var(--dur-fast) var(--ease-out);
38
- z-index: var(--z-tooltip, 50);
38
+ z-index: var(--z-tooltip);
39
39
  }
40
40
 
41
41
  .tooltip-wrapper:hover .tooltip,
package/css/utilities.css CHANGED
@@ -1,81 +1,115 @@
1
1
  /* ================================================================
2
- utilities.css
3
- Single-purpose helper-classes for sma layout-detaljer.
4
- Bygger pa pixel-numerisk konvention (.m-0, .mt-12, .gap-8).
5
-
6
- Ingen styling-logik - bara en CSS-property per klass.
2
+ ds/utilities.css
3
+ Single-purpose helpers. Anvands sparsamt for layout-tweaks som
4
+ inte motiverar en namngiven komponentklass. Inte Tailwind-style
5
+ explosion, utan ett medvetet litet set.
7
6
  ================================================================ */
8
7
 
9
- /* Margin */
8
+
9
+ /* Display ------------------------------------------------------- */
10
+ .flex { display: flex; }
11
+ .flex-col { display: flex; flex-direction: column; }
12
+ .inline { display: inline; }
13
+ .inline-block { display: inline-block; }
14
+ .inline-flex { display: inline-flex; }
15
+ .block { display: block; }
16
+ .is-hidden { display: none; }
17
+
18
+ /* Text wrapping (Sprint 50/CSP A+: ersatter inline word-break-style) */
19
+ .break-word { word-break: break-word; }
20
+
21
+
22
+ /* Flex --------------------------------------------------------- */
23
+ .items-center { align-items: center; }
24
+ .items-baseline { align-items: baseline; }
25
+ .items-start { align-items: flex-start; }
26
+ .items-end { align-items: flex-end; }
27
+ .justify-between { justify-content: space-between; }
28
+ .flex-wrap { flex-wrap: wrap; }
29
+ .flex-1 { flex: 1; }
30
+ .flex-2 { flex: 2; }
31
+
32
+
33
+ /* Gaps --------------------------------------------------------- */
34
+ .gap-sm { gap: var(--space-8); }
35
+ .gap-md { gap: var(--space-12); }
36
+ .gap-lg { gap: var(--space-20); }
37
+ .gap-14 { gap: var(--space-14); }
38
+
39
+
40
+ /* Margins (numerisk pixel-skala + namnvarianter) ---------------- */
10
41
  .m-0 { margin: 0; }
11
42
  .mt-0 { margin-top: 0; }
43
+ .mt-2 { margin-top: var(--space-2); }
12
44
  .mt-4 { margin-top: var(--space-4); }
13
- .mt-8 { margin-top: var(--space-8); }
45
+ .mt-6 { margin-top: var(--space-6); }
46
+ .mt-8, .mt-sm { margin-top: var(--space-8); }
14
47
  .mt-12 { margin-top: var(--space-12); }
15
- .mt-16 { margin-top: var(--space-16); }
16
- .mt-20 { margin-top: var(--space-20); }
17
- .mt-24 { margin-top: var(--space-24); }
48
+ .mt-16, .mt-md { margin-top: var(--space-16); }
49
+ .mt-24, .mt-lg { margin-top: var(--space-24); }
50
+
18
51
  .mb-0 { margin-bottom: 0; }
52
+ .mb-2 { margin-bottom: var(--space-2); }
19
53
  .mb-4 { margin-bottom: var(--space-4); }
20
- .mb-8 { margin-bottom: var(--space-8); }
54
+ .mb-6 { margin-bottom: var(--space-6); }
55
+ .mb-8, .mb-sm { margin-bottom: var(--space-8); }
56
+ .mb-10 { margin-bottom: var(--space-10); }
21
57
  .mb-12 { margin-bottom: var(--space-12); }
22
- .mb-16 { margin-bottom: var(--space-16); }
23
- .mb-20 { margin-bottom: var(--space-20); }
24
- .mb-24 { margin-bottom: var(--space-24); }
25
-
26
- /* Padding */
27
- .p-0 { padding: 0; }
28
- .pt-0 { padding-top: 0; }
29
- .pb-0 { padding-bottom: 0; }
30
-
31
- /* Display */
32
- .is-hidden { display: none !important; }
33
- .flex { display: flex; }
34
- .inline-flex { display: inline-flex; }
35
-
36
- /* Width */
37
- .w-full { width: 100%; }
38
-
39
- /* Flex */
40
- .gap-4 { gap: var(--space-4); }
41
- .gap-8 { gap: var(--space-8); }
42
- .gap-12 { gap: var(--space-12); }
43
- .gap-16 { gap: var(--space-16); }
44
- .flex-column { flex-direction: column; }
45
- .align-center { align-items: center; }
46
- .align-self-start { align-self: flex-start; }
47
- .justify-between { justify-content: space-between; }
58
+ .mb-14 { margin-bottom: var(--space-14); }
59
+ .mb-16, .mb-md { margin-bottom: var(--space-16); }
60
+ .mb-24, .mb-lg { margin-bottom: var(--space-24); }
61
+
62
+ .mr-sm { margin-right: var(--space-8); }
63
+ .ml-auto { margin-left: auto; }
64
+
65
+
66
+ /* Padding ------------------------------------------------------- */
67
+ .py-sm { padding-top: var(--space-8); padding-bottom: var(--space-8); }
68
+
69
+
70
+ /* Width / max-width -------------------------------------------- */
71
+ .w-full { width: 100%; }
72
+ .w-auto { width: auto; }
73
+ .w-100 { width: 100px; }
74
+ .max-w-narrow { max-width: 120px; }
75
+ .max-w-200 { max-width: 200px; }
76
+ .max-w-medium { max-width: 220px; }
77
+
48
78
 
49
- /* Position (CSP-migration: ersatter style="position: ...") */
79
+ /* Min-width (for flex-form-rows) ------------------------------- */
80
+ .min-w-140 { min-width: 140px; }
81
+ .min-w-180 { min-width: 180px; }
82
+
83
+
84
+ /* Text helpers ------------------------------------------------- */
85
+ .text-right { text-align: right; }
86
+ .text-center { text-align: center; }
87
+
88
+
89
+ /* Cursors ------------------------------------------------------ */
90
+ .cursor-pointer { cursor: pointer; }
91
+
92
+
93
+ /* Position (CSP-migration: ersatter style="position: ..."-attribut) */
50
94
  .absolute { position: absolute; }
51
95
  .absolute-fill { position: absolute; inset: 0; }
52
- .relative { position: relative; }
53
96
 
54
- /* Text */
55
- .text-center { text-align: center; }
56
- .text-right { text-align: right; }
57
- .break-word { word-break: break-word; overflow-wrap: anywhere; }
58
- .tabular-nums { font-variant-numeric: tabular-nums; }
59
-
60
- /* Text-color (semantic shortcuts) */
61
- .text-default { color: var(--text-default); }
62
- .text-subtle { color: var(--text-subtle); }
63
- .text-muted { color: var(--text-muted); }
64
- .text-disabled { color: var(--text-disabled); }
65
- .text-positive { color: var(--positive); }
66
- .text-negative { color: var(--negative); }
67
- .text-warning { color: var(--warning); }
68
- .text-accent { color: var(--accent-text); }
69
-
70
- /* Visibility */
71
- .visually-hidden {
72
- position: absolute;
73
- width: 1px;
74
- height: 1px;
75
- padding: 0;
76
- margin: -1px;
77
- overflow: hidden;
78
- clip: rect(0, 0, 0, 0);
79
- white-space: nowrap;
80
- border: 0;
81
- }
97
+
98
+ /* Self-alignment (flex-children) */
99
+ .align-self-start { align-self: flex-start; }
100
+
101
+
102
+ /* Composite flex (vanlig kombination i demos och paneler) */
103
+ .flex-col-gap { display: flex; flex-direction: column; gap: var(--space-8); }
104
+
105
+
106
+ /* Status-color shortcuts (legacy aliases). */
107
+ .positive { color: var(--positive); }
108
+ .negative { color: var(--negative); }
109
+ .accent { color: var(--accent); }
110
+ .warning { color: var(--warning); }
111
+
112
+
113
+ /* Text-color utilities (CSP-migration: ersatter style="color: var(--text-X)") */
114
+ .text-subtle { color: var(--text-subtle); }
115
+ .text-muted { color: var(--text-muted); }
package/package.json CHANGED
@@ -1,12 +1,21 @@
1
1
  {
2
2
  "name": "@klodd/ds",
3
- "version": "3.3.0",
4
- "description": "Klodd Design System - shared tokens, typography, components and JS for Jubb, Ekonom, and future apps. v2.0 inkluderar all komponentkod och delad JS - app-repona haller bara data och affarslogik.",
3
+ "version": "3.4.0",
4
+ "description": "Klodd Design System - shared tokens, typography, components and JS for Jubb, Ekonom, and future apps. v3.4 inkluderar sync/verify/precache CLI sa app-repona inte langre handhaller egna build-script.",
5
5
  "main": "css/index.css",
6
+ "bin": {
7
+ "klodd-ds": "./bin/klodd-ds.js"
8
+ },
6
9
  "files": [
7
10
  "css/",
8
- "js/"
11
+ "js/",
12
+ "bin/",
13
+ "SKILL.md",
14
+ "references/"
9
15
  ],
16
+ "engines": {
17
+ "node": ">=16.7"
18
+ },
10
19
  "keywords": [
11
20
  "design-system",
12
21
  "css",