maverick-wave 4.9.4 → 4.11.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 (117) hide show
  1. package/.claude/skills/maverick-wave/SKILL.md +112 -12
  2. package/.claude/skills/maverick-wave/references/components.md +152 -4
  3. package/.claude/skills/maverick-wave/references/forms.md +26 -0
  4. package/.claude/skills/maverick-wave/references/javascript.md +34 -27
  5. package/.claude/skills/maverick-wave/references/layout.md +38 -3
  6. package/.claude/skills/maverick-wave/references/theming.md +33 -7
  7. package/CHANGELOG.md +6 -0
  8. package/README.md +79 -4
  9. package/index.html +16 -0
  10. package/maverick-wave.min.css +3 -3
  11. package/maverick-wave.min.js +1 -1
  12. package/package.json +2 -2
  13. package/src/js/main.js +71 -1
  14. package/src/partials/accordions-container.html +5 -0
  15. package/src/partials/alerts-container.html +5 -0
  16. package/src/partials/avatars-container.html +5 -0
  17. package/src/partials/badges-container.html +114 -0
  18. package/src/partials/blog-posts-container.html +5 -0
  19. package/src/partials/breadcrumbs-container.html +1 -1
  20. package/src/partials/button-bar-container.html +5 -0
  21. package/src/partials/buttons-container.html +84 -0
  22. package/src/partials/calendar-container.html +1 -1
  23. package/src/partials/cards-container.html +5 -0
  24. package/src/partials/code-container.html +6 -0
  25. package/src/partials/colors-container.html +1 -1
  26. package/src/partials/coming-soon-container.html +4 -0
  27. package/src/partials/divider-container.html +4 -0
  28. package/src/partials/dropdown-container.html +119 -0
  29. package/src/partials/empty-state-container.html +5 -0
  30. package/src/partials/form-container.html +5 -0
  31. package/src/partials/form-elements-container.html +5 -0
  32. package/src/partials/form-field-container.html +5 -0
  33. package/src/partials/gallery-container.html +5 -0
  34. package/src/partials/get-started-container.html +16 -4
  35. package/src/partials/header-container.html +6 -2
  36. package/src/partials/header-utilities-container.html +8 -2
  37. package/src/partials/html-lists-container.html +5 -0
  38. package/src/partials/info-container.html +4 -0
  39. package/src/partials/input-group-container.html +5 -0
  40. package/src/partials/item-lists-container.html +5 -0
  41. package/src/partials/kanban-container.html +1 -1
  42. package/src/partials/kbd-container.html +63 -0
  43. package/src/partials/meta-info-container.html +5 -0
  44. package/src/partials/pagination-container.html +1 -1
  45. package/src/partials/panels-container.html +4 -0
  46. package/src/partials/progress-container.html +4 -0
  47. package/src/partials/ratings-container.html +1 -1
  48. package/src/partials/skeleton-container.html +5 -0
  49. package/src/partials/spinners-container.html +5 -1
  50. package/src/partials/stepper-container.html +4 -0
  51. package/src/partials/tables-container.html +7 -0
  52. package/src/partials/tabs-container.html +35 -13
  53. package/src/partials/tags-container.html +5 -0
  54. package/src/partials/tiles-container.html +1 -1
  55. package/src/partials/typography-container.html +5 -0
  56. package/src/partials/utilities-container.html +153 -0
  57. package/src/scss/abstracts/_mixins.scss +176 -0
  58. package/src/scss/abstracts/_variables.scss +193 -5
  59. package/src/scss/base/_base.scss +103 -2
  60. package/src/scss/base/_reset.scss +43 -1
  61. package/src/scss/base/_typography.scss +47 -0
  62. package/src/scss/components/_accordions.scss +11 -1
  63. package/src/scss/components/_alerts.scss +3 -3
  64. package/src/scss/components/_avatars.scss +27 -6
  65. package/src/scss/components/_badge.scss +157 -0
  66. package/src/scss/components/_blog-post.scss +10 -7
  67. package/src/scss/components/_breadcrumbs.scss +11 -2
  68. package/src/scss/components/_button-bar.scss +9 -2
  69. package/src/scss/components/_buttons.scss +133 -17
  70. package/src/scss/components/_calendar.scss +13 -2
  71. package/src/scss/components/_cards.scss +12 -5
  72. package/src/scss/components/_code.scss +15 -0
  73. package/src/scss/components/_coming-soon.scss +5 -2
  74. package/src/scss/components/_content-slider.scss +1 -1
  75. package/src/scss/components/_dropdown.scss +219 -0
  76. package/src/scss/components/_gallery.scss +17 -8
  77. package/src/scss/components/_index.scss +3 -0
  78. package/src/scss/components/_info.scss +14 -8
  79. package/src/scss/components/_kanban.scss +40 -6
  80. package/src/scss/components/_kbd.scss +43 -0
  81. package/src/scss/components/_lists.scss +26 -23
  82. package/src/scss/components/_modals.scss +71 -6
  83. package/src/scss/components/_pagination.scss +4 -3
  84. package/src/scss/components/_panels.scss +13 -14
  85. package/src/scss/components/_progress.scss +1 -1
  86. package/src/scss/components/_segmented.scss +8 -4
  87. package/src/scss/components/_stepper.scss +3 -3
  88. package/src/scss/components/_tables.scss +5 -8
  89. package/src/scss/components/_tabs.scss +22 -3
  90. package/src/scss/components/_tags.scss +1 -2
  91. package/src/scss/components/_techstack-bucket.scss +8 -5
  92. package/src/scss/components/_theme-toggle.scss +16 -8
  93. package/src/scss/components/_tiles.scss +14 -4
  94. package/src/scss/components/_timelines.scss +9 -6
  95. package/src/scss/components/_toasts.scss +1 -1
  96. package/src/scss/form-elements/_checkbox.scss +2 -1
  97. package/src/scss/form-elements/_form.scss +2 -2
  98. package/src/scss/form-elements/_input-group.scss +30 -1
  99. package/src/scss/form-elements/_input.scss +10 -10
  100. package/src/scss/form-elements/_login.scss +1 -1
  101. package/src/scss/form-elements/_radio.scss +4 -3
  102. package/src/scss/form-elements/_select.scss +9 -10
  103. package/src/scss/form-elements/_slider.scss +11 -11
  104. package/src/scss/form-elements/_textarea.scss +5 -8
  105. package/src/scss/form-elements/_toggle.scss +6 -5
  106. package/src/scss/layout/_footer.scss +14 -7
  107. package/src/scss/layout/_header.scss +18 -17
  108. package/src/scss/layout/_home.scss +1 -1
  109. package/src/scss/layout/_main.scss +6 -6
  110. package/src/scss/layout/_section.scss +7 -4
  111. package/src/scss/utilities/_accessibility.scss +38 -0
  112. package/src/scss/utilities/_aspect.scss +27 -0
  113. package/src/scss/utilities/_display.scss +52 -0
  114. package/src/scss/utilities/_elevation.scss +16 -0
  115. package/src/scss/utilities/_index.scss +2 -0
  116. package/src/scss/utilities/_text.scss +63 -0
  117. package/src/scss/utilities/_touch-targets.scss +63 -0
