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, fields, icons } from '../util/defaults.js'
1
+ import { bars, fields, icons, overlays, ripple } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -78,10 +78,41 @@ export const brutalist = defineTheme({
78
78
  'vw-heading-tracking': '-0.02em',
79
79
  'vw-tab-slider-height': '4px',
80
80
 
81
- // Two frames, no curve. The press is the theme's own slide into its
82
- // shadow, so the shared squash stays out of its way.
83
- 'vw-motion-duration': '80ms',
84
- 'vw-motion-ease': 'steps(2, end)',
81
+ /**
82
+ * Nothing eases and nothing tweens: a state change is the frame it
83
+ * happens in.
84
+ *
85
+ * A stepped curve was the first attempt at saying that, and it says
86
+ * the opposite. Two discrete jumps across 80ms read as a dropped
87
+ * frame rather than as a decision, and on anything that takes longer
88
+ * to arrive — a tooltip, a dialog the size of the screen — the hold
89
+ * between the steps looks like the page has hung. Zero is the only
90
+ * duration that is actually instant.
91
+ *
92
+ * `linear` is what is left for the two things here that are
93
+ * animations rather than transitions — the icon pop and the theme
94
+ * wipe — where a curve would be the theme describing a weight it
95
+ * does not have.
96
+ *
97
+ * The press is the theme's own slide into its shadow, so the shared
98
+ * squash stays out of its way.
99
+ */
100
+ 'vw-motion-duration': '0ms',
101
+ 'vw-motion-ease': 'linear',
102
+ /**
103
+ * The scrim cannot follow it, though, and this is the one place the
104
+ * theme's own rule is wrong. A panel appearing in a single frame is
105
+ * decisive; a whole screen going dark in a single frame is a flash,
106
+ * and the eye reads a flash as a fault rather than as a choice. So
107
+ * the panel keeps its zero and the dimming gets a beat of its own —
108
+ * still linear, still short enough that nothing is waited for.
109
+ *
110
+ * Left at Vuetify's own 300ms the mismatch was the other way round:
111
+ * the panel was there and the room was still darkening a third of a
112
+ * second later.
113
+ */
114
+ 'vw-overlay-duration': '0ms',
115
+ 'vw-scrim-duration': '120ms',
85
116
  'vw-press-scale': '1',
86
117
  'vw-pop-scale': '1.3',
87
118
  'vw-pop-duration': '100ms',
@@ -89,6 +120,26 @@ export const brutalist = defineTheme({
89
120
  'vw-focus-offset': '3px',
90
121
  'vw-theme-transition': '200ms',
91
122
 
123
+ // Hard states to match the hard edges: a pressed control is a
124
+ // different colour, not a slightly darker one.
125
+ 'focus-opacity': 0.2,
126
+ 'activated-opacity': 0.3,
127
+ 'disabled-opacity': 0.5,
128
+ /**
129
+ * A tab is set at body size rather than shrunk to Vuetify's label
130
+ * size — nothing in this theme whispers.
131
+ */
132
+ 'vw-tab-size': '1rem',
133
+
134
+ /**
135
+ * Lime is this theme's active colour — it already marks the table
136
+ * heads, the current page and the slider — so a selected run of text
137
+ * joins them. Solid rather than a tint: nothing here is translucent,
138
+ * and the ink on top is stated rather than left to the browser.
139
+ */
140
+ 'vw-selection-fill': 'rgb(var(--v-theme-secondary))',
141
+ 'vw-selection-color': 'rgb(var(--v-shadow-color))',
142
+
92
143
  // A structural beam, and the dot is a square like everything else.
93
144
  'vw-timeline-line': 'rgb(var(--v-shadow-color))',
94
145
  'vw-timeline-line-width': '4px',
@@ -128,5 +179,14 @@ export const brutalist = defineTheme({
128
179
  sortDesc: 'mdi-menu-down',
129
180
  close: 'mdi-close-thick',
130
181
  }),
182
+ /**
183
+ * No transition at all, which is the only honest answer here. Every
184
+ * other theme animates a surface arriving from somewhere; this one has
185
+ * no depth for it to arrive through, so the panel is simply there —
186
+ * one frame without it, the next frame with it.
187
+ */
188
+ overlays({ dialog: false, menu: false, tooltip: false }),
189
+ // A ripple is a soft, round, spreading thing.
190
+ ripple(false),
131
191
  ],
132
192
  })
@@ -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
  /**
@@ -77,6 +77,18 @@ export const calm = defineTheme({
77
77
  'vw-pop-duration': '280ms',
78
78
  'vw-theme-transition': '560ms',
79
79
 
80
+ // Slow here too, so an overlay drifts in rather than appearing.
81
+ 'vw-overlay-duration': '320ms',
82
+ 'vw-overlay-exit': '240ms',
83
+ /**
84
+ * Every state is a shade quieter than Vuetify draws it. The theme
85
+ * spends colour only on what you can act on, and a wash under
86
+ * something already selected is not one of those things.
87
+ */
88
+ 'focus-opacity': 0.1,
89
+ 'activated-opacity': 0.06,
90
+ 'disabled-opacity': 0.35,
91
+
80
92
  // Barely there, like everything else in this theme.
81
93
  'vw-timeline-line': 'rgba(var(--v-border-color), 0.5)',
82
94
  'vw-timeline-line-width': '1px',
@@ -107,5 +119,15 @@ export const calm = defineTheme({
107
119
  ratingEmpty: 'mdi-circle-outline',
108
120
  close: 'mdi-close',
109
121
  }),
122
+ // Nothing arrives from a direction, and nothing scales: the surface
123
+ // is simply there a moment later than you asked.
124
+ overlays({
125
+ dialog: 'fade-transition',
126
+ menu: 'fade-transition',
127
+ tooltip: 'fade-transition',
128
+ }),
129
+ // The discipline is subtractive, and a ripple is a fill spreading
130
+ // across the one part of the screen you are already looking at.
131
+ ripple(false),
110
132
  ],
