@thinkpixellab-public/px-vue 3.0.81 → 3.0.83

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.
@@ -14,7 +14,13 @@
14
14
  -->
15
15
  <template>
16
16
  <div>
17
- <px-toggle-button :class="toggleButtonClass" variant="icon" :checked.sync="visibleValue">
17
+ <px-toggle-button
18
+ :class="toggleButtonClass"
19
+ variant="icon"
20
+ :checked.sync="visibleValue"
21
+ :controls="drawerA11yId"
22
+ mode="expander"
23
+ >
18
24
  <px-icon :src="toggleIcon" />
19
25
  </px-toggle-button>
20
26
 
@@ -24,14 +30,20 @@
24
30
  v-bind="modalProps"
25
31
  transition-name="px-side-drawer__tr"
26
32
  >
27
- <div :class="bem()">
33
+ <div :id="drawerA11yId" :class="bem()">
28
34
  <div :class="drawerClass">
29
35
  <div :class="bem('top')">
30
36
  <div :class="bem('close')">
31
- <button :class="closeButtonClass" @click="visibleValue = false">
32
- <px-icon :src="closeIcon" />
37
+ <button
38
+ :class="closeButtonClass"
39
+ @click="visibleValue = false"
40
+ :aria-label="closeButtonLabel"
41
+ >
42
+ <px-icon :src="closeIcon" size="1.25" />
33
43
  </button>
34
44
  </div>
45
+ </div>
46
+ <div :class="bem('content')">
35
47
  <slot name="default" />
36
48
  </div>
37
49
  <div :class="bem('bottom')">
@@ -75,9 +87,16 @@ export default {
75
87
 
76
88
  // PxModal (see PxModal for details)
77
89
  modalProps: { type: Object },
90
+
91
+ // accessibility props
92
+ closeButtonLabel: { type: String, default: 'Close' },
78
93
  },
79
94
  // data() { return { b: 0 }; },
80
- // computed: {},
95
+ computed: {
96
+ drawerA11yId() {
97
+ return this.uniqueId('drawer');
98
+ },
99
+ },
81
100
  // watch: {},
82
101
  // mounted() {},
83
102
  // methods: {},
@@ -141,8 +160,21 @@ $dur: 400ms;
141
160
  width: 320px;
142
161
  max-width: 100vw;
143
162
  height: 100%;
144
- background-color: clr(page-bg);
163
+ background-color: clr(page-bg, $alpha: 0.9);
164
+ backdrop-filter: blur(8px);
145
165
  box-shadow: depth-shadow(15, 0.1);
166
+ overflow: auto;
167
+ }
168
+
169
+ &__top {
170
+ position: sticky;
171
+ top: 0;
172
+ background-color: clr(page-bg, $alpha: 0.5);
173
+ backdrop-filter: blur(2px);
174
+ z-index: 1;
175
+ }
176
+ &__content {
177
+ flex: 1;
146
178
  }
147
179
 