@@ -121,10 +121,7 @@
121
121
  transform: translateY(0);
122
122
  }
123
123
 
124
- &:focus-visible {
125
- outline: 2px solid var(--mw-primary-text-color);
126
- outline-offset: 2px;
127
- }
124
+ @include focus-ring;
128
125
 
129
126
  &.open {
130
127
  background: var(--mw-secondary-color);
@@ -162,7 +159,11 @@
162
159
  background: var(--mw-header-burgerbutton-color);
163
160
  border-radius: 1px;
164
161
  position: relative;
165
- transition: all 0.3s ease;
162
+ // `all` on purpose, and the one place in the framework that keeps it: the
163
+ // burger morphs into an X by moving its two bars to the centre, so `top`
164
+ // and `bottom` have to animate - and those are exactly what the shared
165
+ // property list leaves out.
166
+ transition: all var(--mw-duration-base) var(--mw-ease-out);
166
167
 
167
168
  &::before,
168
169
  &::after {
@@ -173,7 +174,7 @@
173
174
  height: 2px;
174
175
  background: var(--mw-header-burgerbutton-color);
175
176
  border-radius: 1px;
176
- transition: all 0.3s ease;
177
+ transition: all var(--mw-duration-base) var(--mw-ease-out);
177
178
  }
178
179
 
179
180
  &::before {
@@ -196,14 +197,16 @@
196
197
  height: 100dvh;
197
198
  background: var(--mw-header-background);
198
199
  border-left: 1px solid var(--mw-header-border);
199
- box-shadow: -10px 0 30px var(--mw-shadow);
200
+ box-shadow:
201
+ -6px 0 12px var(--mw-shadow-near),
202
+ -18px 0 40px var(--mw-shadow-far);
200
203
  z-index: z-index('header') + 3;
201
204
 
202
205
  transform: translateX(100%);
203
206
  visibility: hidden;
204
207
  transition:
205
- transform 0.3s cubic-bezier(0.32, 0.72, 0, 1),
206
- visibility 0.3s;
208
+ transform var(--mw-duration-base) var(--mw-ease-out),
209
+ visibility var(--mw-duration-base);
207
210
 
208
211
  .mw-navbar-list {
209
212
  display: flex;
@@ -269,7 +272,8 @@
269
272
 
270
273
  // Items follow the panel in, slightly staggered
271
274
  .mw-navbar-item {
272
- animation: mw-navbar-item-in 0.3s ease forwards;
275
+ animation: mw-navbar-item-in var(--mw-duration-base) var(--mw-ease-out)
276
+ forwards;
273
277
 
274
278
  @for $i from 1 through 10 {
275
279
  &:nth-child(#{$i}) {
@@ -302,7 +306,7 @@
302
306
  background: var(--mw-overlay-background);
303
307
  backdrop-filter: blur(2px);
304
308
  z-index: z-index('header') - 1;
305
- animation: mw-navbar-scrim-in 0.3s ease;
309
+ animation: mw-navbar-scrim-in var(--mw-duration-base) var(--mw-ease-out);
306
310
  }
307
311
  }
308
312
  }
@@ -364,8 +368,8 @@
364
368
  transform: scaleX(0);
365
369
  transform-origin: center;
366
370
  transition:
367
- transform 0.2s,
368
- opacity 0.2s;
371
+ transform var(--mw-duration-fast),
372
+ opacity var(--mw-duration-fast);
369
373
  opacity: 0;
370
374
  }
371
375
 
@@ -499,10 +503,7 @@
499
503
  border-color: var(--mw-primary-text-color);
500
504
  }
501
505
 
502
- &:focus-visible {
503
- outline: 2px solid var(--mw-primary-text-color);
504
- outline-offset: 2px;
505
- }
506
+ @include focus-ring;
506
507
 
507
508
  &:disabled {
508
509
  opacity: 0.6;
@@ -14,7 +14,7 @@
14
14
  // choose mw-home-content or mw-home-content-fade
15
15
  &-fade {
16
16
  @extend .mw-home-content;
17
- animation: fadeIn 1.7s ease-in;
17
+ animation: fadeIn var(--mw-duration-slower) var(--mw-ease-out);
18
18
  }
19
19
  }
20
20
 
@@ -118,16 +118,16 @@ $_mw-tooltip-gap: 8px;
118
118
  width: max-content;
119
119
  padding: spacing('1') spacing('2');
120
120
  background: var(--mw-gray-color);
121
- color: #efefef;
121
+ color: $fixed-surface-text;
122
122
  font-size: font-size('xs');
123
123
  border-radius: radius('xs');
124
- box-shadow: 0 2px 5px var(--mw-shadow);
124
+ box-shadow: var(--mw-elevation-2);
125
125
  pointer-events: none;
126
126
  opacity: 0;
127
127
  display: none;
128
128
  transition:
129
- opacity 0.2s ease,
130
- display 0.2s allow-discrete;
129
+ opacity var(--mw-duration-fast) var(--mw-ease-out),
130
+ display var(--mw-duration-fast) allow-discrete;
131
131
  z-index: z-index('tooltip');
132
132
  }