111
133
  })
@@ -1,4 +1,4 @@
1
- import { bars, controls, fields, icons } from '../util/defaults.js'
1
+ import { bars, controls, fields, icons, overlays } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -101,6 +101,20 @@ export const candy = defineTheme({
101
101
  'vw-focus-offset': '3px',
102
102
  'vw-theme-transition': '480ms',
103
103
 
104
+ /**
105
+ * The spring above rides along through `--v-vw-motion-ease`, so an
106
+ * overlay overshoots and settles like every other shape here. The
107
+ * exit skips the spring by being too short to overshoot in.
108
+ */
109
+ 'vw-overlay-duration': '260ms',
110
+ 'vw-overlay-exit': '160ms',
111
+ // Loud, like the rest of it: a pressed sweet goes visibly darker.
112
+ 'focus-opacity': 0.2,
113
+ 'activated-opacity': 0.18,
114
+ 'disabled-opacity': 0.4,
115
+ // A big letter in a big circle.
116
+ 'vw-avatar-ratio': '0.46',
117
+
104
118
  // A fat ribbon with rounded ends — see the stylesheet.
105
119
  'vw-timeline-line': 'rgba(var(--v-theme-primary), 0.3)',
106
120
  'vw-timeline-line-width': '6px',
@@ -140,5 +154,14 @@ export const candy = defineTheme({
140
154
  prev: 'mdi-chevron-left',
141
155
  breadcrumbDivider: '•',
142
156
  }),
157
+ /**
158
+ * The dialog comes up from the bottom, the way every app a child has
159
+ * used opens a sheet, and the small surfaces pop rather than fade.
160
+ */
161
+ overlays({
162
+ dialog: 'dialog-bottom-transition',
163
+ menu: 'scale-transition',
164
+ tooltip: 'scale-transition',
165
+ }),
143
166
  ],
144
167
  })
