@maple-kit/ui 0.8.0 → 0.10.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/README.md +5 -2
- package/dist/cx.js +6 -0
- package/dist/icons/chevron.d.ts +4 -0
- package/dist/icons/chevron.js +8 -0
- package/dist/icons/code.d.ts +4 -0
- package/dist/icons/code.js +5 -0
- package/dist/icons/index.d.ts +4 -1
- package/dist/icons/index.js +4 -1
- package/dist/icons/link.d.ts +4 -0
- package/dist/icons/link.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/island/account.js +2 -1
- package/dist/island/approve.js +2 -1
- package/dist/island/content.js +2 -1
- package/dist/island/css.js +5 -17
- package/dist/island/filters.js +2 -1
- package/dist/island/header.js +2 -1
- package/dist/island/island.js +2 -1
- package/dist/island/item.js +2 -1
- package/dist/island/list.js +2 -1
- package/dist/island/new-comment.js +2 -1
- package/dist/island/settings.js +2 -1
- package/dist/island/trigger.js +2 -1
- package/dist/island/unsent.js +2 -1
- package/dist/island/wordmark.d.ts +6 -5
- package/dist/island/wordmark.js +16 -6
- package/dist/maple.d.ts +2 -1
- package/dist/maple.js +2 -1
- package/dist/marks/index.d.ts +2 -1
- package/dist/marks/index.js +3 -2
- package/dist/marks/pixel-leaf.d.ts +20 -0
- package/dist/marks/pixel-leaf.js +39 -0
- package/dist/marks/shape.js +1 -1
- package/dist/mock/css.js +427 -0
- package/dist/mock/index.d.ts +4 -0
- package/dist/mock/index.js +4 -0
- package/dist/mock/language.d.ts +39 -0
- package/dist/mock/language.js +66 -0
- package/dist/mock/layers.js +168 -0
- package/dist/mock/menu.js +85 -0
- package/dist/mock/mock.d.ts +18 -0
- package/dist/mock/mock.js +200 -0
- package/dist/mock/sheet.d.ts +8 -0
- package/dist/mock/sheet.js +9 -0
- package/dist/notice/notice.js +2 -1
- package/dist/part.js +1 -4
- package/dist/root.js +2 -1
- package/dist/sheet-base.d.ts +11 -0
- package/dist/sheet-base.js +173 -0
- package/dist/stylesheet.d.ts +3 -12
- package/dist/stylesheet.js +5 -167
- package/dist/tip.js +1 -1
- package/dist/tokens.js +6 -2
- package/package.json +6 -4
package/dist/mock/css.js
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import "../tokens.js";
|
|
2
|
+
//#region src/mock/css.ts
|
|
3
|
+
function mockCss() {
|
|
4
|
+
return [
|
|
5
|
+
box(),
|
|
6
|
+
suggest(),
|
|
7
|
+
calls(),
|
|
8
|
+
states(),
|
|
9
|
+
menu(),
|
|
10
|
+
foot(),
|
|
11
|
+
banner()
|
|
12
|
+
].join("\n\n");
|
|
13
|
+
}
|
|
14
|
+
function box() {
|
|
15
|
+
return `
|
|
16
|
+
.mk-mock {
|
|
17
|
+
position: absolute;
|
|
18
|
+
top: 12vh;
|
|
19
|
+
left: 50%;
|
|
20
|
+
width: min(560px, calc(100vw - 24px));
|
|
21
|
+
max-height: 70vh;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
translate: -50% 0;
|
|
25
|
+
animation: mk-mock-in var(--mk-dur-island-open) var(--mk-ease-surface);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes mk-mock-in {
|
|
29
|
+
from {
|
|
30
|
+
opacity: 0;
|
|
31
|
+
translate: -50% calc(-1 * var(--mk-rise-card));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.mk-mock-head {
|
|
36
|
+
flex: none;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
gap: 8px;
|
|
40
|
+
padding: 10px 12px;
|
|
41
|
+
border-bottom: 1px solid var(--mk-line);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.mk-mock-field {
|
|
45
|
+
flex: 1 1 auto;
|
|
46
|
+
min-width: 0;
|
|
47
|
+
padding: 4px 0;
|
|
48
|
+
border: 0;
|
|
49
|
+
background: transparent;
|
|
50
|
+
color: var(--mk-fg);
|
|
51
|
+
font: inherit;
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.mk-mock-field:focus-visible {
|
|
56
|
+
outline: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.mk-mock-field::placeholder {
|
|
60
|
+
color: var(--mk-faint);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.mk-mock-key-hint {
|
|
64
|
+
flex: none;
|
|
65
|
+
padding: 1px 5px;
|
|
66
|
+
border: 1px solid var(--mk-line-firm);
|
|
67
|
+
border-radius: var(--mk-r-xs);
|
|
68
|
+
color: var(--mk-faint);
|
|
69
|
+
font-size: 10.5px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.mk-mock-body {
|
|
73
|
+
flex: 1 1 auto;
|
|
74
|
+
min-height: 0;
|
|
75
|
+
overflow-y: auto;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.mk-mock-route {
|
|
79
|
+
flex: none;
|
|
80
|
+
margin: 0;
|
|
81
|
+
padding: 10px 12px 4px;
|
|
82
|
+
color: var(--mk-muted);
|
|
83
|
+
font-size: 11px;
|
|
84
|
+
font-weight: 600;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.mk-mock-route .mk-mono {
|
|
88
|
+
color: var(--mk-fg);
|
|
89
|
+
font-weight: 400;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.mk-mock-fold {
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 4px;
|
|
96
|
+
width: 100%;
|
|
97
|
+
border: 0;
|
|
98
|
+
background: transparent;
|
|
99
|
+
font-family: inherit;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.mk-mock-fold[aria-expanded="true"] svg {
|
|
104
|
+
rotate: 180deg;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.mk-mock-empty {
|
|
108
|
+
margin: 0;
|
|
109
|
+
padding: 14px 12px 16px;
|
|
110
|
+
color: var(--mk-muted);
|
|
111
|
+
text-wrap: pretty;
|
|
112
|
+
}
|
|
113
|
+
`.trim();
|
|
114
|
+
}
|
|
115
|
+
function suggest() {
|
|
116
|
+
return `
|
|
117
|
+
.mk-mock-head {
|
|
118
|
+
position: relative;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.mk-mock-head[data-mk-thinking="true"]::after {
|
|
122
|
+
content: "";
|
|
123
|
+
position: absolute;
|
|
124
|
+
inset: auto 0 -1px;
|
|
125
|
+
height: 2px;
|
|
126
|
+
background: radial-gradient(closest-side, var(--mk-accent), transparent);
|
|
127
|
+
animation: mk-mock-sweep var(--mk-dur-shimmer) var(--mk-ease-swap) infinite;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@keyframes mk-mock-sweep {
|
|
131
|
+
from {
|
|
132
|
+
translate: calc(-1 * var(--mk-shimmer-sweep)) 0;
|
|
133
|
+
}
|
|
134
|
+
to {
|
|
135
|
+
translate: var(--mk-shimmer-sweep) 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.mk-mock-unnamed {
|
|
140
|
+
flex: none;
|
|
141
|
+
margin: 0;
|
|
142
|
+
padding: 8px 12px 0;
|
|
143
|
+
color: var(--mk-muted);
|
|
144
|
+
font-size: 12px;
|
|
145
|
+
}
|
|
146
|
+
`.trim();
|
|
147
|
+
}
|
|
148
|
+
function calls() {
|
|
149
|
+
return `
|
|
150
|
+
.mk-mock-calls {
|
|
151
|
+
margin: 0;
|
|
152
|
+
padding: 4px 6px 6px;
|
|
153
|
+
list-style: none;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.mk-mock-call {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 4px 10px;
|
|
161
|
+
padding: 6px;
|
|
162
|
+
border-radius: var(--mk-r-sm);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.mk-mock-call[data-mk-mocked="true"] {
|
|
166
|
+
background: var(--mk-warn-sub);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.mk-mock-name {
|
|
170
|
+
flex: 1 1 160px;
|
|
171
|
+
min-width: 0;
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: baseline;
|
|
174
|
+
gap: 6px;
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
color: var(--mk-muted);
|
|
177
|
+
font-size: 12px;
|
|
178
|
+
white-space: nowrap;
|
|
179
|
+
text-overflow: ellipsis;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.mk-mock-codec {
|
|
183
|
+
flex: none;
|
|
184
|
+
color: var(--mk-faint);
|
|
185
|
+
font-size: 10px;
|
|
186
|
+
text-transform: uppercase;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.mk-mock-rung {
|
|
190
|
+
flex: none;
|
|
191
|
+
padding: 0 6px;
|
|
192
|
+
border: 1px solid var(--mk-line);
|
|
193
|
+
border-radius: 999px;
|
|
194
|
+
color: var(--mk-faint);
|
|
195
|
+
font-size: 10px;
|
|
196
|
+
white-space: nowrap;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.mk-mock-call[data-mk-mocked="true"] .mk-mock-name {
|
|
200
|
+
color: var(--mk-fg);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.mk-mock-call[data-mk-seen="false"] .mk-mock-name {
|
|
204
|
+
color: var(--mk-faint);
|
|
205
|
+
}
|
|
206
|
+
`.trim();
|
|
207
|
+
}
|
|
208
|
+
function states() {
|
|
209
|
+
return `
|
|
210
|
+
.mk-mock-states {
|
|
211
|
+
flex: 0 1 auto;
|
|
212
|
+
display: flex;
|
|
213
|
+
flex-wrap: wrap;
|
|
214
|
+
justify-content: flex-end;
|
|
215
|
+
gap: 1px;
|
|
216
|
+
margin-left: auto;
|
|
217
|
+
padding: 2px;
|
|
218
|
+
border-radius: var(--mk-r-sm);
|
|
219
|
+
background: var(--mk-sunk);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.mk-mock-state {
|
|
223
|
+
display: inline-flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
gap: 5px;
|
|
226
|
+
padding: 2px 7px;
|
|
227
|
+
border: 0;
|
|
228
|
+
border-radius: var(--mk-r-xs);
|
|
229
|
+
background: transparent;
|
|
230
|
+
color: var(--mk-muted);
|
|
231
|
+
font: inherit;
|
|
232
|
+
font-size: 11px;
|
|
233
|
+
cursor: pointer;
|
|
234
|
+
transition:
|
|
235
|
+
background-color var(--mk-dur-fade) var(--mk-ease-surface),
|
|
236
|
+
color var(--mk-dur-fade) var(--mk-ease-surface);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.mk-mock-state:hover {
|
|
240
|
+
color: var(--mk-fg);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.mk-mock-state[aria-checked="true"] {
|
|
244
|
+
background: var(--mk-fg);
|
|
245
|
+
color: var(--mk-bg);
|
|
246
|
+
font-weight: 600;
|
|
247
|
+
}
|
|
248
|
+
`.trim();
|
|
249
|
+
}
|
|
250
|
+
function menu() {
|
|
251
|
+
return `
|
|
252
|
+
.mk-mock-pick,
|
|
253
|
+
.mk-mock-item {
|
|
254
|
+
display: flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
gap: 6px;
|
|
257
|
+
border: 0;
|
|
258
|
+
background: transparent;
|
|
259
|
+
color: var(--mk-fg);
|
|
260
|
+
font: inherit;
|
|
261
|
+
font-size: 12px;
|
|
262
|
+
cursor: pointer;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.mk-mock-pick {
|
|
266
|
+
flex: none;
|
|
267
|
+
gap: 4px;
|
|
268
|
+
min-width: 80px;
|
|
269
|
+
margin-left: auto;
|
|
270
|
+
padding: 1px 4px 1px 8px;
|
|
271
|
+
border-radius: 999px;
|
|
272
|
+
background: var(--mk-fg);
|
|
273
|
+
color: var(--mk-bg);
|
|
274
|
+
font-size: 11px;
|
|
275
|
+
line-height: 15px;
|
|
276
|
+
font-weight: 600;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.mk-mock-chevron {
|
|
280
|
+
margin-left: auto;
|
|
281
|
+
opacity: 0.6;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.mk-mock-menu {
|
|
285
|
+
position: fixed;
|
|
286
|
+
inset: 0 auto auto 0;
|
|
287
|
+
margin: 0;
|
|
288
|
+
translate: var(--mk-x) var(--mk-y);
|
|
289
|
+
min-width: 132px;
|
|
290
|
+
padding: 3px;
|
|
291
|
+
border: 1px solid var(--mk-line-firm);
|
|
292
|
+
border-radius: var(--mk-r);
|
|
293
|
+
background: var(--mk-bg);
|
|
294
|
+
box-shadow: var(--mk-sh2);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.mk-mock-item {
|
|
298
|
+
width: 100%;
|
|
299
|
+
padding: 5px 8px;
|
|
300
|
+
border-radius: var(--mk-r-sm);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.mk-mock-item:hover,
|
|
304
|
+
.mk-mock-item:focus-visible {
|
|
305
|
+
outline: none;
|
|
306
|
+
background: var(--mk-sunk);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.mk-mock-item[aria-checked="true"] {
|
|
310
|
+
font-weight: 600;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.mk-mock-dot {
|
|
314
|
+
width: 6px;
|
|
315
|
+
height: 6px;
|
|
316
|
+
border-radius: 50%;
|
|
317
|
+
background: var(--mk-ok);
|
|
318
|
+
}
|
|
319
|
+
`.trim();
|
|
320
|
+
}
|
|
321
|
+
function foot() {
|
|
322
|
+
return `
|
|
323
|
+
.mk-mock-foot {
|
|
324
|
+
flex: none;
|
|
325
|
+
display: flex;
|
|
326
|
+
align-items: center;
|
|
327
|
+
gap: 6px;
|
|
328
|
+
padding: 8px 10px;
|
|
329
|
+
border-top: 1px solid var(--mk-line);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.mk-mock-spacer {
|
|
333
|
+
flex: 1 1 auto;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.mk-mock-button {
|
|
337
|
+
display: inline-flex;
|
|
338
|
+
align-items: center;
|
|
339
|
+
gap: 5px;
|
|
340
|
+
padding: 5px 11px;
|
|
341
|
+
border: 1px solid var(--mk-line-firm);
|
|
342
|
+
border-radius: 999px;
|
|
343
|
+
background: var(--mk-bg);
|
|
344
|
+
color: var(--mk-fg);
|
|
345
|
+
font: inherit;
|
|
346
|
+
font-size: 12px;
|
|
347
|
+
font-weight: 500;
|
|
348
|
+
cursor: pointer;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.mk-mock-button[data-mk-quiet="true"] {
|
|
352
|
+
border-color: transparent;
|
|
353
|
+
background: transparent;
|
|
354
|
+
color: var(--mk-muted);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.mk-mock-button[data-mk-quiet="true"]:hover:not(:disabled) {
|
|
358
|
+
color: var(--mk-fg);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.mk-mock-button:disabled {
|
|
362
|
+
color: var(--mk-faint);
|
|
363
|
+
cursor: default;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.mk-mock-button[data-mk-primary="true"] {
|
|
367
|
+
border-color: var(--mk-accent);
|
|
368
|
+
background: var(--mk-accent);
|
|
369
|
+
color: var(--mk-accent-ink);
|
|
370
|
+
font-weight: 600;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.mk-mock-button[data-mk-primary="true"]:disabled {
|
|
374
|
+
opacity: 0.4;
|
|
375
|
+
}
|
|
376
|
+
`.trim();
|
|
377
|
+
}
|
|
378
|
+
function banner() {
|
|
379
|
+
return `
|
|
380
|
+
.mk-mock-banner {
|
|
381
|
+
position: absolute;
|
|
382
|
+
bottom: 12px;
|
|
383
|
+
left: 12px;
|
|
384
|
+
display: flex;
|
|
385
|
+
align-items: center;
|
|
386
|
+
gap: 8px;
|
|
387
|
+
width: max-content;
|
|
388
|
+
max-width: calc(100vw - 160px);
|
|
389
|
+
padding: 4px 4px 4px 12px;
|
|
390
|
+
border: 1px solid var(--mk-warn);
|
|
391
|
+
border-radius: 999px;
|
|
392
|
+
background: var(--mk-warn-sub);
|
|
393
|
+
box-shadow: var(--mk-sh1);
|
|
394
|
+
color: var(--mk-fg);
|
|
395
|
+
font-size: 12px;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.mk-mock-banner-said {
|
|
399
|
+
overflow: hidden;
|
|
400
|
+
white-space: nowrap;
|
|
401
|
+
text-overflow: ellipsis;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.mk-mock-banner-as {
|
|
405
|
+
white-space: normal;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.mk-mock-banner .mk-mock-button {
|
|
409
|
+
flex: none;
|
|
410
|
+
padding: 3px 10px;
|
|
411
|
+
font-size: 11.5px;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
@media (max-width: ${String(639)}px) {
|
|
415
|
+
.mk-mock-banner {
|
|
416
|
+
bottom: 56px;
|
|
417
|
+
left: 50%;
|
|
418
|
+
translate: -50% 0;
|
|
419
|
+
flex-wrap: wrap;
|
|
420
|
+
max-width: calc(100vw - 24px);
|
|
421
|
+
border-radius: var(--mk-r);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
`.trim();
|
|
425
|
+
}
|
|
426
|
+
//#endregion
|
|
427
|
+
export { mockCss };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MOCK_COPY, SHAPE_LABELS, STATE_LABELS, STATE_SENTENCES, bannerSentence, callName, codecOf } from "./language.js";
|
|
2
|
+
import { MapleMock, MapleMockProps } from "./mock.js";
|
|
3
|
+
import { MOCK_CSS } from "./sheet.js";
|
|
4
|
+
export { MOCK_COPY, MOCK_CSS, MapleMock, type MapleMockProps, MapleMock as Mock, SHAPE_LABELS, STATE_LABELS, STATE_SENTENCES, bannerSentence, callName, codecOf };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MOCK_COPY, SHAPE_LABELS, STATE_LABELS, STATE_SENTENCES, bannerSentence, callName, codecOf } from "./language.js";
|
|
2
|
+
import { MOCK_CSS } from "./sheet.js";
|
|
3
|
+
import { MapleMock } from "./mock.js";
|
|
4
|
+
export { MOCK_COPY, MOCK_CSS, MapleMock, MapleMock as Mock, SHAPE_LABELS, STATE_LABELS, STATE_SENTENCES, bannerSentence, callName, codecOf };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { MockState, ShapeSource } from "@maple-kit/core/mock";
|
|
2
|
+
//#region src/mock/language.d.ts
|
|
3
|
+
/** What each state is called on its button. */
|
|
4
|
+
export declare const STATE_LABELS: Readonly<Record<MockState, string>>;
|
|
5
|
+
/** What the banner says a call now does, in a state's own grammar. */
|
|
6
|
+
export declare const STATE_SENTENCES: Readonly<Record<MockState, string>>;
|
|
7
|
+
/** Where a call's shape came from, as the row's tag says it. */
|
|
8
|
+
export declare const SHAPE_LABELS: Readonly<Record<ShapeSource, string>>;
|
|
9
|
+
/** The box's fixed words. */
|
|
10
|
+
export declare const MOCK_COPY: {
|
|
11
|
+
readonly label: "Mock this page";
|
|
12
|
+
readonly field: "Find a call";
|
|
13
|
+
readonly sentence: "Say a state, like “no items yet”";
|
|
14
|
+
readonly unnamed: "That doesn't name a state this page's data can be in.";
|
|
15
|
+
readonly real: "Real";
|
|
16
|
+
readonly escape: "Esc";
|
|
17
|
+
readonly routePrefix: "Calls on";
|
|
18
|
+
readonly nothingRecorded: "Nothing recorded on this page yet. Use the page, then open this again.";
|
|
19
|
+
readonly nothingMatches: "No recorded call matches that.";
|
|
20
|
+
readonly notSeen: "Named by the mock, not recorded on this page";
|
|
21
|
+
readonly shapeFrom: "Shape from";
|
|
22
|
+
readonly copyLink: "Copy link";
|
|
23
|
+
readonly copyRecipe: "Copy recipe";
|
|
24
|
+
readonly copied: "Copied";
|
|
25
|
+
readonly copyFailed: "Could not copy";
|
|
26
|
+
readonly apply: "Apply and reload";
|
|
27
|
+
readonly turnOff: "Turn off";
|
|
28
|
+
readonly edit: "Edit";
|
|
29
|
+
};
|
|
30
|
+
/** The banner's sentence, which names the first call and counts the rest. */
|
|
31
|
+
export declare function bannerSentence(calls: readonly {
|
|
32
|
+
key: string;
|
|
33
|
+
state: MockState;
|
|
34
|
+
}[]): string;
|
|
35
|
+
/** A key without its codec prefix, which the row shows on its own. */
|
|
36
|
+
export declare function callName(key: string): string;
|
|
37
|
+
/** The codec a key belongs to: `rest`, `trpc`. */
|
|
38
|
+
export declare function codecOf(key: string): string;
|
|
39
|
+
//#endregion
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/mock/language.ts
|
|
2
|
+
const STATE_LABELS = {
|
|
3
|
+
empty: "Empty",
|
|
4
|
+
error: "Error",
|
|
5
|
+
forbidden: "Forbidden",
|
|
6
|
+
loading: "Loading",
|
|
7
|
+
one: "One",
|
|
8
|
+
many: "Many",
|
|
9
|
+
long: "Long",
|
|
10
|
+
sparse: "Sparse",
|
|
11
|
+
mixed: "Mixed"
|
|
12
|
+
};
|
|
13
|
+
const STATE_SENTENCES = {
|
|
14
|
+
empty: "is empty",
|
|
15
|
+
error: "fails",
|
|
16
|
+
forbidden: "is forbidden",
|
|
17
|
+
loading: "never answers",
|
|
18
|
+
one: "has one item",
|
|
19
|
+
many: "has many items",
|
|
20
|
+
long: "has long text",
|
|
21
|
+
sparse: "has fields missing",
|
|
22
|
+
mixed: "has a mix of items"
|
|
23
|
+
};
|
|
24
|
+
const SHAPE_LABELS = {
|
|
25
|
+
supplied: "OpenAPI",
|
|
26
|
+
router: "Router types",
|
|
27
|
+
validator: "Validator",
|
|
28
|
+
introspection: "Introspection",
|
|
29
|
+
sample: "Recorded"
|
|
30
|
+
};
|
|
31
|
+
const MOCK_COPY = {
|
|
32
|
+
label: "Mock this page",
|
|
33
|
+
field: "Find a call",
|
|
34
|
+
sentence: "Say a state, like “no items yet”",
|
|
35
|
+
unnamed: "That doesn't name a state this page's data can be in.",
|
|
36
|
+
real: "Real",
|
|
37
|
+
escape: "Esc",
|
|
38
|
+
routePrefix: "Calls on",
|
|
39
|
+
nothingRecorded: "Nothing recorded on this page yet. Use the page, then open this again.",
|
|
40
|
+
nothingMatches: "No recorded call matches that.",
|
|
41
|
+
notSeen: "Named by the mock, not recorded on this page",
|
|
42
|
+
shapeFrom: "Shape from",
|
|
43
|
+
copyLink: "Copy link",
|
|
44
|
+
copyRecipe: "Copy recipe",
|
|
45
|
+
copied: "Copied",
|
|
46
|
+
copyFailed: "Could not copy",
|
|
47
|
+
apply: "Apply and reload",
|
|
48
|
+
turnOff: "Turn off",
|
|
49
|
+
edit: "Edit"
|
|
50
|
+
};
|
|
51
|
+
function bannerSentence(calls) {
|
|
52
|
+
const [first, ...rest] = calls;
|
|
53
|
+
if (first === void 0) return "Mock on";
|
|
54
|
+
const more = rest.length === 0 ? "" : ` and ${String(rest.length)} more`;
|
|
55
|
+
return `Mock on: ${callName(first.key)} ${STATE_SENTENCES[first.state]}${more}`;
|
|
56
|
+
}
|
|
57
|
+
function callName(key) {
|
|
58
|
+
const colon = key.indexOf(":");
|
|
59
|
+
return colon === -1 ? key : key.slice(colon + 1);
|
|
60
|
+
}
|
|
61
|
+
function codecOf(key) {
|
|
62
|
+
const colon = key.indexOf(":");
|
|
63
|
+
return colon === -1 ? "" : key.slice(0, colon);
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { MOCK_COPY, SHAPE_LABELS, STATE_LABELS, STATE_SENTENCES, bannerSentence, callName, codecOf };
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { ChevronIcon } from "../icons/chevron.js";
|
|
2
|
+
import { createElement, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { describeIdentity } from "@maple-kit/core/mock";
|
|
4
|
+
//#region src/mock/layers.ts
|
|
5
|
+
const LAYER_COPY = {
|
|
6
|
+
shownAs: "Shown as",
|
|
7
|
+
role: "Role",
|
|
8
|
+
granted: "Granted",
|
|
9
|
+
takenAway: "Taken away",
|
|
10
|
+
flags: "Flags",
|
|
11
|
+
permissions: "Permissions",
|
|
12
|
+
on: "On",
|
|
13
|
+
off: "Off",
|
|
14
|
+
realValue: "Real value",
|
|
15
|
+
notEvaluated: "Named by the mock, not evaluated on this page",
|
|
16
|
+
serverActs: "The server still acts as you."
|
|
17
|
+
};
|
|
18
|
+
function Layers(props) {
|
|
19
|
+
const { client, state } = props;
|
|
20
|
+
const { identity } = state;
|
|
21
|
+
const panel = useRef(null);
|
|
22
|
+
useShowTaken(panel, state.request);
|
|
23
|
+
const rows = [];
|
|
24
|
+
const grants = [];
|
|
25
|
+
const real = state.realAs;
|
|
26
|
+
const roles = identity?.role?.values ?? [];
|
|
27
|
+
if (roles.length > 0) {
|
|
28
|
+
const role = state.draftAs?.role;
|
|
29
|
+
rows.push(row({
|
|
30
|
+
key: "role",
|
|
31
|
+
name: LAYER_COPY.role,
|
|
32
|
+
set: role !== void 0,
|
|
33
|
+
prose: true
|
|
34
|
+
}, choices(LAYER_COPY.role, roles, {
|
|
35
|
+
set: role,
|
|
36
|
+
real: real?.role
|
|
37
|
+
}, (next) => client.setRole(next))));
|
|
38
|
+
}
|
|
39
|
+
for (const name of identity?.permissions?.values ?? []) {
|
|
40
|
+
const granted = state.draftAs?.permissions?.[name];
|
|
41
|
+
const pick = (next) => client.setPermission(name, next === void 0 ? void 0 : next === LAYER_COPY.granted);
|
|
42
|
+
const current = granted === void 0 ? void 0 : grantedLabel(granted);
|
|
43
|
+
const held = real === void 0 ? void 0 : grantedLabel(real.permissions.includes(name));
|
|
44
|
+
grants.push({
|
|
45
|
+
set: current !== void 0,
|
|
46
|
+
node: row({
|
|
47
|
+
key: `p:${name}`,
|
|
48
|
+
name,
|
|
49
|
+
set: current !== void 0
|
|
50
|
+
}, choices(name, [LAYER_COPY.granted, LAYER_COPY.takenAway], {
|
|
51
|
+
set: current,
|
|
52
|
+
real: held
|
|
53
|
+
}, pick))
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const flags = state.flags.map((flag) => ({
|
|
57
|
+
set: flag.set !== void 0,
|
|
58
|
+
node: flagRow(flag, client)
|
|
59
|
+
}));
|
|
60
|
+
return createElement("div", {
|
|
61
|
+
className: "mk-mock-layers",
|
|
62
|
+
ref: panel
|
|
63
|
+
}, rows.length === 0 ? null : section(LAYER_COPY.shownAs, rows), grants.length === 0 ? null : createElement(Fold, {
|
|
64
|
+
title: LAYER_COPY.permissions,
|
|
65
|
+
rows: grants
|
|
66
|
+
}), flags.length === 0 ? null : createElement(Fold, {
|
|
67
|
+
title: LAYER_COPY.flags,
|
|
68
|
+
rows: flags
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
function Fold(props) {
|
|
72
|
+
const [open, setOpen] = useState(false);
|
|
73
|
+
const { rows, title } = props;
|
|
74
|
+
const shown = open ? rows : rows.filter((folded) => folded.set);
|
|
75
|
+
return createElement("section", { "aria-label": title }, createElement("button", {
|
|
76
|
+
type: "button",
|
|
77
|
+
className: "mk-mock-route mk-mock-fold",
|
|
78
|
+
"aria-expanded": open,
|
|
79
|
+
onClick: () => setOpen(!open)
|
|
80
|
+
}, `${title} · ${String(rows.length)}`, createElement(ChevronIcon, { size: 11 })), shown.length === 0 ? null : createElement("ul", { className: "mk-mock-calls" }, shown.map((folded) => folded.node)));
|
|
81
|
+
}
|
|
82
|
+
function useShowTaken(ref, request) {
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const panel = ref.current;
|
|
85
|
+
if (request === void 0 || panel === null) return;
|
|
86
|
+
const set = panel.querySelectorAll("[data-mk-mocked=\"true\"]");
|
|
87
|
+
const still = panel.ownerDocument.defaultView?.matchMedia("(prefers-reduced-motion: reduce)");
|
|
88
|
+
set[set.length - 1]?.scrollIntoView({
|
|
89
|
+
block: "nearest",
|
|
90
|
+
behavior: still?.matches ? "instant" : "smooth"
|
|
91
|
+
});
|
|
92
|
+
}, [ref, request]);
|
|
93
|
+
}
|
|
94
|
+
function LayerBanner(props) {
|
|
95
|
+
const { active, writes } = props.state;
|
|
96
|
+
const who = describeIdentity(active?.as);
|
|
97
|
+
const flags = Object.keys(active?.flags ?? {}).length;
|
|
98
|
+
const said = [
|
|
99
|
+
who === void 0 ? "" : `Showing as ${who}. ${LAYER_COPY.serverActs}`,
|
|
100
|
+
flags === 0 ? "" : `${plural(flags, "flag")} set.`,
|
|
101
|
+
who === void 0 || writes === 0 ? "" : `${plural(writes, "write")} reached the server as you.`
|
|
102
|
+
].filter(Boolean);
|
|
103
|
+
return said.length === 0 ? null : createElement("span", { className: "mk-mock-banner-as" }, said.join(" "));
|
|
104
|
+
}
|
|
105
|
+
function flagRow(flag, client) {
|
|
106
|
+
const pick = (next) => client.setFlag(flag.key, next);
|
|
107
|
+
const values = flag.type === "boolean" ? [true, false] : flag.variants ?? [];
|
|
108
|
+
const title = flag.seen ? `${LAYER_COPY.realValue}: ${JSON.stringify(flag.value)}` : `${flag.key}: ${LAYER_COPY.notEvaluated}`;
|
|
109
|
+
const labels = values.map(valueLabel);
|
|
110
|
+
const current = flag.set === void 0 ? void 0 : valueLabel(flag.set);
|
|
111
|
+
const real = flag.seen && flag.value !== void 0 ? valueLabel(flag.value) : void 0;
|
|
112
|
+
const control = values.length === 0 ? createElement("span", { className: "mk-mock-rung" }, current ?? valueLabel(flag.value ?? null)) : choices(flag.key, labels, {
|
|
113
|
+
set: current,
|
|
114
|
+
real
|
|
115
|
+
}, (label) => pick(values[labels.indexOf(label ?? "")] ?? void 0));
|
|
116
|
+
return row({
|
|
117
|
+
key: `f:${flag.key}`,
|
|
118
|
+
name: flag.key,
|
|
119
|
+
set: current !== void 0,
|
|
120
|
+
title
|
|
121
|
+
}, control);
|
|
122
|
+
}
|
|
123
|
+
function valueLabel(value) {
|
|
124
|
+
if (value === true) return LAYER_COPY.on;
|
|
125
|
+
if (value === false) return LAYER_COPY.off;
|
|
126
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
127
|
+
}
|
|
128
|
+
function grantedLabel(granted) {
|
|
129
|
+
return granted ? LAYER_COPY.granted : LAYER_COPY.takenAway;
|
|
130
|
+
}
|
|
131
|
+
function plural(count, word) {
|
|
132
|
+
return `${String(count)} ${word}${count === 1 ? "" : "s"}`;
|
|
133
|
+
}
|
|
134
|
+
function section(title, rows) {
|
|
135
|
+
return createElement("section", {
|
|
136
|
+
key: title,
|
|
137
|
+
"aria-label": title
|
|
138
|
+
}, createElement("p", { className: "mk-mock-route" }, title), createElement("ul", { className: "mk-mock-calls" }, rows));
|
|
139
|
+
}
|
|
140
|
+
function row(label, control) {
|
|
141
|
+
const { key, name, prose, set, title } = label;
|
|
142
|
+
return createElement("li", {
|
|
143
|
+
key,
|
|
144
|
+
className: "mk-mock-call",
|
|
145
|
+
"data-mk-mocked": String(set),
|
|
146
|
+
title: title ?? name
|
|
147
|
+
}, createElement("span", { className: prose ? "mk-mock-name" : "mk-mock-name mk-mono" }, name), control);
|
|
148
|
+
}
|
|
149
|
+
function choices(label, options, choice, pick) {
|
|
150
|
+
const shown = choice.set ?? choice.real;
|
|
151
|
+
return createElement("div", {
|
|
152
|
+
className: "mk-mock-states",
|
|
153
|
+
role: "radiogroup",
|
|
154
|
+
"aria-label": label
|
|
155
|
+
}, options.map((option) => createElement("button", {
|
|
156
|
+
key: option,
|
|
157
|
+
type: "button",
|
|
158
|
+
role: "radio",
|
|
159
|
+
className: "mk-mock-state mk-press",
|
|
160
|
+
"aria-checked": option === shown,
|
|
161
|
+
onClick: () => pick(option === choice.set || option === choice.real ? void 0 : option)
|
|
162
|
+
}, option === choice.real ? createElement("span", {
|
|
163
|
+
className: "mk-mock-dot",
|
|
164
|
+
"aria-hidden": true
|
|
165
|
+
}) : null, option)));
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
export { LAYER_COPY, LayerBanner, Layers };
|