vuetiwatch 0.2.0 → 0.2.2

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 (127) hide show
  1. package/README.md +25 -202
  2. package/dist/index.d.ts +2 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/plugin.d.ts.map +1 -1
  7. package/dist/plugin.js +19 -3
  8. package/dist/plugin.js.map +1 -1
  9. package/dist/styles/aurora.css +1 -1
  10. package/dist/styles/aurora.min.css +1 -1
  11. package/dist/styles/brutalist.css +1 -1
  12. package/dist/styles/brutalist.min.css +1 -1
  13. package/dist/styles/calm.css +1 -1
  14. package/dist/styles/calm.min.css +1 -1
  15. package/dist/styles/candy.css +1 -4
  16. package/dist/styles/candy.min.css +1 -1
  17. package/dist/styles/clay.css +1 -1
  18. package/dist/styles/clay.min.css +1 -1
  19. package/dist/styles/core.css +44 -2
  20. package/dist/styles/core.min.css +1 -1
  21. package/dist/styles/darkGlass.css +1 -1
  22. package/dist/styles/darkGlass.min.css +1 -1
  23. package/dist/styles/liquidGlass.css +10 -1
  24. package/dist/styles/liquidGlass.min.css +1 -1
  25. package/dist/styles/lux.css +1 -1
  26. package/dist/styles/lux.min.css +1 -1
  27. package/dist/styles/neon.css +1 -1
  28. package/dist/styles/neon.min.css +1 -1
  29. package/dist/styles/slate.css +1 -1
  30. package/dist/styles/slate.min.css +1 -1
  31. package/dist/styles/soft.css +3 -2
  32. package/dist/styles/soft.min.css +1 -1
  33. package/dist/styles.css +66 -17
  34. package/dist/styles.min.css +1 -1
  35. package/dist/themes/atlas.d.ts +35 -0
  36. package/dist/themes/atlas.d.ts.map +1 -1
  37. package/dist/themes/atlas.js +75 -1
  38. package/dist/themes/atlas.js.map +1 -1
  39. package/dist/themes/atlasDark.d.ts.map +1 -1
  40. package/dist/themes/atlasDark.js +5 -0
  41. package/dist/themes/atlasDark.js.map +1 -1
  42. package/dist/themes/atlasSepia.d.ts.map +1 -1
  43. package/dist/themes/atlasSepia.js +5 -0
  44. package/dist/themes/atlasSepia.js.map +1 -1
  45. package/dist/themes/aurora.d.ts.map +1 -1
  46. package/dist/themes/aurora.js +20 -1
  47. package/dist/themes/aurora.js.map +1 -1
  48. package/dist/themes/brutalist.d.ts.map +1 -1
  49. package/dist/themes/brutalist.js +63 -5
  50. package/dist/themes/brutalist.js.map +1 -1
  51. package/dist/themes/calm.d.ts.map +1 -1
  52. package/dist/themes/calm.js +22 -1
  53. package/dist/themes/calm.js.map +1 -1
  54. package/dist/themes/candy.d.ts.map +1 -1
  55. package/dist/themes/candy.js +23 -1
  56. package/dist/themes/candy.js.map +1 -1
  57. package/dist/themes/clay.d.ts.map +1 -1
  58. package/dist/themes/clay.js +14 -1
  59. package/dist/themes/clay.js.map +1 -1
  60. package/dist/themes/darkGlass.d.ts.map +1 -1
  61. package/dist/themes/darkGlass.js +13 -1
  62. package/dist/themes/darkGlass.js.map +1 -1
  63. package/dist/themes/graphite.d.ts.map +1 -1
  64. package/dist/themes/graphite.js +42 -7
  65. package/dist/themes/graphite.js.map +1 -1
  66. package/dist/themes/liquidGlass.d.ts.map +1 -1
  67. package/dist/themes/liquidGlass.js +41 -5
  68. package/dist/themes/liquidGlass.js.map +1 -1
  69. package/dist/themes/lux.d.ts.map +1 -1
  70. package/dist/themes/lux.js +48 -6
  71. package/dist/themes/lux.js.map +1 -1
  72. package/dist/themes/morph.d.ts.map +1 -1
  73. package/dist/themes/morph.js +21 -1
  74. package/dist/themes/morph.js.map +1 -1
  75. package/dist/themes/neon.d.ts.map +1 -1
  76. package/dist/themes/neon.js +35 -1
  77. package/dist/themes/neon.js.map +1 -1
  78. package/dist/themes/paper.d.ts.map +1 -1
  79. package/dist/themes/paper.js +38 -1
  80. package/dist/themes/paper.js.map +1 -1
  81. package/dist/themes/sketchy.d.ts.map +1 -1
  82. package/dist/themes/sketchy.js +27 -1
  83. package/dist/themes/sketchy.js.map +1 -1
  84. package/dist/themes/slate.d.ts.map +1 -1
  85. package/dist/themes/slate.js +42 -6
  86. package/dist/themes/slate.js.map +1 -1
  87. package/dist/themes/soft.d.ts.map +1 -1
  88. package/dist/themes/soft.js +49 -8
  89. package/dist/themes/soft.js.map +1 -1
  90. package/dist/util/defaults.d.ts +35 -0
  91. package/dist/util/defaults.d.ts.map +1 -1
  92. package/dist/util/defaults.js +51 -0
  93. package/dist/util/defaults.js.map +1 -1
  94. package/package.json +2 -1
  95. package/src/index.ts +2 -2
  96. package/src/plugin.ts +20 -3
  97. package/src/styles/core.css +152 -3
  98. package/src/styles/themes/aurora.css +1 -0
  99. package/src/styles/themes/brutalist.css +1 -0
  100. package/src/styles/themes/calm.css +1 -0
  101. package/src/styles/themes/candy.css +9 -4
  102. package/src/styles/themes/clay.css +1 -0
  103. package/src/styles/themes/darkGlass.css +1 -0
  104. package/src/styles/themes/liquidGlass.css +41 -0
  105. package/src/styles/themes/lux.css +1 -0
  106. package/src/styles/themes/neon.css +1 -0
  107. package/src/styles/themes/slate.css +1 -0
  108. package/src/styles/themes/soft.css +10 -0
  109. package/src/themes/atlas.ts +76 -1
  110. package/src/themes/atlasDark.ts +5 -0
  111. package/src/themes/atlasSepia.ts +5 -0
  112. package/src/themes/aurora.ts +21 -1
  113. package/src/themes/brutalist.ts +65 -5
  114. package/src/themes/calm.ts +23 -1
  115. package/src/themes/candy.ts +24 -1
  116. package/src/themes/clay.ts +15 -1
  117. package/src/themes/darkGlass.ts +14 -1
  118. package/src/themes/graphite.ts +44 -7
  119. package/src/themes/liquidGlass.ts +42 -5
  120. package/src/themes/lux.ts +50 -6
  121. package/src/themes/morph.ts +22 -1
  122. package/src/themes/neon.ts +37 -1
  123. package/src/themes/paper.ts +40 -1
  124. package/src/themes/sketchy.ts +29 -1
  125. package/src/themes/slate.ts +43 -6
  126. package/src/themes/soft.ts +50 -8
  127. package/src/util/defaults.ts +84 -0