133
133
 
@@ -144,8 +144,8 @@ $_mw-tooltip-gap: 8px;
144
144
  opacity: 0;
145
145
  display: none;
146
146
  transition:
147
- opacity 0.2s ease,
148
- display 0.2s allow-discrete;
147
+ opacity var(--mw-duration-fast) var(--mw-ease-out),
148
+ display var(--mw-duration-fast) allow-discrete;
149
149
  z-index: z-index('tooltip');
150
150
  }
151
151
 
@@ -45,7 +45,7 @@
45
45
  }
46
46
 
47
47
  .mw-section-nav {
48
- max-width: 90%;
48
+ max-width: 100%;
49
49
  margin: spacing('0') auto spacing('0') auto;
50
50
  display: flex;
51
51
  flex-wrap: wrap;
@@ -76,11 +76,14 @@
76
76
  color: var(--mw-primary-accent-text-color);
77
77
  }
78
78
 
79
- &:focus-visible {
80
- outline: 2px solid var(--mw-primary-text-color);
81
- outline-offset: 2px;
79
+ &:active:not(:disabled) {
80
+ transform: translateY(1px);
81
+ transition-duration: var(--mw-duration-instant);
82
82
  }
83
83
 
84
+ @include focus-ring;
85
+ @include tappable;
86
+
84
87
  &:disabled {
85
88
  cursor: not-allowed;
86
89
  opacity: 0.6;
@@ -12,3 +12,41 @@
12
12
  white-space: nowrap;
13
13
  border: 0;
14
14
  }
15
+
16
+ // The first thing a keyboard user meets on the page: a link that jumps past the
17
+ // header and the navigation straight to the content. Off-screen until focused,
18
+ // which is why it can be the first element in the body without being seen.
19
+ //
20
+ // <a class="mw-skip-link" href="#main">Skip to content</a>
21
+ .mw-skip-link {
22
+ position: absolute;
23
+ left: spacing('3');
24
+ top: spacing('3');
25
+ z-index: z-index('alert');
26
+ padding: spacing('3') spacing('5');
27
+ border-radius: radius('sm');
28
+ background: var(--mw-primary-color);
29
+ color: var(--mw-primary-accent-text-color);
30
+ font-weight: font-weight('medium');
31
+ box-shadow: var(--mw-elevation-3);
32
+ transform: translateY(calc(-100% - #{spacing('5')}));
33
+ transition: transform var(--mw-duration-fast) var(--mw-ease-out);
34
+
35
+ &:focus-visible {
36
+ transform: translateY(0);
37
+ }
38
+ }
39
+
40
+ // Content that is there for a screen reader but comes back on focus - the same
41
+ // idea as sr-only, for something that has to be reachable by tab.
42
+ .mw-sr-only-focusable:not(:focus):not(:focus-within) {
43
+ position: absolute;
44
+ width: 1px;
45
+ height: 1px;
46
+ padding: 0;
47
+ margin: -1px;
48
+ overflow: hidden;
49
+ clip-path: inset(50%);
50
+ white-space: nowrap;
51
+ border: 0;
52
+ }
@@ -0,0 +1,27 @@
1
+ @use '../abstracts' as *;
2
+
3
+ // Reserves the right box before the image inside it has loaded, which is the
4
+ // whole point: without it the page reflows when the picture arrives and
5
+ // everything below it jumps. The child fills the box and crops rather than
6
+ // stretching.
7
+ $_mw-aspects: (
8
+ 'square': '1 / 1',
9
+ 'video': '16 / 9',
10
+ 'wide': '21 / 9',
11
+ 'portrait': '3 / 4',
12
+ 'photo': '4 / 3',
13
+ );
14
+
15
+ @each $name, $ratio in $_mw-aspects {
16
+ .mw-aspect-#{$name} {
17
+ aspect-ratio: #{$ratio};
18
+
19
+ > img,
20
+ > video,
21
+ > iframe {
22
+ width: 100%;
23
+ height: 100%;
24
+ object-fit: cover;
25
+ }
26
+ }
27
+ }
@@ -43,3 +43,55 @@
43
43
  border-radius: $value;
44
44
  }
45
45
  }
