@ngxsmk/theme 2.0.0 → 3.0.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.
@@ -1,6 +1,6 @@
1
1
  import { DOCUMENT } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { inject, Injectable, signal, computed, effect } from '@angular/core';
3
+ import { inject, Injectable, signal, computed, effect, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER } from '@angular/core';
4
4
 
5
5
  /**
6
6
  * Design token model for the NGXSMK universal theme engine.
@@ -303,6 +303,15 @@ const EASING = {
303
303
  'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
304
304
  emphasized: 'cubic-bezier(0.2, 0, 0, 1)',
305
305
  };
306
+ /** Safe-area inset defaults (fallback to CSS env() variables for iOS/Android/Ionic). */
307
+ const SAFE_AREA = {
308
+ top: 'env(safe-area-inset-top, 0px)',
309
+ bottom: 'env(safe-area-inset-bottom, 0px)',
310
+ left: 'env(safe-area-inset-left, 0px)',
311
+ right: 'env(safe-area-inset-right, 0px)',
312
+ };
313
+ /** Minimum touch target size for mobile accessibility (Apple HIG & Android Material). */
314
+ const TOUCH_TARGET_MIN = '44px';
306
315
 
307
316
  /**
308
317
  * Identity helper that gives `ngxsmk.config.ts` files full type inference:
@@ -454,6 +463,12 @@ function staticVars(theme) {
454
463
  '--ngxsmk-focus-ring': 'var(--ngxsmk-shadow-focus)',
455
464
  '--ngxsmk-focus-ring-error': '0 0 0 2px color-mix(in srgb, var(--ngxsmk-color-error) 15%, transparent), ' +
456
465
  '0 0 0 4px color-mix(in srgb, var(--ngxsmk-color-error) 45%, transparent)',
466
+ // Mobile viewport & safe-area tokens (iOS / Android / Ionic)
467
+ '--ngxsmk-safe-area-top': 'env(safe-area-inset-top, 0px)',
468
+ '--ngxsmk-safe-area-bottom': 'env(safe-area-inset-bottom, 0px)',
469
+ '--ngxsmk-safe-area-left': 'env(safe-area-inset-left, 0px)',
470
+ '--ngxsmk-safe-area-right': 'env(safe-area-inset-right, 0px)',
471
+ '--ngxsmk-touch-target-min': '44px',
457
472
  // Component-specific token defaults
458
473
  ...Object.values(COMPONENT_TOKEN_DEFAULTS).reduce((merged, tokens) => ({ ...merged, ...tokens }), {}),
459
474
  };
@@ -532,12 +547,17 @@ function lightVars(theme) {
532
547
  '--ngxsmk-color-on-surface': '#0A1317',
533
548
  '--ngxsmk-color-surface-variant': theme.neutral[100],
534
549
  '--ngxsmk-color-on-surface-variant': theme.neutral[500],
550
+ '--ngxsmk-color-surface-muted': theme.neutral[50],
551
+ '--ngxsmk-color-surface-elevated': '#FFFFFF',
552
+ '--ngxsmk-color-surface-overlay': '#FFFFFF',
553
+ '--ngxsmk-color-on-surface-muted': theme.neutral[400],
535
554
  '--ngxsmk-color-surface-hover': 'rgb(5 54 89 / 0.05)',
536
555
  '--ngxsmk-color-surface-active': 'rgb(5 54 89 / 0.1)',
537
556
  '--ngxsmk-color-surface-container': '#FFFFFF',
538
557
  '--ngxsmk-color-outline': 'rgb(5 54 89 / 0.1)',
539
558
  '--ngxsmk-color-outline-strong': theme.neutral[200],
540
559
  '--ngxsmk-color-outline-variant': 'rgb(5 54 89 / 0.06)',
560
+ '--ngxsmk-color-outline-subtle': 'rgb(5 54 89 / 0.05)',
541
561
  // Elevation ladder
542
562
  '--ngxsmk-color-surface-1': '#FFFFFF',
543
563
  '--ngxsmk-color-surface-2': theme.neutral[50],
@@ -599,12 +619,17 @@ function darkVars(theme) {
599
619
  '--ngxsmk-color-on-surface': '#DFE2E5',
600
620
  '--ngxsmk-color-surface-variant': '#28292C',
601
621
  '--ngxsmk-color-on-surface-variant': '#AAAFB5',
622
+ '--ngxsmk-color-surface-muted': '#141416',
623
+ '--ngxsmk-color-surface-elevated': '#28292C',
624
+ '--ngxsmk-color-surface-overlay': '#2F3136',
625
+ '--ngxsmk-color-on-surface-muted': '#777C85',
602
626
  '--ngxsmk-color-surface-hover': 'rgb(255 255 255 / 0.05)',
603
627
  '--ngxsmk-color-surface-active': 'rgb(255 255 255 / 0.1)',
604
628
  '--ngxsmk-color-surface-container': '#28292C',
605
629
  '--ngxsmk-color-outline': 'rgb(242 244 246 / 0.1)',
606
630
  '--ngxsmk-color-outline-strong': '#494D53',
607
631
  '--ngxsmk-color-outline-variant': 'rgb(242 244 246 / 0.06)',
632
+ '--ngxsmk-color-outline-subtle': 'rgb(242 244 246 / 0.05)',
608
633
  // Elevation ladder
609
634
  '--ngxsmk-color-surface-1': theme.neutral[800],
610
635
  '--ngxsmk-color-surface-2': theme.neutral[700],
@@ -755,51 +780,127 @@ const presets = {
755
780
  };
756
781
 
757
782
  /**
758
- * Maps NGXSMK semantic color roles to Ionic's color variable namespace.
759
- *
760
- * Ionic expects:
761
- * --ion-color-primary, --ion-color-primary-rgb, --ion-color-primary-shade,
762
- * --ion-color-primary-tint, --ion-color-secondary, etc.
783
+ * Maps NGXSMK semantic color roles to Ionic 7 & 8 color variable specifications.
763
784
  *
764
- * This adapter produces the subset Ionic needs for theming.
785
+ * Emits full color suites (base, rgb, contrast, contrast-rgb, shade, tint),
786
+ * 19-step contrast ladder (--ion-color-step-50..950), safe area mappings, and
787
+ * surface variables for seamless Ionic framework interoperability.
765
788
  */
