@yahoo/uds-create-config 5.35.0 → 5.35.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/entities/system/Component.js +10 -5
- package/dist/entities/system/glyph-identity.js +70 -22
- package/dist/entities/system/style-bag.js +4 -3
- package/dist/framework/render-spec.d.ts +2 -1
- package/dist/framework/render-spec.js +20 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -664,10 +664,11 @@ function canonicalWhen(when) {
|
|
|
664
664
|
function styleBagValue({ config, declaration, name = "<prop>", glyphLibraries }) {
|
|
665
665
|
const domain = valueSchemaOf(declaration, config);
|
|
666
666
|
const bound = declaration?.value;
|
|
667
|
-
if (glyphLibraries && glyphLibraries.length > 0) return
|
|
667
|
+
if (glyphLibraries && glyphLibraries.length > 0) return glyphMemberRefIn({
|
|
668
668
|
config,
|
|
669
|
-
libraries: glyphLibraries
|
|
670
|
-
|
|
669
|
+
libraries: glyphLibraries,
|
|
670
|
+
otherwise: domain
|
|
671
|
+
});
|
|
671
672
|
if (declaration?.type === "slot" && !isValueSlot(declaration)) return z.union([domain, z.never()], { error: () => `\`${name}\` is a slot, so a rule may set it to a string of content and nothing else. A glyph or a nested element is an anatomy node under the layer's node — \`{ "element": { "__ref": "icon:<library>/<Name>" }, "visible": { "$state": "<prop>", "eq": "<value>" } }\` to show one per variant value — and the instance's own content arrives through the prop.` });
|
|
672
673
|
if (!isRef(bound) || kindOf(bound.__ref) !== "style-property") return domain;
|
|
673
674
|
const property = pathOf(bound.__ref);
|
|
@@ -1140,10 +1141,14 @@ const Preview = defineSubEntity({
|
|
|
1140
1141
|
for (const [name, decl] of Object.entries(body.states ?? {})) when[name] = stateConditionValue(decl).optional();
|
|
1141
1142
|
return z.strictObject({
|
|
1142
1143
|
when: z.strictObject(when, { error: previewShapeError }).nullable().default(null),
|
|
1143
|
-
props: z.record(z.string(), z.unknown()).transform((props) => bindPreviewGlyphs({
|
|
1144
|
+
props: z.record(z.string(), z.unknown()).transform((props, ctx) => bindPreviewGlyphs({
|
|
1144
1145
|
config,
|
|
1145
1146
|
props,
|
|
1146
|
-
glyphProps
|
|
1147
|
+
glyphProps,
|
|
1148
|
+
refuse: (message) => ctx.addIssue({
|
|
1149
|
+
code: "custom",
|
|
1150
|
+
message
|
|
1151
|
+
})
|
|
1147
1152
|
}))
|
|
1148
1153
|
}, { error: previewShapeError });
|
|
1149
1154
|
}
|
|
@@ -173,15 +173,55 @@ function glyphOfLibrary({ library, module, leaves }) {
|
|
|
173
173
|
return identity.name;
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
|
+
/** Why a string under a glyph key is refused: it names no member of the libraries the key reaches. */
|
|
177
|
+
function notAMember({ spelled, libraries }) {
|
|
178
|
+
return `\`${spelled}\` is not a member of ${libraries.map((library) => `the icon library "${library}"`).join(" or ")}, which this key draws from.`;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The member ref a written glyph name spells under `libraries`: the member's name (`StarIcon`), its
|
|
182
|
+
* path (`phosphor/StarIcon`) or its ref's spelling (`icon:phosphor/StarIcon`). A bare name resolves
|
|
183
|
+
* under the first listed library holding it, in the order the key's declaration names them.
|
|
184
|
+
* `undefined` when no listed library holds what the string names.
|
|
185
|
+
*/
|
|
186
|
+
function spelledGlyphRef({ config, libraries, spelled }) {
|
|
187
|
+
const colon = spelled.indexOf(":");
|
|
188
|
+
const path = colon !== -1 && spelled.slice(0, colon) === "icon" ? spelled.slice(colon + 1) : spelled;
|
|
189
|
+
for (const library of libraries) {
|
|
190
|
+
const name = path.startsWith(`${library}/`) ? path.slice(library.length + 1) : path;
|
|
191
|
+
if (memberLeaves(config, `icon:${library}`).includes(name)) return { __ref: `icon:${library}/${name}` };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
176
194
|
/**
|
|
177
|
-
* The glyph form for a key that reaches a library through a forward (`icon` → `icon/name`)
|
|
178
|
-
*
|
|
179
|
-
* config
|
|
180
|
-
*
|
|
181
|
-
*
|
|
195
|
+
* The glyph form for a key that reaches a library through a forward (`icon` → `icon/name`),
|
|
196
|
+
* answered as the member ref `icon:<library>/<name>`: the component, its `package:` ref, the member
|
|
197
|
+
* ref a stored config holds, or a string spelling a member ({@link spelledGlyphRef}). The ref names
|
|
198
|
+
* its library, so a key reaching several resolves without a lookup.
|
|
199
|
+
*
|
|
200
|
+
* Every string is answered here, so a string that names no member is refused rather than stored as
|
|
201
|
+
* text the receiving prop cannot draw. The empty string is the one exception: it is how a surface
|
|
202
|
+
* clears a glyph over a default, and passes through as written. Each library's component arm refuses
|
|
203
|
+
* by cause, so a glyph of a library the key does not reach says so. `otherwise` takes every value
|
|
204
|
+
* that is not a string.
|
|
182
205
|
*/
|
|
183
|
-
function glyphMemberRefIn({ config, libraries }) {
|
|
184
|
-
const
|
|
206
|
+
function glyphMemberRefIn({ config, libraries, otherwise }) {
|
|
207
|
+
const spelledArm = z.string().transform((spelled, ctx) => {
|
|
208
|
+
if (spelled === "") return spelled;
|
|
209
|
+
const ref = spelledGlyphRef({
|
|
210
|
+
config,
|
|
211
|
+
libraries,
|
|
212
|
+
spelled
|
|
213
|
+
});
|
|
214
|
+
if (ref) return ref;
|
|
215
|
+
ctx.addIssue({
|
|
216
|
+
code: "custom",
|
|
217
|
+
message: notAMember({
|
|
218
|
+
spelled,
|
|
219
|
+
libraries
|
|
220
|
+
})
|
|
221
|
+
});
|
|
222
|
+
return z.NEVER;
|
|
223
|
+
});
|
|
224
|
+
const componentArms = libraries.map((library) => {
|
|
185
225
|
const facts = libraryGlyphFacts({
|
|
186
226
|
config,
|
|
187
227
|
target: `icon:${library}`
|
|
@@ -193,14 +233,14 @@ function glyphMemberRefIn({ config, libraries }) {
|
|
|
193
233
|
const name = path.slice(library.length + 1);
|
|
194
234
|
return path.startsWith(`${library}/`) && facts.leaves.includes(name) ? name : void 0;
|
|
195
235
|
};
|
|
196
|
-
return z.union([
|
|
197
|
-
z.custom((value) => memberOfRef(value) !== void 0).transform((value) => toRef(memberOfRef(value))),
|
|
198
|
-
z.string().refine((name) => facts.leaves.includes(name)).transform(toRef),
|
|
199
|
-
glyphOfLibrary(facts).transform((name) => toRef(name))
|
|
200
|
-
]);
|
|
236
|
+
return z.union([z.custom((value) => memberOfRef(value) !== void 0).transform((value) => toRef(memberOfRef(value))), glyphOfLibrary(facts).transform((name) => toRef(name))]);
|
|
201
237
|
});
|
|
202
|
-
|
|
203
|
-
return z.union(
|
|
238
|
+
const nonString = z.custom((value) => typeof value !== "string").pipe(otherwise);
|
|
239
|
+
return z.union([
|
|
240
|
+
spelledArm,
|
|
241
|
+
...componentArms,
|
|
242
|
+
nonString
|
|
243
|
+
]);
|
|
204
244
|
}
|
|
205
245
|
/** `icon:<library>/<name>` for a glyph identity a library of this config claims; `undefined` when
|
|
206
246
|
* none does. */
|
|
@@ -218,11 +258,11 @@ function glyphMemberRefOf(config, identity) {
|
|
|
218
258
|
* way `defaultProps` are. Once an owner is known, this pass binds each such ref to
|
|
219
259
|
* `icon:<library>/<name>` through the library whose package ships it, at the top level and inside a
|
|
220
260
|
* stored element's props, which is the spelling the build writes when it reads `.preview()` from
|
|
221
|
-
* source. A
|
|
222
|
-
*
|
|
223
|
-
* package's export and stays as written.
|
|
261
|
+
* source. A string spelling a member under one of the owner's glyph props (`glyphProps`) binds
|
|
262
|
+
* through that prop's libraries ({@link spelledGlyphRef}), and one naming no member is refused. A
|
|
263
|
+
* `package:` ref no library claims is another package's export and stays as written.
|
|
224
264
|
*/
|
|
225
|
-
function bindPreviewGlyphs({ config, props, glyphProps = {} }) {
|
|
265
|
+
function bindPreviewGlyphs({ config, props, glyphProps = {}, refuse }) {
|
|
226
266
|
const bind = (value) => {
|
|
227
267
|
if (typeof value !== "object" || value === null) return value;
|
|
228
268
|
if (Array.isArray(value)) return value.map(bind);
|
|
@@ -234,10 +274,18 @@ function bindPreviewGlyphs({ config, props, glyphProps = {} }) {
|
|
|
234
274
|
};
|
|
235
275
|
const out = bind(props);
|
|
236
276
|
for (const [prop, libraries] of Object.entries(glyphProps)) {
|
|
237
|
-
const
|
|
238
|
-
if (typeof
|
|
239
|
-
const
|
|
240
|
-
|
|
277
|
+
const spelled = out[prop];
|
|
278
|
+
if (typeof spelled !== "string" || spelled === "") continue;
|
|
279
|
+
const ref = spelledGlyphRef({
|
|
280
|
+
config,
|
|
281
|
+
libraries,
|
|
282
|
+
spelled
|
|
283
|
+
});
|
|
284
|
+
if (ref) out[prop] = ref;
|
|
285
|
+
else refuse?.(notAMember({
|
|
286
|
+
spelled,
|
|
287
|
+
libraries
|
|
288
|
+
}));
|
|
241
289
|
}
|
|
242
290
|
return out;
|
|
243
291
|
}
|
|
@@ -59,10 +59,11 @@ const Style = defineSubEntity({
|
|
|
59
59
|
config,
|
|
60
60
|
body: parent
|
|
61
61
|
})[key];
|
|
62
|
-
if (libraries && libraries.length > 0) return
|
|
62
|
+
if (libraries && libraries.length > 0) return glyphMemberRefIn({
|
|
63
63
|
config,
|
|
64
|
-
libraries
|
|
65
|
-
|
|
64
|
+
libraries,
|
|
65
|
+
otherwise: styleValue
|
|
66
|
+
});
|
|
66
67
|
}
|
|
67
68
|
if (declared) return styleValue;
|
|
68
69
|
if (!config.resolve("style-property", key)) return styleValue;
|
|
@@ -389,7 +389,8 @@ declare function withoutTruthyTerm({
|
|
|
389
389
|
* rather than 51 conditioned siblings copying a library's index into every component that draws a
|
|
390
390
|
* glyph.
|
|
391
391
|
*
|
|
392
|
-
*
|
|
392
|
+
* A member ref (`icon:phosphor/StarIcon`), the form a glyph is stored in, names the type itself when
|
|
393
|
+
* its library is one the prop draws from ({@link memberRefType}). A name is looked up in the prop's domain, which is known two ways, in order: the prop delegates it (`value` is a ref to the library, or
|
|
393
394
|
* a list of refs for a host drawing from several, which is the shape that keeps 1,530 names in one
|
|
394
395
|
* place), or the prop enumerates its values and the member is found by asking which group declares
|
|
395
396
|
* it. The second exists because a config migrated from v1 spells an icon prop as an enumeration, and
|
|
@@ -869,18 +869,24 @@ function spentBy({ condition, prop }) {
|
|
|
869
869
|
* rather than 51 conditioned siblings copying a library's index into every component that draws a
|
|
870
870
|
* glyph.
|
|
871
871
|
*
|
|
872
|
-
*
|
|
872
|
+
* A member ref (`icon:phosphor/StarIcon`), the form a glyph is stored in, names the type itself when
|
|
873
|
+
* its library is one the prop draws from ({@link memberRefType}). A name is looked up in the prop's domain, which is known two ways, in order: the prop delegates it (`value` is a ref to the library, or
|
|
873
874
|
* a list of refs for a host drawing from several, which is the shape that keeps 1,530 names in one
|
|
874
875
|
* place), or the prop enumerates its values and the member is found by asking which group declares
|
|
875
876
|
* it. The second exists because a config migrated from v1 spells an icon prop as an enumeration, and
|
|
876
877
|
* a glyph is no less resolvable for it.
|
|
877
878
|
*/
|
|
878
879
|
function boundElementType(config, componentPath, prop, value) {
|
|
879
|
-
if (typeof value !== "string" || !value) return void 0;
|
|
880
|
-
if (value.includes("/")) return void 0;
|
|
881
880
|
const decl = resolveComponentProps(config, componentPath)[prop];
|
|
882
881
|
const single = refOf(decl?.value);
|
|
883
882
|
const targets = refListOf(decl?.value) ?? (single ? [single] : []);
|
|
883
|
+
if (isRef(value) && kindOf(value) === "icon") return memberRefType({
|
|
884
|
+
config,
|
|
885
|
+
targets,
|
|
886
|
+
value
|
|
887
|
+
});
|
|
888
|
+
if (typeof value !== "string" || !value) return void 0;
|
|
889
|
+
if (value.includes("/")) return void 0;
|
|
884
890
|
if (targets.length > 0) {
|
|
885
891
|
for (const target of targets) {
|
|
886
892
|
if (memberOf(target) !== void 0) continue;
|
|
@@ -893,6 +899,17 @@ function boundElementType(config, componentPath, prop, value) {
|
|
|
893
899
|
return matches.length === 1 ? `icon:${matches[0]?.path}` : void 0;
|
|
894
900
|
}
|
|
895
901
|
/**
|
|
902
|
+
* The type a member ref names, when the member exists and belongs to one of the prop's libraries
|
|
903
|
+
* (`targets`); a prop that delegates no domain takes any member the config holds. A ref outside
|
|
904
|
+
* them is `undefined`, so the node falls back as it does for a name no library holds.
|
|
905
|
+
*/
|
|
906
|
+
function memberRefType({ config, targets, value }) {
|
|
907
|
+
if (!config.resolveRef(value.__ref)) return void 0;
|
|
908
|
+
if (targets.length === 0) return value.__ref;
|
|
909
|
+
const path = pathOf(value);
|
|
910
|
+
return targets.some((target) => kindOf(target) === "icon" && memberOf(target) === void 0 && path.startsWith(`${pathOf(target)}/`)) ? value.__ref : void 0;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
896
913
|
* The props of an instance that the component CONSUMES rather than passes on — the same split the
|
|
897
914
|
* emitted module's destructuring makes (`downlevel.ts`, `styleRuleBindings`).
|
|
898
915
|
*
|