46
+
47
+ // Responsive display
48
+ $_mw-responsive-displays: (none, block, flex, inline-flex, grid, inline-block);
49
+
50
+ @each $bp in ('sm', 'md', 'lg', 'xl') {
51
+ @include media-up($bp) {
52
+ @each $value in $_mw-responsive-displays {
53
+ .mw-d-#{$bp}-#{$value} {
54
+ display: #{$value};
55
+ }
56
+ }
57
+ }
58
+ }
59
+
60
+ // The two everyone actually reaches for, spelled out. `md` is the divide: below
61
+ // it a phone, at it and above a tablet with room for a second column.
62
+ .mw-hide-mobile {
63
+ @include media-down('md') {
64
+ display: none !important;
65
+ }
66
+ }
67
+
68
+ .mw-hide-desktop {
69
+ @include media-up('md') {
70
+ display: none !important;
71
+ }
72
+ }
73
+
74
+ // Overflow, for the wrappers that hold something wider than the phone they are
75
+ // being read on
76
+ .mw-overflow-auto {
77
+ overflow: auto;
78
+ }
79
+
80
+ .mw-overflow-x-auto {
81
+ overflow-x: auto;
82
+ overscroll-behavior-x: contain;
83
+ }
84
+
85
+ .mw-overflow-hidden {
86
+ overflow: hidden;
87
+ }
88
+
89
+ // Snap a horizontal strip so it comes to rest on an item instead of halfway
90
+ // between two - a row of cards swiped through on a phone
91
+ .mw-snap-x {
92
+ scroll-snap-type: x mandatory;
93
+
94
+ > * {
95
+ scroll-snap-align: start;
96
+ }
97
+ }
@@ -0,0 +1,16 @@
1
+ @use '../abstracts' as *;
2
+
3
+ // The elevation ramp as classes, for a surface a project draws itself. Same
4
+ // five steps every component uses - see the elevation() function.
5
+ //
6
+ // 0 is not "no shadow it forgot to set", it is "explicitly flat": for taking a
7
+ // component off the page it normally floats above.
8
+ .mw-elevation-0 {
9
+ box-shadow: none;
10
+ }
11
+
12
+ @for $level from 1 through 5 {
13
+ .mw-elevation-#{$level} {
14
+ box-shadow: var(--mw-elevation-#{$level});
15
+ }
16
+ }
@@ -1,5 +1,7 @@
1
1
  @forward 'accessibility';