766
789
  const ionicVarsAdapter = {
767
790
  name: 'ionic',
768
- vars(theme) {
769
- const vars = {};
770
- // Primary
771
- vars['--ion-color-primary'] = theme.brandBase;
772
- vars['--ion-color-primary-rgb'] = hexToRgbStr(theme.brandBase);
773
- vars['--ion-color-primary-shade'] = shiftLightnessHex(theme.brandBase, -14);
774
- vars['--ion-color-primary-tint'] = shiftLightnessHex(theme.brandBase, 8);
775
- // Secondary
776
- vars['--ion-color-secondary'] = theme.secondaryBase;
777
- vars['--ion-color-secondary-rgb'] = hexToRgbStr(theme.secondaryBase);
778
- vars['--ion-color-secondary-shade'] = shiftLightnessHex(theme.secondaryBase, -14);
779
- vars['--ion-color-secondary-tint'] = shiftLightnessHex(theme.secondaryBase, 8);
780
- // Tertiary (derived from brand hue + 64)
781
- const tertiary = deriveScale(rotateHue(theme.brandBase, 64));
782
- vars['--ion-color-tertiary'] = tertiary[500];
783
- vars['--ion-color-tertiary-rgb'] = hexToRgbStr(tertiary[500]);
784
- vars['--ion-color-tertiary-shade'] = tertiary[600];
785
- vars['--ion-color-tertiary-tint'] = tertiary[400];
786
- // Semantic status colors
787
- for (const [name, hex] of Object.entries(theme.semantic)) {
788
- vars[`--ion-color-${name}`] = hex;
789
- vars[`--ion-color-${name}-rgb`] = hexToRgbStr(hex);
791
+ vars(theme, options) {
792
+ if (options?.isDark) {
793
+ return this.darkVars ? this.darkVars(theme) : buildLightVars(theme);
790
794
  }
791
- // Background / surface
792
- vars['--ion-background-color'] = theme.neutral[50];
793
- vars['--ion-background-color-rgb'] = hexToRgbStr(theme.neutral[50]);
794
- vars['--ion-text-color'] = '#0A1317';
795
- vars['--ion-text-color-rgb'] = '10, 19, 23';
796
- // Typography
797
- vars['--ion-font-family'] = theme.fontFamily.sans;
798
- // Border radius (Ionic uses --ion-border-radius)
799
- vars['--ion-border-radius'] = theme.radius[theme.radiusBase];
800
- return vars;
795
+ return buildLightVars(theme);
796
+ },
797
+ darkVars(theme) {
798
+ return buildDarkVars(theme);
801
799
  },
802
800
  };
801
+ function buildColorSuite(prefix, baseHex, vars) {
802
+ const contrastHex = getContrastHex(baseHex);
803
+ vars[`--ion-color-${prefix}`] = baseHex;
804
+ vars[`--ion-color-${prefix}-rgb`] = hexToRgbStr(baseHex);
805
+ vars[`--ion-color-${prefix}-contrast`] = contrastHex;
806
+ vars[`--ion-color-${prefix}-contrast-rgb`] = hexToRgbStr(contrastHex);
807
+ vars[`--ion-color-${prefix}-shade`] = shiftLightnessHex(baseHex, -12);
808
+ vars[`--ion-color-${prefix}-tint`] = shiftLightnessHex(baseHex, 10);
809
+ }
810
+ function buildLightVars(theme) {
811
+ const vars = {};
812
+ // Primary & Secondary
813
+ buildColorSuite('primary', theme.brandBase, vars);
814
+ buildColorSuite('secondary', theme.secondaryBase, vars);
815
+ // Tertiary (derived from brand hue + 64)
816
+ const tertiary = deriveScale(rotateHue(theme.brandBase, 64));
817
+ buildColorSuite('tertiary', tertiary[500], vars);
818
+ // Status & Feedback colors
819
+ const successHex = theme.semantic['success'] ?? '#0D8626';
820
+ const warningHex = theme.semantic['warning'] ?? '#E9AF08';
821
+ const dangerHex = theme.semantic['error'] ?? '#E3193B';
822
+ const infoHex = theme.semantic['info'] ?? '#2563EB';
823
+ buildColorSuite('success', successHex, vars);
824
+ buildColorSuite('warning', warningHex, vars);
825
+ buildColorSuite('danger', dangerHex, vars);
826
+ buildColorSuite('info', infoHex, vars);
827
+ // Medium / Light / Dark baseline scales
828
+ buildColorSuite('light', theme.neutral[100] ?? '#F1F4F7', vars);
829
+ buildColorSuite('medium', theme.neutral[500] ?? '#778593', vars);
830
+ buildColorSuite('dark', theme.neutral[900] ?? '#18181A', vars);
831
+ // Background / Surfaces
832
+ const bgHex = theme.neutral[50] ?? '#FFFFFF';
833
+ const textHex = '#0A1317';
834
+ vars['--ion-background-color'] = bgHex;
835
+ vars['--ion-background-color-rgb'] = hexToRgbStr(bgHex);
836
+ vars['--ion-text-color'] = textHex;
837
+ vars['--ion-text-color-rgb'] = hexToRgbStr(textHex);
838
+ vars['--ion-card-background'] = '#FFFFFF';
839
+ vars['--ion-item-background'] = '#FFFFFF';
840
+ vars['--ion-item-color'] = textHex;
841
+ vars['--ion-toolbar-background'] = bgHex;
842
+ vars['--ion-toolbar-color'] = textHex;
843
+ vars['--ion-tab-bar-background'] = '#FFFFFF';
844
+ vars['--ion-border-color'] = theme.neutral[200] ?? '#CCD3DB';
845
+ // Typography & Radius
846
+ vars['--ion-font-family'] = theme.fontFamily.sans;
847
+ vars['--ion-border-radius'] = theme.radius[theme.radiusBase];
848
+ // Stepped colors for light mode (interpolated between bg and text)
849
+ interpolateSteppedColors(bgHex, textHex, vars);
850
+ // Safe area insets
851
+ vars['--ion-safe-area-top'] = 'var(--ngxsmk-safe-area-top, env(safe-area-inset-top, 0px))';
852
+ vars['--ion-safe-area-bottom'] =
853
+ 'var(--ngxsmk-safe-area-bottom, env(safe-area-inset-bottom, 0px))';
854
+ vars['--ion-safe-area-left'] = 'var(--ngxsmk-safe-area-left, env(safe-area-inset-left, 0px))';
855
+ vars['--ion-safe-area-right'] = 'var(--ngxsmk-safe-area-right, env(safe-area-inset-right, 0px))';
856
+ return vars;
857
+ }
858
+ function buildDarkVars(theme) {
859
+ const vars = {};
860
+ // Primary & Secondary dark adjustments
861
+ const primaryDark = theme.brand[400] ?? theme.brandBase;
862
+ const secondaryDark = theme.secondary[400] ?? theme.secondaryBase;
863
+ buildColorSuite('primary', primaryDark, vars);
864
+ buildColorSuite('secondary', secondaryDark, vars);
865
+ // Tertiary
866
+ const tertiary = deriveScale(rotateHue(theme.brandBase, 64));
867
+ buildColorSuite('tertiary', tertiary[400] ?? tertiary[500], vars);
868
+ // Status & Feedback
869
+ buildColorSuite('success', shiftLightnessHex(theme.semantic['success'] ?? '#0D8626', 10), vars);
870
+ buildColorSuite('warning', shiftLightnessHex(theme.semantic['warning'] ?? '#E9AF08', 8), vars);
871
+ buildColorSuite('danger', shiftLightnessHex(theme.semantic['error'] ?? '#E3193B', 10), vars);
872
+ buildColorSuite('info', shiftLightnessHex(theme.semantic['info'] ?? '#2563EB', 10), vars);
873
+ buildColorSuite('light', theme.neutral[800] ?? '#1F1F22', vars);
874
+ buildColorSuite('medium', theme.neutral[400] ?? '#778593', vars);
875
+ buildColorSuite('dark', theme.neutral[100] ?? '#F1F4F7', vars);
876
+ // Dark backgrounds & surfaces
877
+ const darkBgHex = '#111112';
878
+ const darkTextHex = '#DFE2E5';
879
+ const darkSurface = '#1F1F22';
880
+ vars['--ion-background-color'] = darkBgHex;
881
+ vars['--ion-background-color-rgb'] = hexToRgbStr(darkBgHex);
882
+ vars['--ion-text-color'] = darkTextHex;
883
+ vars['--ion-text-color-rgb'] = hexToRgbStr(darkTextHex);
884
+ vars['--ion-card-background'] = darkSurface;
885
+ vars['--ion-item-background'] = darkSurface;
886
+ vars['--ion-item-color'] = darkTextHex;
887
+ vars['--ion-toolbar-background'] = '#18181A';
888
+ vars['--ion-toolbar-color'] = darkTextHex;
889
+ vars['--ion-tab-bar-background'] = '#18181A';
890
+ vars['--ion-border-color'] = 'rgba(242, 244, 246, 0.1)';
891
+ // Typography & Radius
892
+ vars['--ion-font-family'] = theme.fontFamily.sans;
893
+ vars['--ion-border-radius'] = theme.radius[theme.radiusBase];
894
+ // Stepped colors for dark mode
895
+ interpolateSteppedColors(darkBgHex, darkTextHex, vars);
896
+ // Safe area insets
897
+ vars['--ion-safe-area-top'] = 'var(--ngxsmk-safe-area-top, env(safe-area-inset-top, 0px))';
898
+ vars['--ion-safe-area-bottom'] =
899
+ 'var(--ngxsmk-safe-area-bottom, env(safe-area-inset-bottom, 0px))';
900
+ vars['--ion-safe-area-left'] = 'var(--ngxsmk-safe-area-left, env(safe-area-inset-left, 0px))';
901
+ vars['--ion-safe-area-right'] = 'var(--ngxsmk-safe-area-right, env(safe-area-inset-right, 0px))';
902
+ return vars;
903
+ }
803
904
  /** Default NGXSMK adapter — emits `--ngxsmk-*` variables. */
804
905
  const cssVarsAdapter = {
805
906
  name: 'ngxsmk',
@@ -807,18 +908,26 @@ const cssVarsAdapter = {
807
908
  };
808
909
  // ─── Helpers ──────────────────────────────────────────────
809
910
  function hexToRgbStr(hex) {
810
- const h = hex.replace('#', '');
811
- const r = parseInt(h.substring(0, 2), 16);
812
- const g = parseInt(h.substring(2, 4), 16);
813
- const b = parseInt(h.substring(4, 6), 16);
911
+ const clean = hex.replace('#', '');
912
+ const r = parseInt(clean.substring(0, 2), 16) || 0;
913
+ const g = parseInt(clean.substring(2, 4), 16) || 0;
914
+ const b = parseInt(clean.substring(4, 6), 16) || 0;
814
915
  return `${r}, ${g}, ${b}`;
815
916
  }
917
+ function getContrastHex(hex) {
918
+ const clean = hex.replace('#', '');
919
+ const r = parseInt(clean.substring(0, 2), 16) || 0;
920
+ const g = parseInt(clean.substring(2, 4), 16) || 0;
921
+ const b = parseInt(clean.substring(4, 6), 16) || 0;
922
+ // Standard WCAG relative luminance approximation
923
+ const yiq = (r * 299 + g * 587 + b * 114) / 1000;
924
+ return yiq >= 150 ? '#000000' : '#FFFFFF';
925
+ }
816
926
  function shiftLightnessHex(hex, amount) {
817
- // Simple hex lightness shift — import from color.ts would be circular
818
- const h = hex.replace('#', '');
819
- let r = parseInt(h.substring(0, 2), 16);
820
- let g = parseInt(h.substring(2, 4), 16);
821
- let b = parseInt(h.substring(4, 6), 16);
927
+ const clean = hex.replace('#', '');
928
+ let r = parseInt(clean.substring(0, 2), 16) || 0;
929
+ let g = parseInt(clean.substring(2, 4), 16) || 0;
930
+ let b = parseInt(clean.substring(4, 6), 16) || 0;
822
931
  if (amount > 0) {
823
932
  r = Math.min(255, r + Math.round((255 - r) * (amount / 100)));
824
933
  g = Math.min(255, g + Math.round((255 - g) * (amount / 100)));
@@ -830,7 +939,28 @@ function shiftLightnessHex(hex, amount) {
830
939
  g = Math.max(0, Math.round(g * factor));
831
940
  b = Math.max(0, Math.round(b * factor));
832
941
  }
833
- return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
942
+ return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`.toUpperCase();
943
+ }
944
+ function interpolateSteppedColors(bgHex, textHex, vars) {
945
+ const cleanBg = bgHex.replace('#', '');
946
+ const cleanText = textHex.replace('#', '');
947
+ const bgR = parseInt(cleanBg.substring(0, 2), 16) || 0;
948
+ const bgG = parseInt(cleanBg.substring(2, 4), 16) || 0;
949
+ const bgB = parseInt(cleanBg.substring(4, 6), 16) || 0;
950
+ const textR = parseInt(cleanText.substring(0, 2), 16) || 0;
951
+ const textG = parseInt(cleanText.substring(2, 4), 16) || 0;
952
+ const textB = parseInt(cleanText.substring(4, 6), 16) || 0;
953
+ const steps = [
954
+ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
955
+ ];
956
+ for (const step of steps) {
957
+ const weight = step / 1000;
958
+ const r = Math.round(bgR * (1 - weight) + textR * weight);
959
+ const g = Math.round(bgG * (1 - weight) + textG * weight);
960
+ const b = Math.round(bgB * (1 - weight) + textB * weight);
961
+ const hex = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`.toUpperCase();
962
+ vars[`--ion-color-step-${step}`] = hex;
963
+ }
834
964
  }
835
965
 
836
966
  const STYLE_ID = 'ngxsmk-theme';
@@ -862,7 +992,7 @@ class NgxThemeInjectorService {
862
992
  if (!style) {
863
993
  style = this.document.createElement('style');
864
994
  style.id = STYLE_ID;
865
- head.appendChild(style);
995
+ head?.appendChild(style);
866
996
  }
867
997
  let css = buildThemeCss(config);
868
998
  if (adapter) {
@@ -870,7 +1000,9 @@ class NgxThemeInjectorService {
870
1000
  const platformVars = adapter.vars(resolved);
871
1001
  css += '\n' + this.buildAdapterCss(adapter.name, platformVars);
872
1002
  }
873
- style.textContent = css;
1003
+ if (style) {
1004
+ style.textContent = css;
1005
+ }
874
1006
  }
875
1007
  /**
876
1008
  * Apply Ionic-specific token variables alongside the standard NGXSMK theme.
@@ -882,11 +1014,14 @@ class NgxThemeInjectorService {
882
1014
  if (!style) {
883
1015
  style = this.document.createElement('style');
884
1016
  style.id = IONIC_STYLE_ID;
885
- head.appendChild(style);
1017
+ head?.appendChild(style);
886
1018
  }
887
1019
  const resolved = resolveTheme(config);
888
- const vars = ionicVarsAdapter.vars(resolved);
889
- style.textContent = this.buildAdapterCss('ionic', vars);
1020
+ const lightVars = ionicVarsAdapter.vars(resolved);
1021
+ const darkVars = ionicVarsAdapter.darkVars ? ionicVarsAdapter.darkVars(resolved) : undefined;
1022
+ if (style) {
1023
+ style.textContent = this.buildAdapterCss('ionic', lightVars, darkVars);
1024
+ }
890
1025
  }
891
1026
  /** Remove a runtime-applied theme, falling back to the build-time CSS. */
892
1027
  clearTheme() {
@@ -896,9 +1031,15 @@ class NgxThemeInjectorService {
896
1031
  clearIonicTheme() {
897
1032
  this.document.getElementById(IONIC_STYLE_ID)?.remove();
898
1033
  }
899
- buildAdapterCss(adapterName, vars) {
1034
+ buildAdapterCss(adapterName, vars, darkVars) {
900
1035
  const lines = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`);
901
- return `/* @ngxsmk/theme — ${adapterName} adapter */\n:root {\n${lines.join('\n')}\n}`;
1036
+ let result = `/* @ngxsmk/theme — ${adapterName} adapter */\n:root {\n${lines.join('\n')}\n}`;
1037
+ if (darkVars && Object.keys(darkVars).length > 0) {
1038
+ const darkLines = Object.entries(darkVars).map(([k, v]) => ` ${k}: ${v};`);
1039
+ result += `\n\n:root.dark, body.dark, html.dark, [data-theme="dark"] {\n${darkLines.join('\n')}\n}`;
1040
+ result += `\n\n@media (prefers-color-scheme: dark) {\n :root:not(.light) {\n ${darkLines.join('\n ')}\n }\n}`;
1041
+ }
1042
+ return result;
902
1043
  }
903
1044
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxThemeInjectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
904
1045
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxThemeInjectorService, providedIn: 'root' }); }
@@ -983,6 +1124,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImpor
983
1124
  args: [{ providedIn: 'root' }]
984
1125
  }], ctorParameters: () => [] });
985
1126
 
1127
+ /**
1128
+ * Standalone provider for Angular 18-22+ applications that automatically
1129
+ * synchronizes NGXSMK design tokens with Ionic 7/8 CSS variables on startup.
1130
+ *
1131
+ * @example
1132
+ * ```ts
1133
+ * export const appConfig: ApplicationConfig = {
1134
+ * providers: [
1135
+ * provideIonicAngular(),
1136
+ * provideNgxsmkIonicTheme(),
1137
+ * ]
1138
+ * };
1139
+ * ```
1140
+ */
1141
+ function provideNgxsmkIonicTheme(config) {
1142
+ return makeEnvironmentProviders([
1143
+ {
1144
+ provide: ENVIRONMENT_INITIALIZER,
1145
+ multi: true,
1146
+ useValue: () => {
1147
+ const theme = inject(NgxsmkThemeService);
1148
+ theme.applyIonicTheme(config ?? violetPreset);
1149
+ },
1150
+ },
1151
+ ]);
1152
+ }
1153
+
986
1154
  /*
987
1155
  * Public API Surface of @ngxsmk/theme
988
1156
  */
@@ -991,5 +1159,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImpor
991
1159
  * Generated bundle index. Do not edit.
992
1160
  */
993
1161
 
994
- export { CONTROL_HEIGHT, CONTROL_HEIGHTS, DEFAULT_FONT_FAMILY, DEFAULT_NEUTRAL, DEFAULT_SEMANTIC, DEFAULT_TYPOGRAPHY, DURATION, EASING, FONT_WEIGHT, ICON_SIZE, LEADING, NgxThemeInjectorService, NgxsmkThemeService, OPACITY, RADIUS, SHADOW, SPACING, TRACKING, Z_INDEX, buildThemeCss, cssVarsAdapter, defineConfig, deriveScale, emeraldPreset, hexToOklch, ionicVarsAdapter, neutralPreset, oklchToHex, presets, resolveTheme, rosePreset, rotateHue, shiftLightness, violetPreset };
1162
+ export { CONTROL_HEIGHT, CONTROL_HEIGHTS, DEFAULT_FONT_FAMILY, DEFAULT_NEUTRAL, DEFAULT_SEMANTIC, DEFAULT_TYPOGRAPHY, DURATION, EASING, FONT_WEIGHT, ICON_SIZE, LEADING, NgxThemeInjectorService, NgxsmkThemeService, OPACITY, RADIUS, SAFE_AREA, SHADOW, SPACING, TOUCH_TARGET_MIN, TRACKING, Z_INDEX, buildThemeCss, cssVarsAdapter, defineConfig, deriveScale, emeraldPreset, hexToOklch, ionicVarsAdapter, neutralPreset, oklchToHex, presets, provideNgxsmkIonicTheme, resolveTheme, rosePreset, rotateHue, shiftLightness, violetPreset };
995
1163
  //# sourceMappingURL=ngxsmk-theme.mjs.map