@sit-onyx/storybook-utils 1.0.0-beta.22 → 1.0.0-beta.23
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sit-onyx/storybook-utils",
|
|
3
3
|
"description": "Storybook utilities for Vue",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.23",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Schwarz IT KG",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"storybook": ">= 8.2.0",
|
|
28
28
|
"storybook-dark-mode": ">= 4",
|
|
29
29
|
"@sit-onyx/icons": "^1.0.0-beta.0",
|
|
30
|
-
"sit-onyx": "^1.0.0-beta.
|
|
30
|
+
"sit-onyx": "^1.0.0-beta.22"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"deepmerge-ts": "^7.1.0"
|
|
@@ -156,16 +156,20 @@ test("should generate source code for slots with bindings", () => {
|
|
|
156
156
|
type TestBindings = {
|
|
157
157
|
foo: string;
|
|
158
158
|
bar?: number;
|
|
159
|
+
boo: {
|
|
160
|
+
mimeType: string;
|
|
161
|
+
};
|
|
159
162
|
};
|
|
160
163
|
|
|
161
164
|
const slots = {
|
|
162
|
-
a: ({ foo, bar }: TestBindings) => `Slot with bindings ${foo} and ${
|
|
163
|
-
b: ({ foo }: TestBindings) =>
|
|
165
|
+
a: ({ foo, bar, boo }: TestBindings) => `Slot with bindings ${foo}, ${bar} and ${boo.mimeType}`,
|
|
166
|
+
b: ({ foo, boo }: TestBindings) =>
|
|
167
|
+
h("a", { href: foo, target: foo, type: boo.mimeType, ...boo }, `Test link: ${foo}`),
|
|
164
168
|
};
|
|
165
169
|
|
|
166
|
-
const expectedCode = `<template #a="{ foo, bar }">Slot with bindings {{ foo }} and {{
|
|
170
|
+
const expectedCode = `<template #a="{ foo, bar, boo }">Slot with bindings {{ foo }}, {{ bar }} and {{ boo.mimeType }}</template>
|
|
167
171
|
|
|
168
|
-
<template #b="{ foo }"><a :href="foo" :target="foo">Test link: {{ foo }}</a></template>`;
|
|
172
|
+
<template #b="{ foo, boo }"><a :href="foo" :target="foo" :type="boo.mimeType" v-bind="boo">Test link: {{ foo }}</a></template>`;
|
|
169
173
|
|
|
170
174
|
const actualCode = generateSlotSourceCode(slots, Object.keys(slots), {
|
|
171
175
|
imports: {},
|
|
@@ -8,6 +8,20 @@ import { SourceType } from "storybook/internal/docs-tools";
|
|
|
8
8
|
import { isVNode, type VNode } from "vue";
|
|
9
9
|
import { replaceAll } from "./preview";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Used to get the tracking data from the proxy.
|
|
13
|
+
* A symbol is unique, so when using it as a key it can't be accidentally accessed.
|
|
14
|
+
*/
|
|
15
|
+
const TRACKING_SYMBOL = Symbol("DEEP_ACCESS_SYMBOL");
|
|
16
|
+
|
|
17
|
+
type TrackingProxy = {
|
|
18
|
+
[TRACKING_SYMBOL]: true;
|
|
19
|
+
toString: () => string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const isProxy = (obj: unknown): obj is TrackingProxy =>
|
|
23
|
+
!!(obj && typeof obj === "object" && TRACKING_SYMBOL in obj);
|
|
24
|
+
|
|
11
25
|
/**
|
|
12
26
|
* Context that is passed down to nested components/slots when generating the source code for a single story.
|
|
13
27
|
*/
|
|
@@ -184,6 +198,10 @@ export const generatePropsSourceCode = (
|
|
|
184
198
|
if (slotNames.includes(propName)) return;
|
|
185
199
|
if (value == undefined) return; // do not render undefined/null values
|
|
186
200
|
|
|
201
|
+
if (isProxy(value)) {
|
|
202
|
+
value = value!.toString();
|
|
203
|
+
}
|
|
204
|
+
|
|
187
205
|
switch (typeof value) {
|
|
188
206
|
case "string":
|
|
189
207
|
if (value === "") return; // do not render empty strings
|
|
@@ -225,7 +243,7 @@ export const generatePropsSourceCode = (
|
|
|
225
243
|
case "object": {
|
|
226
244
|
properties.push({
|
|
227
245
|
name: propName,
|
|
228
|
-
value: formatObject(value),
|
|
246
|
+
value: formatObject(value ?? {}),
|
|
229
247
|
// to follow Vue best practices, complex values like object and arrays are
|
|
230
248
|
// usually placed inside the <script setup> block instead of inlining them in the <template>
|
|
231
249
|
templateFn: undefined,
|
|
@@ -373,25 +391,60 @@ const generateSlotChildrenSourceCode = (
|
|
|
373
391
|
(param) => !["{", "}"].includes(param),
|
|
374
392
|
);
|
|
375
393
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}, {});
|
|
380
|
-
|
|
381
|
-
const returnValue = child(parameters);
|
|
382
|
-
let slotSourceCode = generateSlotChildrenSourceCode([returnValue], ctx);
|
|
383
|
-
|
|
384
|
-
// if slot bindings are used for properties of other components, our {{ paramName }} is incorrect because
|
|
385
|
-
// it would generate e.g. my-prop="{{ paramName }}", therefore, we replace it here to e.g. :my-prop="paramName"
|
|
394
|
+
// We create proxy to track how and which properties of a parameter are accessed
|
|
395
|
+
const parameters: Record<string, string> = {};
|
|
396
|
+
const proxied: Record<string, TrackingProxy> = {};
|
|
386
397
|
paramNames.forEach((param) => {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
398
|
+
parameters[param] = `{{ ${param} }}`;
|
|
399
|
+
// TODO: we should be able to extend the proxy logic here and maybe get rid of the `generatePropsSourceCode` code
|
|
400
|
+
proxied[param] = new Proxy(
|
|
401
|
+
{
|
|
402
|
+
// we use the symbol to identify the proxy
|
|
403
|
+
[TRACKING_SYMBOL]: true,
|
|
404
|
+
} as TrackingProxy,
|
|
405
|
+
{
|
|
406
|
+
// getter is called when any prop of the parameter is read
|
|
407
|
+
get: (t, key) => {
|
|
408
|
+
if (key === TRACKING_SYMBOL) {
|
|
409
|
+
// allow retrieval of the tracking data
|
|
410
|
+
return t[TRACKING_SYMBOL];
|
|
411
|
+
}
|
|
412
|
+
if ([Symbol.toPrimitive, Symbol.toStringTag, "toString"].includes(key)) {
|
|
413
|
+
// when the parameter is used as a string we return the parameter name
|
|
414
|
+
// we use the double brace notation as we don't know if the parameter is used in text or in a binding
|
|
415
|
+
return () => `{{ ${param} }}`;
|
|
416
|
+
}
|
|
417
|
+
if (key === "v-bind") {
|
|
418
|
+
// if this key is returned we just return the parameter name
|
|
419
|
+
return `${param}`;
|
|
420
|
+
}
|
|
421
|
+
// otherwise a specific key of the parameter was accessed
|
|
422
|
+
// we use the double brace notation as we don't know if the parameter is used in text or in a binding
|
|
423
|
+
return `{{ ${param}.${key.toString()} }}`;
|
|
424
|
+
},
|
|
425
|
+
// ownKeys is called, among other uses, when an object is destructured
|
|
426
|
+
// in this case we assume the parameter is supposed to be bound using "v-bind"
|
|
427
|
+
// Therefore we only return one special key "v-bind" and the getter will be called afterwards with it
|
|
428
|
+
ownKeys: () => {
|
|
429
|
+
return [`v-bind`];
|
|
430
|
+
},
|
|
431
|
+
/** called when destructured */
|
|
432
|
+
getOwnPropertyDescriptor: () => ({
|
|
433
|
+
configurable: true,
|
|
434
|
+
enumerable: true,
|
|
435
|
+
value: param,
|
|
436
|
+
writable: true,
|
|
437
|
+
}),
|
|
438
|
+
},
|
|
391
439
|
);
|
|
392
440
|
});
|
|
393
441
|
|
|
394
|
-
|
|
442
|
+
const returnValue = child(proxied);
|
|
443
|
+
const slotSourceCode = generateSlotChildrenSourceCode([returnValue], ctx);
|
|
444
|
+
|
|
445
|
+
// if slot bindings are used for properties of other components, our {{ paramName }} is incorrect because
|
|
446
|
+
// it would generate e.g. my-prop="{{ paramName }}", therefore, we replace it here to e.g. :my-prop="paramName"
|
|
447
|
+
return replaceAll(slotSourceCode, / (\S+)="{{ (\S+) }}"/g, ` :$1="$2"`);
|
|
395
448
|
}
|
|
396
449
|
|
|
397
450
|
case "bigint":
|