@@ -1,4 +1,4 @@
1
- import { bars, controls, fields, icons, tables } from '../util/defaults.js'
1
+ import { bars, controls, fields, icons, overlays, ripple, tables } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -32,13 +32,24 @@ export const slate = defineTheme({
32
32
  error: '#C53030',
33
33
  info: '#2B6CB0',
34
34
  success: '#2F855A',
35
- warning: '#B7791F',
35
+ /**
36
+ * Deepened rather than re-inked. Vuetify picks the label colour by
37
+ * APCA and settles for about 3:1 on WCAG, which is the bar for large
38
+ * text rather than for a button label — so this theme states `on-*`
39
+ * wherever the automatic pick falls short.
40
+ *
41
+ * Warning is the case where doing that made things worse. The ochre
42
+ * sat where WCAG wanted black and APCA wanted white by a wide margin
43
+ * (71 to 39), and the forced dark label did not even clear 4.5:1
44
+ * (4.48:1). Taking 12 per cent of lightness out of the hue satisfies both:
45
+ * white now reads 4.53:1 on the filled button, APCA 79, and the colour
46
+ * as text on the surface goes from 3.64:1 — under the bar it was
47
+ * being held to elsewhere — to 4.53:1. The label is left to the
48
+ * automatic pick, which is white.
49
+ */
50
+ warning: '#A16B1B',
36
51
  'on-surface': '#1A202C',
37
52
  'on-background': '#1A202C',
38
- // Vuetify picks the label colour by luminance and settles for
39
- // about 3:1, which is the bar for large text rather than for a
40
- // button label. Measured on the filled buttons: warning 3.6:1 → 4.5:1.
41
- 'on-warning': '#1A202C',
42
53
  },
43
54
  variables: {
44
55
  /* A panel standing on its own — a bare list, sheet, banner or table.
@@ -72,6 +83,20 @@ export const slate = defineTheme({
72
83
  'vw-pop-duration': '160ms',
73
84
  'vw-focus-ring': '2px solid rgb(var(--v-theme-primary))',
74
85
 
86
+ // The dashboard's own tempo, applied to the panels that float over it.
87
+ 'vw-overlay-duration': '120ms',
88
+ 'vw-overlay-exit': '90ms',
89
+ // The focus ring above carries the keyboard; the wash only has to not
90
+ // fight it. The active row, though, has to be findable in a table of
91
+ // a hundred.
92
+ 'focus-opacity': 0.12,
93
+ 'activated-opacity': 0.12,
94
+ 'disabled-opacity': 0.42,
95
+ 'theme-code': '#EAEEF3',
96
+ 'theme-on-code': '#1A202C',
97
+ 'theme-kbd': '#EAEEF3',
98
+ 'theme-on-kbd': '#1A202C',
99
+
75
100
  // Dense and structural: a 2px rule and a square dot.
76
101
  'vw-timeline-line': 'rgba(var(--v-theme-primary), 0.35)',
77
102
  'vw-timeline-line-width': '2px',
@@ -109,5 +134,17 @@ export const slate = defineTheme({
109
134
  sortAsc: 'mdi-menu-up',
110
135
  sortDesc: 'mdi-menu-down',
111
136
  }),
137
+ /**
138
+ * A dropdown drops. Everything else fades: a dialog over a dashboard is
139
+ * a change of subject, not an entrance, and the data behind it should
140
+ * not be dragged around while it arrives.
141
+ */
142
+ overlays({
143
+ dialog: 'fade-transition',
144
+ menu: 'slide-y-transition',
145
+ tooltip: 'fade-transition',
146
+ }),
147
+ // Dense rows and a spreading ink blot do not go together.
148
+ ripple(false),
112
149
  ],
113
150
  })