@@ -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
  /**
@@ -75,6 +75,13 @@ export const clay = defineTheme({
75
75
  'vw-pop-scale': '1.25',
76
76
  'vw-pop-duration': '280ms',
77
77
 
78
+ // Soft mass takes a moment to arrive, as it takes one to squash.
79
+ 'vw-overlay-duration': '220ms',
80
+ 'vw-overlay-exit': '160ms',
81
+ // The shapes are bright and the fills are generous; the states match.
82
+ 'focus-opacity': 0.16,
83
+ 'activated-opacity': 0.16,
84
+
78
85
  // A channel pressed into the ground rather than a line on it.
79
86
  'vw-timeline-line': 'rgb(var(--v-theme-background))',
80
87
  'vw-timeline-line-width': '8px',
@@ -100,5 +107,12 @@ export const clay = defineTheme({
100
107
  ratingEmpty: 'mdi-star-outline',
101
108
  close: 'mdi-close-circle',
102
109
  }),
110
+ // Inflated, so it inflates: every floating shape swells into place
111
+ // rather than sliding or fading.
112
+ overlays({
113
+ dialog: 'scale-transition',
114
+ menu: 'scale-transition',
115
+ tooltip: 'scale-transition',
116
+ }),
103
117
  ],
104
118
  })
@@ -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
  /**
@@ -71,6 +71,13 @@ export const darkGlass = defineTheme({
71
71
  'vw-pop-scale': '1.18',
72
72
  'vw-pop-duration': '240ms',
73
73
 
74
+ // Glass slides, and it takes its time doing it.
75
+ 'vw-overlay-duration': '260ms',
76
+ 'vw-overlay-exit': '200ms',
77
+ // The ground is dark enough that a state has to be lit to register.
78
+ 'focus-opacity': 0.16,
79
+ 'activated-opacity': 0.14,
80
+
74
81
  // Violet through the glass.
75
82
  'vw-timeline-line': 'rgba(var(--v-theme-primary), 0.45)',
76
83
  'vw-timeline-line-width': '2px',
@@ -97,5 +104,11 @@ export const darkGlass = defineTheme({
97
104
  ratingFull: 'mdi-star',
98
105
  ratingEmpty: 'mdi-star-outline',
99
106
  }),
107
+ // Sheets slide; the tip, which is not a sheet, fades.
108
+ overlays({
109
+ dialog: 'slide-y-transition',
110
+ menu: 'slide-y-transition',
111
+ tooltip: 'fade-transition',
112
+ }),
100
113
  ],
101
114
  })
@@ -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
  /**
@@ -95,6 +95,35 @@ export const graphite = defineTheme({
95
95
  'vw-focus-ring': '1px solid rgba(var(--v-theme-primary), 0.85)',
96
96
  'vw-theme-transition': '260ms',
97
97
 
98
+ // The overlays repaint at the same 90ms as everything else; the
99
+ // linear easing above reaches them through `--v-vw-motion-ease`.
100
+ 'vw-overlay-duration': '90ms',
101
+ 'vw-overlay-exit': '70ms',
102
+ /**
103
+ * `primary` here is a near-white, so a tonal fill drawn at Vuetify's
104
+ * 0.12 is a pale grey on a near-black ground — the one place this
105
+ * palette needs more of the accent rather than less.
106
+ */
107
+ 'activated-opacity': 0.14,
108
+ 'focus-opacity': 0.18,
109
+ 'disabled-opacity': 0.4,
110
+ /**
111
+ * The theme ships a mono stack for exactly this, and a developer tool
112
+ * shows more code than prose. Both take the raised surface rather
113
+ * than Vuetify's stock grey.
114
+ */
115
+ 'theme-code': '#16191D',
116
+ 'theme-on-code': '#E6E9ED',
117
+ 'theme-kbd': '#1B1E23',
118
+ 'theme-on-kbd': '#E6E9ED',
119
+
120
+ /**
121
+ * `primary` is a near-white here, and a wash of it over near-black
122
+ * text is a grey haze. The indigo held in `secondary` is what every
123
+ * editor this theme is modelled on selects with.
124
+ */
125
+ 'vw-selection-fill': 'rgba(var(--v-theme-secondary), 0.4)',
126
+
98
127
  // Hairline and squared off, like every other edge here.
99
128
  'vw-timeline-line': 'rgba(var(--v-border-color), 0.35)',
100
129
  'vw-timeline-line-width': '1px',
@@ -104,17 +133,15 @@ export const graphite = defineTheme({
104
133
  },
105
134
  defaults: [
106
135
  {
107
- // No ripple anywhere: it is a Material animation about the weight of
108
- // a surface, and nothing in this theme has any.
109
136
  // No `density` here on purpose: Vuetify subtracts it from the size
110
137
  // height, and a compact `x-small` button ends up shorter than its
111
138
  // own label. The tight geometry comes from the radius instead.
112
- VBtn: { variant: 'flat', ripple: false },
139
+ // The ripple is off through `ripple(false)` below, which reaches the
140
+ // tick boxes this list used to miss.
141
+ VBtn: { variant: 'flat' },
113
142
  VCard: { variant: 'outlined' },
114
143
  VAlert: { variant: 'outlined', density: 'compact' },
115
- VChip: { variant: 'outlined', size: 'small', ripple: false },
116
- VListItem: { ripple: false },
117
- VTab: { ripple: false },
144
+ VChip: { variant: 'outlined', size: 'small' },
118
145
  // Flush stacked rows rather than floating panels with gaps.
119
146
  VExpansionPanels: { variant: 'accordion' },
120
147
  VNavigationDrawer: { border: 'e' },
@@ -146,5 +173,15 @@ export const graphite = defineTheme({
146
173
  close: 'mdi-close',
147
174
  breadcrumbDivider: '/',
148
175
  }),
176
+ /**
177
+ * Nothing here has weight, so nothing arrives from anywhere: a panel is
178
+ * repainted rather than opened. Linear, at the same 90ms as the rest.
179
+ */
180
+ overlays({
181
+ dialog: 'fade-transition',
182
+ menu: 'fade-transition',
183
+ tooltip: 'fade-transition',
184
+ }),
185
+ ripple(false),
149
186
  ],
150
187
  })
