@klodd/ds 5.8.0 → 5.10.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/SKILL.md CHANGED
@@ -7,10 +7,13 @@ description: Design memory for the @klodd/ds shared design system used by the tw
7
7
 
8
8
  ## Status
9
9
  Designsystem-auditen (2026-05-20, se `audits/00-summary.md`) slutförd -
10
- alla tre sprintar klara:
10
+ alla sex sprintar klara:
11
11
  - Sprint 1: dead-code-städning + topbar-bump (5.4.3)
12
12
  - Sprint 2: component-token-konsolidering, ADR 0024-backfill, light-theme-removal (5.5.0)
13
13
  - Sprint 3: base.css-extraktion till paketets base/interactions.css (5.6.0)
14
+ - Sprint 4: JS-extraktion (sheet + toast) + deprecated-selektor-grep i verify (5.7.0 + 5.7.1)
15
+ - Sprint 5: width/height-tokens (--measure-*, --content-max-*) + stylelint-regel no-literal-dimension (5.8.0)
16
+ - Sprint 6: clerk-init-extraktion (waitForClerkBase, clerkLogout, KloddDS.clerkReady, fetchPatch opt-in) + async-progress clerkReady-race-fix (5.9.0)
14
17
 
15
18
  ## Vad detta är
16
19
  Gemensamt designsystem på npm (`@klodd/ds@5.x`). Tre-lagers tokens,
@@ -2,77 +2,19 @@
2
2
  base/interactions.css
3
3
  Delade interaktions- och beteendelager, lyfta från appernas
4
4
  byte-identiska ds/base.css i Sprint 3:
5
- - Reset + html/body
6
5
  - Touch-cleanup (eliminera webb-tells: tap-callout, 300ms-delay)
7
6
  - Hero-glow (radial gradient, opt-in via .with-hero-glow)
8
7
  - First-load entry animation (hero/stat-cards/bottom-nav)
9
8
  - Press-feedback (asymmetri 80ms in / 160ms out, iOS-feel)
10
9
  - Pull-to-refresh indicator
11
10
  - View transitions (same-document, 160ms snappy)
12
- Laddas efter base/pwa.css, typography.css, layout.css.
13
- ================================================================ */
14
11
 
12
+ Reset + html/body-defaults flyttades till base/reset.css 2026-05-22
13
+ (Åtgärd 1, @layer-fasen). Reset hör i @layer klodd.reset, denna fil
14
+ i @layer klodd.base.
15
15
 
16
- /* ================================================================
17
- ==== RESET
16
+ Laddas efter base/pwa.css, typography.css, layout.css.
18
17
  ================================================================ */
19
- *, *::before, *::after {
20
- box-sizing: border-box;
21
- margin: 0;
22
- padding: 0;
23
- }
24
-
25
- html {
26
- /* Sprint A4: Touch-cleanup. Eliminera webb-tells. */
27
- -webkit-tap-highlight-color: transparent;
28
- -webkit-text-size-adjust: 100%;
29
- text-size-adjust: 100%;
30
- /* Sprint E4: smooth scroll for hash-anchors. Reduced-motion-safe. */
31
- scroll-behavior: smooth;
32
- }
33
-
34
- html, body {
35
- min-height: 100vh; /* fallback */
36
- min-height: 100dvh; /* dynamisk viewport, tar hansyn till iOS-toolbar */
37
- background: var(--surface-page);
38
- color: var(--text-default);
39
- font-family: var(--font-sans);
40
- font-size: var(--fs-14);
41
- font-weight: var(--fw-regular);
42
- line-height: var(--lh-base);
43
- letter-spacing: var(--ls-base);
44
- -webkit-font-smoothing: antialiased;
45
- -moz-osx-font-smoothing: grayscale;
46
- overscroll-behavior: none;
47
- }
48
-
49
- /* Sprint G2: reservera utrymme i botten sa sista content inte goms
50
- bakom fixed bottom-nav. */
51
- body {
52
- padding-bottom: var(--bottom-nav-clearance);
53
- }
54
-
55
- a {
56
- color: var(--accent-9);
57
- text-decoration: none;
58
- }
59
- @media (hover: hover) and (pointer: fine) {
60
- a:hover { text-decoration: underline; }
61
- }
62
-
63
- button { font-family: inherit; }
64
-
65
- /* Tabular numerals dar siffror jamfors visuellt. */
66
- .num,
67
- .num-display,
68
- .num-value,
69
- .num-inline,
70
- .stat-card__value,
71
- .list-row__amount,
72
- .hero__amount,
73
- .hero__amount--card {
74
- font-variant-numeric: tabular-nums;
75
- }
76
18
 