2
+ @forward 'aspect';
2
3
  @forward 'display';
4
+ @forward 'elevation';
3
5
  @forward 'flex';
4
6
  @forward 'spacing';
5
7
  @forward 'text';
@@ -115,3 +115,66 @@
115
115
  line-height: 1.8;
116
116
  }
117
117
  }
118
+
119
+ // Overflow
120
+ .mw-text-truncate {
121
+ overflow: hidden;
122
+ text-overflow: ellipsis;
123
+ white-space: nowrap;
124
+ min-width: 0;
125
+ }
126
+
127
+ @each $lines in (2, 3, 4, 5) {
128
+ .mw-text-clamp-#{$lines} {
129
+ display: -webkit-box;
130
+ -webkit-line-clamp: $lines;
131
+ line-clamp: $lines;
132
+ -webkit-box-orient: vertical;
133
+ overflow: hidden;
134
+ }
135
+ }
136
+
137
+ .mw-text-nowrap {
138
+ white-space: nowrap;
139
+ }
140
+
141
+ // For anything that has no spaces to break at - a URL, a hash, an API key -
142
+ // and would otherwise push the page sideways on a phone
143
+ .mw-text-break {
144
+ overflow-wrap: anywhere;
145
+ word-break: break-word;
146
+ }
147
+
148
+ // Wrapping
149
+ .mw-text-balance {
150
+ text-wrap: balance;
151
+ }
152
+
153
+ .mw-text-pretty {
154
+ text-wrap: pretty;
155
+ }
156
+
157
+ .mw-text-uppercase {
158
+ text-transform: uppercase;
159
+ letter-spacing: 0.05em;
160
+ }
161
+
162
+ .mw-text-capitalize {
163
+ text-transform: capitalize;
164
+ }
165
+
166
+ // A kicker or an eyebrow over a heading - the small, spaced, upper-case line
167
+ // that says what section this is
168
+ .mw-text-eyebrow {
169
+ font-size: font-size('2xs');
170
+ font-weight: font-weight('bold');
171
+ letter-spacing: 0.12em;
172
+ text-transform: uppercase;
173
+ color: var(--mw-text-muted-color);
174
+ }
175
+
176
+ // Sets the measure a column of text is comfortable at. Anything past roughly 75
177
+ // characters and the eye loses the start of the next line on the way back.
178
+ .mw-text-measure {
179
+ max-width: 68ch;
180
+ }
@@ -12,6 +12,14 @@
12
12
  // component defaults without needing extra specificity.
