@mk-kit/ui 0.56.0 → 0.58.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.
@@ -7,7 +7,7 @@ import { Observable } from 'rxjs';
7
7
 
8
8
  /** Shared primitive types used across mk-kit components. */
9
9
 
10
- const STORAGE_KEY = 'mk-kit-theme';
10
+ const STORAGE_KEY$1 = 'mk-kit-theme';
11
11
  const THEME_ATTR = 'data-mk-theme';
12
12
  const DENSITY_STORAGE_KEY = 'mk-kit-density';
13
13
  const DENSITY_ATTR = 'data-mk-density';
@@ -126,7 +126,7 @@ class MkThemeService {
126
126
  root.setAttribute(THEME_ATTR, pref);
127
127
  }
128
128
  try {
129
- localStorage.setItem(STORAGE_KEY, pref);
129
+ localStorage.setItem(STORAGE_KEY$1, pref);
130
130
  }
131
131
  catch {
132
132
  /* storage may be unavailable (private mode) — ignore */
@@ -229,7 +229,7 @@ class MkThemeService {
229
229
  if (!this.isBrowserEnv())
230
230
  return 'system';
231
231
  try {
232
- const stored = localStorage.getItem(STORAGE_KEY);
232
+ const stored = localStorage.getItem(STORAGE_KEY$1);
233
233
  if (stored === 'light' || stored === 'dark' || stored === 'system') {
234
234
  return stored;
235
235
  }
@@ -265,6 +265,146 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
265
265
  args: [{ providedIn: 'root' }]
266
266
  }], ctorParameters: () => [] });
267
267
 