77
19
 
78
20
  /* ================================================================
@@ -0,0 +1,58 @@
1
+ /* ================================================================
2
+ base/reset.css
3
+ Reset-lager: nollstallning + element-defaults. Wrappas i
4
+ @layer klodd.reset (lagsta cascade-prioritet) av css/index.css.
5
+
6
+ Box-sizing samt html/body bas-styling (bakgrund, farg, font,
7
+ font-smoothing, tap-highlight, text-size-adjust, overscroll-
8
+ behavior) ags av base/pwa.css och dupliceras medvetet INTE har -
9
+ pwa.css har identiska varden och tar det ansvaret. Denna fil
10
+ haller bara de reset-deklarationer som pwa.css inte tacker.
11
+
12
+ Lyft ur base/interactions.css 2026-05-22 (Atgard 1, @layer-fasen).
13
+ ================================================================ */
14
+
15
+ *, *::before, *::after {
16
+ margin: 0;
17
+ padding: 0;
18
+ }
19
+
20
+ html {
21
+ /* Sprint E4: smooth scroll for hash-anchors. Reduced-motion-safe. */
22
+ scroll-behavior: smooth;
23
+ }
24
+
25
+ html, body {
26
+ min-height: 100vh; /* fallback */
27
+ min-height: 100dvh; /* dynamisk viewport, tar hansyn till iOS-toolbar */
28
+ font-weight: var(--fw-regular);
29
+ letter-spacing: var(--ls-base);
30
+ }
31
+
32
+ /* Sprint G2: reservera utrymme i botten sa sista content inte goms
33
+ bakom fixed bottom-nav. */
34
+ body {
35
+ padding-bottom: var(--bottom-nav-clearance);
36
+ }
37
+
38
+ a {
39
+ color: var(--accent-9);
40
+ text-decoration: none;
41
+ }
42
+ @media (hover: hover) and (pointer: fine) {
43
+ a:hover { text-decoration: underline; }
44
+ }
45
+
46
+ button { font-family: inherit; }
47
+
48
+ /* Tabular numerals dar siffror jamfors visuellt. */
49
+ .num,
50
+ .num-display,
51
+ .num-value,
52
+ .num-inline,
53
+ .stat-card__value,
54
+ .list-row__amount,
55
+ .hero__amount,
56
+ .hero__amount--card {
57
+ font-variant-numeric: tabular-nums;
58
+ }
package/css/index.css CHANGED
@@ -1,8 +1,24 @@
1
1
  /* ================================================================
2
2
  @klodd/ds - convenience-import
3
- Importerar hela designsystemet i kanonisk ordning. App-specifika
4
- tema-filer (apps/jubb.css, apps/ekonom.css, apps/klodd.css)
5
- importeras separat eftersom bara en ar aktiv per pageload.
3
+ Importerar hela designsystemet i kanonisk ordning, wrappat i en
4
+ namngiven @layer-hierarki (Atgard 1, 2026-05-22).
5
+
6
+ Cascade-lager (lag prioritet -> hog):
7
+ klodd.reset - base/reset.css (nollstallning, element-defaults)
8
+ klodd.tokens - 00-primitives.css + 10-semantic.css
9
+ klodd.base - base/pwa.css, typography.css, layout.css,
10
+ interactions.css
11
+ klodd.components - components/*.css
12
+ klodd.utilities - utilities.css
13
+
14
+ Per-app-overrides (Jubb/Ekonom ds/<app>.css) wrappas i
15
+ @layer klodd.theme, som deklareras efter klodd.utilities och
16
+ darmed vinner over komponenter via cascade-ordning - inte via
17
+ hogre specificitet.
18
+
19
+ App-specifika tema-filer (apps/jubb.css, apps/ekonom.css,
20
+ apps/klodd.css) importeras separat via base.html eftersom bara
21
+ en ar aktiv per pageload - de ingar inte i denna fil.
6
22
 
7
23
  Anvandning:
8
24
  <link rel="stylesheet" href="@klodd/ds/css/index.css">
@@ -13,73 +29,72 @@
13
29
  @import '@klodd/ds/css/apps/jubb.css';
14
30
  ================================================================ */
15
31
 
16
- /* Foundation */
17
- @import './00-primitives.css';
18
- @import './10-semantic.css';
19
- @import './utilities.css';
32
+ /* Layer-ordning deklareras forst sa cascade-prioriteten ar bestamd
33
+ innan nagon regel laddas. Maste sta fore alla @import. */
34
+ @layer klodd.reset, klodd.tokens, klodd.base,
35
+ klodd.components, klodd.utilities;
20
36
 