148
180
  &__close {
@@ -153,7 +185,7 @@ $dur: 400ms;
153
185
  &__icon-button {
154
186
  @include button-icon(
155
187
  (
156
- padding: 0.5em,
188
+ padding: 1em,
157
189
  min-height: 0,
158
190
  min-width: 0,
159
191
  )
@@ -28,6 +28,8 @@
28
28
  :height="calcHeight"
29
29
  :width="calcWidth"
30
30
  :title="title"
31
+ :role="role"
32
+ :focusable="focusable"
31
33
  v-on="$listeners"
32
34
  />
33
35
  </template>
@@ -63,6 +65,12 @@ export default {
63
65
 
64
66
  // set the title for accessibility
65
67
  title: { type: String, default: null },
68
+
69
+ // the role applied for accessibility
70
+ role: { type: String, default: 'img' },
71
+
72
+ // focusable false by default for accessibility in older browsers
73
+ focusable: { type: Boolean, default: false },
66
74
  },
67
75
  data() {
68
76
  return { svgWidth: null, svgHeight: null, svgViewBox: null };
@@ -11,8 +11,10 @@
11
11
  bem({ checked: syncChecked, icon: iconReady, ...variantsMap }),
12
12
  checkedClass && syncChecked ? checkedClass : null,
13
13
  ]"
14
- role="switch"
15
- :aria-checked="syncChecked ? 'true' : 'false'"
14
+ :role="ariaRole"
15
+ :aria-checked="ariaChecked"
16
+ :aria-expanded="ariaExpanded"
17
+ :aria-controls="controls"
16
18
  v-on="$listeners"
17
19
  v-bind="$attrs"
18
20
  @click="toggleChecked"
@@ -49,6 +51,12 @@ export default {
49
51
 
50
52
  // the size of the icon
51
53
  iconSize: { default: null },
54
+
55
+ // the mode of the toggle button (switch | expander)
56
+ mode: { type: String, default: 'switch' },
57
+
58
+ // id of the element that this toggle button controls
59
+ controls: { type: String, default: null },
52
60
  },
53
61
  computed: {
54
62
  hasIcon() {
@@ -65,6 +73,22 @@ export default {
65
73
  iconOpacity() {
66
74
  return this.syncChecked ? 1 : 0;
67
75
  },
76
+ isSwitch() {
77
+ return this.mode === 'switch';
78
+ },
79
+ ariaRole() {
80
+ return this.mode === 'expander' ? 'button' : 'switch';
81
+ },
82
+ ariaChecked() {
83
+ if (!this.isSwitch) return null;
84
+
85
+ return this.syncChecked ? 'true' : 'false';
86
+ },
87
+ ariaExpanded() {
88
+ if (this.isSwitch) return null;
89
+
90
+ return this.syncChecked ? 'true' : 'false';
91
+ },
68
92
  },
69
93
  data() {
70
94
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinkpixellab-public/px-vue",
3
- "version": "3.0.81",
3
+ "version": "3.0.83",
4
4
  "description": "General purpose Vue components and helpers that can be used across projects.",
5
5
  "author": "Pixel Lab",
6
6
  "license": "MIT",
package/utils/cssStr.js CHANGED
@@ -79,7 +79,7 @@ function cssUnit(val) {
79
79
  if (!val) {
80
80
  return '';
81
81
  }
82
- const allowedUnits = ['em', 'px', '%', 'rem', 'vw', 'vh', 'ex', 'ch', 'vmin', 'vmax'];
82
+ const allowedUnits = ['em', 'px', '%', 'rem', 'vw', 'vh', 'ex', 'ch', 'vmin', 'vmax', 'fr'];
83
83
 
84
84
  val = val
85
85
  .toString()
@@ -216,6 +216,70 @@ function cssPxFallback(val, allowNumberless = false) {
216
216
  return cssUnitFallback(val, 'px', allowNumberless);
217
217
  }
218
218
 
219
+ /**
220
+ * Returns true if the value is a valid calc() function
221
+ */
222
+ function cssIsCalc(val) {
223
+ if (val && typeof val == 'string' && val.indexOf('calc') > -1) {
224
+ return /^calc\(.+\)$/.test(val.trim());
225
+ }
226
+ return false;
227
+ }
228
+
229
+ /**
230
+ * Takes two css values and adds them together. If they have the same unit, it just adds them
231
+ * together. If they have different units, it creates a calc() function.
232
+ *
233
+ * cssCalcAdd('100%', '5em') => 'calc(100% + 5em)'
234
+ * cssCalcAdd('100%', '-5em') => 'calc(100% - 5em)'
235
+ * cssCalcAdd('auto', cssCalcAdd('0px', 'auto')) => 'auto'
236
+ * cssCalcAdd('100%', cssCalcAdd('-2em', '-5em')) => 'calc(100% - 7em)'
237
+ * cssCalcAdd('100%', cssCalcAdd('-2em', '10px')) => 'calc(100% - calc(2em + 10px))'
238
+ */
239
+
240
+ function cssCalcAdd(val1 = 0, val2 = 0, op = '+') {
241
+ const num1 = cssNum(val1);
242
+ const num2 = cssNum(val2);
243
+
244
+ const isCalc1 = cssIsCalc(val1);
245
+ const isCalc2 = cssIsCalc(val2);
246
+
247
+ // if either is equivalent to 0, return the other
248
+
249
+ if (!num1 && !isCalc1) {
250
+ return val2;
251
+ }
252
+
253
+ if (!num2 && !isCalc2) {
254
+ return val1;
255
+ }
256
+
257
+ const unit1 = cssUnit(val1);
258
+ const unit2 = cssUnit(val2);
259
+
260
+ if (unit1 == unit2) {
261
+ if (op == '-') {
262
+ return num1 - num2 + unit1;
263
+ } else {
264
+ return num1 + num2 + unit1;
265
+ }
266
+ }
267
+
268
+ if (num2 < 0) {
269
+ const reverseOp = op == '+' ? '-' : '+';
270
+ return `calc(${val1} ${reverseOp} ${num2 * -1}${unit2})`;
271
+ }
272
+
273
+ return `calc(${val1} ${op} ${val2})`;
274
+ }
275
+
276
+ /**
277
+ * Samem as cssCalcAdd with the op set to '-'. Makes reading code a little easier.
278
+ */
279
+ function cssCalcSubtract(val1 = 0, val2 = 0) {
280
+ return cssCalcAdd(val1, val2, '-');
281
+ }
282
+
219
283
  export {
220
284
  cssPx,
221
285
  cssEm,
@@ -229,4 +293,7 @@ export {
229
293
  cssUnitFallback,
230
294
  cssEmFallback,
231
295
  cssPxFallback,
296
+ cssIsCalc,
297
+ cssCalcAdd,
298
+ cssCalcSubtract,
232
299
  };