@dumiflex/wp-kit 0.5.0 → 0.7.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.
- package/CHANGELOG.md +47 -0
- package/README.md +5 -0
- package/package.json +4 -3
- package/src/Avatar.vue +1 -1
- package/src/Banner.vue +4 -4
- package/src/BundlePreview.vue +254 -0
- package/src/Button.vue +73 -44
- package/src/Checkbox.vue +201 -63
- package/src/Chip.vue +5 -2
- package/src/CodeBlock.vue +1 -1
- package/src/ColorField.vue +60 -6
- package/src/CombinePreview.vue +150 -0
- package/src/Combobox.vue +10 -14
- package/src/ConfirmModal.vue +12 -22
- package/src/ConstraintMatrixPreview.vue +6 -22
- package/src/ConstraintPreview.vue +259 -0
- package/src/ContextMenu.vue +11 -30
- package/src/CopyButton.vue +1 -1
- package/src/DataTable.vue +0 -2
- package/src/DatePicker.vue +1 -1
- package/src/DerivationCondition.vue +68 -0
- package/src/DerivationPreview.vue +345 -0
- package/src/Disclosure.vue +2 -1
- package/src/Drawer.vue +2 -2
- package/src/DropZone.vue +2 -2
- package/src/FixedValuesPreview.vue +184 -0
- package/src/HsvPicker.vue +2 -2
- package/src/IconPicker.vue +32 -103
- package/src/IconPickerPanel.vue +132 -0
- package/src/ImageGrid.vue +2 -2
- package/src/Lightbox.vue +2 -2
- package/src/LoadingMark.vue +6 -61
- package/src/Modal.vue +109 -44
- package/src/ModalShell.vue +26 -5
- package/src/Pagination.vue +4 -4
- package/src/PayloadPreview.vue +154 -0
- package/src/Popover.vue +68 -12
- package/src/PostDetailSkeleton.vue +65 -0
- package/src/PostGridSkeleton.vue +61 -0
- package/src/PreviewGroup.vue +75 -0
- package/src/ProfileSkeleton.vue +73 -0
- package/src/RadioGroup.vue +5 -4
- package/src/RichText.vue +61 -0
- package/src/SearchInput.vue +1 -1
- package/src/Select.vue +53 -158
- package/src/SelectionBar.vue +90 -0
- package/src/SettingGroup.vue +57 -0
- package/src/SettingRow.vue +127 -0
- package/src/Skeleton.vue +1 -1
- package/src/Slider.vue +166 -55
- package/src/SortableList.vue +1 -1
- package/src/TagInput.vue +1 -1
- package/src/Timeline.vue +2 -2
- package/src/WildcardPreview.vue +607 -0
- package/src/WorkingLine.vue +234 -0
- package/src/WpIconButton.vue +3 -2
- package/src/WpImageZoom.vue +7 -7
- package/src/WpSegmented.vue +3 -1
- package/src/WpSwitch.vue +1 -1
- package/src/WpTabs.vue +1 -1
- package/src/_modal-motion.css +1 -1
- package/src/button.css +8 -6
- package/src/canvas-motion.ts +251 -0
- package/src/floating.ts +5 -0
- package/src/hsv.ts +1 -1
- package/src/kind-colour.ts +24 -1
- package/src/linkify.ts +142 -0
- package/src/loading-mark-motion.ts +12 -155
- package/src/matrix-axis.ts +28 -0
- package/src/menu.css +51 -0
- package/src/motion.css +73 -0
- package/src/pi-icons.ts +51 -0
- package/src/preview-readers.ts +401 -0
- package/src/preview.css +194 -0
- package/src/slider-math.ts +45 -1
- package/src/theme/looks.css +6 -19
- package/src/theme/tokens.css +12 -1108
- package/src/tokens.ts +15 -4
- package/src/tooltip.css +8 -5
- package/src/useDialogFocus.ts +11 -2
- package/src/working-line-motion.ts +135 -0
- package/src/CloseButton.vue +0 -69
- package/src/ColorPicker.vue +0 -201
- package/src/ConfirmDialog.vue +0 -165
- package/src/RangeSlider.vue +0 -183
- package/src/Toggle.vue +0 -36
- package/src/WpButton.vue +0 -75
- package/src/WpCheck.vue +0 -104
- package/src/_skeleton.css +0 -50
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Derivation as rule cards: what it reads / writes / sends to negatives,
|
|
4
|
+
* then per rule IF / ELSE IF / ELSE with nested AND / OR groups and every
|
|
5
|
+
* action numbered (the action plus its schema v8 `extra_actions`).
|
|
6
|
+
*/
|
|
7
|
+
import { computed, ref } from "vue";
|
|
8
|
+
import TokenizedValue from "./TokenizedValue.vue";
|
|
9
|
+
import DerivationCondition from "./DerivationCondition.vue";
|
|
10
|
+
import Disclosure from "./Disclosure.vue";
|
|
11
|
+
import {
|
|
12
|
+
derivationRules,
|
|
13
|
+
varFlow,
|
|
14
|
+
type ActionOp,
|
|
15
|
+
type DerivationRule,
|
|
16
|
+
type Obj,
|
|
17
|
+
} from "./preview-readers";
|
|
18
|
+
|
|
19
|
+
const props = defineProps<{
|
|
20
|
+
/** The whole module row (the var summary reads it). */
|
|
21
|
+
payload: Obj | null;
|
|
22
|
+
inner: Obj | null;
|
|
23
|
+
refMap: ReadonlyMap<string, string>;
|
|
24
|
+
}>();
|
|
25
|
+
|
|
26
|
+
const OPEN_RULES = 3;
|
|
27
|
+
|
|
28
|
+
const rules = computed(() => derivationRules(props.inner));
|
|
29
|
+
const flow = computed(() => varFlow(props.payload));
|
|
30
|
+
const branchCount = computed(() =>
|
|
31
|
+
rules.value.reduce((n, r) => n + r.branches.length + (r.fallback ? 1 : 0), 0),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const OP_LABEL: Record<ActionOp, string> = {
|
|
35
|
+
set: "SET",
|
|
36
|
+
append: "APPEND",
|
|
37
|
+
prepend: "PREPEND",
|
|
38
|
+
neg_add: "+ NEGATIVE",
|
|
39
|
+
neg_replace: "REPLACE NEG",
|
|
40
|
+
other: "",
|
|
41
|
+
};
|
|
42
|
+
function opLabel(op: ActionOp, mode: string): string {
|
|
43
|
+
return OP_LABEL[op] || mode.toUpperCase();
|
|
44
|
+
}
|
|
45
|
+
function ruleSummary(r: DerivationRule): string {
|
|
46
|
+
const n = r.branches.length;
|
|
47
|
+
const parts = [`${n} branch${n === 1 ? "" : "es"}${r.fallback ? " + else" : ""}`];
|
|
48
|
+
const targets = [
|
|
49
|
+
...new Set(
|
|
50
|
+
[...r.branches.flatMap((b) => b.actions), ...(r.fallback ?? [])]
|
|
51
|
+
.filter((a) => a.op !== "neg_add" && a.op !== "neg_replace")
|
|
52
|
+
.map((a) => a.target),
|
|
53
|
+
),
|
|
54
|
+
];
|
|
55
|
+
if (targets.length) parts.push(`sets ${targets.join(", ")}`);
|
|
56
|
+
return parts.join(" · ");
|
|
57
|
+
}
|
|
58
|
+
const toggled = ref(new Set<number>());
|
|
59
|
+
function isOpen(i: number): boolean {
|
|
60
|
+
const byDefault = i < OPEN_RULES;
|
|
61
|
+
return toggled.value.has(i) ? !byDefault : byDefault;
|
|
62
|
+
}
|
|
63
|
+
function toggle(i: number): void {
|
|
64
|
+
const next = new Set(toggled.value);
|
|
65
|
+
if (next.has(i)) next.delete(i);
|
|
66
|
+
else next.add(i);
|
|
67
|
+
toggled.value = next;
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<div class="wp-pv wp-derivation">
|
|
73
|
+
<div class="wp-pv-stats">
|
|
74
|
+
<div class="wp-pv-stat">
|
|
75
|
+
<b>{{ rules.length }}</b><span>rule{{ rules.length === 1 ? "" : "s" }}</span>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="wp-pv-stat">
|
|
78
|
+
<b>{{ branchCount }}</b><span>branches</span>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="wp-dv-io">
|
|
82
|
+
<div v-if="flow.reads.length">
|
|
83
|
+
<span class="wp-pv-label">Reads</span>
|
|
84
|
+
<code
|
|
85
|
+
v-for="v in flow.reads"
|
|
86
|
+
:key="`r-${v}`"
|
|
87
|
+
class="wp-dv-var"
|
|
88
|
+
>${{ v }}</code>
|
|
89
|
+
</div>
|
|
90
|
+
<div v-if="flow.sets.length">
|
|
91
|
+
<span class="wp-pv-label">Writes</span>
|
|
92
|
+
<code
|
|
93
|
+
v-for="v in flow.sets"
|
|
94
|
+
:key="`w-${v}`"
|
|
95
|
+
class="wp-dv-var"
|
|
96
|
+
>${{ v }}</code>
|
|
97
|
+
</div>
|
|
98
|
+
<div v-if="flow.negatives.length">
|
|
99
|
+
<span class="wp-pv-label">Negatives</span>
|
|
100
|
+
<code
|
|
101
|
+
v-for="v in flow.negatives"
|
|
102
|
+
:key="`n-${v}`"
|
|
103
|
+
class="wp-dv-var wp-dv-var--neg"
|
|
104
|
+
>{{ v }}</code>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div
|
|
109
|
+
v-for="(r, ri) in rules"
|
|
110
|
+
:key="ri"
|
|
111
|
+
class="wp-dv-rule wp-derivation__rule"
|
|
112
|
+
>
|
|
113
|
+
<Disclosure
|
|
114
|
+
flush
|
|
115
|
+
lazy
|
|
116
|
+
class="wp-dv-rule__fold"
|
|
117
|
+
:open="isOpen(ri)"
|
|
118
|
+
@update:open="toggle(ri)"
|
|
119
|
+
>
|
|
120
|
+
<template #summary>
|
|
121
|
+
<b class="wp-dv-rule__name">Rule {{ ri + 1 }}</b><span class="wp-dv-rule__sum">{{ ruleSummary(r) }}</span>
|
|
122
|
+
</template>
|
|
123
|
+
<div
|
|
124
|
+
v-for="(b, bi) in r.branches"
|
|
125
|
+
:key="bi"
|
|
126
|
+
class="wp-dv-branch wp-derivation__branch"
|
|
127
|
+
>
|
|
128
|
+
<span class="wp-dv-kw">{{ bi === 0 ? "IF" : "ELSE IF" }}</span>
|
|
129
|
+
<div class="wp-dv-body">
|
|
130
|
+
<DerivationCondition
|
|
131
|
+
v-if="b.condition"
|
|
132
|
+
:cond="b.condition"
|
|
133
|
+
/>
|
|
134
|
+
<span
|
|
135
|
+
v-else
|
|
136
|
+
class="wp-dv-none"
|
|
137
|
+
>(no condition)</span>
|
|
138
|
+
<ol class="wp-dv-steps">
|
|
139
|
+
<li
|
|
140
|
+
v-for="(a, ai) in b.actions"
|
|
141
|
+
:key="ai"
|
|
142
|
+
data-test="derivation-action"
|
|
143
|
+
>
|
|
144
|
+
<span class="wp-dv-i">{{ ai + 1 }}</span>
|
|
145
|
+
<span class="wp-dv-op-cell">
|
|
146
|
+
<span
|
|
147
|
+
class="wp-dv-op"
|
|
148
|
+
:data-op="a.op"
|
|
149
|
+
>{{ opLabel(a.op, a.mode) }}</span>
|
|
150
|
+
<code class="wp-dv-target wp-derivation__target">{{ a.target }}</code>
|
|
151
|
+
</span>
|
|
152
|
+
<span class="wp-dv-val"><TokenizedValue
|
|
153
|
+
:value="a.value"
|
|
154
|
+
:uuid-to-name="refMap"
|
|
155
|
+
/></span>
|
|
156
|
+
</li>
|
|
157
|
+
</ol>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
<div
|
|
161
|
+
v-if="r.fallback"
|
|
162
|
+
class="wp-dv-branch wp-derivation__branch is-else"
|
|
163
|
+
>
|
|
164
|
+
<span class="wp-dv-kw wp-dv-kw--else">ELSE</span>
|
|
165
|
+
<div class="wp-dv-body">
|
|
166
|
+
<ol class="wp-dv-steps">
|
|
167
|
+
<li
|
|
168
|
+
v-for="(a, ai) in r.fallback"
|
|
169
|
+
:key="ai"
|
|
170
|
+
data-test="derivation-action"
|
|
171
|
+
>
|
|
172
|
+
<span class="wp-dv-i">{{ ai + 1 }}</span>
|
|
173
|
+
<span class="wp-dv-op-cell">
|
|
174
|
+
<span
|
|
175
|
+
class="wp-dv-op"
|
|
176
|
+
:data-op="a.op"
|
|
177
|
+
>{{ opLabel(a.op, a.mode) }}</span>
|
|
178
|
+
<code class="wp-dv-target wp-derivation__target">{{ a.target }}</code>
|
|
179
|
+
</span>
|
|
180
|
+
<span class="wp-dv-val"><TokenizedValue
|
|
181
|
+
:value="a.value"
|
|
182
|
+
:uuid-to-name="refMap"
|
|
183
|
+
/></span>
|
|
184
|
+
</li>
|
|
185
|
+
</ol>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</Disclosure>
|
|
189
|
+
</div>
|
|
190
|
+
<div class="wp-dv-pad" />
|
|
191
|
+
</div>
|
|
192
|
+
</template>
|
|
193
|
+
|
|
194
|
+
<style scoped src="./preview.css"></style>
|
|
195
|
+
<style scoped>
|
|
196
|
+
.wp-dv-io {
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-wrap: wrap;
|
|
199
|
+
gap: 10px 24px;
|
|
200
|
+
padding: 12px 16px;
|
|
201
|
+
border-bottom: 1px solid var(--wp-border);
|
|
202
|
+
}
|
|
203
|
+
.wp-dv-io > div {
|
|
204
|
+
display: flex;
|
|
205
|
+
flex-wrap: wrap;
|
|
206
|
+
align-items: center;
|
|
207
|
+
gap: 6px;
|
|
208
|
+
}
|
|
209
|
+
.wp-dv-var {
|
|
210
|
+
font-family: var(--wp-font-mono);
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
color: var(--wp-success);
|
|
213
|
+
}
|
|
214
|
+
.wp-dv-var--neg {
|
|
215
|
+
color: var(--wp-danger-text, var(--wp-danger));
|
|
216
|
+
background: color-mix(in oklab, var(--wp-danger) 10%, transparent);
|
|
217
|
+
border-radius: min(3px, var(--wp-radius-cap, 999px));
|
|
218
|
+
padding: 0 4px;
|
|
219
|
+
}
|
|
220
|
+
.wp-dv-rule {
|
|
221
|
+
margin: 14px 16px 0;
|
|
222
|
+
border: 1px solid var(--wp-border);
|
|
223
|
+
border-radius: min(10px, var(--wp-radius-cap, 999px));
|
|
224
|
+
overflow: hidden;
|
|
225
|
+
}
|
|
226
|
+
.wp-dv-rule__name {
|
|
227
|
+
font-size: 12.5px;
|
|
228
|
+
}
|
|
229
|
+
.wp-dv-rule__sum {
|
|
230
|
+
min-width: 0;
|
|
231
|
+
overflow: hidden;
|
|
232
|
+
color: var(--wp-text-dim);
|
|
233
|
+
font-size: 11.5px;
|
|
234
|
+
font-weight: 400;
|
|
235
|
+
text-overflow: ellipsis;
|
|
236
|
+
white-space: nowrap;
|
|
237
|
+
}
|
|
238
|
+
.wp-dv-branch {
|
|
239
|
+
display: grid;
|
|
240
|
+
grid-template-columns: 64px minmax(0, 1fr);
|
|
241
|
+
}
|
|
242
|
+
.wp-dv-branch + .wp-dv-branch {
|
|
243
|
+
border-top: 1px solid var(--wp-border);
|
|
244
|
+
}
|
|
245
|
+
.wp-dv-kw {
|
|
246
|
+
padding: 12px 0 0 14px;
|
|
247
|
+
font-family: var(--wp-font-mono);
|
|
248
|
+
font-size: 10.5px;
|
|
249
|
+
font-weight: 700;
|
|
250
|
+
letter-spacing: 0.06em;
|
|
251
|
+
color: var(--wp-accent-text);
|
|
252
|
+
}
|
|
253
|
+
.wp-dv-kw--else {
|
|
254
|
+
color: var(--wp-text-dim);
|
|
255
|
+
}
|
|
256
|
+
.wp-dv-body {
|
|
257
|
+
display: flex;
|
|
258
|
+
flex-direction: column;
|
|
259
|
+
align-items: flex-start;
|
|
260
|
+
gap: 10px;
|
|
261
|
+
padding: 10px 14px 12px 0;
|
|
262
|
+
min-width: 0;
|
|
263
|
+
}
|
|
264
|
+
.wp-dv-none {
|
|
265
|
+
font-size: 12px;
|
|
266
|
+
color: var(--wp-text-dim);
|
|
267
|
+
}
|
|
268
|
+
.wp-dv-steps {
|
|
269
|
+
list-style: none;
|
|
270
|
+
margin: 0;
|
|
271
|
+
padding: 0;
|
|
272
|
+
width: 100%;
|
|
273
|
+
display: flex;
|
|
274
|
+
flex-direction: column;
|
|
275
|
+
gap: 6px;
|
|
276
|
+
}
|
|
277
|
+
.wp-dv-steps li {
|
|
278
|
+
display: grid;
|
|
279
|
+
grid-template-columns: 18px minmax(120px, max-content) minmax(0, 1fr);
|
|
280
|
+
align-items: baseline;
|
|
281
|
+
gap: 8px;
|
|
282
|
+
}
|
|
283
|
+
.wp-dv-i {
|
|
284
|
+
font-family: var(--wp-font-mono);
|
|
285
|
+
font-size: 11px;
|
|
286
|
+
color: var(--wp-text-dim);
|
|
287
|
+
text-align: right;
|
|
288
|
+
}
|
|
289
|
+
.wp-dv-op-cell {
|
|
290
|
+
display: inline-flex;
|
|
291
|
+
align-items: baseline;
|
|
292
|
+
gap: 6px;
|
|
293
|
+
white-space: nowrap;
|
|
294
|
+
}
|
|
295
|
+
.wp-dv-op {
|
|
296
|
+
font-family: var(--wp-font-mono);
|
|
297
|
+
font-size: 10px;
|
|
298
|
+
font-weight: 600;
|
|
299
|
+
padding: 2px 6px;
|
|
300
|
+
border-radius: min(5px, var(--wp-radius-cap, 999px));
|
|
301
|
+
background: var(--wp-bg-3);
|
|
302
|
+
color: var(--wp-text-muted);
|
|
303
|
+
}
|
|
304
|
+
.wp-dv-op[data-op="set"] {
|
|
305
|
+
background: color-mix(in oklab, var(--wp-success) 14%, transparent);
|
|
306
|
+
color: var(--wp-success);
|
|
307
|
+
}
|
|
308
|
+
.wp-dv-op[data-op="append"],
|
|
309
|
+
.wp-dv-op[data-op="prepend"] {
|
|
310
|
+
background: color-mix(in oklab, var(--wp-info) 16%, transparent);
|
|
311
|
+
color: color-mix(in oklab, var(--wp-info) 55%, white);
|
|
312
|
+
}
|
|
313
|
+
.wp-dv-op[data-op="neg_add"],
|
|
314
|
+
.wp-dv-op[data-op="neg_replace"] {
|
|
315
|
+
background: color-mix(in oklab, var(--wp-danger) 16%, transparent);
|
|
316
|
+
color: var(--wp-danger-text, var(--wp-danger));
|
|
317
|
+
}
|
|
318
|
+
.wp-dv-target {
|
|
319
|
+
font-family: var(--wp-font-mono);
|
|
320
|
+
font-size: 12px;
|
|
321
|
+
color: var(--wp-success);
|
|
322
|
+
}
|
|
323
|
+
.wp-dv-val {
|
|
324
|
+
font-family: var(--wp-font-mono);
|
|
325
|
+
font-size: 12px;
|
|
326
|
+
line-height: 1.6;
|
|
327
|
+
padding: 3px 9px;
|
|
328
|
+
border-radius: min(5px, var(--wp-radius-cap, 999px));
|
|
329
|
+
background: var(--wp-bg-3);
|
|
330
|
+
color: var(--wp-text);
|
|
331
|
+
overflow-wrap: anywhere;
|
|
332
|
+
min-width: 0;
|
|
333
|
+
}
|
|
334
|
+
.wp-dv-pad {
|
|
335
|
+
height: 14px;
|
|
336
|
+
}
|
|
337
|
+
@container (max-width: 640px) {
|
|
338
|
+
.wp-dv-steps li {
|
|
339
|
+
grid-template-columns: 18px minmax(0, 1fr);
|
|
340
|
+
}
|
|
341
|
+
.wp-dv-val {
|
|
342
|
+
grid-column: 2;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
</style>
|
package/src/Disclosure.vue
CHANGED
|
@@ -120,7 +120,8 @@ function toggle(): void {
|
|
|
120
120
|
.wp-disclosure__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
121
121
|
.wp-disclosure__chev {
|
|
122
122
|
flex: none;
|
|
123
|
-
|
|
123
|
+
/* A whole even size: 0.75em came to 9px and sat half a pixel off. */
|
|
124
|
+
font-size: 10px;
|
|
124
125
|
color: var(--wp-text-muted);
|
|
125
126
|
transition: transform var(--wp-motion-swap) var(--wp-motion-curve-collapse);
|
|
126
127
|
}
|
package/src/Drawer.vue
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Tab stays inside it and focus goes back where it was. With `modal` off
|
|
6
6
|
* there is no backdrop, Tab moves on to the page and the page stays usable.
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
8
|
+
import Button from "./Button.vue";
|
|
9
9
|
import { ref, useId, useSlots } from "vue";
|
|
10
10
|
import { useDialogFocus } from "./useDialogFocus";
|
|
11
11
|
|
|
@@ -66,7 +66,7 @@ useDialogFocus(panel, () => props.open, {
|
|
|
66
66
|
<h3 v-if="title" :id="titleId" class="wp-drawer__title">{{ title }}</h3>
|
|
67
67
|
<slot name="header" />
|
|
68
68
|
<span class="wp-spacer" />
|
|
69
|
-
<
|
|
69
|
+
<Button variant="ghost" icon="times" aria-label="Close" kbd="Esc" data-test="drawer-close" @click="close" />
|
|
70
70
|
</header>
|
|
71
71
|
<div class="wp-drawer__body">
|
|
72
72
|
<slot />
|
package/src/DropZone.vue
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { computed, ref } from "vue";
|
|
17
17
|
import { dragItemMaybeAccepted, fileAccepted, formatBytes } from "./drop-zone";
|
|
18
|
-
import
|
|
18
|
+
import Button from "./Button.vue";
|
|
19
19
|
|
|
20
20
|
export interface RejectedFile { file: File; reason: string }
|
|
21
21
|
|
|
@@ -152,7 +152,7 @@ defineExpose({ browse });
|
|
|
152
152
|
<span class="wp-drop__label">{{ over === "refuse" ? refuseWhy : mainLabel }}</span>
|
|
153
153
|
<span v-if="hint && over !== 'refuse'" class="wp-drop__hint">{{ hint }}{{ maxSize ? ` · up to ${formatBytes(maxSize)}` : "" }}</span>
|
|
154
154
|
</span>
|
|
155
|
-
<
|
|
155
|
+
<Button class="wp-drop__browse" variant="secondary" size="sm" icon="pi-folder-open" :disabled="disabled" @click="browse">{{ browseLabel }}</Button>
|
|
156
156
|
<input ref="inputEl" class="wp-drop__input" type="file" :accept="accept" :multiple="multiple" tabindex="-1" aria-hidden="true" @change="onPicked">
|
|
157
157
|
</div>
|
|
158
158
|
</template>
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/** Fixed values as a searchable variable → value → negative table, paged so
|
|
3
|
+
* a long list stays short until asked. */
|
|
4
|
+
import { computed, ref } from "vue";
|
|
5
|
+
import TokenizedValue from "./TokenizedValue.vue";
|
|
6
|
+
import { fixedValues, scanText, type FixedValue, type Obj } from "./preview-readers";
|
|
7
|
+
import SearchInput from "./SearchInput.vue";
|
|
8
|
+
import Button from "./Button.vue";
|
|
9
|
+
import Chip from "./Chip.vue";
|
|
10
|
+
|
|
11
|
+
const props = defineProps<{
|
|
12
|
+
inner: Obj | null;
|
|
13
|
+
refMap: ReadonlyMap<string, string>;
|
|
14
|
+
}>();
|
|
15
|
+
|
|
16
|
+
const PAGE = 10;
|
|
17
|
+
const LONG_CHARS = 110;
|
|
18
|
+
|
|
19
|
+
const rows = computed(() => fixedValues(props.inner));
|
|
20
|
+
const negCount = computed(() => rows.value.filter((r) => r.negative).length);
|
|
21
|
+
const refCount = computed(
|
|
22
|
+
() =>
|
|
23
|
+
rows.value.filter((r) => {
|
|
24
|
+
const s = scanText(r.value);
|
|
25
|
+
return s.refs || s.picks;
|
|
26
|
+
}).length,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const search = ref("");
|
|
30
|
+
const onlyNeg = ref(false);
|
|
31
|
+
const filtering = computed(() => search.value.trim() !== "" || onlyNeg.value);
|
|
32
|
+
const visible = computed<FixedValue[]>(() => {
|
|
33
|
+
const q = search.value.trim().toLowerCase();
|
|
34
|
+
return rows.value.filter(
|
|
35
|
+
(r) =>
|
|
36
|
+
(!onlyNeg.value || r.negative) &&
|
|
37
|
+
(!q ||
|
|
38
|
+
r.name.toLowerCase().includes(q) ||
|
|
39
|
+
r.value.toLowerCase().includes(q) ||
|
|
40
|
+
r.negative.toLowerCase().includes(q)),
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
const showAll = ref(false);
|
|
44
|
+
const shown = computed(() =>
|
|
45
|
+
showAll.value || filtering.value ? visible.value : visible.value.slice(0, PAGE),
|
|
46
|
+
);
|
|
47
|
+
const expanded = ref(new Set<number>());
|
|
48
|
+
function toggle(i: number): void {
|
|
49
|
+
const next = new Set(expanded.value);
|
|
50
|
+
if (next.has(i)) next.delete(i);
|
|
51
|
+
else next.add(i);
|
|
52
|
+
expanded.value = next;
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div class="wp-pv">
|
|
58
|
+
<div class="wp-pv-stats">
|
|
59
|
+
<div class="wp-pv-stat">
|
|
60
|
+
<b>{{ rows.length }}</b><span>variable{{ rows.length === 1 ? "" : "s" }}</span>
|
|
61
|
+
</div>
|
|
62
|
+
<div
|
|
63
|
+
v-if="negCount"
|
|
64
|
+
class="wp-pv-stat"
|
|
65
|
+
>
|
|
66
|
+
<b>{{ negCount }}</b><span>with a negative</span>
|
|
67
|
+
</div>
|
|
68
|
+
<div
|
|
69
|
+
v-if="refCount"
|
|
70
|
+
class="wp-pv-stat"
|
|
71
|
+
>
|
|
72
|
+
<b>{{ refCount }}</b><span>use picks / @refs</span>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
<div
|
|
76
|
+
v-if="rows.length > 6 || negCount"
|
|
77
|
+
class="wp-pv-tool"
|
|
78
|
+
>
|
|
79
|
+
<SearchInput
|
|
80
|
+
v-if="rows.length > 6"
|
|
81
|
+
v-model="search"
|
|
82
|
+
:placeholder="`Filter ${rows.length} values…`"
|
|
83
|
+
data-test="fixed-search"
|
|
84
|
+
class="wp-pv-search"
|
|
85
|
+
/>
|
|
86
|
+
<Chip
|
|
87
|
+
v-if="negCount"
|
|
88
|
+
size="sm"
|
|
89
|
+
color="var(--wp-danger)"
|
|
90
|
+
:pressed="onlyNeg"
|
|
91
|
+
@click="onlyNeg = !onlyNeg"
|
|
92
|
+
>Has negative</Chip>
|
|
93
|
+
<span
|
|
94
|
+
v-if="filtering"
|
|
95
|
+
class="wp-pv-count"
|
|
96
|
+
>{{ visible.length }} of {{ rows.length }}</span>
|
|
97
|
+
</div>
|
|
98
|
+
<table class="wp-pv-table">
|
|
99
|
+
<colgroup>
|
|
100
|
+
<col class="wp-pv-col-n">
|
|
101
|
+
<col style="width: 150px">
|
|
102
|
+
<col>
|
|
103
|
+
<col
|
|
104
|
+
v-if="negCount"
|
|
105
|
+
style="width: 28%"
|
|
106
|
+
>
|
|
107
|
+
</colgroup>
|
|
108
|
+
<thead>
|
|
109
|
+
<tr>
|
|
110
|
+
<th />
|
|
111
|
+
<th>Variable</th>
|
|
112
|
+
<th>Value</th>
|
|
113
|
+
<th v-if="negCount">
|
|
114
|
+
Negative
|
|
115
|
+
</th>
|
|
116
|
+
</tr>
|
|
117
|
+
</thead>
|
|
118
|
+
<tbody>
|
|
119
|
+
<tr
|
|
120
|
+
v-for="(r, i) in shown"
|
|
121
|
+
:key="i"
|
|
122
|
+
data-test="fixed-row"
|
|
123
|
+
>
|
|
124
|
+
<td class="wp-pv-n">
|
|
125
|
+
{{ i + 1 }}
|
|
126
|
+
</td>
|
|
127
|
+
<td class="wp-pv-var">
|
|
128
|
+
${{ r.name }}
|
|
129
|
+
</td>
|
|
130
|
+
<td>
|
|
131
|
+
<div :class="{ 'wp-pv-clamp': r.value.length > LONG_CHARS && !expanded.has(i) }">
|
|
132
|
+
<TokenizedValue
|
|
133
|
+
:value="r.value"
|
|
134
|
+
:uuid-to-name="refMap"
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
<Button
|
|
138
|
+
v-if="r.value.length > LONG_CHARS"
|
|
139
|
+
variant="link"
|
|
140
|
+
size="sm"
|
|
141
|
+
@click="toggle(i)"
|
|
142
|
+
>{{ expanded.has(i) ? "Show less" : "Show all" }}</Button>
|
|
143
|
+
</td>
|
|
144
|
+
<td
|
|
145
|
+
v-if="negCount"
|
|
146
|
+
class="wp-pv-neg-cell"
|
|
147
|
+
>
|
|
148
|
+
<span
|
|
149
|
+
v-if="r.negative"
|
|
150
|
+
data-test="fixed-negative"
|
|
151
|
+
>
|
|
152
|
+
<span class="wp-pv-negtag">NEG</span>
|
|
153
|
+
<TokenizedValue
|
|
154
|
+
:value="r.negative"
|
|
155
|
+
:uuid-to-name="refMap"
|
|
156
|
+
/>
|
|
157
|
+
</span>
|
|
158
|
+
</td>
|
|
159
|
+
</tr>
|
|
160
|
+
</tbody>
|
|
161
|
+
</table>
|
|
162
|
+
<p
|
|
163
|
+
v-if="!visible.length"
|
|
164
|
+
class="wp-pv-empty"
|
|
165
|
+
>
|
|
166
|
+
No values match.
|
|
167
|
+
</p>
|
|
168
|
+
<div
|
|
169
|
+
v-if="!filtering && visible.length > PAGE"
|
|
170
|
+
class="wp-pv-more"
|
|
171
|
+
>
|
|
172
|
+
<Button
|
|
173
|
+
variant="link"
|
|
174
|
+
size="sm"
|
|
175
|
+
data-test="fixed-more"
|
|
176
|
+
@click="showAll = !showAll"
|
|
177
|
+
>
|
|
178
|
+
{{ showAll ? "Show fewer" : `Show ${visible.length - PAGE} more` }}
|
|
179
|
+
</Button>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</template>
|
|
183
|
+
|
|
184
|
+
<style scoped src="./preview.css"></style>
|
package/src/HsvPicker.vue
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* HsvPicker — saturation/value square + hue slider.
|
|
4
4
|
*
|
|
5
|
-
* Shared between
|
|
5
|
+
* Shared between ColorField / TweaksPanel AND the canvas
|
|
6
6
|
* bundle modal. CSS uses `--wp-*` tokens with hardcoded fallbacks so
|
|
7
7
|
* the picker renders inside the extension where the manager spacing
|
|
8
8
|
* tokens (`--wp-space-*`) aren't loaded.
|
|
@@ -167,7 +167,7 @@ const hueCursorStyle = computed(() => ({
|
|
|
167
167
|
position: absolute;
|
|
168
168
|
width: 14px;
|
|
169
169
|
height: 14px;
|
|
170
|
-
border-radius: 50
|
|
170
|
+
border-radius: min(50%, var(--wp-radius-cap, 999px));
|
|
171
171
|
border: 2px solid #fff;
|
|
172
172
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.45);
|
|
173
173
|
transform: translate(-50%, -50%);
|