21
- /* Base layer */
22
- @import './base/pwa.css';
23
- @import './base/typography.css';
24
- @import './base/layout.css';
25
- @import './base/interactions.css';
37
+ /* Reset */
38
+ @import url('base/reset.css') layer(klodd.reset);
26
39
 
27
- /* Komponenter */
28
- @import './components/button.css';
29
- @import './components/input.css';
30
- @import './components/badge.css';
31
- @import './components/card.css';
32
- @import './components/nav.css';
33
- @import './components/feedback.css';
34
- @import './components/overlay.css';
35
- @import './components/icon.css';
36
- @import './components/hero-roll.css';
37
- @import './components/divider.css';
38
- @import './components/progress.css';
39
- @import './components/progress-bar.css';
40
- @import './components/async-progress.css';
41
- @import './components/tooltip.css';
42
- @import './components/dropdown.css';
43
-
44
- /* v2.0.0 - flyttade fran app-repona */
45
- @import './components/banner.css';
46
- @import './components/panel.css';
47
- @import './components/profile-panel.css';
48
- @import './components/hub-card.css';
49
- @import './components/stat.css';
50
- @import './components/form.css';
51
- @import './components/setting-row.css';
52
- @import './components/collapsible.css';
53
- /* hbar.css + split-bar.css RADERADE v5.0.0 (ADR 0022) - .progress
54
- med composition-pattern (label utanfor + .progress) ersatter hbar.
55
- split-bar ersatt av kv-list (siffror) eller flera .progress
56
- side-by-side. */
57
- @import './components/hero.css';
58
- @import './components/chip.css';
59
- @import './components/avatar.css';
60
- @import './components/list-row.css';
61
- @import './components/table.css';
62
- @import './components/auth.css';
63
- @import './components/swipe-stack.css';
64
- @import './components/inline-edit.css';
65
- @import './components/upload-spinner.css';
66
- @import './components/tab-bar.css';
67
- @import './components/pill-nav.css';
68
- @import './components/pwa-avatar.css';
40
+ /* Tokens */
41
+ @import url('00-primitives.css') layer(klodd.tokens);
42
+ @import url('10-semantic.css') layer(klodd.tokens);
69
43
 
70
- /* v3.1.0 - generic kategori-monster (token-binding via app-domain-CSS) */
71
- @import './components/colored-row.css';
72
- /* colored-bar.css RADERAD v5.0.0 (ADR 0022) - .progress aterkonsolidering
73
- ovanfor inkorporerar --bar-accent-binding. */
44
+ /* Base */
45
+ @import url('base/pwa.css') layer(klodd.base);
46
+ @import url('base/typography.css') layer(klodd.base);
47
+ @import url('base/layout.css') layer(klodd.base);
48
+ @import url('base/interactions.css') layer(klodd.base);
74
49
 
75
- /* v3.5.1 - sheet-content (sprint-65 form-monster, generiska BEM-namn) */
76
- @import './components/sheet-content.css';
50
+ /* Komponenter */
51
+ @import url('components/button.css') layer(klodd.components);
52
+ @import url('components/input.css') layer(klodd.components);
53
+ @import url('components/badge.css') layer(klodd.components);
54
+ @import url('components/card.css') layer(klodd.components);
55
+ @import url('components/nav.css') layer(klodd.components);
56
+ @import url('components/feedback.css') layer(klodd.components);
57
+ @import url('components/overlay.css') layer(klodd.components);
58
+ @import url('components/icon.css') layer(klodd.components);
59
+ @import url('components/hero-roll.css') layer(klodd.components);
60
+ @import url('components/divider.css') layer(klodd.components);
61
+ @import url('components/progress.css') layer(klodd.components);
62
+ @import url('components/progress-bar.css') layer(klodd.components);
63
+ @import url('components/async-progress.css') layer(klodd.components);
64
+ @import url('components/tooltip.css') layer(klodd.components);
65
+ @import url('components/dropdown.css') layer(klodd.components);
66
+ @import url('components/banner.css') layer(klodd.components);
67
+ @import url('components/panel.css') layer(klodd.components);
68
+ @import url('components/profile-panel.css') layer(klodd.components);
69
+ @import url('components/hub-card.css') layer(klodd.components);
70
+ @import url('components/stat.css') layer(klodd.components);
71
+ @import url('components/form.css') layer(klodd.components);
72
+ @import url('components/setting-row.css') layer(klodd.components);
73
+ @import url('components/collapsible.css') layer(klodd.components);
74
+ @import url('components/hero.css') layer(klodd.components);
75
+ @import url('components/chip.css') layer(klodd.components);
76
+ @import url('components/avatar.css') layer(klodd.components);
77
+ @import url('components/list-row.css') layer(klodd.components);
78
+ @import url('components/table.css') layer(klodd.components);
79
+ @import url('components/auth.css') layer(klodd.components);
80
+ @import url('components/swipe-stack.css') layer(klodd.components);
81
+ @import url('components/inline-edit.css') layer(klodd.components);
82
+ @import url('components/upload-spinner.css') layer(klodd.components);
83
+ @import url('components/tab-bar.css') layer(klodd.components);
84
+ @import url('components/pill-nav.css') layer(klodd.components);
85
+ @import url('components/pwa-avatar.css') layer(klodd.components);
86
+ @import url('components/colored-row.css') layer(klodd.components);
87
+ @import url('components/sheet-content.css') layer(klodd.components);
88
+ @import url('components/kv-list.css') layer(klodd.components);
89
+ @import url('components/offline.css') layer(klodd.components);
77
90
 
