@thinkpixellab-public/px-vue 4.0.11 → 4.0.13
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.
- package/assets/icons/ellipsis.svg +1 -0
- package/assets/icons/eyedropper.svg +1 -0
- package/bases/PxBaseColor.vue +186 -0
- package/bases/PxBaseItems.vue +2 -2
- package/bases/PxBaseSvg.vue +36 -40
- package/bases/PxBaseUniqueId.vue +5 -8
- package/components/PxBalancedText.vue +13 -5
- package/components/PxCodeSample.vue +90 -0
- package/components/PxColorPalette.vue +118 -0
- package/components/PxColorPaletteButton.vue +140 -0
- package/components/PxColorPanel.vue +267 -0
- package/components/PxColorPicker.vue +144 -0
- package/components/PxFlex.vue +1 -1
- package/components/PxIcon.vue +19 -5
- package/components/PxIconButton.vue +4 -9
- package/components/PxLabeledInput.vue +54 -0
- package/components/PxSvgRender.vue +39 -0
- package/components/PxTable.vue +125 -51
- package/package.json +3 -1
- package/stories/PxCodeSample.stories.js +53 -0
- package/stories/PxColorPalette.stories.js +59 -0
- package/stories/PxColorPanel.stories.js +45 -0
- package/stories/PxColorPicker.stories.js +44 -0
- package/stories/PxLabeledInput.stories.js +44 -0
- package/stories/PxSvgRender.stories.js +40 -0
- package/test/PxBaseColor.test.js +54 -0
- package/utils/color.js +50 -0
- package/utils/drag.js +17 -4
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Describe this component...
|
|
3
|
+
-->
|
|
4
|
+
<template>
|
|
5
|
+
<button :class="bem({ selected, pending })" :style="{ color: hslaStr }">
|
|
6
|
+
<span />
|
|
7
|
+
<slot />
|
|
8
|
+
</button>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
// import { mapState } from 'vuex';
|
|
13
|
+
// import Component from '~/components/Component.vue';
|
|
14
|
+
// import Mixin from '~/components/Mixin.vue';
|
|
15
|
+
import { hsvaToHsla, hslaToStr } from '../utils/color.js';
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
name: 'px-color-palette-button',
|
|
19
|
+
props: {
|
|
20
|
+
hsva: {
|
|
21
|
+
type: Object,
|
|
22
|
+
default: () => {
|
|
23
|
+
return { h: 0, s: 0, v: 0, a: 0 };
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
selected: { type: Boolean, default: false },
|
|
27
|
+
pending: { type: Boolean, default: false },
|
|
28
|
+
},
|
|
29
|
+
// data() { return { b: 0 }; },
|
|
30
|
+
computed: {
|
|
31
|
+
hslaStr() {
|
|
32
|
+
return hslaToStr(hsvaToHsla(this.hsva), true);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
// watch: {},
|
|
36
|
+
// mounted() {},
|
|
37
|
+
// methods: {},
|
|
38
|
+
};
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<style lang="scss">
|
|
42
|
+
@use '../styles/px.scss' as *;
|
|
43
|
+
|
|
44
|
+
@function color-wheel-gradient($count, $blend: true, $sat: 100%, $light: 50%) {
|
|
45
|
+
$grad: 'conic-gradient(';
|
|
46
|
+
@for $i from 1 through $count {
|
|
47
|
+
$color: hsl(360 - divide(360, $count) * $i, $sat, $light);
|
|
48
|
+
$start: percentage(divide($i - 1, $count));
|
|
49
|
+
$stop: percentage(divide($i, $count));
|
|
50
|
+
$end: if($i == $count, ')', ',');
|
|
51
|
+
|
|
52
|
+
@if $blend {
|
|
53
|
+
$grad: '#{$grad} #{$color} #{$start}#{$end}';
|
|
54
|
+
} @else {
|
|
55
|
+
$grad: '#{$grad} #{$color} #{$start}, #{$color} #{$stop}#{$end}';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@return unquote($grad);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.px-color-palette-button {
|
|
63
|
+
@include control-reset();
|
|
64
|
+
|
|
65
|
+
position: relative;
|
|
66
|
+
aspect-ratio: 1;
|
|
67
|
+
width: 2em;
|
|
68
|
+
border-radius: 50%;
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
|
|
74
|
+
@include transition(transform, $dur: 0.2s);
|
|
75
|
+
|
|
76
|
+
@include checkered-background(
|
|
77
|
+
$width: 0.25em,
|
|
78
|
+
$color: rgba(black, 0.1),
|
|
79
|
+
$color-alt: transparent
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
> span {
|
|
83
|
+
@include abs();
|
|
84
|
+
border-radius: inherit;
|
|
85
|
+
background-color: currentColor;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&:before,
|
|
89
|
+
&:after {
|
|
90
|
+
border-radius: inherit;
|
|
91
|
+
@include transition(all, $dur: 0.3s);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@include before() {
|
|
95
|
+
@include abs(-2px);
|
|
96
|
+
border: 2px solid black;
|
|
97
|
+
opacity: 0;
|
|
98
|
+
}
|
|
99
|
+
@include after() {
|
|
100
|
+
@include abs();
|
|
101
|
+
border: 1.5px solid white;
|
|
102
|
+
opacity: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
&:hover {
|
|
106
|
+
transform: scale(1.1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&:active {
|
|
110
|
+
transform: scale(1) !important;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
&--selected {
|
|
114
|
+
&:before,
|
|
115
|
+
&:after {
|
|
116
|
+
opacity: 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&--pending > span {
|
|
121
|
+
@include abs(-0.5px);
|
|
122
|
+
background-color: transparent;
|
|
123
|
+
background-image: color-wheel-gradient(8, false, $light: 50%);
|
|
124
|
+
@include after() {
|
|
125
|
+
@include abs(4px);
|
|
126
|
+
background-color: rgba(white, 0.8);
|
|
127
|
+
border: 0px solid white;
|
|
128
|
+
border-radius: 50%;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&--pending {
|
|
133
|
+
color: black !important;
|
|
134
|
+
// &:before {
|
|
135
|
+
// border: 1px solid rgba(black, 0.5);
|
|
136
|
+
// opacity: 1;
|
|
137
|
+
// }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
</style>
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="bem()"
|
|
4
|
+
:style="{
|
|
5
|
+
'--px-color-panel-hsl': hslStr,
|
|
6
|
+
'--px-color-panel-hsla': hslaStr,
|
|
7
|
+
'--px-color-panel-hsla-transparent': hslaTransparentStr,
|
|
8
|
+
'--px-color-panel-hsl-hue': hueStr,
|
|
9
|
+
'--px-color-panel-contrast': contrastStr,
|
|
10
|
+
}"
|
|
11
|
+
>
|
|
12
|
+
<div ref="satval" :class="[bem('satval'), satValPanelClass]">
|
|
13
|
+
<div
|
|
14
|
+
:class="bem('sel', { satval: true })"
|
|
15
|
+
:style="{
|
|
16
|
+
left: cssPcnt(s),
|
|
17
|
+
top: cssPcnt(1 - v),
|
|
18
|
+
}"
|
|
19
|
+
></div>
|
|
20
|
+
</div>
|
|
21
|
+
<div :class="bem('sliders')">
|
|
22
|
+
<div :class="[bem('hue'), hueSliderClass]" ref="hue">
|
|
23
|
+
<div
|
|
24
|
+
:class="bem('sel', { hue: true })"
|
|
25
|
+
:style="{
|
|
26
|
+
left: cssPcnt(h / 360),
|
|
27
|
+
}"
|
|
28
|
+
></div>
|
|
29
|
+
</div>
|
|
30
|
+
<div v-if="alphaEnabled" :class="[bem('alpha'), alphaSliderClass]" ref="alpha">
|
|
31
|
+
<div
|
|
32
|
+
:class="bem('sel', { alpha: true })"
|
|
33
|
+
:style="{
|
|
34
|
+
left: cssPcnt(a),
|
|
35
|
+
}"
|
|
36
|
+
></div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div :class="bem('swatch')"></div>
|
|
40
|
+
<PxIconButton
|
|
41
|
+
v-if="eyedropperEnabled && eyedropperSupported"
|
|
42
|
+
:class="[bem('eyedropper'), eyedropperClass]"
|
|
43
|
+
@click="setColorFromEyedropper"
|
|
44
|
+
:src="EyeDropperSvg"
|
|
45
|
+
:size="0.85"
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
import Drag from '../utils/drag.js';
|
|
52
|
+
import PxBaseColor from '../bases/PxBaseColor.vue';
|
|
53
|
+
import PxIconButton from './PxIconButton.vue';
|
|
54
|
+
import EyeDropperSvg from '../assets/icons/eyedropper.svg';
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
name: 'px-color-panel',
|
|
58
|
+
mixins: [PxBaseColor],
|
|
59
|
+
components: { PxIconButton },
|
|
60
|
+
props: {
|
|
61
|
+
hueSliderClass: { type: String, default: '' },
|
|
62
|
+
alphaSliderClass: { type: String, default: '' },
|
|
63
|
+
satValPanelClass: { type: String, default: '' },
|
|
64
|
+
eyedropperClass: { type: String, default: '' },
|
|
65
|
+
eyedropperEnabled: { type: Boolean, default: true },
|
|
66
|
+
eyedropperIcon: { type: String, default: EyeDropperSvg },
|
|
67
|
+
swatchVisible: { type: Boolean, default: true },
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
data() {
|
|
71
|
+
return {
|
|
72
|
+
EyeDropperSvg,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// watch: {},
|
|
77
|
+
mounted() {
|
|
78
|
+
if (this.$refs.satval) {
|
|
79
|
+
this.satvalDrag = new Drag(this.$refs.satval, {
|
|
80
|
+
startThreshold: 0,
|
|
81
|
+
lock: null,
|
|
82
|
+
onStart: this.onSatvalDrag,
|
|
83
|
+
onDrag: this.onSatvalDrag,
|
|
84
|
+
excludeSelector: this.dragExcludeSelector,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.$refs.hue) {
|
|
89
|
+
this.hueDrag = new Drag(this.$refs.hue, {
|
|
90
|
+
startThreshold: 0,
|
|
91
|
+
lock: null,
|
|
92
|
+
onStart: this.onHueDrag,
|
|
93
|
+
onDrag: this.onHueDrag,
|
|
94
|
+
excludeSelector: this.dragExcludeSelector,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (this.alphaEnabled && this.$refs.alpha) {
|
|
99
|
+
this.alphaDrag = new Drag(this.$refs.alpha, {
|
|
100
|
+
startThreshold: 0,
|
|
101
|
+
lock: null,
|
|
102
|
+
onStart: this.onAlphaDrag,
|
|
103
|
+
onDrag: this.onAlphaDrag,
|
|
104
|
+
excludeSelector: this.dragExcludeSelector,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
beforeDestroy() {
|
|
109
|
+
if (this.satvalDrag) {
|
|
110
|
+
this.satvalDrag.destroy();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (this.hueDrag) {
|
|
114
|
+
this.hueDrag.destroy();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (this.alphaDrag) {
|
|
118
|
+
this.alphaDrag.destroy();
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
methods: {
|
|
122
|
+
onSatvalDrag(e) {
|
|
123
|
+
this.s = Math.max(0, Math.min(1, e.elementXPos));
|
|
124
|
+
this.v = Math.max(0, Math.min(1, 1 - e.elementYPos));
|
|
125
|
+
},
|
|
126
|
+
onHueDrag(e) {
|
|
127
|
+
this.h = 360 * Math.max(0, Math.min(1, e.elementXPos));
|
|
128
|
+
},
|
|
129
|
+
onAlphaDrag(e) {
|
|
130
|
+
this.a = Math.max(0, Math.min(1, e.elementXPos));
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
</script>
|
|
135
|
+
|
|
136
|
+
<style lang="scss">
|
|
137
|
+
@use '../styles/px.scss' as *;
|
|
138
|
+
|
|
139
|
+
@at-root {
|
|
140
|
+
:root {
|
|
141
|
+
--px-color-panel-aspect: 1;
|
|
142
|
+
--px-color-panel-gap: 0.5em;
|
|
143
|
+
--px-color-panel-radius: 0.5em;
|
|
144
|
+
--px-color-panel-slider-height: 0.5em;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.px-color-panel {
|
|
149
|
+
width: 20em;
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
aspect-ratio: var(--px-color-panel-aspect);
|
|
153
|
+
gap: var(--px-color-panel-gap) 0;
|
|
154
|
+
|
|
155
|
+
// prettier-ignore
|
|
156
|
+
@include grid-art(
|
|
157
|
+
(
|
|
158
|
+
'auto | #(0, 1fr) |',
|
|
159
|
+
'satval | satval | #(0,1fr)',
|
|
160
|
+
'swatch | sliders | auto',
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
&__satval {
|
|
165
|
+
grid-area: satval;
|
|
166
|
+
flex: 1;
|
|
167
|
+
position: relative;
|
|
168
|
+
display: block;
|
|
169
|
+
width: 100%;
|
|
170
|
+
border-radius: var(--px-color-panel-radius);
|
|
171
|
+
|
|
172
|
+
background-image: linear-gradient(rgba(0, 0, 0, 0), #000),
|
|
173
|
+
linear-gradient(90deg, #fff, var(--px-color-panel-hsl-hue));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
&__sliders {
|
|
177
|
+
grid-area: sliders;
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
justify-content: center;
|
|
181
|
+
gap: var(--px-color-panel-gap);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
&__hue,
|
|
185
|
+
&__alpha {
|
|
186
|
+
position: relative;
|
|
187
|
+
display: block;
|
|
188
|
+
width: 100%;
|
|
189
|
+
height: 0.66em;
|
|
190
|
+
border-radius: var(--px-color-panel-radius);
|
|
191
|
+
flex: none;
|
|
192
|
+
align-self: center;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
&__hue {
|
|
196
|
+
grid-area: hue;
|
|
197
|
+
background-image: linear-gradient(90deg, red, yellow, lime, aqua, blue, fuchsia, red);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
&__alpha {
|
|
201
|
+
grid-area: alpha;
|
|
202
|
+
|
|
203
|
+
@include checkered-background(
|
|
204
|
+
$width: 0.25em,
|
|
205
|
+
$color: rgba(black, 0.1),
|
|
206
|
+
$color-alt: transparent
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
@include after() {
|
|
210
|
+
@include abs();
|
|
211
|
+
border-radius: inherit;
|
|
212
|
+
background-image: linear-gradient(
|
|
213
|
+
to right,
|
|
214
|
+
var(--px-color-panel-hsla-transparent) 0%,
|
|
215
|
+
var(--px-color-panel-hsl) 100%
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
&__sel {
|
|
221
|
+
position: absolute;
|
|
222
|
+
top: 100%;
|
|
223
|
+
left: 100%;
|
|
224
|
+
transform: translate(-50%, -50%);
|
|
225
|
+
width: 1px;
|
|
226
|
+
height: 1px;
|
|
227
|
+
width: 0.66em;
|
|
228
|
+
height: 0.66em;
|
|
229
|
+
background-color: var(--px-color-panel-hsl);
|
|
230
|
+
border: 1px solid white;
|
|
231
|
+
border-radius: 50%;
|
|
232
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
|
|
233
|
+
z-index: 1;
|
|
234
|
+
|
|
235
|
+
&:hover {
|
|
236
|
+
z-index: 2;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
&--hue {
|
|
240
|
+
top: 50%;
|
|
241
|
+
background-color: var(--px-color-panel-hsl-hue);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
&--alpha {
|
|
245
|
+
top: 50%;
|
|
246
|
+
background-color: var(--px-color-panel-hsla);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
&__swatch {
|
|
251
|
+
grid-area: swatch;
|
|
252
|
+
aspect-ratio: 1;
|
|
253
|
+
border-radius: 50%;
|
|
254
|
+
background-color: var(--px-color-panel-hsla);
|
|
255
|
+
margin-inline-end: var(--px-color-panel-gap);
|
|
256
|
+
border: 1px solid rgba(black, 0.1);
|
|
257
|
+
min-height: 1.66em;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
&__eyedropper {
|
|
261
|
+
grid-area: swatch;
|
|
262
|
+
margin-inline-end: var(--px-color-panel-gap);
|
|
263
|
+
color: var(--px-color-panel-contrast);
|
|
264
|
+
aspect-ratio: 1;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
</style>
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="bem()">
|
|
3
|
+
<PxColorPaletteButton @click="click" :hsva="hsva" :selected="selected" :pending="pending">
|
|
4
|
+
<PxIcon :class="bem('icon')" v-bind="calcIconAttrs" :style="{ color: calcIconColor }" />
|
|
5
|
+
</PxColorPaletteButton>
|
|
6
|
+
<PxFloat
|
|
7
|
+
:popupClass="bem('popup')"
|
|
8
|
+
v-model:visible="popupVisible"
|
|
9
|
+
variant="none"
|
|
10
|
+
placement="bottom-center"
|
|
11
|
+
>
|
|
12
|
+
<PxColorPanel
|
|
13
|
+
:class="bem('panel')"
|
|
14
|
+
:color="hsva"
|
|
15
|
+
:alphaEnabled="alphaEnabled"
|
|
16
|
+
:eyedropperEnabled="eyedropperMode === 'popup'"
|
|
17
|
+
format="hsva"
|
|
18
|
+
@change="panelColorChange"
|
|
19
|
+
></PxColorPanel>
|
|
20
|
+
</PxFloat>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import PxFloat from './PxFloat.vue';
|
|
26
|
+
import PxColorPanel from './PxColorPanel.vue';
|
|
27
|
+
import PxColorPaletteButton from './PxColorPaletteButton.vue';
|
|
28
|
+
import PxBaseColor from '../bases/PxBaseColor.vue';
|
|
29
|
+
import propsFilter from '../utils/propsFilter.js';
|
|
30
|
+
import { PxIcon, PxIconSrcOrAttrs } from './PxIcon.vue';
|
|
31
|
+
import EyeDropperSvg from '../assets/icons/eyedropper.svg';
|
|
32
|
+
import EllipsisSvg from '../assets/icons/ellipsis.svg';
|
|
33
|
+
|
|
34
|
+
const PxColorPicker = {
|
|
35
|
+
name: 'px-color-picker',
|
|
36
|
+
components: { PxFloat, PxColorPanel, PxColorPaletteButton, PxIcon },
|
|
37
|
+
mixins: [PxBaseColor],
|
|
38
|
+
props: {
|
|
39
|
+
/**
|
|
40
|
+
* An icon to display inside the button. If a string is provided, it will be interpreted as
|
|
41
|
+
* the src of the icon. If an object is provided, it will be passed directly to the icon
|
|
42
|
+
* component as props (with a filter applied to ensure no fallback attributes).
|
|
43
|
+
*/
|
|
44
|
+
icon: { type: [String, Object], default: null },
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Convenience prop for setting the icon if the icon prop hasn't been set. Allowed values
|
|
48
|
+
* are 'eyedropper' and 'ellipsis'.
|
|
49
|
+
*/
|
|
50
|
+
iconFallback: { type: String, default: null },
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Describes how to integrate the eyedropper into the color picker. Allowed values are:
|
|
54
|
+
* 'none' - don't show the eyedropper
|
|
55
|
+
* 'popup' - show the eyedropper in the popup
|
|
56
|
+
* 'only' - only show the eyedropper (instead of the standard dialog)
|
|
57
|
+
*/
|
|
58
|
+
eyedropperMode: { type: String, default: 'none' },
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Makes the color picker appear selected (passed to the PxColorPaletteButton component)
|
|
62
|
+
*/
|
|
63
|
+
selected: { type: Boolean, default: false },
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Gives the color picker a pending appearance (passed to the PxColorPaletteButton component)
|
|
67
|
+
*/
|
|
68
|
+
pending: { type: Boolean, default: false },
|
|
69
|
+
},
|
|
70
|
+
data() {
|
|
71
|
+
return { popupVisible: false };
|
|
72
|
+
},
|
|
73
|
+
computed: {
|
|
74
|
+
calcIconAttrs() {
|
|
75
|
+
if (this.icon) {
|
|
76
|
+
return PxIconSrcOrAttrs(this.icon);
|
|
77
|
+
} else if (this.iconFallback) {
|
|
78
|
+
switch (this.iconFallback) {
|
|
79
|
+
case 'eyedropper':
|
|
80
|
+
return { src: EyeDropperSvg, size: 0.9 };
|
|
81
|
+
case 'ellipsis':
|
|
82
|
+
return { src: EllipsisSvg };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
calcIconColor() {
|
|
87
|
+
if (this.pending) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return this.contrastStr;
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
// watch: {},
|
|
94
|
+
// mounted() {},
|
|
95
|
+
methods: {
|
|
96
|
+
panelColorChange(hsva) {
|
|
97
|
+
this.setColorHsva(hsva);
|
|
98
|
+
},
|
|
99
|
+
click() {
|
|
100
|
+
this.$emit('click');
|
|
101
|
+
if (this.eyedropperMode === 'only') {
|
|
102
|
+
this.setColorFromEyedropper();
|
|
103
|
+
} else {
|
|
104
|
+
this.popupVisible = true;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// helper function that filters out props that are not defined in the component when using v-bind to
|
|
111
|
+
// set PxColorFilter props
|
|
112
|
+
function PxColorPickerPropsFilter(attrs) {
|
|
113
|
+
return propsFilter(PxColorPicker)(attrs);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// defaut export
|
|
117
|
+
export default PxColorPicker;
|
|
118
|
+
|
|
119
|
+
// named exports
|
|
120
|
+
export { PxColorPicker, PxColorPickerPropsFilter };
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<style lang="scss">
|
|
124
|
+
@use '../styles/px.scss' as *;
|
|
125
|
+
|
|
126
|
+
@at-root {
|
|
127
|
+
:root {
|
|
128
|
+
--px-color-picker-popup-bg: #{clr(page-bg)};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
.px-color-picker {
|
|
132
|
+
&__panel {
|
|
133
|
+
width: 10em;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
&__popup {
|
|
137
|
+
padding: 0.66em;
|
|
138
|
+
border-radius: 0.75em;
|
|
139
|
+
|
|
140
|
+
background-color: var(--px-color-picker-popup-bg);
|
|
141
|
+
@include depth-shadow(20, 0.15);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
</style>
|
package/components/PxFlex.vue
CHANGED
|
@@ -32,7 +32,7 @@ export default {
|
|
|
32
32
|
wrap: { type: Boolean, default: false },
|
|
33
33
|
|
|
34
34
|
/** Equivalent to the align-items css property (aligns items relative to each other). */
|
|
35
|
-
align: { type: String, default: '
|
|
35
|
+
align: { type: String, default: 'start', validator: val => alignments.includes(val) },
|
|
36
36
|
|
|
37
37
|
/** Maps to the justify-content css property (justifies the content within the container). */
|
|
38
38
|
justify: { type: String, default: 'start', validator: val => alignments.includes(val) },
|
package/components/PxIcon.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<PxSvgRender v-if="isSvgString" :class="bem()" :svg="svgString" v-bind="bindAttrs" />
|
|
3
3
|
<inline-svg
|
|
4
4
|
v-else
|
|
5
5
|
:class="bem()"
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<script>
|
|
14
14
|
import InlineSvg from 'vue-inline-svg';
|
|
15
15
|
import PxBaseSvg from '../bases/PxBaseSvg.vue';
|
|
16
|
+
import PxSvgRender from './PxSvgRender.vue';
|
|
16
17
|
import { cssNum, cssEmFallback, cssPx } from '../utils/cssStr.js';
|
|
17
18
|
import propsFilter from '../utils/propsFilter.js';
|
|
18
19
|
|
|
@@ -70,7 +71,7 @@ export default defineNuxtPlugin(nuxtApp => {
|
|
|
70
71
|
const PxIcon = {
|
|
71
72
|
name: 'px-icon',
|
|
72
73
|
mixins: [PxBaseSvg],
|
|
73
|
-
components: { InlineSvg },
|
|
74
|
+
components: { InlineSvg, PxSvgRender },
|
|
74
75
|
props: {
|
|
75
76
|
/**
|
|
76
77
|
* A string that either represents the key (name) of an app-level icon or the svg src for
|
|
@@ -183,8 +184,6 @@ const PxIcon = {
|
|
|
183
184
|
return this.transformDefault(svg);
|
|
184
185
|
},
|
|
185
186
|
},
|
|
186
|
-
|
|
187
|
-
// mounted() {},
|
|
188
187
|
};
|
|
189
188
|
|
|
190
189
|
// helper function that filters out props that are not defined in the component when using v-bind to
|
|
@@ -193,11 +192,26 @@ function PxIconPropsFilter(attrs) {
|
|
|
193
192
|
return propsFilter(PxIcon)(attrs);
|
|
194
193
|
}
|
|
195
194
|
|
|
195
|
+
// helper function that makes that creates PxIcon attributes from a src string or attrs object
|
|
196
|
+
function PxIconSrcOrAttrs(srcOrAttrs, size = 1) {
|
|
197
|
+
if (!srcOrAttrs) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// if the src is a string, we assume it is the src attribute
|
|
202
|
+
if (typeof srcOrAttrs === 'string') {
|
|
203
|
+
return { src: srcOrAttrs, size };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// if the src is an object, we assume it is the attrs object
|
|
207
|
+
return PxIconPropsFilter(srcOrAttrs);
|
|
208
|
+
}
|
|
209
|
+
|
|
196
210
|
// defaut export
|
|
197
211
|
export default PxIcon;
|
|
198
212
|
|
|
199
213
|
// named exports
|
|
200
|
-
export { PxIcon, PxIconPropsFilter };
|
|
214
|
+
export { PxIcon, PxIconPropsFilter, PxIconSrcOrAttrs };
|
|
201
215
|
</script>
|
|
202
216
|
|
|
203
217
|
<style lang="scss">
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script>
|
|
17
|
-
import { PxIcon,
|
|
17
|
+
import { PxIcon, PxIconSrcOrAttrs } from './PxIcon.vue';
|
|
18
18
|
import PxBase from '../bases/PxBase.vue';
|
|
19
19
|
import PxBaseToggle from '../bases/PxBaseToggle.vue';
|
|
20
20
|
|
|
@@ -75,14 +75,7 @@ export default {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
src: this.icon,
|
|
81
|
-
size: this.size || 1,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return PxIconPropsFilter(this.icon);
|
|
78
|
+
return PxIconSrcOrAttrs(this.icon);
|
|
86
79
|
},
|
|
87
80
|
|
|
88
81
|
calcIconChecked() {
|
|
@@ -132,6 +125,8 @@ export default {
|
|
|
132
125
|
.px-icon-button {
|
|
133
126
|
// VARIANTS
|
|
134
127
|
|
|
128
|
+
@include control-reset();
|
|
129
|
+
|
|
135
130
|
&--default {
|
|
136
131
|
@include controls.button-icon(
|
|
137
132
|
(
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Describe this component...
|
|
3
|
+
-->
|
|
4
|
+
<template>
|
|
5
|
+
<div :class="bem({ ...variantsMap })">
|
|
6
|
+
<label :for="calcInputId" :class="[bem('label'), labelClass]">
|
|
7
|
+
<slot name="label">
|
|
8
|
+
{{ label }}
|
|
9
|
+
</slot>
|
|
10
|
+
</label>
|
|
11
|
+
<slot name="default" :id="calcInputId" />
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
import PxBaseUniqueId from '../bases/PxBaseUniqueId.vue';
|
|
17
|
+
import PxBaseVariants from '../bases/PxBaseVariants.vue';
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
name: 'px-labeled-input',
|
|
21
|
+
// components: { Component },
|
|
22
|
+
mixins: [PxBaseUniqueId, PxBaseVariants],
|
|
23
|
+
props: {
|
|
24
|
+
label: { type: String, default: 'Input' },
|
|
25
|
+
labelClass: { type: [String, Array], default: null },
|
|
26
|
+
prefix: { type: String, default: 'input' },
|
|
27
|
+
inputId: { type: String, default: null },
|
|
28
|
+
},
|
|
29
|
+
// data() { return { b: 0 }; },
|
|
30
|
+
computed: {
|
|
31
|
+
calcInputId() {
|
|
32
|
+
if (this.inputId) {
|
|
33
|
+
return this.inputId;
|
|
34
|
+
} else {
|
|
35
|
+
return this.uniqueId(this.prefix);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
// watch: {},
|
|
40
|
+
// mounted() {},
|
|
41
|
+
// methods: {},
|
|
42
|
+
};
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<style lang="scss">
|
|
46
|
+
@use '../styles/px.scss' as *;
|
|
47
|
+
|
|
48
|
+
.px-labeled-input {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: flex-start;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: 0.5em;
|
|
53
|
+
}
|
|
54
|
+
</style>
|