@@ -1,4 +1,4 @@
1
- import { bars, controls, fields, icons, tables } from '../util/defaults.js'
1
+ import { bars, controls, fields, icons, overlays, tables } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -48,10 +48,20 @@ export const liquidGlass = defineTheme({
48
48
  warning: '#FF9500',
49
49
  'on-surface': '#1C1C1E',
50
50
  'on-background': '#1C1C1E',
51
- // Vuetify picks the label colour by luminance and settles for
52
- // about 3:1, which is the bar for large text rather than for a
53
- // button label. Measured on the filled buttons: info 4:1 5.2:1, error 3.5:1 → 4.8:1.
54
- 'on-info': '#000000',
51
+ /**
52
+ * Vuetify picks the label colour by luminance and settles for about
53
+ * 3:1, which is the bar for large text rather than for a button
54
+ * label. Measured on the filled buttons: error 3.5:1 → 4.8:1.
55
+ *
56
+ * `info` is deliberately not in this list. It is the same `#0071ED`
57
+ * as `primary`, and forcing a label on one of them and not the other
58
+ * put two different inks on one colour in one theme. It is also the
59
+ * one hue here that sits almost exactly on the crossover: black and
60
+ * white both measure 4.58:1, so nothing is bought by stating either,
61
+ * while APCA separates them 79 to 33 in white's favour. Vuetify's own
62
+ * pick is white, which is what the platform this theme follows puts
63
+ * on system blue, so the theme says nothing and lets it.
64
+ */
55
65
  'on-error': '#1C1C1E',
56
66
  'on-success': '#06140A',
57
67
  'on-warning': '#1A1004',
@@ -100,6 +110,23 @@ export const liquidGlass = defineTheme({
100
110
  'vw-pop-duration': '300ms',
101
111
  'vw-theme-transition': '520ms',
102
112
 
113
+ /**
114
+ * The iOS curve above carries overlays too, through
115
+ * `--v-vw-motion-ease`: fast out of the gate, then a long settle.
116
+ */
117
+ 'vw-overlay-duration': '320ms',
118
+ 'vw-overlay-exit': '220ms',
119
+ /**
120
+ * The scrim, and with it the pane's own fade — the stylesheet reads
121
+ * this same number for the opacity leg of the entrance. Short, so the
122
+ * frost is alight while the pane is still arriving; see the note over
123
+ * the rule for why the two have to agree.
124
+ */
125
+ 'vw-scrim-duration': '120ms',
126
+ // Through glass a state is a change of light, not a block of colour.
127
+ 'focus-opacity': 0.12,
128
+ 'activated-opacity': 0.12,
129
+
103
130
  // Frosted, so the line is a highlight rather than a rule.
104
131
  'vw-timeline-line': 'rgba(var(--v-theme-on-surface), 0.18)',
105
132
  'vw-timeline-line-width': '2px',
@@ -134,5 +161,15 @@ export const liquidGlass = defineTheme({
134
161
  sortAsc: 'mdi-chevron-up',
135
162
  sortDesc: 'mdi-chevron-down',
136
163
  }),
164
+ /**
165
+ * A sheet of glass scales up from the control that summoned it, which
166
+ * is what the platform this theme follows does. The tooltip fades:
167
+ * it is one word, and a word that grows is a word you re-read.
168
+ */
169
+ overlays({
170
+ dialog: 'scale-transition',
171
+ menu: 'scale-transition',
172
+ tooltip: 'fade-transition',
173
+ }),
137
174
  ],
138
175
  })
package/src/themes/lux.ts CHANGED
@@ -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
  /**
@@ -33,13 +33,24 @@ export const lux = defineTheme({
33
33
  error: '#96322A',
34
34
  info: '#3D5A73',
35
35
  success: '#4A6B4F',
36
- warning: '#A8791E',
36
+ /**
37
+ * Deepened rather than re-inked. Vuetify picks the label colour by
38
+ * APCA and settles for about 3:1 on WCAG, which is the bar for large
39
+ * text rather than for a button label — so this theme states `on-*`
40
+ * wherever the automatic pick falls short.
41
+ *
42
+ * Warning is the case where doing that made things worse. The ochre
43
+ * sat where WCAG wanted black and APCA wanted white by a wide margin
44
+ * (73 to 37), and the forced dark label did not even clear 4.5:1
45
+ * (4.49:1). Taking 9 per cent of lightness out of the hue satisfies both:
46
+ * white now reads 4.56:1 on the filled button, APCA 79, and the colour
47
+ * as text on the surface goes from 3.88:1 — under the bar it was
48
+ * being held to elsewhere — to 4.56:1. The label is left to the
49
+ * automatic pick, which is white.
50
+ */
51
+ warning: '#996E1B',
37
52
  'on-surface': '#1A1A1A',
38
53
  'on-background': '#1A1A1A',
39
- // Vuetify picks the label colour by luminance and settles for
40
- // about 3:1, which is the bar for large text rather than for a
41
- // button label. Measured on the filled buttons: warning 3.9:1 → 4.5:1.
42
- 'on-warning': '#1A1A1A',
43
54
  },