78
- /* v3.9.0 - lyft fran Ekonoms LEGACY-sektion (Sprint 5 MADR 0009) */
79
- @import './components/kv-list.css';
80
- @import './components/offline.css';
91
+ /* Utilities */
92
+ @import url('utilities.css') layer(klodd.utilities);
81
93
 
82
- /* column-bar.css + dual-bar.css RADERADE v5.0.0 (ADR 0022) -
83
- amorterings-historik visas som kv-list (siffror) istallet for
84
- vertikala staplar; equity-split visas som tva .progress med
85
- label-row ovan istallet for dual-bar. */
94
+ /* ----------------------------------------------------------------
95
+ Raderade komponenter (ater-introducera inte):
96
+ hbar.css, split-bar.css, colored-bar.css, column-bar.css,
97
+ dual-bar.css - RADERADE v5.0.0 (ADR 0022). .progress med
98
+ composition-pattern ersatter hbar/colored-bar; kv-list eller
99
+ flera .progress side-by-side ersatter split-/column-/dual-bar.
100
+ ---------------------------------------------------------------- */
@@ -91,12 +91,23 @@
91
91
  this.failed = false;
92
92
  this.consecutiveErrors = 0;
93
93
  if (this.pollTimer !== null) return;
94
- // Forsta poll efter 100ms sa ev. fetch-patches (auth-tokens etc)
95
- // hinner appliceras.
96
- setTimeout(() => this._poll(), 100);
94
+ // Forsta poll vantar in KloddDS.clerkReady (clerk-init.js) sa en
95
+ // ev. fetch-Bearer-patch ar installerad innan vi traffar /api/.
96
+ // Ersatter en tidigare blind setTimeout(_poll, 100)-gissning som
97
+ // tappade racet vid langsam Clerk.load(). Saknas clerkReady
98
+ // (clerk-init.js ej laddad) pollar _firstPoll direkt - graceful
99
+ // degradation.
100
+ this._firstPoll();
97
101
  this.pollTimer = setInterval(() => this._poll(), this.cfg.pollInterval);
98
102
  }
99
103
 