@@ -1,4 +1,4 @@
1
- import { bars, fields, icons } from '../util/defaults.js'
1
+ import { bars, fields, icons, overlays } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -35,13 +35,35 @@ export const soft = defineTheme({
35
35
  warning: '#F5B851',
36
36
  'on-surface': '#2E2A3B',
37
37
  'on-background': '#2E2A3B',
38
- // Vuetify's automatic pick lands on white here, which is worse by
39
- // both models this reads w6.0/a56 against w2.3/a50.
40
- 'on-secondary': '#2E2A3B',
41
- // Vuetify picks the label colour by luminance and settles for
42
- // about 3:1, which is the bar for large text rather than for a
43
- // button label. Measured on the filled buttons: error 2.8:1 4.9:1.
44
- 'on-error': '#2E2A3B',
38
+ /**
39
+ * The one stated exception in the package, and it is deliberate.
40
+ *
41
+ * White on these pastels does not clear WCAG's 4.5:1 for a button
42
+ * label: secondary 2.33:1, error 2.84:1, info 2.25:1, success 2.21:1,
43
+ * warning 1.77:1. The dark ink that white replaced carried 4.89:1 to
44
+ * 11.86:1, and APCA agrees with WCAG on every one of them — so this
45
+ * is not a case of the two models disagreeing and a hue needing a few
46
+ * points of lightness, which is how every other theme here resolves
47
+ * it. The only arrangement that gets white over the bar takes these
48
+ * hues down 23 to 39 per cent, and a pastel darkened by a third is
49
+ * not a pastel: it would be a different theme wearing this one's name.
50
+ *
51
+ * So the trade is made the other way round, once, in the theme whose
52
+ * whole proposition is softness — and it is a trade, not an oversight.
53
+ * A screen that has to be read by everyone should reach for a theme
54
+ * that measures; `atlas` and `graphite` exist for that, and `soft` is
55
+ * for the onboarding flow and the marketing page where the palette is
56
+ * the point. `docs/contrast.md` says as much next to the claim it
57
+ * qualifies.
58
+ *
59
+ * `primary` is not listed because it needs no help: at #705EEF white
60
+ * already reads 4.63:1 and is the automatic pick.
61
+ */
62
+ 'on-secondary': '#FFFFFF',
63
+ 'on-error': '#FFFFFF',
64
+ 'on-info': '#FFFFFF',
65
+ 'on-success': '#FFFFFF',
66
+ 'on-warning': '#FFFFFF',
45
67
  },
46
68
  variables: {
47
69
  /* A panel standing on its own — a bare list, sheet, banner or table.
@@ -69,6 +91,16 @@ export const soft = defineTheme({
69
91
  'vw-pop-scale': '1.22',
70
92
  'vw-pop-duration': '260ms',
71
93
 
94
+ // Unhurried here as well, with the exit a touch quicker so a
95
+ // dismissed panel does not linger.
96
+ 'vw-overlay-duration': '250ms',
97
+ 'vw-overlay-exit': '180ms',
98
+ // Tonal fills are this theme's colour, so they are drawn to be seen.
99
+ 'focus-opacity': 0.14,
100
+ 'activated-opacity': 0.14,
101
+ // Bigger initials inside the circle, to match everything else here.
102
+ 'vw-avatar-ratio': '0.44',
103
+
72
104
  // Thick and pastel, matching the radii.
73
105
  'vw-timeline-line': 'rgba(var(--v-theme-primary), 0.25)',
74
106
  'vw-timeline-line-width': '5px',
@@ -102,5 +134,15 @@ export const soft = defineTheme({
102
134
  ratingEmpty: 'mdi-heart-outline',
103
135
  close: 'mdi-close-circle',
104
136
  }),
137
+ /**
138
+ * Friendly rather than efficient: a dialog swells into place, a menu
139
+ * drops from the control that opened it. The ripple stays — this is one
140
+ * of the themes with a surface soft enough to justify it.
141
+ */
142
+ overlays({
143
+ dialog: 'scale-transition',
144
+ menu: 'slide-y-transition',
145
+ tooltip: 'scale-transition',
146
+ }),
105
147
  ],
106
148
  })