44
55
  variables: {
45
56
  /* A panel standing on its own — a bare list, sheet, banner or table.
@@ -77,6 +88,31 @@ export const lux = defineTheme({
77
88
  'vw-focus-ring': '1px solid rgb(var(--v-theme-primary))',
78
89
  'vw-theme-transition': '520ms',
79
90
 
91
+ // The same unhurried curve the rest of the theme moves on.
92
+ 'vw-overlay-duration': '240ms',
93
+ 'vw-overlay-exit': '180ms',
94
+ // Restraint applies to states too: an outline and a hairline of
95
+ // wash, never a block of colour.
96
+ 'focus-opacity': 0.12,
97
+ 'activated-opacity': 0.08,
98
+ 'disabled-opacity': 0.35,
99
+ /**
100
+ * A tab is a label in this theme, set at the same size as the caps on
101
+ * the buttons rather than at Vuetify's body-sized default — the wide
102
+ * tracking below needs the smaller size to stay a line and not a
103
+ * heading.
104
+ */
105
+ 'vw-tab-size': '0.75rem',
106
+ /**
107
+ * Initials set small inside a generous circle: the air around a mark
108
+ * is the whole point of the register this theme is written in.
109
+ */
110
+ 'vw-avatar-ratio': '0.34',
111
+
112
+ // Ink again in `primary`, so the highlight is the theme's gold —
113
+ // the one flourish it allows itself, spent where a reader drags.
114
+ 'vw-selection-fill': 'rgba(var(--v-theme-secondary), 0.25)',
115
+
80
116
  // A gold hairline; the dot stays a circle.
81
117
  'vw-timeline-line': 'rgba(var(--v-theme-primary), 0.55)',
82
118
  'vw-timeline-line-width': '1px',
@@ -109,5 +145,13 @@ export const lux = defineTheme({
109
145
  // An em dash rather than a slash — the one flourish the theme allows.
110
146
  breadcrumbDivider: '—',
111
147
  }),
148
+ // Expensive things do not bounce. They fade, slowly, and stop.
149
+ overlays({
150
+ dialog: 'fade-transition',
151
+ menu: 'fade-transition',
152
+ tooltip: 'fade-transition',
153
+ }),
154
+ // Material's ink blot is the loudest thing this theme could do.
155
+ ripple(false),
112
156
  ],
113
157
  })
@@ -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
  /**
@@ -75,6 +75,17 @@ export const morph = defineTheme({
75
75
  'vw-pop-scale': '1.15',
76
76
  'vw-pop-duration': '220ms',
77
77
 
78
+ // Quiet, like the relief itself.
79
+ 'vw-overlay-duration': '180ms',
80
+ 'vw-overlay-exit': '140ms',
81
+ /**
82
+ * The relief carries the whole theme, and a wash of colour on top of
83
+ * it flattens the light it is built from — so the states stay under
84
+ * what Vuetify draws.
85
+ */
86
+ 'focus-opacity': 0.12,
87
+ 'activated-opacity': 0.1,
88
+
78
89
  // The same groove the fields are, turned on its side.
