@code-coaching/vuetiful 0.23.1 → 0.24.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 (151) hide show
  1. package/dist/style.css +1 -1
  2. package/dist/types/components/VBootstrap.vue.d.ts +1 -1
  3. package/dist/types/components/atoms/VAvatar.vue.d.ts +1 -1
  4. package/dist/types/components/atoms/VLightSwitch.vue.d.ts +7 -3
  5. package/dist/types/components/atoms/index.d.ts +13 -13
  6. package/dist/types/components/index.d.ts +2 -2
  7. package/dist/types/components/molecules/VAlert.vue.d.ts +1 -1
  8. package/dist/types/components/molecules/VCodeBlock.vue.d.ts +2 -2
  9. package/dist/types/components/molecules/VDrawer.vue.d.ts +1 -1
  10. package/dist/types/components/molecules/VListbox/VListbox.vue.d.ts +1 -1
  11. package/dist/types/components/molecules/VRail/VRail.vue.d.ts +1 -1
  12. package/dist/types/components/molecules/VRail/VRailTile.vue.d.ts +1 -1
  13. package/dist/types/components/molecules/index.d.ts +21 -21
  14. package/dist/types/directives/clipboard.d.ts +1 -1
  15. package/dist/types/directives/index.d.ts +1 -1
  16. package/dist/types/index.d.ts +6 -6
  17. package/dist/types/props/props.d.ts +1 -1
  18. package/dist/types/services/dark-mode.service.d.ts +13 -13
  19. package/dist/types/services/drawer.service.d.ts +1 -1
  20. package/dist/types/services/index.d.ts +6 -6
  21. package/dist/types/types/index.d.ts +1 -1
  22. package/dist/types/utils/colors/colors.service.d.ts +69 -0
  23. package/dist/types/utils/index.d.ts +7 -3
  24. package/dist/types/utils/theme/theme-switcher.vue.d.ts +1 -1
  25. package/dist/types/utils/theme/theme.service.d.ts +9 -24
  26. package/dist/types/utils/theme/themes.d.ts +35 -0
  27. package/dist/vuetiful.es.mjs +456 -161
  28. package/dist/vuetiful.umd.js +71 -16
  29. package/package.json +1 -1
  30. package/src/assets/main.css +6 -6
  31. package/src/components/VBootstrap.vue +43 -43
  32. package/src/components/atoms/VAvatar.test.ts +71 -71
  33. package/src/components/atoms/VAvatar.vue +22 -23
  34. package/src/components/atoms/VBadge.test.ts +11 -11
  35. package/src/components/atoms/VBadge.vue +2 -2
  36. package/src/components/atoms/VButton.test.ts +82 -82
  37. package/src/components/atoms/VButton.vue +20 -21
  38. package/src/components/atoms/VChip.test.ts +11 -11
  39. package/src/components/atoms/VChip.vue +3 -3
  40. package/src/components/atoms/VLightSwitch.test.ts +63 -14
  41. package/src/components/atoms/VLightSwitch.vue +35 -46
  42. package/src/components/atoms/VRadio/VRadioDescription.test.ts +13 -13
  43. package/src/components/atoms/VRadio/VRadioDescription.vue +2 -2
  44. package/src/components/atoms/VRadio/VRadioGroup.test.ts +40 -40
  45. package/src/components/atoms/VRadio/VRadioGroup.vue +19 -22
  46. package/src/components/atoms/VRadio/VRadioItem.test.ts +67 -67
  47. package/src/components/atoms/VRadio/VRadioItem.vue +10 -13
  48. package/src/components/atoms/VRadio/VRadioLabel.test.ts +13 -13
  49. package/src/components/atoms/VRadio/VRadioLabel.vue +5 -3
  50. package/src/components/atoms/VSwitch/VSwitch.test.ts +33 -33
  51. package/src/components/atoms/VSwitch/VSwitch.vue +24 -27
  52. package/src/components/atoms/VSwitch/VSwitchDescription.test.ts +13 -13
  53. package/src/components/atoms/VSwitch/VSwitchDescription.vue +2 -2
  54. package/src/components/atoms/VSwitch/VSwitchGroup.test.ts +9 -9
  55. package/src/components/atoms/VSwitch/VSwitchGroup.vue +2 -2
  56. package/src/components/atoms/VSwitch/VSwitchLabel.test.ts +19 -19
  57. package/src/components/atoms/VSwitch/VSwitchLabel.vue +2 -2
  58. package/src/components/atoms/index.ts +13 -13
  59. package/src/components/index.ts +2 -2
  60. package/src/components/molecules/VAccordion/VAccordion.test.ts +11 -17
  61. package/src/components/molecules/VAccordion/VAccordion.vue +3 -3
  62. package/src/components/molecules/VAccordion/VAccordionItem.test.ts +55 -55
  63. package/src/components/molecules/VAccordion/VAccordionItem.vue +9 -22
  64. package/src/components/molecules/VAlert.test.ts +38 -38
  65. package/src/components/molecules/VAlert.vue +25 -47
  66. package/src/components/molecules/VCard/VCard.test.ts +25 -25
  67. package/src/components/molecules/VCard/VCard.vue +13 -15
  68. package/src/components/molecules/VCard/VCardBody.test.ts +14 -14
  69. package/src/components/molecules/VCard/VCardBody.vue +4 -8
  70. package/src/components/molecules/VCard/VCardFooter.test.ts +22 -22
  71. package/src/components/molecules/VCard/VCardFooter.vue +10 -8
  72. package/src/components/molecules/VCard/VCardHeader.test.ts +25 -25
  73. package/src/components/molecules/VCard/VCardHeader.vue +7 -8
  74. package/src/components/molecules/VCodeBlock.test.ts +63 -63
  75. package/src/components/molecules/VCodeBlock.vue +27 -34
  76. package/src/components/molecules/VDrawer.test.ts +5 -5
  77. package/src/components/molecules/VDrawer.vue +10 -10
  78. package/src/components/molecules/VListbox/VListbox.test.ts +53 -53
  79. package/src/components/molecules/VListbox/VListbox.vue +31 -32
  80. package/src/components/molecules/VListbox/VListboxButton.test.ts +13 -13
  81. package/src/components/molecules/VListbox/VListboxButton.vue +5 -5
  82. package/src/components/molecules/VListbox/VListboxItem.test.ts +25 -25
  83. package/src/components/molecules/VListbox/VListboxItem.vue +7 -8
  84. package/src/components/molecules/VListbox/VListboxItems.test.ts +14 -14
  85. package/src/components/molecules/VListbox/VListboxItems.vue +9 -11
  86. package/src/components/molecules/VListbox/VListboxLabel.test.ts +10 -10
  87. package/src/components/molecules/VListbox/VListboxLabel.vue +2 -2
  88. package/src/components/molecules/VPreview.test.ts +26 -26
  89. package/src/components/molecules/VPreview.vue +22 -27
  90. package/src/components/molecules/VRail/VRail.test.ts +5 -5
  91. package/src/components/molecules/VRail/VRail.vue +7 -7
  92. package/src/components/molecules/VRail/VRailTile.test.ts +26 -28
  93. package/src/components/molecules/VRail/VRailTile.vue +13 -11
  94. package/src/components/molecules/VShell.test.ts +5 -5
  95. package/src/components/molecules/VShell.vue +11 -20
  96. package/src/components/molecules/VTabs/VTab.test.ts +69 -52
  97. package/src/components/molecules/VTabs/VTab.vue +13 -17
  98. package/src/components/molecules/VTabs/VTabPanel.test.ts +8 -8
  99. package/src/components/molecules/VTabs/VTabPanel.vue +1 -1
  100. package/src/components/molecules/VTabs/VTabs.test.ts +36 -36
  101. package/src/components/molecules/VTabs/VTabs.vue +18 -22
  102. package/src/components/molecules/index.ts +21 -21
  103. package/src/directives/clipboard.test.ts +9 -9
  104. package/src/directives/clipboard.ts +2 -2
  105. package/src/directives/index.ts +1 -1
  106. package/src/env.d.ts +2 -2
  107. package/src/index.ts +7 -7
  108. package/src/props/index.ts +1 -1
  109. package/src/props/props.ts +44 -44
  110. package/src/services/dark-mode.service.test.ts +64 -194
  111. package/src/services/dark-mode.service.ts +35 -54
  112. package/src/services/drawer.service.test.ts +21 -21
  113. package/src/services/drawer.service.ts +10 -10
  114. package/src/services/highlight.service.test.ts +12 -12
  115. package/src/services/highlight.service.ts +1 -1
  116. package/src/services/index.ts +6 -6
  117. package/src/services/rail.service.test.ts +7 -7
  118. package/src/services/rail.service.ts +2 -2
  119. package/src/services/settings.service.test.ts +5 -5
  120. package/src/services/settings.service.ts +1 -1
  121. package/src/styles/all.css +7 -7
  122. package/src/styles/elements/buttons.css +1 -1
  123. package/src/styles/elements/forms.css +7 -7
  124. package/src/styles/elements.css +13 -13
  125. package/src/styles/transitions.css +2 -2
  126. package/src/styles/typography.css +5 -5
  127. package/src/themes/theme-rocket.css +10 -10
  128. package/src/themes/theme-sahara.css +13 -13
  129. package/src/themes/theme-seafoam.css +13 -13
  130. package/src/themes/theme-seasonal.css +4 -4
  131. package/src/themes/theme-skeleton.css +7 -7
  132. package/src/themes/theme-vintage.css +12 -12
  133. package/src/themes/theme-vuetiful-0.0.1.css +13 -13
  134. package/src/types/index.ts +46 -46
  135. package/src/types/tailwind.ts +2 -21
  136. package/src/utils/colors/colors.service.ts +293 -0
  137. package/src/utils/index.ts +7 -3
  138. package/src/utils/platform/platform.service.test.ts +6 -6
  139. package/src/utils/platform/platform.service.ts +1 -1
  140. package/src/utils/theme/callback.test.ts +11 -7
  141. package/src/utils/theme/remove.test.ts +11 -9
  142. package/src/utils/theme/theme-switcher.vue +43 -49
  143. package/src/utils/theme/theme.service.test.ts +194 -84
  144. package/src/utils/theme/theme.service.ts +141 -81
  145. package/src/utils/theme/themes.ts +122 -0
  146. package/dist/types/components/index.test.d.ts +0 -1
  147. package/dist/types/index.test.d.ts +0 -1
  148. package/dist/types/utils/index.test.d.ts +0 -1
  149. package/src/components/index.test.ts +0 -10
  150. package/src/index.test.ts +0 -26
  151. package/src/utils/index.test.ts +0 -11
