@yahoo/uds-create-config 5.68.1 → 5.68.2
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/dist/framework/anatomy-check.d.ts +11 -3
- package/dist/framework/anatomy-check.js +42 -1
- package/dist/framework/render-spec.js +22 -8
- package/dist/renderer/wrapRegistry.js +5 -1
- package/dist/renderer/wrappers/component-refs.d.ts +4 -1
- package/dist/renderer/wrappers/component-refs.js +20 -6
- package/dist/renderer/wrappers/html-aliases.d.ts +4 -0
- package/dist/renderer/wrappers/html-aliases.js +6 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* them.
|
|
12
12
|
*
|
|
13
13
|
* Two ways in. {@link snapshotHtml} reads the markup `react-dom/server` produces, which is what
|
|
14
|
-
* `uds anatomy` compares in a Bun process — structure, text
|
|
14
|
+
* `uds anatomy` compares in a Bun process — structure, text, classes, inline style and a plain tag's
|
|
15
|
+
* attributes, since no layout runs there.
|
|
15
16
|
* A browser surface snapshots live DOM instead (the studio's `?anatomyCheck=true`), and adds computed
|
|
16
17
|
* style to each node; {@link diffRendered} compares whatever a node carries.
|
|
17
18
|
*/
|
|
@@ -34,10 +35,17 @@ interface RenderedNode {
|
|
|
34
35
|
readonly style: Readonly<Record<string, string>>;
|
|
35
36
|
/** `true` when `style` holds inline declarations rather than a computed subset. */
|
|
36
37
|
readonly inlineStyle?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* A plain tag's attributes — an element that is no component's layer, such as an svg `<path>`,
|
|
40
|
+
* whose attributes are often its paint (`fill-opacity`, `stroke-width`, `d`). Left out for a layer,
|
|
41
|
+
* whose attributes come from its component, and where the snapshot can't read them. See
|
|
42
|
+
* {@link paintAttributesOf} for what is skipped.
|
|
43
|
+
*/
|
|
44
|
+
readonly attributes?: Readonly<Record<string, string>>;
|
|
37
45
|
/** What the alignment matches on — see {@link renderedSignatureOf}. */
|
|
38
46
|
readonly signature: string;
|
|
39
47
|
}
|
|
40
|
-
type AnatomyIssueKind = /** The module renders this element and the anatomy does not. */'missing' /** The anatomy renders this element and the module does not. */ | 'extra' /** Both render it — aligned as the same layer — as different elements (`div` against `span`). */ | 'tag' /** Both render it, with different own text. */ | 'text' /** Both render it, with a computed style that differs beyond tolerance. */ | 'style'
|
|
48
|
+
type AnatomyIssueKind = /** The module renders this element and the anatomy does not. */'missing' /** The anatomy renders this element and the module does not. */ | 'extra' /** Both render it — aligned as the same layer — as different elements (`div` against `span`). */ | 'tag' /** Both render it, with different own text. */ | 'text' /** Both render it as a plain tag, with an attribute that differs or that one side lacks. */ | 'attribute' /** Both render it, with a computed style that differs beyond tolerance. */ | 'style'
|
|
41
49
|
/** Both render it, with different class sets. Classes are how a style arrives, so where a
|
|
42
50
|
* computed style is available this is informational; where none is (markup only) it is the
|
|
43
51
|
* paint difference itself — see `diffRendered`'s `classesFail`. */
|
|
@@ -90,7 +98,7 @@ interface DiffOptions {
|
|
|
90
98
|
*
|
|
91
99
|
* Elements align by signature in document order; what the module renders and the anatomy does not
|
|
92
100
|
* is `missing`, the reverse is `extra`. Aligned elements then compare own text, computed style (when
|
|
93
|
-
* both sides carry it) and class set.
|
|
101
|
+
* both sides carry it), a plain tag's attributes (when both sides carry them) and class set.
|
|
94
102
|
*/
|
|
95
103
|
declare function diffRendered(anatomy: readonly RenderedNode[], instance: readonly RenderedNode[], options?: DiffOptions): AnatomyReport;
|
|
96
104
|
/** The allowlist spelling of an issue: kind, node, and the property for a style difference. */
|
|
@@ -161,6 +161,31 @@ function ownTextOf(element) {
|
|
|
161
161
|
for (const child of element.children) if ("text" in child) text += child.text;
|
|
162
162
|
return text.replace(/\s+/g, " ").trim();
|
|
163
163
|
}
|
|
164
|
+
/** Attributes that name an id rather than paint: React mints ids per render, so the two sides differ. */
|
|
165
|
+
const ID_ATTRIBUTES = new Set([
|
|
166
|
+
"id",
|
|
167
|
+
"for",
|
|
168
|
+
"aria-activedescendant",
|
|
169
|
+
"aria-controls",
|
|
170
|
+
"aria-describedby",
|
|
171
|
+
"aria-labelledby",
|
|
172
|
+
"aria-owns"
|
|
173
|
+
]);
|
|
174
|
+
/**
|
|
175
|
+
* The attributes of a plain tag that the two renderings should agree on: every one but `class` and
|
|
176
|
+
* `style` (compared on their own), `data-*` (markers), and what names an id — an id attribute, or a
|
|
177
|
+
* value pointing at one (`url(#…)`, `#…`).
|
|
178
|
+
*/
|
|
179
|
+
function paintAttributesOf(attributes) {
|
|
180
|
+
const out = {};
|
|
181
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
182
|
+
if (name === "class" || name === "style" || name.startsWith("data-")) continue;
|
|
183
|
+
if (ID_ATTRIBUTES.has(name)) continue;
|
|
184
|
+
if (value.includes("url(#") || value.startsWith("#")) continue;
|
|
185
|
+
out[name] = value;
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
164
189
|
function firstComponentRoot(node) {
|
|
165
190
|
for (const child of node.children) {
|
|
166
191
|
if ("text" in child) continue;
|
|
@@ -190,6 +215,7 @@ function snapshotHtml(html) {
|
|
|
190
215
|
classes: (element.attributes.class ?? "").split(/\s+/).filter(Boolean).sort(),
|
|
191
216
|
style: inlineStyleOf(element.attributes.style),
|
|
192
217
|
inlineStyle: true,
|
|
218
|
+
...component === void 0 ? { attributes: paintAttributesOf(element.attributes) } : {},
|
|
193
219
|
signature: renderedSignatureOf(element.tag, component, layer)
|
|
194
220
|
});
|
|
195
221
|
for (const child of element.children) if (!("text" in child)) visit(child);
|
|
@@ -255,7 +281,7 @@ function nodeLabel(node, ordinal) {
|
|
|
255
281
|
*
|
|
256
282
|
* Elements align by signature in document order; what the module renders and the anatomy does not
|
|
257
283
|
* is `missing`, the reverse is `extra`. Aligned elements then compare own text, computed style (when
|
|
258
|
-
* both sides carry it) and class set.
|
|
284
|
+
* both sides carry it), a plain tag's attributes (when both sides carry them) and class set.
|
|
259
285
|
*/
|
|
260
286
|
function diffRendered(anatomy, instance, options = {}) {
|
|
261
287
|
const issues = [];
|
|
@@ -310,6 +336,21 @@ function diffRendered(anatomy, instance, options = {}) {
|
|
|
310
336
|
instance: vb === void 0 ? void 0 : normalizeStyleValue(vb)
|
|
311
337
|
});
|
|
312
338
|
}
|
|
339
|
+
if (a.attributes && b.attributes) {
|
|
340
|
+
const names = [...new Set([...Object.keys(a.attributes), ...Object.keys(b.attributes)])].sort();
|
|
341
|
+
for (const name of names) {
|
|
342
|
+
const va = a.attributes[name];
|
|
343
|
+
const vb = b.attributes[name];
|
|
344
|
+
if (va === vb) continue;
|
|
345
|
+
issues.push({
|
|
346
|
+
kind: "attribute",
|
|
347
|
+
node: label,
|
|
348
|
+
property: name,
|
|
349
|
+
anatomy: va,
|
|
350
|
+
instance: vb
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
313
354
|
const onlyA = a.classes.filter((c) => !b.classes.includes(c));
|
|
314
355
|
const onlyB = b.classes.filter((c) => !a.classes.includes(c));
|
|
315
356
|
if (onlyA.length || onlyB.length) issues.push({
|
|
@@ -975,6 +975,7 @@ function slotTargets(config, path, body) {
|
|
|
975
975
|
}
|
|
976
976
|
function computeSlotTargets(config, body) {
|
|
977
977
|
const byLayer = /* @__PURE__ */ new Map();
|
|
978
|
+
const targeted = /* @__PURE__ */ new Map();
|
|
978
979
|
const untargeted = [];
|
|
979
980
|
for (const [from, decl] of Object.entries(body.props ?? {})) {
|
|
980
981
|
if (decl?.type === "slot") {
|
|
@@ -988,11 +989,15 @@ function computeSlotTargets(config, body) {
|
|
|
988
989
|
if (decl?.type !== "forward") continue;
|
|
989
990
|
if (!routesContent(config, body.layers, decl)) continue;
|
|
990
991
|
const target = refOf(decl.target);
|
|
991
|
-
if (target)
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
992
|
+
if (target) {
|
|
993
|
+
const layer = pathOf(target);
|
|
994
|
+
const route = {
|
|
995
|
+
...decl,
|
|
996
|
+
from
|
|
997
|
+
};
|
|
998
|
+
byLayer.set(layer, route);
|
|
999
|
+
targeted.set(layer, [...(targeted.get(layer) ?? []).filter((other) => intoName(other.into) !== intoName(route.into)), route]);
|
|
1000
|
+
} else untargeted.push({
|
|
996
1001
|
...decl,
|
|
997
1002
|
from,
|
|
998
1003
|
untargeted: true
|
|
@@ -1003,6 +1008,7 @@ function computeSlotTargets(config, body) {
|
|
|
1003
1008
|
if (root && content && !byLayer.has(root)) byLayer.set(root, content);
|
|
1004
1009
|
return {
|
|
1005
1010
|
byLayer,
|
|
1011
|
+
targeted,
|
|
1006
1012
|
untargeted
|
|
1007
1013
|
};
|
|
1008
1014
|
}
|
|
@@ -1024,9 +1030,9 @@ function computeSlotTargets(config, body) {
|
|
|
1024
1030
|
function slotTargetsOf(config, path) {
|
|
1025
1031
|
const body = bodyOf(config, path);
|
|
1026
1032
|
if (!body) return [];
|
|
1027
|
-
const {
|
|
1033
|
+
const { targeted: targetedByLayer, untargeted } = slotTargets(config, path, body);
|
|
1028
1034
|
const root = rootKeyOf(body.layers ?? {});
|
|
1029
|
-
return [...[...
|
|
1035
|
+
return [...[...targetedByLayer].flatMap(([layer, routes]) => routes.map((decl) => [layer, decl])).map(([layer, decl]) => ({
|
|
1030
1036
|
layer,
|
|
1031
1037
|
from: decl.from,
|
|
1032
1038
|
into: intoName(decl.into)
|
|
@@ -1288,7 +1294,7 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1288
1294
|
...Object.fromEntries(Object.entries(pins).map(([key, value]) => key.startsWith("_") ? [key, value === true || value === "true"] : [key, value]))
|
|
1289
1295
|
};
|
|
1290
1296
|
const consumed = consumedProps(config, path, body);
|
|
1291
|
-
const { byLayer: targets } = slotTargets(config, path, body);
|
|
1297
|
+
const { byLayer: targets, targeted: targetedRoutes } = slotTargets(config, path, body);
|
|
1292
1298
|
const valueRoutes = /* @__PURE__ */ new Map();
|
|
1293
1299
|
for (const route of valueForwards(config, body)) {
|
|
1294
1300
|
const routes = valueRoutes.get(route.layer) ?? [];
|
|
@@ -1331,6 +1337,7 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1331
1337
|
let contentPlaced = false;
|
|
1332
1338
|
const routedFroms = /* @__PURE__ */ new Set();
|
|
1333
1339
|
for (const target of targets.values()) routedFroms.add(target.from);
|
|
1340
|
+
for (const routes of targetedRoutes.values()) for (const route of routes) routedFroms.add(route.from);
|
|
1334
1341
|
const positioned = /* @__PURE__ */ new Set();
|
|
1335
1342
|
for (const node of Object.values(anatomy)) {
|
|
1336
1343
|
const prop = slotAnatomyPropOf(node);
|
|
@@ -1428,6 +1435,8 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1428
1435
|
}
|
|
1429
1436
|
const slot = layer ? targets.get(layer) : void 0;
|
|
1430
1437
|
const slotValue = slot && !subtreeBinds(anatomy, key, slot.from) && !(positioned.has(slot.from) && isText(instanceProps[slot.from])) ? instanceProps[slot.from] : void 0;
|
|
1438
|
+
const siblingRoutes = layer ? (targetedRoutes.get(layer) ?? []).filter((route) => route !== slot) : [];
|
|
1439
|
+
const siblingValues = Object.fromEntries(siblingRoutes.filter((route) => instanceProps[route.from] !== void 0 && !subtreeBinds(anatomy, key, route.from)).map((route) => [intoName(route.into), instanceProps[route.from]]));
|
|
1431
1440
|
const props = layer ? {
|
|
1432
1441
|
...withoutKeys(authoredProps(config, node.props), ruleKeysFor(config, path, layer, state, pins)),
|
|
1433
1442
|
"data-uds-component": path,
|
|
@@ -1438,6 +1447,7 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1438
1447
|
...isRoot ? componentStateAttributes(componentStates(config, path), state) : {},
|
|
1439
1448
|
...isRoot || type === void 0 || kindOf(type) !== "component" ? forcedModifierAttributes(pins, path) : {},
|
|
1440
1449
|
...isRoot ? rest : {},
|
|
1450
|
+
...siblingValues,
|
|
1441
1451
|
...slot && slotValue !== void 0 ? { [intoName(slot.into)]: slotValue } : {},
|
|
1442
1452
|
...layerProps[layer],
|
|
1443
1453
|
className: classesFor(config, path, layer, state, [
|
|
@@ -1513,6 +1523,10 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1513
1523
|
if (placedFills.length) slots[name] = placedFills;
|
|
1514
1524
|
}
|
|
1515
1525
|
if (overridden && routed) slots[overridden] = [...routed];
|
|
1526
|
+
for (const route of siblingRoutes) {
|
|
1527
|
+
const fills = instanceSlots?.[route.from];
|
|
1528
|
+
if (fills?.length) slots[intoName(route.into)] = [...fills];
|
|
1529
|
+
}
|
|
1516
1530
|
if (routed?.length && !overridden && !(slot && positioned.has(slot.from))) children.push(...routed);
|
|
1517
1531
|
const placed = place(nested, type, props, children, keyHint, Object.keys(slots).length ? slots : void 0);
|
|
1518
1532
|
if (visible === void 0) withCondition(nested, placed, { visible: node.visible });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FragmentRenderer } from "./primitives/FragmentRenderer.js";
|
|
2
2
|
import { SlotRenderer } from "./primitives/SlotRenderer.js";
|
|
3
|
+
import { glyphMemberFor } from "../spec/glyph-members.js";
|
|
3
4
|
import { wrapComponentRefs } from "./wrappers/component-refs.js";
|
|
4
5
|
import { wrapEventBridge } from "./wrappers/event-bridge.js";
|
|
5
6
|
import { wrapGlyphProps } from "./wrappers/glyph-props.js";
|
|
@@ -28,7 +29,10 @@ function wrapRegistry(reg, descriptor, iconMembers) {
|
|
|
28
29
|
};
|
|
29
30
|
const stylePropNames = descriptor?.stylePropClasses ? new Set([...Object.keys(descriptor.stylePropClasses), ...Object.values(descriptor.cssPropertyToStyleProp ?? {})]) : void 0;
|
|
30
31
|
const holder = {};
|
|
31
|
-
const final = aliasHtmlTypes(wrapInlineStyleProps(wrapNormalizeHex(wrapEventBridge(wrapGlyphProps(wrapComponentRefs(base, (type) => holder.registry?.[type]
|
|
32
|
+
const final = aliasHtmlTypes(wrapInlineStyleProps(wrapNormalizeHex(wrapEventBridge(wrapGlyphProps(wrapComponentRefs(base, (type) => holder.registry?.[type], iconMembers ? (ref) => glyphMemberFor({
|
|
33
|
+
ref,
|
|
34
|
+
members: iconMembers
|
|
35
|
+
}) : void 0), descriptor?.glyphProps, iconMembers)), stylePropNames), {
|
|
32
36
|
cssPropertyToStyleProp: descriptor?.cssPropertyToStyleProp,
|
|
33
37
|
layoutComponents: descriptor?.layoutComponents,
|
|
34
38
|
textComponents: descriptor?.textComponents
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ComponentRegistry, ComponentRenderer } from '@json-render/react';
|
|
2
|
+
import { type PreviewRef } from '../../spec/preview-elements';
|
|
2
3
|
/**
|
|
3
4
|
* A component handed as a prop VALUE (`icon={DotsThreeIcon}`) crosses the config as a bare ref,
|
|
4
5
|
* `{ __ref: 'icon:phosphor/DotsThreeIcon' }`, keyed the way the registry keys the component. This
|
|
@@ -11,4 +12,6 @@ import type { ComponentRegistry, ComponentRenderer } from '@json-render/react';
|
|
|
11
12
|
* like any spec element. One component per ref, so the receiving component's element type is stable
|
|
12
13
|
* across renders and React keeps the glyph mounted.
|
|
13
14
|
*/
|
|
14
|
-
export declare function wrapComponentRefs(reg: ComponentRegistry, resolve: (type: string) => ComponentRenderer | undefined
|
|
15
|
+
export declare function wrapComponentRefs(reg: ComponentRegistry, resolve: (type: string) => ComponentRenderer | undefined,
|
|
16
|
+
/** The member an `icon:` ref names, for a glyph nested inside a prop's data. */
|
|
17
|
+
glyphOf?: (ref: PreviewRef) => unknown): ComponentRegistry;
|
|
@@ -20,14 +20,24 @@ function hasRefDeep(value) {
|
|
|
20
20
|
if (isComponentRef(value)) return true;
|
|
21
21
|
return (Array.isArray(value) ? value : Object.values(value)).some(hasRefDeep);
|
|
22
22
|
}
|
|
23
|
-
function reviveDeep(value, revive) {
|
|
23
|
+
function reviveDeep({ value, revive, glyphOf, nested = false }) {
|
|
24
24
|
if (typeof value !== "object" || value === null) return value;
|
|
25
25
|
if ("$$typeof" in value) return value;
|
|
26
26
|
if (isPreviewElement(value)) return value;
|
|
27
|
-
if (isComponentRef(value)) return revive(value);
|
|
28
|
-
if (Array.isArray(value)) return value.map((item) => reviveDeep(
|
|
27
|
+
if (isComponentRef(value)) return (nested ? glyphOf?.(value) : void 0) ?? revive(value);
|
|
28
|
+
if (Array.isArray(value)) return value.map((item) => reviveDeep({
|
|
29
|
+
value: item,
|
|
30
|
+
revive,
|
|
31
|
+
glyphOf,
|
|
32
|
+
nested: true
|
|
33
|
+
}));
|
|
29
34
|
const out = {};
|
|
30
|
-
for (const [key, member] of Object.entries(value)) out[key] = reviveDeep(
|
|
35
|
+
for (const [key, member] of Object.entries(value)) out[key] = reviveDeep({
|
|
36
|
+
value: member,
|
|
37
|
+
revive,
|
|
38
|
+
glyphOf,
|
|
39
|
+
nested: true
|
|
40
|
+
});
|
|
31
41
|
return out;
|
|
32
42
|
}
|
|
33
43
|
/**
|
|
@@ -42,7 +52,7 @@ function reviveDeep(value, revive) {
|
|
|
42
52
|
* like any spec element. One component per ref, so the receiving component's element type is stable
|
|
43
53
|
* across renders and React keeps the glyph mounted.
|
|
44
54
|
*/
|
|
45
|
-
function wrapComponentRefs(reg, resolve) {
|
|
55
|
+
function wrapComponentRefs(reg, resolve, glyphOf) {
|
|
46
56
|
const revived = /* @__PURE__ */ new Map();
|
|
47
57
|
const revive = (ref) => {
|
|
48
58
|
const type = ref.__ref;
|
|
@@ -72,7 +82,11 @@ function wrapComponentRefs(reg, resolve) {
|
|
|
72
82
|
...renderProps,
|
|
73
83
|
element: {
|
|
74
84
|
...renderProps.element,
|
|
75
|
-
props:
|
|
85
|
+
props: Object.fromEntries(Object.entries(props).map(([name, value]) => [name, reviveDeep({
|
|
86
|
+
value,
|
|
87
|
+
revive,
|
|
88
|
+
glyphOf
|
|
89
|
+
})]))
|
|
76
90
|
}
|
|
77
91
|
});
|
|
78
92
|
};
|
|
@@ -5,6 +5,10 @@ import { ComponentRegistry } from "@json-render/react";
|
|
|
5
5
|
* Set to `true` on an intrinsic element whose props are the tag's own attributes. A style-prop key
|
|
6
6
|
* whose value names no class is then kept as the attribute rather than dropped, so a captured
|
|
7
7
|
* `<svg width={16}>` keeps its `width`. The key never reaches the DOM.
|
|
8
|
+
*
|
|
9
|
+
* An element a component's render placed inline (the anatomy marker, `data-uds-anatomy`) is one
|
|
10
|
+
* without the flag: its props are the JSX attributes the module renders as attributes, so a
|
|
11
|
+
* `<path fillOpacity={0}>` keeps its `fill-opacity` as the module does.
|
|
8
12
|
*/
|
|
9
13
|
declare const VERBATIM_ATTRIBUTES = "__verbatimAttributes";
|
|
10
14
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "../../framework/render-spec.js";
|
|
1
2
|
import { specContent } from "../spec-content.js";
|
|
2
3
|
import React from "react";
|
|
3
4
|
//#region src/renderer/wrappers/html-aliases.tsx
|
|
@@ -16,6 +17,10 @@ const FORBIDDEN_INTRINSIC_PROPS = new Set(["dangerouslySetInnerHTML"]);
|
|
|
16
17
|
* Set to `true` on an intrinsic element whose props are the tag's own attributes. A style-prop key
|
|
17
18
|
* whose value names no class is then kept as the attribute rather than dropped, so a captured
|
|
18
19
|
* `<svg width={16}>` keeps its `width`. The key never reaches the DOM.
|
|
20
|
+
*
|
|
21
|
+
* An element a component's render placed inline (the anatomy marker, `data-uds-anatomy`) is one
|
|
22
|
+
* without the flag: its props are the JSX attributes the module renders as attributes, so a
|
|
23
|
+
* `<path fillOpacity={0}>` keeps its `fill-opacity` as the module does.
|
|
19
24
|
*/
|
|
20
25
|
const VERBATIM_ATTRIBUTES = "__verbatimAttributes";
|
|
21
26
|
const NullEl = () => null;
|
|
@@ -43,7 +48,7 @@ function aliasHtmlTypes(reg, stylePropClasses) {
|
|
|
43
48
|
if (typeof prop === "string" && INTRINSIC_TAG_RE.test(prop)) {
|
|
44
49
|
const IntrinsicEl = ({ element, children, slots }) => {
|
|
45
50
|
const props = element.props;
|
|
46
|
-
const verbatim = props?.[
|
|
51
|
+
const verbatim = props?.["__verbatimAttributes"] === true || typeof props?.["data-uds-anatomy"] === "string";
|
|
47
52
|
const intrinsicProps = {};
|
|
48
53
|
const styleClasses = [];
|
|
49
54
|
for (const [key, value] of Object.entries(props ?? {})) {
|