268
+ /** High-saturation, distinct, energising accents — the set the `momentum` preset was designed around. */
269
+ const MK_ACCENTS = {
270
+ indigo: { fill: '#5B4FE0', ink: '#5B4FE0', name: 'Indigo' },
271
+ blue: { fill: '#2E7DF6', ink: '#2E7DF6', name: 'Focus blue' },
272
+ teal: { fill: '#12B5A5', ink: '#0E9C8E', name: 'Teal' },
273
+ violet: { fill: '#8B5CF6', ink: '#8B5CF6', name: 'Violet' },
274
+ coral: { fill: '#FF6B3D', ink: '#F0561F', name: 'Coral' },
275
+ lime: { fill: '#46C24A', ink: '#2FA336', name: 'Lime' },
276
+ pink: { fill: '#EC4899', ink: '#DB2777', name: 'Magenta' },
277
+ bumblebee: { fill: '#FFC400', ink: '#D99E00', name: 'Bumblebee' },
278
+ };
279
+ /** Picker order. */
280
+ const MK_ACCENT_ORDER = ['indigo', 'blue', 'teal', 'violet', 'coral', 'lime', 'pink', 'bumblebee'];
281
+ /** The swatch a picker shows for an accent (bumblebee is the black / yellow split). */
282
+ function mkAccentSwatch(key) {
283
+ return key === 'bumblebee' ? 'linear-gradient(135deg,#16161F 0 48%,#FFC400 52% 100%)' : MK_ACCENTS[key].fill;
284
+ }
285
+ /** `#rrggbb` → `rgba(r,g,b,a)`. */
286
+ function mkHexAlpha(hex, alpha) {
287
+ const n = parseInt(hex.slice(1), 16);
288
+ return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${alpha})`;
289
+ }
290
+ const STORAGE_KEY = 'mk-kit-accent';
291
+ const ATTR = 'data-mk-accent';
292
+ /**
293
+ * Runtime accent — the user picks one of {@link MK_ACCENTS} and every kit
294
+ * control recolours: the service writes the `--mk-primary` family
295
+ * (`primary`, `-hover`, `-active`, `-subtle`, `-subtle-hover`,
296
+ * `-subtle-text`), `--mk-focus-ring`, `--mk-selected-bg` / `-text` and three
297
+ * accent tokens of its own — `--mk-accent`, `--mk-accent-ink`,
298
+ * `--mk-accent-glow` — onto `<html>`, and mirrors the key as
299
+ * `data-mk-accent`. Hover / active are a touch darker in light and a touch
300
+ * lighter in dark (it follows {@link MkThemeService}). The choice persists
301
+ * in `localStorage` (`mk-kit-accent`); nothing is written until `set()` is
302
+ * called, so an app that never picks keeps the preset's own primary.
303
+ *
304
+ * ```ts
305
+ * readonly accent = inject(MkAccentService);
306
+ * accent.set('coral'); // every button, ring and chip turns coral
307
+ * accent.key(); // 'coral'
308
+ * mkAccentSwatch(accent.key()); // for the picker
309
+ * ```
310
+ */
311
+ class MkAccentService {
312
+ document = inject(DOCUMENT);
313
+ theme = inject(MkThemeService);
314
+ isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
315
+ _key = signal(this.readInitial(), /* @ts-ignore */
316
+ ...(ngDevMode ? [{ debugName: "_key" }] : /* istanbul ignore next */ []));
317
+ /** The chosen accent, or `null` while the preset's own primary is in use. */
318
+ key = this._key.asReadonly();
319
+ /** The chosen accent's definition (indigo when none is chosen). */
320
+ accent = computed(() => MK_ACCENTS[this._key() ?? 'indigo'], /* @ts-ignore */
321
+ ...(ngDevMode ? [{ debugName: "accent" }] : /* istanbul ignore next */ []));
322
+ constructor() {
323
+ effect(() => {
324
+ const key = this._key();
325
+ const dark = this.theme.isDark();
326
+ if (!this.isBrowser)
327
+ return;
328
+ const root = this.document.documentElement;
329
+ if (!key) {
330
+ root.removeAttribute(ATTR);
331
+ for (const p of WRITTEN)
332
+ root.style.removeProperty(p);
333
+ return;
334
+ }
335
+ const { fill, ink: lightInk } = MK_ACCENTS[key];
336
+ const hover = dark ? `color-mix(in srgb, ${fill} 88%, white)` : `color-mix(in srgb, ${fill} 90%, black)`;
337
+ const active = dark ? `color-mix(in srgb, ${fill} 78%, white)` : `color-mix(in srgb, ${fill} 80%, black)`;
338
+ const ink = dark ? `color-mix(in srgb, ${fill} 72%, white)` : lightInk;
339
+ const s = root.style;
340
+ s.setProperty('--mk-primary', fill);
341
+ s.setProperty('--mk-primary-hover', hover);
342
+ s.setProperty('--mk-primary-active', active);
343
+ s.setProperty('--mk-primary-subtle', `color-mix(in srgb, ${fill} 12%, var(--mk-surface))`);
344
+ s.setProperty('--mk-primary-subtle-hover', `color-mix(in srgb, ${fill} 20%, var(--mk-surface))`);
345
+ s.setProperty('--mk-primary-subtle-text', ink);
346
+ s.setProperty('--mk-focus-ring', fill);
347
+ s.setProperty('--mk-selected-bg', `color-mix(in srgb, ${fill} 12%, var(--mk-surface))`);
348
+ s.setProperty('--mk-selected-text', ink);
349
+ s.setProperty('--mk-accent', fill);
350
+ s.setProperty('--mk-accent-ink', ink);
351
+ s.setProperty('--mk-accent-glow', mkHexAlpha(fill, 0.45));
352
+ root.setAttribute(ATTR, key);
353
+ });
354
+ }
355
+ /** Pick an accent; persisted. */
356
+ set(key) {
357
+ this._key.set(key);
358
+ try {
359
+ localStorage.setItem(STORAGE_KEY, key);
360
+ }
361
+ catch {
362
+ /* ignore */
363
+ }
364
+ }
365
+ /** Back to the preset's own primary; the stored choice is cleared. */
366
+ reset() {
367
+ this._key.set(null);
368
+ try {
369
+ localStorage.removeItem(STORAGE_KEY);
370
+ }
371
+ catch {
372
+ /* ignore */
373
+ }
374
+ }
375
+ readInitial() {
376
+ if (!this.isBrowser)
377
+ return null;
378
+ try {
379
+ const v = localStorage.getItem(STORAGE_KEY);
380
+ return v && v in MK_ACCENTS ? v : null;
381
+ }
382
+ catch {
383
+ return null;
384
+ }
385
+ }
386
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkAccentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
387
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkAccentService, providedIn: 'root' });
388
+ }
389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkAccentService, decorators: [{
390
+ type: Injectable,
391
+ args: [{ providedIn: 'root' }]
392
+ }], ctorParameters: () => [] });
393
+ const WRITTEN = [
394
+ '--mk-primary',
395
+ '--mk-primary-hover',
396
+ '--mk-primary-active',
397
+ '--mk-primary-subtle',
398
+ '--mk-primary-subtle-hover',
399
+ '--mk-primary-subtle-text',
400
+ '--mk-focus-ring',
401
+ '--mk-selected-bg',
402
+ '--mk-selected-text',
403
+ '--mk-accent',
404
+ '--mk-accent-ink',
405
+ '--mk-accent-glow',
406
+ ];
407
+
268
408
  /** The default scale (same numbers as Tailwind, so mental models transfer). */
269
409
  const MK_DEFAULT_BREAKPOINTS = {
270
410
  sm: 640,
@@ -1302,6 +1442,14 @@ const MK_DEFAULT_I18N = {
1302
1442
  translationEditorReset: 'Restore the original text',
1303
1443
  translationEditorExport: 'Export CSV',
1304
1444
  translationEditorKeys: 'keys',
1445
+ sessionExpiryTitle: 'Your session is about to end',
1446
+ sessionExpiryExtend: 'Stay signed in',
1447
+ sessionExpiryExtending: 'Extending…',
1448
+ sessionExpiryLogout: 'Sign out now',
1449
+ sessionExpiryBody: (countdown) => `For security you will be signed out in ${countdown}. Unsaved changes will be lost.`,
1450
+ scannerTitle: 'Scan a code',
1451
+ scannerHint: 'Point the camera at a barcode or QR code. It is read automatically.',
1452
+ scannerCameraError: 'The camera could not be started. Check the browser permissions.',
1305
1453
  resultsCount: (count) => (count === 1 ? '1 result' : `${count} results`),
1306
1454
  previousPage: 'Go to previous page',
1307
1455
  nextPage: 'Go to next page',
@@ -1917,5 +2065,5 @@ function mkSignalErrorMessage(errors, strings, overrides) {
1917
2065
  * Generated bundle index. Do not edit.
1918
2066
  */
1919
2067
 
1920
- export { MK_BREAKPOINTS, MK_DEFAULT_BREAKPOINTS, MK_DEFAULT_DATE_NAMES, MK_DEFAULT_I18N, MK_DEFAULT_VALIDATION, MK_I18N, MK_OVERLAY_DATA, MK_OVERLAY_ROOT, MkAnchoredPanel, MkBreakpointService, MkFieldContext, MkFocusTrap, MkLiveAnnouncer, MkOverlayRef, MkOverlayService, MkThemeService, mkBodyLevelAncestor, mkFirstErrorMessage, mkGetFocusable, mkIsResponsive, mkMergeI18n, mkSignalErrorMessage, mkSignalErrorsToValidationErrors, mkValidatorChange, provideMkI18n };
2068
+ export { MK_ACCENTS, MK_ACCENT_ORDER, MK_BREAKPOINTS, MK_DEFAULT_BREAKPOINTS, MK_DEFAULT_DATE_NAMES, MK_DEFAULT_I18N, MK_DEFAULT_VALIDATION, MK_I18N, MK_OVERLAY_DATA, MK_OVERLAY_ROOT, MkAccentService, MkAnchoredPanel, MkBreakpointService, MkFieldContext, MkFocusTrap, MkLiveAnnouncer, MkOverlayRef, MkOverlayService, MkThemeService, mkAccentSwatch, mkBodyLevelAncestor, mkFirstErrorMessage, mkGetFocusable, mkHexAlpha, mkIsResponsive, mkMergeI18n, mkSignalErrorMessage, mkSignalErrorsToValidationErrors, mkValidatorChange, provideMkI18n };
1921
2069
  //# sourceMappingURL=mk-kit-ui-core.mjs.map