13
13
  // ---------------------------------------------------------------------------
14
14
  @media (pointer: coarse), (max-width: #{breakpoint('md')}) {
15
+ // The default button was the one that got missed. Its padding and line-height
16
+ // add up to about 35px, which is under the 44px every platform guideline asks
17
+ // for and the size a thumb actually is. Only the height grows - the padding
18
+ // is what sets the label's relationship to the edges and is right as it is.
19
+ .mw-btn {
20
+ min-height: 2.75rem;
21
+ }
22
+
15
23
  .mw-btn-sm {
16
24
  min-height: 2.5rem;
17
25
  }
@@ -22,6 +30,13 @@
22
30
  min-height: 2.5rem;
23
31
  }
24
32
 
33
+ // The base fields sit at 2.35rem from the control scale, which is right under
34
+ // a pointer and short of a thumb. Same floor as the button beside them.
35
+ .mw-input,
36
+ .mw-select {
37
+ min-height: 2.75rem;
38
+ }
39
+
25
40
  .mw-input,
26
41
  .mw-input-sm,
27
42
  .mw-input-lg,
@@ -45,6 +60,25 @@
45
60
  min-height: 2.5rem;
46
61
  }
47
62
 
63
+ // Rows of a list, items of a menu, links in a footer, pages of a pager - the
64
+ // controls that are a line of text on a desktop and a target on a phone
65
+ .mw-dropdown-item,
66
+ .mw-accordion-header,
67
+ .mw-modal-close,
68
+ .mw-breadcrumbs-item a {
69
+ min-height: 2.75rem;
70
+ display: flex;
71
+ align-items: center;
72
+ }
73
+
74
+ // A checkbox or radio is tapped by its label as much as by the box, so the
75
+ // whole row has to be the target - which it only is if the row is tall enough
76
+ .mw-checkbox,
77
+ .mw-radio,
78
+ .mw-toggle {
79
+ min-height: 2.5rem;
80
+ }
81
+
48
82
  .mw-calendar-day {
49
83
  min-height: 44px;
50
84
  }
@@ -64,3 +98,32 @@
64
98
  }
65
99
  }
66
100
  }
101
+
102
+ // Sideways scroll
103
+ .mw-table-responsive,
104
+ .mw-tabs-nav {
105
+ overscroll-behavior-x: contain;
106
+ -webkit-overflow-scrolling: touch;
107
+ }
108
+
109
+ // Phone layout
110
+ @include media-down('md') {
111
+ :root {
112
+ --mw-section-padding-block: #{spacing('6')};
113
+ }
114
+ }
115
+
116
+ @include media-down('sm') {
117
+ // Cards sit edge to edge on a phone, so the padding inside them is all that
118
+ // separates the text from the screen edge - it cannot be the desktop value
119
+ .mw-card-simple {
120
+ padding: spacing('4');
121
+ }
122
+
123
+ // A row of actions on a phone stacks, and stacked buttons that are each as
124
+ // wide as their label look like a list of unrelated things
125
+ .mw-form-actions .mw-btn,
126
+ .mw-card-footer .mw-btn {
127
+ flex: 1 1 auto;
128
+ }
129
+ }