@@ -1,12 +1,12 @@
1
1
  /* https://fonts.google.com/specimen/Playfair+Display?query=playfair&noto.query=Abril */
2
- @import url("https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
2
+ @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
3
3
 
4
4
  :root {
5
5
  /* =~= Theme Styles =~= */
6
- --theme-font-family-base: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
7
- "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji",
8
- "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
9
- --theme-font-family-heading: "Playfair Display", serif;
6
+ --theme-font-family-base: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
7
+ 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
8
+ 'Noto Color Emoji';
9
+ --theme-font-family-heading: 'Playfair Display', serif;
10
10
  --theme-font-color-base: var(--color-surface-900);
11
11
  --theme-font-color-dark: var(--color-secondary-100);
12
12
  --theme-rounded-base: 16px;
@@ -100,12 +100,12 @@
100
100
  --color-surface-900: 18 102 104; /* ⬅ #126668 */
101
101
  }
102
102
 
103
- [data-theme="seafoam"] h1,
104
- [data-theme="seafoam"] h2,
105
- [data-theme="seafoam"] h3,
106
- [data-theme="seafoam"] h4,
107
- [data-theme="seafoam"] h5,
108
- [data-theme="seafoam"] h6 {
103
+ [data-theme='seafoam'] h1,
104
+ [data-theme='seafoam'] h2,
105
+ [data-theme='seafoam'] h3,
106
+ [data-theme='seafoam'] h4,
107
+ [data-theme='seafoam'] h5,
108
+ [data-theme='seafoam'] h6 {
109
109
  font-weight: bold;
110
110
  font-style: italic;
111
111
  letter-spacing: 1px;
@@ -114,9 +114,9 @@
114
114
  /* #213253 | #08847c */
115
115
  /* Applied to body with `<body data-theme="seafoam">` */
116
116
  /* Created with: https://csshero.org/mesher/ */
117
- [data-theme="seafoam"] {
117
+ [data-theme='seafoam'] {
118
118
  background: linear-gradient(0deg, rgba(203, 221, 254, 0.75) 0%, rgba(163, 209, 206, 0.75) 100%);
119
119
  }
120
- .dark [data-theme="seafoam"] {
120
+ .dark [data-theme='seafoam'] {
121
121
  background: linear-gradient(0deg, rgba(33, 50, 83, 1) 0%, rgba(8, 132, 124, 1) 100%);
122
122
  }
@@ -1,12 +1,12 @@
1
1
  /* A New Years inspired theme. */
2
2
 
3
3
  /* https://fonts.google.com/specimen/Quicksand?query=Quicksand */
4
- @import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap");
4
+ @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap');
5
5
 
6
6
  :root {
7
7
  /* =~= Theme Properties =~= */
8
8
  --theme-font-family-base: system-ui;
9
- --theme-font-family-heading: "Quicksand", sans-serif;
9
+ --theme-font-family-heading: 'Quicksand', sans-serif;
10
10
  --theme-font-color-base: var(--color-surface-500);
11
11
  --theme-font-color-dark: var(--color-surface-200);
12
12
  --theme-rounded-base: 12px;
@@ -101,13 +101,13 @@
101
101
  }
102
102
 
103
103
  /* Applied to body with `<body data-theme="seasonal">` */
104
- [data-theme="seasonal"] {
104
+ [data-theme='seasonal'] {
105
105
  /* prettier-ignore */
106
106
  background-image:
107
107
  radial-gradient(at 22% 100%, hsla(39,68%,50%,0.23) 0px, transparent 50%),
108
108
  radial-gradient(at 80% 100%, hsla(189,100%,56%,0.33) 0px, transparent 50%);
109
109
  }
110
- .dark [data-theme="seasonal"] {
110
+ .dark [data-theme='seasonal'] {
111
111
  /* prettier-ignore */
112
112
  background-image:
113
113
  radial-gradient(at 22% 0%, hsla(39,68%,50%,0.15) 0px, transparent 50%),
@@ -1,5 +1,5 @@
1
1
  /* https://fonts.google.com/specimen/Lato?query=lato&noto.query=Abril */
2
- @import url("https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap");
2
+ @import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');
3
3
 
4
4
  :root {
5
5
  /* =~= Theme Properties =~= */
@@ -99,12 +99,12 @@
99
99
  }
100
100
 
101
101
  /* Headings */
102
- [data-theme="skeleton"] h1,
103
- [data-theme="skeleton"] h2,
104
- [data-theme="skeleton"] h3,
105
- [data-theme="skeleton"] h4,
106
- [data-theme="skeleton"] h5,
107
- [data-theme="skeleton"] h6 {
102
+ [data-theme='skeleton'] h1,
103
+ [data-theme='skeleton'] h2,
104
+ [data-theme='skeleton'] h3,
105
+ [data-theme='skeleton'] h4,
106
+ [data-theme='skeleton'] h5,
107
+ [data-theme='skeleton'] h6 {
108
108
  font-weight: bold;
109
109
  }
110
110
 
@@ -1,12 +1,12 @@
1
1
  /* https://fonts.google.com/specimen/Abril+Fatface?query=Abril+Fatface&noto.query=Abril */
2
- @import url("https://fonts.googleapis.com/css2?family=Abril+Fatface&display=swap");
2
+ @import url('https://fonts.googleapis.com/css2?family=Abril+Fatface&display=swap');
3
3
  /* https://fonts.google.com/noto/specimen/Noto+Sans?query=sans */
4
- @import url("https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100;0,200;0,300;0,400;1,100;1,200;1,300&display=swap");
4
+ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100;0,200;0,300;0,400;1,100;1,200;1,300&display=swap');
5
5
 
6
6
  :root {
7
7
  /* =~= Theme Styles =~= */
8
- --theme-font-family-base: "Noto Sans", sans-serif;
9
- --theme-font-family-heading: "Abril Fatface", cursive;
8
+ --theme-font-family-base: 'Noto Sans', sans-serif;
9
+ --theme-font-family-heading: 'Abril Fatface', cursive;
10
10
  --theme-font-color-base: var(--color-primary-900);
11
11
  --theme-font-color-dark: var(--color-primary-100);
12
12
  --theme-rounded-base: 2px;
@@ -100,24 +100,24 @@
100
100
  --color-surface-900: 31 27 24; /* ⬅ #1f1b18 */
101
101
  }
102
102
 
103
- [data-theme="vintage"] h1,
104
- [data-theme="vintage"] h2,
105
- [data-theme="vintage"] h3,
106
- [data-theme="vintage"] h4,
107
- [data-theme="vintage"] h5,
108
- [data-theme="vintage"] h6 {
103
+ [data-theme='vintage'] h1,
104
+ [data-theme='vintage'] h2,
105
+ [data-theme='vintage'] h3,
106
+ [data-theme='vintage'] h4,
107
+ [data-theme='vintage'] h5,
108
+ [data-theme='vintage'] h6 {
109
109
  letter-spacing: 1px;
110
110
  }
111
111
 
112
112
  /* Applied to body with `<body data-theme="vintage">` */
113
113
  /* Created with: https://csshero.org/mesher/ */
114
- [data-theme="vintage"] {
114
+ [data-theme='vintage'] {
115
115
  /* prettier-ignore */
116
116
  background-image:
117
117
  radial-gradient(at 100% 0%, hsla(135,34%,70%,0.20) 0px, transparent 50%),
118
118
  radial-gradient(at 85% 100%, hsla(31,83%,50%,0.20) 0px, transparent 50%);
119
119
  }
120
- .dark [data-theme="vintage"] {
120
+ .dark [data-theme='vintage'] {
121
121
  /* prettier-ignore */
122
122
  background-image:
123
123
  radial-gradient(at 100% 0%, hsla(135,34%,70%,0.14) 0px, transparent 50%),
@@ -1,10 +1,10 @@
1
1
  /* https://fonts.google.com/specimen/Quicksand?query=Quicksand */
2
- @import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap");
2
+ @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap');
3
3
 
4
4
  :root {
5
5
  /* =~= Theme Properties =~= */
6
- --theme-font-family-base: "Quicksand", sans-serif;
7
- --theme-font-family-heading: "Quicksand", sans-serif;
6
+ --theme-font-family-base: 'Quicksand', sans-serif;
7
+ --theme-font-family-heading: 'Quicksand', sans-serif;
8
8
  --theme-font-color-base: var(--color-surface-900);
9
9
  --theme-font-color-dark: var(--color-tertiary-50);
10
10
  --theme-rounded-base: 12px;
@@ -98,27 +98,27 @@
98
98
  --color-surface-900: 49 50 118; /* ⬅ #313276 */
99
99
  }
100
100
 
101
- [data-theme="vuetiful"] h1,
102
- [data-theme="vuetiful"] h2,
103
- [data-theme="vuetiful"] h3,
104
- [data-theme="vuetiful"] h4,
105
- [data-theme="vuetiful"] h5,
106
- [data-theme="vuetiful"] h6,
107
- [data-theme="vuetiful"] a,
108
- [data-theme="vuetiful"] button {
101
+ [data-theme='vuetiful'] h1,
102
+ [data-theme='vuetiful'] h2,
103
+ [data-theme='vuetiful'] h3,
104
+ [data-theme='vuetiful'] h4,
105
+ [data-theme='vuetiful'] h5,
106
+ [data-theme='vuetiful'] h6,
107
+ [data-theme='vuetiful'] a,
108
+ [data-theme='vuetiful'] button {
109
109
  font-weight: bold;
110
110
  }
111
111
 
112
112
  /* Applied to body with `<body data-theme="vuetiful">` */
113
113
  /* Created with: https://csshero.org/mesher/ */
114
- [data-theme="vuetiful"] {
114
+ [data-theme='vuetiful'] {
115
115
  /* prettier-ignore */
116
116
  background-image:
117
117
  radial-gradient(at 76% 0%, hsla(189,100%,56%,0.36) 0px, transparent 50%),
118
118
  radial-gradient(at 1% 0%, hsla(340,100%,76%,0.26) 0px, transparent 50%),
119
119
  radial-gradient(at 20% 100%, hsla(241,100%,70%,0.47) 0px, transparent 50%);
120
120
  }
121
- .dark [data-theme="vuetiful"] {
121
+ .dark [data-theme='vuetiful'] {
122
122
  /* prettier-ignore */
123
123
  background-image:
124
124
  radial-gradient(at 76% 0%, hsla(189,100%,56%,0.20) 0px, transparent 50%),
@@ -1,4 +1,4 @@
1
- export * from "./tailwind";
1
+ export * from './tailwind';
2
2
 
3
3
  /**
4
4
  * The commented string unions are to use in PropType<> for Vue components,
@@ -6,54 +6,54 @@ export * from "./tailwind";
6
6
  **/
7
7
 
8
8
  export const Variant = {
9
- Filled: "filled",
10
- FilledPrimary: "filled-primary",
11
- FilledSecondary: "filled-secondary",
12
- FilledTertiary: "filled-tertiary",
13
- FilledSuccess: "filled-success",
14
- FilledWarning: "filled-warning",
15
- FilledError: "filled-error",
16
- FilledSurface: "filled-surface",
17
- Ringed: "ringed",
18
- RingedPrimary: "ringed-primary",
19
- RingedSecondary: "ringed-secondary",
20
- RingedTertiary: "ringed-tertiary",
21
- RingedSuccess: "ringed-success",
22
- RingedWarning: "ringed-warning",
23
- RingedError: "ringed-error",
24
- RingedSurface: "ringed-surface",
25
- Ghost: "ghost",
26
- GhostPrimary: "ghost-primary",
27
- GhostSecondary: "ghost-secondary",
28
- GhostTertiary: "ghost-tertiary",
29
- GhostSuccess: "ghost-success",
30
- GhostWarning: "ghost-warning",
31
- GhostError: "ghost-error",
32
- GhostSurface: "ghost-surface",
33
- Soft: "soft",
34
- SoftPrimary: "soft-primary",
35
- SoftSecondary: "soft-secondary",
36
- SoftTertiary: "soft-tertiary",
37
- SoftSuccess: "soft-success",
38
- SoftWarning: "soft-warning",
39
- SoftError: "soft-error",
40
- SoftSurface: "soft-surface",
41
- Glass: "glass",
42
- GlassPrimary: "glass-primary",
43
- GlassSecondary: "glass-secondary",
44
- GlassTertiary: "glass-tertiary",
45
- GlassSuccess: "glass-success",
46
- GlassWarning: "glass-warning",
47
- GlassError: "glass-error",
48
- GlassSurface: "glass-surface",
9
+ Filled: 'filled',
10
+ FilledPrimary: 'filled-primary',
11
+ FilledSecondary: 'filled-secondary',
12
+ FilledTertiary: 'filled-tertiary',
13
+ FilledSuccess: 'filled-success',
14
+ FilledWarning: 'filled-warning',
15
+ FilledError: 'filled-error',
16
+ FilledSurface: 'filled-surface',
17
+ Ringed: 'ringed',
18
+ RingedPrimary: 'ringed-primary',
19
+ RingedSecondary: 'ringed-secondary',
20
+ RingedTertiary: 'ringed-tertiary',
21
+ RingedSuccess: 'ringed-success',
22
+ RingedWarning: 'ringed-warning',
23
+ RingedError: 'ringed-error',
24
+ RingedSurface: 'ringed-surface',
25
+ Ghost: 'ghost',
26
+ GhostPrimary: 'ghost-primary',
27
+ GhostSecondary: 'ghost-secondary',
28
+ GhostTertiary: 'ghost-tertiary',
29
+ GhostSuccess: 'ghost-success',
30
+ GhostWarning: 'ghost-warning',
31
+ GhostError: 'ghost-error',
32
+ GhostSurface: 'ghost-surface',
33
+ Soft: 'soft',
34
+ SoftPrimary: 'soft-primary',
35
+ SoftSecondary: 'soft-secondary',
36
+ SoftTertiary: 'soft-tertiary',
37
+ SoftSuccess: 'soft-success',
38
+ SoftWarning: 'soft-warning',
39
+ SoftError: 'soft-error',
40
+ SoftSurface: 'soft-surface',
41
+ Glass: 'glass',
42
+ GlassPrimary: 'glass-primary',
43
+ GlassSecondary: 'glass-secondary',
44
+ GlassTertiary: 'glass-tertiary',
45
+ GlassSuccess: 'glass-success',
46
+ GlassWarning: 'glass-warning',
47
+ GlassError: 'glass-error',
48
+ GlassSurface: 'glass-surface',
49
49
  };
50
50
  // "filled" | "filled-primary" | "filled-secondary" | "filled-tertiary" | "filled-success" | "filled-warning" | "filled-error" | "filled-surface" | "ringed" | "ringed-primary" | "ringed-secondary" | "ringed-tertiary" | "ringed-success" | "ringed-warning" | "ringed-error" | "ringed-surface" | "ghost" | "ghost-primary" | "ghost-secondary" | "ghost-tertiary" | "ghost-success" | "ghost-warning" | "ghost-error" | "ghost-surface" | "soft" | "soft-primary" | "soft-secondary" | "soft-tertiary" | "soft-success" | "soft-warning" | "soft-error" | "soft-surface" | "glass" | "glass-primary" | "glass-secondary" | "glass-tertiary" | "glass-success" | "glass-warning" | "glass-error" | "glass-surface" |
51
51
 
52
52
  export const Size = {
53
- XS: "xs",
54
- SM: "sm",
55
- MD: "md",
56
- LG: "lg",
57
- XL: "xl",
53
+ XS: 'xs',
54
+ SM: 'sm',
55
+ MD: 'md',
56
+ LG: 'lg',
57
+ XL: 'xl',
58
58
  };
59
59
  // "xs" | "sm" | "md" | "lg" | "xl"
@@ -1,26 +1,7 @@
1
- export const tailwindNumbers = [
2
- "50",
3
- "100",
4
- "200",
5
- "300",
6
- "400",
7
- "500",
8
- "600",
9
- "700",
10
- "800",
11
- "900",
12
- ] as const;
1
+ export const tailwindNumbers = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900'] as const;
13
2
 
14
3
  export type TailwindNumbers = (typeof tailwindNumbers)[number];
15
4
 
16
- export const semanticNames = [
17
- "primary",
18
- "secondary",
19
- "tertiary",
20
- "success",
21
- "warning",
22
- "error",
23
- "surface",
24
- ] as const;
5
+ export const semanticNames = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'error', 'surface'] as const;
25
6
 
26
7
  export type SemanticNames = (typeof semanticNames)[number];
@@ -0,0 +1,293 @@
1
+ // This file is taken from Skeleton - wrapped in a useColors composable function
2
+ type ContrastLevel = 'AA' | 'AAA';
3
+ type ContrastSize = 'small' | 'large';
4
+
5
+ export interface Report {
6
+ emoji: string;
7
+ note: string;
8
+ }
9
+
10
+ export interface PassReport {
11
+ textColor: string;
12
+ backgroundColor: string;
13
+ contrast: number;
14
+ report: Report;
15
+ smallAA: boolean;
16
+ smallAAA: boolean;
17
+ largeAA: boolean;
18
+ largeAAA: boolean;
19
+ fails: boolean;
20
+ }
21
+
22
+ export type Palette = {
23
+ [key: number]: {
24
+ hex: string;
25
+ rgb: string;
26
+ on: string;
27
+ };
28
+ };
29
+
30
+ export const semanticNames = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'error', 'surface'] as const;
31
+ export type SemanticNames = (typeof semanticNames)[number];
32
+ export interface ColorSettings {
33
+ key: SemanticNames;
34
+ label: string;
35
+ hex: string;
36
+ rgb: string;
37
+ on: string;
38
+ }
39
+
40
+ type Rgb = {
41
+ r: number;
42
+ g: number;
43
+ b: number;
44
+ };
45
+
46
+ const useColors = () => {
47
+ function hexToRgb(hex: string): Rgb | null {
48
+ const sanitizedHex = hex.replaceAll('##', '#');
49
+ const colorParts = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(sanitizedHex);
50
+
51
+ if (!colorParts) return null;
52
+
53
+ const [, r, g, b] = colorParts;
54
+
55
+ return {
56
+ r: parseInt(r, 16),
57
+ g: parseInt(g, 16),
58
+ b: parseInt(b, 16),
59
+ } as Rgb;
60
+ }
61
+
62
+ function hexToTailwindRgbString(hex: string): string {
63
+ const sanitizedHex = hex.replaceAll('##', '#');
64
+ const colorParts = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(sanitizedHex);
65
+
66
+ if (!colorParts) return '(invalid)';
67
+
68
+ const [, r, g, b] = colorParts;
69
+
70
+ return `${parseInt(r, 16)} ${parseInt(g, 16)} ${parseInt(b, 16)}`;
71
+ }
72
+
73
+ function rgbToHex(r: number, g: number, b: number): string {
74
+ const toHex = (c: number) => `0${c.toString(16)}`.slice(-2);
75
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
76
+ }
77
+
78
+ function generateA11yOnColor(hex: string): '255 255 255' | '0 0 0' {
79
+ const black = calculateRatio(hex, '#000000');
80
+ const white = calculateRatio(hex, '#FFFFFF');
81
+ return black < white ? '0 0 0' : '255 255 255';
82
+ }
83
+
84
+ function lighten(hex: string, intensity: number): string {
85
+ const color = hexToRgb(`#${hex}`);
86
+
87
+ if (!color) return '';
88
+
89
+ const r = Math.round(color.r + (255 - color.r) * intensity);
90
+ const g = Math.round(color.g + (255 - color.g) * intensity);
91
+ const b = Math.round(color.b + (255 - color.b) * intensity);
92
+
93
+ return rgbToHex(r, g, b);
94
+ }
95
+
96
+ function darken(hex: string, intensity: number): string {
97
+ const color = hexToRgb(hex);
98
+
99
+ if (!color) return '';
100
+
101
+ const r = Math.round(color.r * intensity);
102
+ const g = Math.round(color.g * intensity);
103
+ const b = Math.round(color.b * intensity);
104
+
105
+ return rgbToHex(r, g, b);
106
+ }
107
+
108
+ function generatePalette(baseColor: string): Palette {
109
+ const hexValidation = new RegExp(/^#[0-9a-f]{6}$/i);
110
+ if (!hexValidation.test(baseColor)) baseColor = '#CCCCCC';
111
+
112
+ const hex500 = `#${baseColor}`.replace('##', '#');
113
+
114
+ const response: Palette = {
115
+ 500: { hex: hex500, rgb: hexToTailwindRgbString(hex500), on: generateA11yOnColor(hex500) },
116
+ };
117
+
118
+ const intensityMap: { [key: number]: number } = {
119
+ 50: 0.85,
120
+ 100: 0.8,
121
+ 200: 0.75,
122
+ 300: 0.6,
123
+ 400: 0.3,
124
+ 600: 0.9,
125
+ 700: 0.75,
126
+ 800: 0.6,
127
+ 900: 0.49,
128
+ };
129
+
130
+ [50, 100, 200, 300, 400].forEach((level) => {
131
+ const hex = lighten(baseColor, intensityMap[level]);
132
+ response[level] = { hex, rgb: hexToTailwindRgbString(hex), on: generateA11yOnColor(hex) };
133
+ });
134
+
135
+ [600, 700, 800, 900].forEach((level) => {
136
+ const hex = darken(baseColor, intensityMap[level]);
137
+ response[level] = { hex, rgb: hexToTailwindRgbString(hex), on: generateA11yOnColor(hex) };
138
+ });
139
+
140
+ return response as Palette;
141
+ }
142
+
143
+ const contrastLevels: Record<
144
+ ContrastSize,
145
+ {
146
+ [key in ContrastLevel]: number;
147
+ }
148
+ > = {
149
+ /** For text that is less than 18pt */
150
+ small: {
151
+ AA: 1 / 4.5,
152
+ AAA: 1 / 7,
153
+ },
154
+ /** For text that is at or is larger than 18pt */
155
+ large: {
156
+ AA: 1 / 3,
157
+ AAA: 1 / 4.5,
158
+ },
159
+ };
160
+
161
+ /** Takes the RGB and returns the luminance of it */
162
+ function getLuminance(r: Rgb): number;
163
+ function getLuminance(r: number, g: number, b: number): number;
164
+ function getLuminance(r: number | Rgb, g?: number, b?: number) {
165
+ const { _r, _g, _b } = typeof r === 'object' ? { _r: r.r, _g: r.g, _b: r.b } : { _r: r, _g: g, _b: b }; // I'm not really happy with this ternary, but it works
166
+ // we can't use !_r shorthand here because 0 is a valid value
167
+ if (_r === undefined || _g === undefined || _b === undefined) throw new Error('Invalid RGB value!');
168
+ const a = [_r, _g, _b].map(function (v) {
169
+ v /= 255;
170
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
171
+ });
172
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
173
+ }
174
+
175
+ function destringRgb(rgbString: string): Rgb {
176
+ const rgb = rgbString.match(/(\d+),?\s*(\d+),?\s*(\d+)/); // matches "255, 255, 255" and "255 255 255"
177
+ if (!rgb) throw new Error('Invalid RGB string!');
178
+ return { r: parseInt(rgb[1], 10), g: parseInt(rgb[2], 10), b: parseInt(rgb[3], 10) };
179
+ }
180
+
181
+ // overload to specify that when there is no returnType, it will always return Rgb
182
+ function handleStringColor(colorString: string): Rgb;
183
+ function handleStringColor(colorString: string, returnType: 'rgb'): Rgb;
184
+ function handleStringColor(colorString: string, returnType: 'hex'): string;
185
+ function handleStringColor(colorString: string, returnType?: 'hex' | 'rgb'): string | Rgb;
186
+ function handleStringColor(colorString: string, returnType: 'hex' | 'rgb' = 'rgb'): string | Rgb {
187
+ // if it's a css variable
188
+ if (colorString.includes('--')) {
189
+ colorString = colorString.replace(/var\(|\)/g, ''); // grab just the variable name
190
+ const cssVarHydrated = getComputedStyle(document.documentElement).getPropertyValue(colorString).trim();
191
+ return handleStringColor(cssVarHydrated, returnType);
192
+ }
193
+ // if it has spaces, it's an rgb string
194
+ if (colorString.includes(' ')) {
195
+ const rgb = destringRgb(colorString);
196
+ return returnType === 'hex' ? rgbToHex(rgb.r, rgb.g, rgb.b) : rgb;
197
+ }
198
+
199
+ // if it's a hex string
200
+ if (colorString.includes('#')) {
201
+ const rgb = hexToRgb(colorString);
202
+ if (!rgb) return '(invalid)';
203
+ return returnType === 'hex' ? colorString : rgb;
204
+ }
205
+ return colorString;
206
+ }
207
+
208
+ function calculateRatio(luminance1: string | number, luminance2: string | number) {
209
+ const lum1 = typeof luminance1 === 'string' ? getLuminance(handleStringColor(luminance1)) : luminance1;
210
+ const lum2 = typeof luminance2 === 'string' ? getLuminance(handleStringColor(luminance2)) : luminance2;
211
+ if (lum1 === undefined || lum2 === undefined) throw new Error('Luminance is undefined!');
212
+ return lum1 > lum2 ? (lum2 + 0.05) / (lum1 + 0.05) : (lum1 + 0.05) / (lum2 + 0.05);
213
+ }
214
+
215
+ function textPasses(textColor: string, backgroundColor: string, size: ContrastSize, level: ContrastLevel) {
216
+ const ratio = calculateRatio(textColor, backgroundColor);
217
+ return ratio <= contrastLevels[size][level];
218
+ }
219
+
220
+ function hexValueIsValid(textColor: string) {
221
+ return /^#[0-9A-F]{6}$/i.test(textColor);
222
+ }
223
+
224
+ /** A catch-all function to give a report on what size and level a given combination achieves. */
225
+ function getPassReport(textColor: string, backgroundColor: string): PassReport {
226
+ const _textColor = handleStringColor(textColor, 'hex');
227
+ const _backgroundColor = handleStringColor(backgroundColor, 'hex');
228
+ const contrast = calculateRatio(_textColor, _backgroundColor);
229
+ const smallAA = textPasses(_textColor, _backgroundColor, 'small', 'AA');
230
+ const smallAAA = textPasses(_textColor, _backgroundColor, 'small', 'AAA');
231
+ const largeAA = textPasses(_textColor, _backgroundColor, 'large', 'AA');
232
+ const largeAAA = textPasses(_textColor, _backgroundColor, 'large', 'AAA');
233
+ const fails = !smallAA && !smallAAA && !largeAA && !largeAAA;
234
+ const AAAEmoji = '<i class="fa-solid fa-heart"></i>';
235
+ const AAEmoji = '<i class="fa-solid fa-star"></i>';
236
+ const largeAAEmoji = '<i class="fa-solid fa-star-half-stroke"></i>';
237
+ const failEmoji = '<i class="fa-solid fa-triangle-exclamation"></i>';
238
+ const report = {
239
+ emoji: smallAAA ? AAAEmoji : smallAA ? AAEmoji : largeAA ? largeAAEmoji : failEmoji,
240
+ note:
241
+ `${_textColor} and ${_backgroundColor} ` +
242
+ (smallAAA
243
+ ? 'has great contrast!'
244
+ : smallAA
245
+ ? 'is satisfactory for larger text'
246
+ : largeAA
247
+ ? 'has poor contrast'
248
+ : 'fail contrast guidelines'),
249
+ };
250
+ return {
251
+ textColor: _textColor,
252
+ backgroundColor: _backgroundColor,
253
+ contrast,
254
+ report,
255
+ smallAA,
256
+ smallAAA,
257
+ largeAA,
258
+ largeAAA,
259
+ fails,
260
+ };
261
+ }
262
+
263
+ const hexValuesAreValid = (colors: Array<ColorSettings>) => {
264
+ let valid = true;
265
+ colors?.forEach((color: ColorSettings) => {
266
+ valid = valid && hexValueIsValid(color.hex);
267
+ });
268
+
269
+ return valid;
270
+ };
271
+
272
+ return {
273
+ hexToRgb,
274
+ hexToTailwindRgbString,
275
+ rgbToHex,
276
+ generateA11yOnColor,
277
+ lighten,
278
+ darken,
279
+ generatePalette,
280
+ contrastLevels,
281
+ getLuminance,
282
+ destringRgb,
283
+ handleStringColor,
284
+ calculateRatio,
285
+ textPasses,
286
+ hexValueIsValid,
287
+ getPassReport,
288
+ hexValuesAreValid,
289
+ semanticNames
290
+ };
291
+ };
292
+
293
+ export { useColors };
@@ -1,4 +1,8 @@
1
- import ThemeSwitcher from "./theme/theme-switcher.vue";
2
- import { useTheme } from "./theme/theme.service";
1
+ import type { ColorSettings, Palette, PassReport, Report, SemanticNames } from './colors/colors.service';
2
+ import { useColors } from './colors/colors.service';
3
+ import { usePlatform } from './platform/platform.service';
4
+ import ThemeSwitcher from './theme/theme-switcher.vue';
5
+ import { useTheme } from './theme/theme.service';
3
6
 
4
- export { ThemeSwitcher, useTheme };
7
+ export { ThemeSwitcher, useColors, usePlatform, useTheme };
8
+ export type { ColorSettings, Palette, PassReport, Report, SemanticNames };