79
90
  'vw-timeline-line': 'rgb(var(--v-theme-background))',
80
91
  'vw-timeline-line-width': '8px',
@@ -100,5 +111,15 @@ export const morph = defineTheme({
100
111
  ratingFull: 'mdi-circle',
101
112
  ratingEmpty: 'mdi-circle-outline',
102
113
  }),
114
+ /**
115
+ * A dialog is pressed out of the ground like everything else, so it
116
+ * grows into place. Menus and tips fade instead: they are small enough
117
+ * that scaling them reads as a twitch rather than as relief.
118
+ */
119
+ overlays({
120
+ dialog: 'scale-transition',
121
+ menu: 'fade-transition',
122
+ tooltip: 'fade-transition',
123
+ }),
103
124
  ],
104
125
  })
@@ -1,4 +1,4 @@
1
- import { bars, fields, icons, surfaces, tables } from '../util/defaults.js'
1
+ import { bars, fields, icons, overlays, ripple, surfaces, tables } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -82,6 +82,33 @@ export const neon = defineTheme({
82
82
  'vw-focus-ring': '2px solid rgb(var(--v-theme-secondary))',
83
83
  'vw-theme-transition': '180ms',
84
84
 
85
+ // A terminal repaints; the linear easing above comes along through
86
+ // `--v-vw-motion-ease`, so nothing here accelerates.
87
+ 'vw-overlay-duration': '110ms',
88
+ 'vw-overlay-exit': '80ms',
89
+ /**
90
+ * Phosphor, not ink: a lit state on this ground has to be visibly
91
+ * lit, and Vuetify's 0.12 disappears into the black.
92
+ */
93
+ 'focus-opacity': 0.24,
94
+ 'activated-opacity': 0.25,
95
+ // The one theme where a code block is the native register.
96
+ 'theme-code': '#04121A',
97
+ 'theme-on-code': '#00F0FF',
98
+ 'theme-kbd': '#04121A',
99
+ 'theme-on-kbd': '#00F0FF',
100
+ // A tab is a label on a terminal chrome, set with the same wide
101
+ // tracking the buttons use and a size that keeps it on one line.
102
+ 'vw-tab-size': '0.8125rem',
103
+
104
+ /**
105
+ * A terminal selects with a solid block and inverts the glyphs under
106
+ * it, which is also the only way cyan text stays readable once a
107
+ * cyan tint is laid over it.
108
+ */
109
+ 'vw-selection-fill': 'rgb(var(--v-theme-primary))',
110
+ 'vw-selection-color': 'rgb(var(--v-theme-background))',
111
+
85
112
  // A lit filament; the glow is in the stylesheet.
86
113
  'vw-timeline-line': 'rgb(var(--v-theme-secondary))',
87
114
  'vw-timeline-line-width': '2px',
@@ -117,5 +144,14 @@ export const neon = defineTheme({
117
144
  sortDesc: 'mdi-chevron-down',
118
145
  close: 'mdi-close',
119
146
  }),
147
+ // A screen repaints: the panel lights up where it stands rather than
148
+ // travelling to get there.
149
+ overlays({
150
+ dialog: 'fade-transition',
151
+ menu: 'fade-transition',
152
+ tooltip: 'fade-transition',
153
+ }),
154
+ // Nothing in a terminal ripples.
155
+ ripple(false),
120
156
  ],
121
157
  })