@@ -38,6 +38,36 @@ const CONTROL_COMPONENTS = [
38
38
  'VSwitch',
39
39
  ] as const
40
40
 
41
+ /**
42
+ * Everything that draws a Material ripple.
43
+ *
44
+ * Longer than it looks, because a defaults key is matched by component
45
+ * name and several of these only look like a `VBtn`. The tab, the app-bar
46
+ * nav icon and the fab each declare their own prop set and hand it to a
47
+ * `VBtn` themselves, so a `VBtn` default never reaches them; the checkbox,
48
+ * the radio and the switch all reach one `VSelectionControl` underneath
49
+ * but arrive there under three different names. A theme that turned the
50
+ * ripple off on buttons alone would still get one from the hamburger and
51
+ * from every tick box on the screen.
52
+ */
53
+ const RIPPLE_COMPONENTS = [
54
+ 'VBtn',
55
+ 'VTab',
56
+ 'VAppBarNavIcon',
57
+ 'VFab',
58
+ 'VChip',
59
+ 'VCard',
60
+ 'VListItem',
61
+ 'VExpansionPanelTitle',
62
+ 'VStepperItem',
63
+ 'VRating',
64
+ 'VCheckbox',
65
+ 'VCheckboxBtn',
66
+ 'VRadio',
67
+ 'VRadioGroup',
68
+ 'VSwitch',
69
+ ] as const
70
+
41
71
  /** Containers that share the `flat` / `border` props. */
