@klodd/ds 3.12.4 → 3.14.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.
@@ -424,8 +424,6 @@
424
424
  --max-w-form: 560px;
425
425
  --max-w-bottom-nav: 572px;
426
426
  --max-w-nav-desktop: 720px;
427
- --max-w-install-chip: 580px;
428
- --max-w-install-chip-desktop: 380px;
429
427
 
430
428
  --content-max-width: 640px;
431
429
  }
@@ -435,6 +433,10 @@
435
433
  ==== PWA / SAFE AREA
436
434
  env(safe-area-inset-*) anvands for iOS-notch/home-indicator.
437
435
  Touch-min 44px ar Apples HIG-rekommendation.
436
+ --viewport-height defaultar till 100vh, overrideas av JS
437
+ (pwa-register.js syncViewport) via visualViewport.height -
438
+ fungerar som iOS-cold-start-fix (lasningen tvingar WebKit
439
+ att stabilisera viewport-geometri).
438
440
  ================================================================ */
439
441
  :root {
440
442
  --safe-top: env(safe-area-inset-top, 0px);
@@ -442,6 +444,8 @@
442
444
  --safe-left: env(safe-area-inset-left, 0px);
443
445
  --safe-right: env(safe-area-inset-right, 0px);
444
446
 
447
+ --viewport-height: 100vh;
448
+
445
449
  --touch-min: 44px;
446
450
 
447
451
  /* Bottom-nav-tokens lever i 10-semantic.css som calc-baserade
@@ -226,8 +226,8 @@
226
226
  --shadow-card: 0 8px 16px color-mix(in oklch, var(--gray-12) 8%, transparent);
227
227
 
228
228
  /* Bakat-kompat: --shadow-float ar nu alias till --shadow-card.
229
- Befintliga komponenter (chip.install-chip, overlay.dialog/sheet,
230
- feedback.toast) fortsatter funka utan andring. Migration till
229
+ Befintliga komponenter (overlay.dialog/sheet, feedback.toast,
230
+ nav.bottom-nav) fortsatter funka utan andring. Migration till
231
231
  --shadow-card per komponent kan ske gradvis. */
232
232
  --shadow-float: var(--shadow-card);
233
233
 
@@ -1,6 +1,6 @@
1
1
  /* ================================================================
2
2
  components/chip.css
3
- Pills- och chips-familjen: fem fristående blocks som delar
3
+ Pills- och chips-familjen: fyra fristående blocks som delar
4
4
  form-språket (rounded-full, kompakt padding, inline-flex).
5
5
 
6
6
  Blocks:
@@ -8,7 +8,6 @@
8
8
  .chip-list - sibling-wrapper för chips i rad (har __item/__delete/__add)
9
9
  .brand-pill - projekt-namn-pill i topbar
10
10
  .month-pill - navigations-pill för månadsbyte (Ekonom)
11
- .install-chip - PWA install-prompt som flyter ovan bottom-nav
12
11
 
13
12
  HTML-relationer:
14
13
  .chip-list innehåller .chip-list__item (egna BEM-element, ej .chip)
@@ -17,8 +16,8 @@
17
16
  Modifiers:
18
17
  .chip --accent/-positive/-negative/-warning/-faint
19
18
 
20
- .install-chip har egna BEM-element (__text/__install/__dismiss) plus
21
- keyframe-animation install-chip-up (respekterar prefers-reduced-motion).
19
+ v3.13.0: .install-chip (PWA install-prompt) borttagen tillsammans
20
+ med tillhörande JS i pwa-register.js.
22
21
  ================================================================ */
23
22
  .chip {
24
23
  display: inline-flex;
@@ -206,112 +205,7 @@
206
205
  }
207
206
 
208
207
 
209
- /* ================================================================
210
- ==== INSTALL-CHIP
211
- PWA install-prompt som flyter ovan bottom-nav.
212
- ================================================================ */
213
- .install-chip {
214
- position: fixed;
215
- bottom: calc(84px + var(--safe-bottom));
216
- left: var(--space-12);
217
- right: var(--space-12);
218
- max-width: 480px;
219
- margin: 0 auto;
220
- background: var(--surface-raised);
221
- border: 1px solid var(--border-subtle);
222
- border-radius: var(--radius-full);
223
- padding: var(--space-10) var(--space-10) var(--space-10) var(--space-18);
224
- display: flex;
225
- align-items: center;
226
- gap: var(--space-10);
227
- font-size: var(--fs-13);
228
- color: var(--text-default);
229
- z-index: var(--z-overlay, 60);
230
- animation: install-chip-up 0.28s var(--ease-out);
231
- box-shadow: var(--shadow-float);
232
- }
233
-
234
- .install-chip__text { flex: 1; min-width: 0; }
235
-
236
- .install-chip__install {
237
- background: var(--accent-9);
238
- color: var(--text-on-accent);
239
- border: none;
240
- padding: var(--space-8) var(--space-14);
241
- border-radius: var(--radius-full);
242
- font-size: var(--fs-12);
243
- font-weight: var(--fw-medium);
244
- font-family: inherit;
245
- cursor: pointer;
246
- white-space: nowrap;
247
- transition: background var(--dur-fast) var(--ease-default);
248
- }
249
-
250
- @media (hover: hover) and (pointer: fine) {
251
- .install-chip__install:hover { background: var(--accent-10); }
252
- }
253
-
254
- .install-chip__install:focus-visible {
255
- outline: 2px solid var(--border-focus);
256
- outline-offset: 2px;
257
- }
258
-
259
- .install-chip__install:active {
260
- background: var(--surface-active);
261
- transform: scale(0.97);
262
- transition: transform 80ms var(--ease-spring-snappy);
263
- }
264
-
265
- .install-chip__install:disabled,
266
- .install-chip__install[aria-disabled="true"] {
267
- opacity: 0.5;
268
- cursor: not-allowed;
269
- pointer-events: none;
270
- }
271
-
272
- .install-chip__dismiss {
273
- background: transparent;
274
- border: none;
275
- color: var(--text-subtle);
276
- font-size: var(--fs-18);
277
- line-height: 1;
278
- padding: var(--space-6) var(--space-10);
279
- cursor: pointer;
280
- min-width: 36px;
281
- transition: color var(--dur-fast) var(--ease-default);
282
- }
283
-
284
- @media (hover: hover) and (pointer: fine) {
285
- .install-chip__dismiss:hover { color: var(--text-default); }
286
- }
287
-
288
- .install-chip__dismiss:focus-visible {
289
- outline: 2px solid var(--border-focus);
290
- outline-offset: 2px;
291
- }
292
-
293
- .install-chip__dismiss:active {
294
- background: var(--surface-active);
295
- transform: scale(0.97);
296
- transition: transform 80ms var(--ease-spring-snappy);
297
- }
298
-
299
- .install-chip__dismiss:disabled,
300
- .install-chip__dismiss[aria-disabled="true"] {
301
- opacity: 0.5;
302
- cursor: not-allowed;
303
- pointer-events: none;
304
- }
305
-
306
- @keyframes install-chip-up {
307
- from { transform: translateY(calc(100% + 100px)); opacity: 0; }
308
- to { transform: translateY(0); opacity: 1; }
309
- }
310
-
311
208
  @media (prefers-reduced-motion: reduce) {
312
- .install-chip { animation: none; }
313
209
  .chip-list__delete:active,
314
- .chip-list__add:active,
315
- .install-chip__install:active,
316
- .install-chip__dismiss:active { transform: none; }
210
+ .chip-list__add:active { transform: none; }
317
211
  }
@@ -1,17 +1,18 @@
1
1
  /*--------------------------------------------------------------
2
- @klodd/ds - PWA-registrering + install-prompts
2
+ @klodd/ds - PWA-registrering
3
3
 
4
4
  Auto-detekterar app-namn fran <html data-app="X">-attributet.
5
- Defaults: appName = capitalize(data-app), appKey = data-app, swPath = "/sw.js".
5
+ Defaults: appName = capitalize(data-app), swPath = "/sw.js".
6
6
  Funkar identiskt for Jubb och Ekonom utan konfiguration.
7
7
 
8
- Manuell override: KloddPWA.init({ appName, appKey, swPath }) innan load.
8
+ Manuell override: KloddPWA.init({ appName, swPath }) innan load.
9
9
 
10
10
  Funktioner:
11
11
  - isNetworkError() - iOS-saker nat-detektering (window.isNetworkError)
12
12
  - SW-registrering med updateViaCache: 'none'
13
- - Install-prompt (beforeinstallprompt for Chrome/Android)
14
- - iOS install-hint (Safari har ingen beforeinstallprompt)
13
+
14
+ Install-prompts (beforeinstallprompt + iOS-hint) borttagna 3.13.0.
15
+ PWA-installation sker numera enbart via browserns inbyggda meny.
15
16
  --------------------------------------------------------------*/
16
17
  (function (root, doc) {
17
18
  'use strict';
@@ -25,9 +26,7 @@
25
26
  const cap = dataApp.charAt(0).toUpperCase() + dataApp.slice(1);
26
27
  return {
27
28
  appName: userCfg.appName || cap,
28
- appKey: userCfg.appKey || dataApp,
29
29
  swPath: userCfg.swPath || '/sw.js',
30
- minVisits: userCfg.minVisits || 3,
31
30
  };
32
31
  }
33
32
 
@@ -63,91 +62,23 @@
63
62
  }
64
63
 
65
64
  /*------------------------------------------------------------
66
- Install-prompt (Android / Chrome / Edge)
65
+ Viewport-sync (iOS PWA cold-start fix)
66
+ iOS Safari beraknar env(safe-area-inset-bottom) felaktigt vid
67
+ forsta render i PWA-standalone. Att tidigt lasa
68
+ visualViewport.height + skriva till en CSS-custom-property
69
+ tvingar WebKit att stabilisera sin viewport-geometri innan
70
+ layout-pass kor klart.
71
+
72
+ --viewport-height-tokenet ar tillagg for framtida konsumenter
73
+ som behover en JS-driven viewport-hojd. Defaulter till 100vh
74
+ i 00-primitives.css.
67
75
  ------------------------------------------------------------*/
68
- let deferredInstallPrompt = null;
69
-
70
- function setupInstallPrompt(cfg) {
71
- root.addEventListener('beforeinstallprompt', function (e) {
72
- e.preventDefault();
73
- deferredInstallPrompt = e;
74
- maybeShowInstallChip(cfg);
75
- });
76
- }
77
-
78
- function maybeShowInstallChip(cfg) {
79
- if (sessionStorage.getItem(cfg.appKey + '_install_dismissed')) return;
80
- if (root.matchMedia('(display-mode: standalone)').matches) return;
81
- const visits = parseInt(localStorage.getItem(cfg.appKey + '_visits') || '0', 10) + 1;
82
- localStorage.setItem(cfg.appKey + '_visits', String(visits));
83
- if (visits < cfg.minVisits) return;
84
- showInstallChip(cfg);
85
- }
86
-
87
- function showInstallChip(cfg) {
88
- const id = cfg.appKey + '-install-chip';
89
- if (doc.getElementById(id)) return;
90
-
91
- const chip = doc.createElement('div');
92
- chip.className = 'install-chip';
93
- chip.id = id;
94
- chip.setAttribute('role', 'dialog');
95
- chip.setAttribute('aria-label', 'Installera ' + cfg.appName);
96
- chip.innerHTML =
97
- '<span>Installera ' + cfg.appName + ' på hemskärmen</span>' +
98
- '<button type="button" data-install>Installera</button>' +
99
- '<button type="button" data-dismiss aria-label="Stäng">×</button>';
100
- doc.body.appendChild(chip);
101
-
102
- chip.querySelector('[data-install]').addEventListener('click', async function () {
103
- if (!deferredInstallPrompt) { chip.remove(); return; }
104
- deferredInstallPrompt.prompt();
105
- try { await deferredInstallPrompt.userChoice; } catch (e) {}
106
- deferredInstallPrompt = null;
107
- chip.remove();
108
- });
109
- chip.querySelector('[data-dismiss]').addEventListener('click', function () {
110
- sessionStorage.setItem(cfg.appKey + '_install_dismissed', '1');
111
- chip.remove();
112
- });
113
- }
114
-
115
- /*------------------------------------------------------------
116
- iOS install-hint
117
- Safari har ingen beforeinstallprompt - manuell flow via "Dela" ->
118
- "Lagg till pa hemskarmen". Visa diskret hint efter N besok.
119
- ------------------------------------------------------------*/
120
- function setupIOSHint(cfg) {
121
- root.addEventListener('load', function () {
122
- const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !root.MSStream;
123
- const inStandalone = root.matchMedia('(display-mode: standalone)').matches
124
- || root.navigator.standalone;
125
- if (!isIOS || inStandalone) return;
126
- if (sessionStorage.getItem(cfg.appKey + '_ios_install_dismissed')) return;
127
- const visits = parseInt(localStorage.getItem(cfg.appKey + '_visits') || '0', 10);
128
- if (visits < cfg.minVisits) return;
129
- showIOSInstallHint(cfg);
130
- });
131
- }
132
-
133
- function showIOSInstallHint(cfg) {
134
- const id = cfg.appKey + '-ios-install-hint';
135
- if (doc.getElementById(id)) return;
136
-
137
- const hint = doc.createElement('div');
138
- hint.className = 'install-chip install-chip-ios';
139
- hint.id = id;
140
- hint.setAttribute('role', 'dialog');
141
- hint.setAttribute('aria-label', 'Installera ' + cfg.appName + ' pa iOS');
142
- hint.innerHTML =
143
- '<span>Tryck <strong>Dela</strong> → <strong>Lägg till på hemskärmen</strong></span>' +
144
- '<button type="button" data-dismiss aria-label="Stäng">×</button>';
145
- doc.body.appendChild(hint);
146
-
147
- hint.querySelector('[data-dismiss]').addEventListener('click', function () {
148
- sessionStorage.setItem(cfg.appKey + '_ios_install_dismissed', '1');
149
- hint.remove();
150
- });
76
+ function syncViewport() {
77
+ if (!root.visualViewport) return;
78
+ doc.documentElement.style.setProperty(
79
+ '--viewport-height',
80
+ root.visualViewport.height + 'px'
81
+ );
151
82
  }
152
83
 
153
84
  /*------------------------------------------------------------
@@ -160,6 +91,9 @@
160
91
  root.KloddPWA.config = cfg;
161
92
 
162
93
  registerSW(cfg);
163
- setupInstallPrompt(cfg);
164
- setupIOSHint(cfg);
94
+
95
+ if (root.visualViewport) {
96
+ root.visualViewport.addEventListener('resize', syncViewport);
97
+ }
98
+ syncViewport();
165
99
  })(typeof window !== 'undefined' ? window : globalThis, document);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klodd/ds",
3
- "version": "3.12.4",
3
+ "version": "3.14.0",
4
4
  "description": "Klodd shared design system - tokens, components, JS",
5
5
  "main": "css/index.css",
6
6
  "bin": {
@@ -191,8 +191,8 @@ För varje entry gäller:
191
191
  - **INTE:** Vanlig `<h1>` (anvand `.heading-1`)
192
192
 
193
193
  ### chip (`chip.css`)
194
- - **Blocks:** `.chip`, `.chip-list` (sibling-wrapper for chips i rad), `.brand-pill`, `.month-pill`, `.install-chip` (PWA install-prompt)
195
- - **Element:** `.chip-list__item`, `.chip-list__text`, `.chip-list__form`, `.chip-list__delete`, `.chip-list__add`, `.install-chip__text`, `.install-chip__install`, `.install-chip__dismiss`
194
+ - **Blocks:** `.chip`, `.chip-list` (sibling-wrapper for chips i rad), `.brand-pill`, `.month-pill`
195
+ - **Element:** `.chip-list__item`, `.chip-list__text`, `.chip-list__form`, `.chip-list__delete`, `.chip-list__add`
196
196
  - **Modifiers:** `.chip--accent/-positive/-negative/-warning/-faint`
197
197
  - **Anvand:** Kort-format pills med dot-prefix (status, kategori, count)
198
198
  - **INTE:** Form-inputs (anvand `.input`)