104
+ async _firstPoll() {
105
+ if (window.KloddDS && window.KloddDS.clerkReady) {
106
+ await window.KloddDS.clerkReady;
107
+ }
108
+ this._poll();
109
+ }
110
+
100
111
  stop() {
101
112
  if (this.pollTimer !== null) {
102
113
  clearInterval(this.pollTimer);
@@ -0,0 +1,109 @@
1
+ /* @klodd/ds - clerk-init
2
+ *
3
+ * Delad Clerk-initialisering for apparna som konsumerar @klodd/ds.
4
+ * Extraherad ur appernas app.js (tidigare byte-identiska kopior med
5
+ * tva divergenser: fetch-Bearer-patchen och logout-redirecten).
6
+ *
7
+ * Exponerar tre globals:
8
+ *
9
+ * window.waitForClerkBase(cb, attempts)
10
+ * Pollar window.Clerk var 200ms (max 50 forsok) och kor cb nar
11
+ * SDK:n finns. Anvands ocksa av page-login.js.
12
+ *
13
+ * window.clerkLogout()
14
+ * Async. signOut() + redirect till config.logoutRedirect. Satts
15
+ * upp av initClerk eftersom den behover config-vardet.
16
+ *
17
+ * KloddDS.clerkReady
18
+ * Promise som resolvar nar Clerk.load() ar klar. Resolvar i ett
19
+ * finally - alltsa aven om Clerk.load() kastar - sa konsumenter
20
+ * inte hanger for evigt vid en Clerk-storning. Resolvar oavsett
21
+ * fetchPatch-konfiguration. Representerar "Clerk ar redo", inte
22
+ * "patchen ar installerad". Tidiga /api/-fetchers (AsyncProgress)
23
+ * awaitar den istallet for att gissa en setTimeout-delay.
24
+ *
25
+ * KloddDS.initClerk(config) startar allt. config-falt:
26
+ *
27
+ * fetchPatch (default false)
28
+ * Om true: patcha window.fetch sa /api/-anrop far en
29
+ * Authorization: Bearer-header. Fallback nar cookies inte gar
30
+ * igenom (PWA-standalone pa iOS). Opt-in per app.
31
+ *
32
+ * logoutRedirect (default "/")
33
+ * Dit clerkLogout navigerar efter signOut().
34
+ *
35
+ * initClerk anropas via en liten extern per-app config-fil
36
+ * (clerk-config.js) - CSP utan 'unsafe-inline' tillater inte
37
+ * inline-script. defer-ordning garanterar att initClerk finns nar
38
+ * config-filen kor.
39
+ */
40
+ (function () {
41
+ "use strict";
42
+
43
+ window.KloddDS = window.KloddDS || {};
44
+
45
+ // clerkReady skapas direkt nar denna fil kor, sa konsumenter kan
46
+ // awaita den aven innan initClerk hunnit anropas. resolve-funktionen
47
+ // sparas sa initClerk-callbacken kan resolva den.
48
+ let resolveClerkReady;
49
+ window.KloddDS.clerkReady = new Promise(function (resolve) {
50
+ resolveClerkReady = resolve;
51
+ });
52
+
53
+ function waitForClerkBase(cb, attempts) {
54
+ if (window.Clerk) return cb();
55
+ if ((attempts || 0) > 50) return console.error("Clerk JS failed to load");
56
+ setTimeout(function () { waitForClerkBase(cb, (attempts || 0) + 1); }, 200);
57
+ }
58
+ window.waitForClerkBase = waitForClerkBase;
59
+
60
+ // Patchar window.fetch sa /api/-anrop far Authorization: Bearer som
61
+ // fallback nar cookies inte gar igenom (PWA-standalone pa iOS).
62
+ // Oforandrad logik fran Jubbs tidigare app.js-inline-version.
63
+ function installFetchPatch() {
64
+ if (!window.Clerk.session) return;
65
+ const originalFetch = window.fetch.bind(window);
66
+ window.fetch = async function (input, init) {
67
+ try {
68
+ const url = typeof input === "string" ? input : input.url;
69
+ if (url && (url.startsWith("/api/") || url.startsWith(window.location.origin + "/api/"))) {
70
+ const token = await window.Clerk.session.getToken();
71
+ if (token) {
72
+ init = init || {};
73
+ init.headers = new Headers(init.headers || {});
74
+ init.headers.set("Authorization", "Bearer " + token);
75
+ }
76
+ }
77
+ } catch (e) {
78
+ console.warn("Clerk token fetch failed", e);
79
+ }
80
+ return originalFetch(input, init);
81
+ };
82
+ }
83
+
84
+ function initClerk(config) {
85
+ const cfg = Object.assign(
86
+ { fetchPatch: false, logoutRedirect: "/" },
87
+ config || {}
88
+ );
89
+ waitForClerkBase(async function () {
90
+ try {
91
+ await window.Clerk.load();
92
+ if (cfg.fetchPatch) installFetchPatch();
93
+ } catch (e) {
94
+ console.log("Clerk init:", e);
95
+ } finally {
96
+ // finally: clerkReady resolvar aven om Clerk.load() kastade,
97
+ // sa await KloddDS.clerkReady aldrig hanger for evigt.
98
+ resolveClerkReady();
99
+ window.clerkLogout = async function () {
100
+ if (window.Clerk) {
101
+ await window.Clerk.signOut();
102
+ }
103
+ window.location.href = cfg.logoutRedirect;
104
+ };
105
+ }
106
+ }, 0);
107
+ }
108
+ window.KloddDS.initClerk = initClerk;
109
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klodd/ds",
3
- "version": "5.8.0",
3
+ "version": "5.10.0",
4
4
  "description": "Klodd shared design system - tokens, components, JS",
5
5
  "main": "css/index.css",
6
6
  "bin": {