vuetiwatch 0.1.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 (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/dist/index.d.ts +11 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +6 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/plugin.d.ts +41 -0
  8. package/dist/plugin.d.ts.map +1 -0
  9. package/dist/plugin.js +58 -0
  10. package/dist/plugin.js.map +1 -0
  11. package/dist/registry.d.ts +17 -0
  12. package/dist/registry.d.ts.map +1 -0
  13. package/dist/registry.js +37 -0
  14. package/dist/registry.js.map +1 -0
  15. package/dist/styles/aurora.css +74 -0
  16. package/dist/styles/aurora.min.css +1 -0
  17. package/dist/styles/brutalist.css +48 -0
  18. package/dist/styles/brutalist.min.css +1 -0
  19. package/dist/styles/calm.css +21 -0
  20. package/dist/styles/calm.min.css +1 -0
  21. package/dist/styles/clay.css +44 -0
  22. package/dist/styles/clay.min.css +1 -0
  23. package/dist/styles/core.css +140 -0
  24. package/dist/styles/core.min.css +1 -0
  25. package/dist/styles/darkGlass.css +43 -0
  26. package/dist/styles/darkGlass.min.css +1 -0
  27. package/dist/styles/liquidGlass.css +100 -0
  28. package/dist/styles/liquidGlass.min.css +1 -0
  29. package/dist/styles/lux.css +21 -0
  30. package/dist/styles/lux.min.css +1 -0
  31. package/dist/styles/morph.css +37 -0
  32. package/dist/styles/morph.min.css +1 -0
  33. package/dist/styles/neon.css +41 -0
  34. package/dist/styles/neon.min.css +1 -0
  35. package/dist/styles/paper.css +17 -0
  36. package/dist/styles/paper.min.css +1 -0
  37. package/dist/styles/sketchy.css +25 -0
  38. package/dist/styles/sketchy.min.css +1 -0
  39. package/dist/styles/slate.css +16 -0
  40. package/dist/styles/slate.min.css +1 -0
  41. package/dist/styles/soft.css +46 -0
  42. package/dist/styles/soft.min.css +1 -0
  43. package/dist/styles.css +686 -0
  44. package/dist/styles.min.css +1 -0
  45. package/dist/themes/aurora.d.ts +10 -0
  46. package/dist/themes/aurora.d.ts.map +1 -0
  47. package/dist/themes/aurora.js +86 -0
  48. package/dist/themes/aurora.js.map +1 -0
  49. package/dist/themes/brutalist.d.ts +10 -0
  50. package/dist/themes/brutalist.d.ts.map +1 -0
  51. package/dist/themes/brutalist.js +103 -0
  52. package/dist/themes/brutalist.js.map +1 -0
  53. package/dist/themes/calm.d.ts +11 -0
  54. package/dist/themes/calm.d.ts.map +1 -0
  55. package/dist/themes/calm.js +88 -0
  56. package/dist/themes/calm.js.map +1 -0
  57. package/dist/themes/classic.d.ts +6 -0
  58. package/dist/themes/classic.d.ts.map +1 -0
  59. package/dist/themes/classic.js +23 -0
  60. package/dist/themes/classic.js.map +1 -0
  61. package/dist/themes/clay.d.ts +8 -0
  62. package/dist/themes/clay.d.ts.map +1 -0
  63. package/dist/themes/clay.js +80 -0
  64. package/dist/themes/clay.js.map +1 -0
  65. package/dist/themes/darkGlass.d.ts +7 -0
  66. package/dist/themes/darkGlass.d.ts.map +1 -0
  67. package/dist/themes/darkGlass.js +77 -0
  68. package/dist/themes/darkGlass.js.map +1 -0
  69. package/dist/themes/index.d.ts +15 -0
  70. package/dist/themes/index.d.ts.map +1 -0
  71. package/dist/themes/index.js +15 -0
  72. package/dist/themes/index.js.map +1 -0
  73. package/dist/themes/liquidGlass.d.ts +19 -0
  74. package/dist/themes/liquidGlass.d.ts.map +1 -0
  75. package/dist/themes/liquidGlass.js +111 -0
  76. package/dist/themes/liquidGlass.js.map +1 -0
  77. package/dist/themes/lux.d.ts +8 -0
  78. package/dist/themes/lux.d.ts.map +1 -0
  79. package/dist/themes/lux.js +91 -0
  80. package/dist/themes/lux.js.map +1 -0
  81. package/dist/themes/morph.d.ts +10 -0
  82. package/dist/themes/morph.d.ts.map +1 -0
  83. package/dist/themes/morph.js +82 -0
  84. package/dist/themes/morph.js.map +1 -0
  85. package/dist/themes/neon.d.ts +7 -0
  86. package/dist/themes/neon.d.ts.map +1 -0
  87. package/dist/themes/neon.js +96 -0
  88. package/dist/themes/neon.js.map +1 -0
  89. package/dist/themes/paper.d.ts +7 -0
  90. package/dist/themes/paper.d.ts.map +1 -0
  91. package/dist/themes/paper.js +88 -0
  92. package/dist/themes/paper.js.map +1 -0
  93. package/dist/themes/sketchy.d.ts +11 -0
  94. package/dist/themes/sketchy.d.ts.map +1 -0
  95. package/dist/themes/sketchy.js +88 -0
  96. package/dist/themes/sketchy.js.map +1 -0
  97. package/dist/themes/slate.d.ts +7 -0
  98. package/dist/themes/slate.d.ts.map +1 -0
  99. package/dist/themes/slate.js +89 -0
  100. package/dist/themes/slate.js.map +1 -0
  101. package/dist/themes/soft.d.ts +7 -0
  102. package/dist/themes/soft.d.ts.map +1 -0
  103. package/dist/themes/soft.js +84 -0
  104. package/dist/themes/soft.js.map +1 -0
  105. package/dist/types.d.ts +40 -0
  106. package/dist/types.d.ts.map +1 -0
  107. package/dist/types.js +2 -0
  108. package/dist/types.js.map +1 -0
  109. package/dist/util/defaults.d.ts +62 -0
  110. package/dist/util/defaults.d.ts.map +1 -0
  111. package/dist/util/defaults.js +100 -0
  112. package/dist/util/defaults.js.map +1 -0
  113. package/dist/util/defineTheme.d.ts +21 -0
  114. package/dist/util/defineTheme.d.ts.map +1 -0
  115. package/dist/util/defineTheme.js +25 -0
  116. package/dist/util/defineTheme.js.map +1 -0
  117. package/dist/util/merge.d.ts +8 -0
  118. package/dist/util/merge.d.ts.map +1 -0
  119. package/dist/util/merge.js +17 -0
  120. package/dist/util/merge.js.map +1 -0
  121. package/package.json +75 -0
  122. package/src/index.ts +35 -0
  123. package/src/plugin.ts +116 -0
  124. package/src/registry.ts +64 -0
  125. package/src/styles/core.css +311 -0
  126. package/src/styles/index.css +30 -0
  127. package/src/styles/themes/aurora.css +86 -0
  128. package/src/styles/themes/brutalist.css +59 -0
  129. package/src/styles/themes/calm.css +31 -0
  130. package/src/styles/themes/clay.css +60 -0
  131. package/src/styles/themes/darkGlass.css +69 -0
  132. package/src/styles/themes/liquidGlass.css +172 -0
  133. package/src/styles/themes/lux.css +31 -0
  134. package/src/styles/themes/morph.css +53 -0
  135. package/src/styles/themes/neon.css +56 -0
  136. package/src/styles/themes/paper.css +32 -0
  137. package/src/styles/themes/sketchy.css +34 -0
  138. package/src/styles/themes/slate.css +26 -0
  139. package/src/styles/themes/soft.css +63 -0
  140. package/src/themes/aurora.ts +86 -0
  141. package/src/themes/brutalist.ts +103 -0
  142. package/src/themes/calm.ts +88 -0
  143. package/src/themes/classic.ts +23 -0
  144. package/src/themes/clay.ts +80 -0
  145. package/src/themes/darkGlass.ts +77 -0
  146. package/src/themes/index.ts +14 -0
  147. package/src/themes/liquidGlass.ts +111 -0
  148. package/src/themes/lux.ts +91 -0
  149. package/src/themes/morph.ts +82 -0
  150. package/src/themes/neon.ts +96 -0
  151. package/src/themes/paper.ts +88 -0
  152. package/src/themes/sketchy.ts +88 -0
  153. package/src/themes/slate.ts +89 -0
  154. package/src/themes/soft.ts +84 -0
  155. package/src/types.ts +44 -0
  156. package/src/util/defaults.ts +164 -0
  157. package/src/util/defineTheme.ts +49 -0
  158. package/src/util/merge.ts +23 -0
@@ -0,0 +1,164 @@
1
+ import type { VuetiwatchDefaults } from '../types.js'
2
+ import { mergeDeep } from './merge.js'
3
+
4
+ type Props = Record<string, unknown>
5
+
6
+ /** Every component that renders a `v-field` and shares its `variant` prop. */
7
+ const FIELD_COMPONENTS = [
8
+ 'VTextField',
9
+ 'VTextarea',
10
+ 'VSelect',
11
+ 'VAutocomplete',
12
+ 'VCombobox',
13
+ 'VFileInput',
14
+ ] as const
15
+
16
+ /** The subset of those that opens a menu, and so draws a dropdown glyph. */
17
+ const MENU_COMPONENTS = [
18
+ 'VSelect',
19
+ 'VAutocomplete',
20
+ 'VCombobox',
21
+ ] as const
22
+
23
+ /** Selection controls that share the `density` prop. */
24
+ const CONTROL_COMPONENTS = [
25
+ 'VCheckbox',
26
+ 'VRadioGroup',
27
+ 'VSwitch',
28
+ ] as const
29
+
30
+ /** Containers that share the `flat` / `border` props. */
31
+ const BAR_COMPONENTS = [
32
+ 'VAppBar',
33
+ 'VToolbar',
34
+ ] as const
35
+
36
+ /** Surfaces that share the `variant` prop with cards. */
37
+ const SURFACE_COMPONENTS = [
38
+ 'VCard',
39
+ 'VAlert',
40
+ 'VChip',
41
+ ] as const
42
+
43
+ const spread = (names: readonly string[], props: Props): VuetiwatchDefaults =>
44
+ Object.fromEntries(names.map(name => [name, props]))
45
+
46
+ /**
47
+ * Applies the same props to every field-based input, so a theme states its
48
+ * input style once instead of six times.
49
+ */
50
+ export const fields = (props: Props): VuetiwatchDefaults =>
51
+ spread(FIELD_COMPONENTS, props)
52
+
53
+ /** Applies the same props to checkboxes, radio groups and switches. */
54
+ export const controls = (props: Props): VuetiwatchDefaults =>
55
+ spread(CONTROL_COMPONENTS, props)
56
+
57
+ /** Applies the same props to app bars and toolbars. */
58
+ export const bars = (props: Props): VuetiwatchDefaults =>
59
+ spread(BAR_COMPONENTS, props)
60
+
61
+ /** Applies the same props to cards, alerts and chips. */
62
+ export const surfaces = (props: Props): VuetiwatchDefaults =>
63
+ spread(SURFACE_COMPONENTS, props)
64
+
65
+ /** Applies the same `density` to lists and both table components. */
66
+ export const tables = (density: 'default' | 'comfortable' | 'compact'): VuetiwatchDefaults => ({
67
+ VList: { density },
68
+ VTable: { density },
69
+ VDataTable: { density },
70
+ })
71
+
72
+ /**
73
+ * Layers default sets over each other so helpers compose without a later
74
+ * component key wiping an earlier one — `{ VSwitch: { density } }` followed
75
+ * by `{ VSwitch: { inset } }` keeps both.
76
+ */
77
+ export const combine = (...parts: VuetiwatchDefaults[]): VuetiwatchDefaults =>
78
+ parts.reduce<VuetiwatchDefaults>((acc, part) => mergeDeep(acc, part), {})
79
+
80
+ /**
81
+ * Glyphs a theme can swap.
82
+ *
83
+ * Vuetify's icon *set* (`mdi`, `fa`, a custom SVG set) is global
84
+ * configuration and is not reactive, so it cannot vary per theme. Which
85
+ * glyph a component reaches for is an ordinary prop, though, and props go
86
+ * through defaults like everything else — so a theme can pick outlines
87
+ * where it is thin, solids where it is loud, and circles where it is round.
88
+ *
89
+ * Names must exist in whatever set the app installed; a missing one renders
90
+ * as blank. Everything here is left undefined by default, so a theme states
91
+ * only what it changes.
92
+ */
93
+ export interface VuetiwatchIcons {
94
+ /** Opens a select menu, an expansion panel or a list group. */
95
+ dropdown?: string
96
+ /** Closes the same. */
97
+ collapse?: string
98
+ next?: string
99
+ prev?: string
100
+ first?: string
101
+ last?: string
102
+ checkboxOn?: string
103
+ checkboxOff?: string
104
+ radioOn?: string
105
+ radioOff?: string
106
+ ratingFull?: string
107
+ ratingEmpty?: string
108
+ /** The clear affordance inside a field. */
109
+ clear?: string
110
+ /** Dismisses a chip or an alert. */
111
+ close?: string
112
+ sortAsc?: string
113
+ sortDesc?: string
114
+ /** Separates breadcrumb items; a plain string, not an icon name. */
115
+ breadcrumbDivider?: string
116
+ }
117
+
118
+ /** Spreads one semantic icon set across every component that draws it. */
119
+ export function icons (set: VuetiwatchIcons): VuetiwatchDefaults {
120
+ const out: Record<string, Props> = {}
121
+
122
+ /**
123
+ * Merges rather than assigns, because a component can draw more than one
124
+ * of these glyphs — a select carries both `menuIcon` and `clearIcon`, and
125
+ * assigning would drop whichever came first. Props the theme left unset
126
+ * are skipped so they fall through to Vuetify's own.
127
+ */
128
+ const put = (names: readonly string[], props: Props) => {
129
+ const given = Object.entries(props).filter(([, value]) => value !== undefined)
130
+
131
+ if (!given.length) return
132
+
133
+ for (const name of names) {
134
+ out[name] = { ...out[name], ...Object.fromEntries(given) }
135
+ }
136
+ }
137
+
138
+ const paging = {
139
+ nextIcon: set.next,
140
+ prevIcon: set.prev,
141
+ firstIcon: set.first,
142
+ lastIcon: set.last,
143
+ }
144
+
145
+ put(FIELD_COMPONENTS, { clearIcon: set.clear })
146
+ put(MENU_COMPONENTS, { menuIcon: set.dropdown })
147
+ put(['VExpansionPanelTitle', 'VList'], {
148
+ expandIcon: set.dropdown,
149
+ collapseIcon: set.collapse,
150
+ })
151
+ put(['VPagination', 'VDataTable'], paging)
152
+ put(['VDataTable'], { sortAscIcon: set.sortAsc, sortDescIcon: set.sortDesc })
153
+ put(['VSlideGroup'], { nextIcon: set.next, prevIcon: set.prev })
154
+ put(['VCheckbox', 'VCheckboxBtn'], {
155
+ trueIcon: set.checkboxOn,
156
+ falseIcon: set.checkboxOff,
157
+ })
158
+ put(['VRadio'], { trueIcon: set.radioOn, falseIcon: set.radioOff })
159
+ put(['VRating'], { fullIcon: set.ratingFull, emptyIcon: set.ratingEmpty })
160
+ put(['VChip', 'VAlert'], { closeIcon: set.close })
161
+ put(['VBreadcrumbs'], { divider: set.breadcrumbDivider })
162
+
163
+ return out
164
+ }
@@ -0,0 +1,49 @@
1
+ import type { ThemeDefinition } from 'vuetify'
2
+ import type { VuetiwatchDefaults, VuetiwatchMeta, VuetiwatchTheme } from '../types.js'
3
+ import { combine } from './defaults.js'
4
+
5
+ /**
6
+ * Applied under every theme's own defaults.
7
+ *
8
+ * A slider with no `color` falls back to `surface-variant`, which reads as
9
+ * dead grey whatever the palette — so the controls whose whole job is to
10
+ * show a value are coloured here once. A theme overrides this the way it
11
+ * overrides anything else.
12
+ */
13
+ const baseDefaults: VuetiwatchDefaults = {
14
+ VSlider: { color: 'primary' },
15
+ VRangeSlider: { color: 'primary' },
16
+ }
17
+
18
+ export interface DefineThemeOptions<Name extends string = string> {
19
+ name: Name
20
+ meta: VuetiwatchMeta
21
+ /**
22
+ * Colors and CSS variables. Only what the theme actually changes: Vuetify
23
+ * merges every theme over its own `light` or `dark` before use, picking
24
+ * the one matching `dark`, so anything left out is inherited rather than
25
+ * missing.
26
+ */
27
+ theme: ThemeDefinition
28
+ /**
29
+ * Component defaults, as one object or as layers to fold together —
30
+ * `combine()` is applied for you, so helpers compose without a later
31
+ * component key wiping an earlier one.
32
+ */
33
+ defaults?: VuetiwatchDefaults | VuetiwatchDefaults[]
34
+ }
35
+
36
+ export function defineTheme<const Name extends string> (
37
+ options: DefineThemeOptions<Name>,
38
+ ): VuetiwatchTheme<Name> {
39
+ const layers = options.defaults
40
+ ? [options.defaults].flat()
41
+ : []
42
+
43
+ return {
44
+ name: options.name,
45
+ meta: options.meta,
46
+ theme: options.theme,
47
+ defaults: combine(baseDefaults, ...layers),
48
+ }
49
+ }
@@ -0,0 +1,23 @@
1
+ type Plain = Record<string, any>
2
+
3
+ const isPlainObject = (value: unknown): value is Plain =>
4
+ value !== null && typeof value === 'object' && !Array.isArray(value)
5
+
6
+ /**
7
+ * Recursively merges `source` onto `target` without mutating either.
8
+ * Arrays and primitives from `source` replace the target value outright.
9
+ */
10
+ export function mergeDeep<T extends Plain> (target: T, source?: Plain): T {
11
+ if (!source) return { ...target }
12
+
13
+ const out: Plain = { ...target }
14
+
15
+ for (const key of Object.keys(source)) {
16
+ const a = out[key]
17
+ const b = source[key]
18
+
19
+ out[key] = isPlainObject(a) && isPlainObject(b) ? mergeDeep(a, b) : b
20
+ }
21
+
22
+ return out as T
23
+ }