@@ -1,4 +1,4 @@
1
- import { bars, fields, icons, surfaces } from '../util/defaults.js'
1
+ import { bars, fields, icons, overlays, ripple, surfaces } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -70,6 +70,33 @@ export const paper = defineTheme({
70
70
  'vw-pop-scale': '1.1',
71
71
  'vw-pop-duration': '180ms',
72
72
 
73
+ /**
74
+ * Overlays keep the page's own speed. Vuetify's 300ms fade belongs to
75
+ * a theme with depth to travel through; nothing here has any, so a
76
+ * panel arrives the way a printed page is turned over — at once.
77
+ */
78
+ 'vw-overlay-duration': '140ms',
79
+ 'vw-overlay-exit': '110ms',
80
+ // Ink is either on the paper or it is not, so the states are set by
81
+ // how much ink rather than by how much glow.
82
+ 'focus-opacity': 0.14,
83
+ 'activated-opacity': 0.1,
84
+ 'disabled-opacity': 0.4,
85
+ // Set in type rather than in a grey box: a code span takes the same
86
+ // tinted stock the panels do.
87
+ 'theme-code': '#F1EEE4',
88
+ 'theme-on-code': '#14110E',
89
+ 'theme-kbd': '#F1EEE4',
90
+ 'theme-on-kbd': '#14110E',
91
+
92
+ /**
93
+ * `primary` here is ink, and a quarter-strength black is a smudge
94
+ * rather than a highlight. The selection takes the theme's second
95
+ * colour instead — a marker drawn over the type, which is what
96
+ * highlighting on paper actually looks like.
97
+ */
98
+ 'vw-selection-fill': 'rgba(var(--v-theme-secondary), 0.28)',
99
+
73
100
  // A line of ink dots, the way a printed rule breaks up.
74
101
  'vw-timeline-line': 'repeating-linear-gradient(to bottom, rgba(var(--v-border-color), 0.55) 0 2px, transparent 2px 6px)',
75
102
  'vw-timeline-line-width': '1px',
@@ -103,5 +130,17 @@ export const paper = defineTheme({
103
130
  sortDesc: 'mdi-arrow-down',
104
131
  close: 'mdi-close',
105
132
  }),
133
+ /**
134
+ * Flat, and quick about it. A sheet of paper does not scale up out of
135
+ * the page it was lying on — it is either shown or it is not.
136
+ */
137
+ overlays({
138
+ dialog: 'fade-transition',
139
+ menu: 'fade-transition',
140
+ tooltip: 'fade-transition',
141
+ }),
142
+ // A ripple is a Material animation about a surface with weight, and
143
+ // this theme prints rather than raises.
144
+ ripple(false),
106
145
  ],
107
146
  })
@@ -1,4 +1,4 @@
1
- import { bars, fields, icons, surfaces } from '../util/defaults.js'
1
+ import { bars, fields, icons, overlays, ripple, surfaces } from '../util/defaults.js'
2
2
  import { defineTheme } from '../util/defineTheme.js'
3
3
 
4
4
  /**
@@ -77,6 +77,26 @@ export const sketchy = defineTheme({
77
77
  'vw-pop-scale': '1.25',
78
78
  'vw-pop-duration': '200ms',
79
79
 
80
+ /**
81
+ * Overlays opt out of the stepped easing above.
82
+ *
83
+ * Two frames read as a drawn line on a control the size of a button;
84
+ * on a panel the size of the screen the hold between them reads as a
85
+ * dropped frame, which is the same thing that made `brutalist` look
86
+ * like it had hung. The steps stay where they are small enough to be
87
+ * charm — the press, the hover, the icon pop.
88
+ */
89
+ 'vw-overlay-duration': '140ms',
90
+ 'vw-overlay-exit': '100ms',
91
+ 'vw-overlay-ease': 'ease-out',
92
+ // Marker on paper: a state is a scribble over the shape, not a tint.
93
+ 'focus-opacity': 0.2,
94
+ 'activated-opacity': 0.15,
95
+
96
+ // Pencil in `primary`, so the highlighter is the second colour and
97
+ // drawn heavier than elsewhere — a marker, not a tint.
98
+ 'vw-selection-fill': 'rgba(var(--v-theme-secondary), 0.35)',
99
+
80
100
  // Dashes of uneven length, as if drawn in one pass.
81
101
  'vw-timeline-line': 'repeating-linear-gradient(to bottom, rgba(var(--v-border-color), 0.7) 0 7px, transparent 7px 11px, rgba(var(--v-border-color), 0.7) 11px 15px, transparent 15px 23px)',
82
102
  'vw-timeline-line-width': '2px',
@@ -104,5 +124,13 @@ export const sketchy = defineTheme({
104
124
  ratingEmpty: 'mdi-star-outline',
105
125
  close: 'mdi-close-thick',
106
126
  }),
127
+ // Two frames, like everything else here: the panel is drawn in.
128
+ overlays({
129
+ dialog: 'scale-transition',
130
+ menu: 'fade-transition',
131
+ tooltip: 'fade-transition',
132
+ }),
133
+ // Nothing in a pencil mock-up ripples.
134
+ ripple(false),
107
135
  ],
108
136
  })