42
72
  const BAR_COMPONENTS = [
43
73
  'VAppBar',
@@ -73,6 +103,60 @@ export const bars = (props: Props): VuetiwatchDefaults =>
73
103
  export const surfaces = (props: Props): VuetiwatchDefaults =>
74
104
  spread(SURFACE_COMPONENTS, props)
75
105
 
106
+ /**
107
+ * Turns the Material ripple off — or back on — everywhere one is drawn.
108
+ *
109
+ * The ripple is an animation about the weight of a surface, so a theme
110
+ * with no weight to describe is better off without it: it delays the
111
+ * moment a control looks like it answered, which on a screen someone
112
+ * works in all day is the one thing motion must never do.
113
+ */
114
+ export const ripple = (on: boolean): VuetiwatchDefaults =>
115
+ spread(RIPPLE_COMPONENTS, { ripple: on })
116
+
117
+ /**
118
+ * How each floating surface arrives.
119
+ *
120
+ * Vuetify names its transitions and resolves them from a string, so this
121
+ * is an ordinary prop like any other — which is what lets a theme own its
122
+ * overlays as well as its colours. `false` means no animation at all: the
123
+ * surface is simply there, which is the honest answer for a theme that
124
+ * draws no depth to move through.
125
+ *
126
+ * `menu` reaches the select, the autocomplete and the combobox as well,
127
+ * but not by one route: autocomplete and combobox let the `VMenu` they
128
+ * render take the global default, while `VSelect` declares a `transition`
129
+ * prop of its own and hands it down, which shadows that default entirely.
130
+ * So the select is named here too, and a theme still states its menus once.
131
+ */
132
+ export interface VuetiwatchOverlays {
133
+ /** A modal. Vuetify's own is `dialog-transition`. */
134
+ dialog?: string | false
135
+ /** A dropdown, a select's list, a context menu. */
136
+ menu?: string | false
137
+ /** A tooltip. Vuetify scales it in and fades it out. */
138
+ tooltip?: string | false
139
+ /** A snackbar. */
140
+ snackbar?: string | false
141
+ }
142
+
143
+ export function overlays (set: VuetiwatchOverlays): VuetiwatchDefaults {
144
+ const byComponent = {
145
+ VDialog: set.dialog,
146
+ VMenu: set.menu,
147
+ // Shadows the `VMenu` default above rather than inheriting it.
148
+ VSelect: set.menu,
149
+ VTooltip: set.tooltip,
150
+ VSnackbar: set.snackbar,
151
+ }
152
+
153
+ return Object.fromEntries(
154
+ Object.entries(byComponent)
155
+ .filter(([, transition]) => transition !== undefined)
156
+ .map(([name, transition]) => [name, { transition }]),
157
+ )
158
+ }
159
+
76
160
  /** Applies the same `density` to lists and both table components. */
77
161
  export const tables = (density: 'default' | 'comfortable' | 'compact'): VuetiwatchDefaults => ({
78
162
  VList: { density },