@wix/himalaya-cli 0.1237.0 → 0.1238.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/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +8 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +16 -1
- package/dist/cli.mjs +207 -30
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/component-reference.json +1 -1
- package/guides/component-reference.md +11 -1
- package/guides/designing-himi-screens.md +33 -2
- package/guides/recipe-four-state.md +21 -8
- package/package.json +2 -2
|
@@ -192,6 +192,14 @@ export declare function emptyState(props: {
|
|
|
192
192
|
actionId: string;
|
|
193
193
|
params?: Record<string, string>;
|
|
194
194
|
};
|
|
195
|
+
/** Required with `action` (#3846) — the CTA label; there is no default. */
|
|
196
|
+
actionLabel?: string;
|
|
197
|
+
/** `typography` token names (#3846). Defaults: "bodyEmphasis" / "caption". */
|
|
198
|
+
titleStyle?: string;
|
|
199
|
+
subtitleStyle?: string;
|
|
200
|
+
/** The CTA Button's `style` / `size` (#3846). Defaults: "secondary" / "sm". */
|
|
201
|
+
actionStyle?: "primary" | "secondary" | "plain";
|
|
202
|
+
actionSize?: "sm" | "md";
|
|
195
203
|
}): Component;
|
|
196
204
|
export declare function appIntent(pkg: string, type: string, props: unknown, opts?: {
|
|
197
205
|
id?: string;
|
package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts
CHANGED
|
@@ -549,13 +549,28 @@ export interface CollapsingHeaderProps {
|
|
|
549
549
|
/** 0.0 = static, 1.0 = full parallax (default 0.5). */
|
|
550
550
|
parallaxFactor?: number;
|
|
551
551
|
}
|
|
552
|
+
/**
|
|
553
|
+
* The ONE standard empty state: a centred stack of icon tile, title, subtitle and
|
|
554
|
+
* button, in that order. Only `title` is required; an absent part draws nothing and keeps
|
|
555
|
+
* no gap. Padding and gaps come from the `spacing` tokens, text from `typography`.
|
|
556
|
+
*/
|
|
552
557
|
export interface EmptyStateProps {
|
|
553
558
|
title: string;
|
|
554
559
|
subtitle?: string;
|
|
555
560
|
icon?: IconRef;
|
|
561
|
+
/** The CTA. Drawn as a real `Button` (see `actionStyle` / `actionSize`). */
|
|
556
562
|
action?: Action;
|
|
557
|
-
/** #1059 — CTA label
|
|
563
|
+
/** #1059 — CTA label, also its accessibility label. REQUIRED when `action` is set:
|
|
564
|
+
* there is no default, `himi validate` reports an error, and no button is drawn. */
|
|
558
565
|
actionLabel?: string;
|
|
566
|
+
/** `typography` token for the title. Default `"bodyEmphasis"`. */
|
|
567
|
+
titleStyle?: string;
|
|
568
|
+
/** `typography` token for the subtitle. Default `"caption"`. */
|
|
569
|
+
subtitleStyle?: string;
|
|
570
|
+
/** The CTA's Button `style`. Default `"secondary"`. */
|
|
571
|
+
actionStyle?: "primary" | "secondary" | "plain";
|
|
572
|
+
/** The CTA's Button `size`. Default `"sm"`. */
|
|
573
|
+
actionSize?: "sm" | "md";
|
|
559
574
|
}
|
|
560
575
|
export interface InterpolatedText {
|
|
561
576
|
template: string;
|
package/dist/cli.mjs
CHANGED
|
@@ -10413,6 +10413,41 @@ function mediaFieldFindings(descriptor) {
|
|
|
10413
10413
|
visit(descriptor, "", true);
|
|
10414
10414
|
return out2;
|
|
10415
10415
|
}
|
|
10416
|
+
function emptyStateFindings(descriptor) {
|
|
10417
|
+
const out2 = [];
|
|
10418
|
+
const visit = (v2, path2, atRoot) => {
|
|
10419
|
+
if (Array.isArray(v2)) {
|
|
10420
|
+
v2.forEach((x2, i2) => visit(x2, `${path2}[${i2}]`, false));
|
|
10421
|
+
return;
|
|
10422
|
+
}
|
|
10423
|
+
if (!v2 || typeof v2 !== "object") return;
|
|
10424
|
+
const record2 = v2;
|
|
10425
|
+
const body = record2.body;
|
|
10426
|
+
if (body?.package === "himalaya" && body.type === "EmptyState") {
|
|
10427
|
+
const p2 = body.props ?? {};
|
|
10428
|
+
const base = path2 ? `${path2}.body.props` : "body.props";
|
|
10429
|
+
const label2 = p2.actionLabel;
|
|
10430
|
+
if (p2.action != null && (typeof label2 !== "string" || label2.trim() === "")) {
|
|
10431
|
+
out2.push({
|
|
10432
|
+
path: `${base}.actionLabel`,
|
|
10433
|
+
message: "EmptyState.action is set but EmptyState.actionLabel is missing. There is no default label: the renderers draw no button, so the action is unreachable. Set `actionLabel` to the button text (it is also the accessibility label), or remove `action`"
|
|
10434
|
+
});
|
|
10435
|
+
}
|
|
10436
|
+
if (p2.actionStyle !== void 0 && !(typeof p2.actionStyle === "string" && EMPTY_STATE_ACTION_STYLES.has(p2.actionStyle))) {
|
|
10437
|
+
out2.push({ path: `${base}.actionStyle`, message: `EmptyState.actionStyle must be "primary", "secondary" or "plain", got ${JSON.stringify(p2.actionStyle)}` });
|
|
10438
|
+
}
|
|
10439
|
+
if (p2.actionSize !== void 0 && !(typeof p2.actionSize === "string" && EMPTY_STATE_ACTION_SIZES.has(p2.actionSize))) {
|
|
10440
|
+
out2.push({ path: `${base}.actionSize`, message: `EmptyState.actionSize must be "sm" or "md", got ${JSON.stringify(p2.actionSize)}` });
|
|
10441
|
+
}
|
|
10442
|
+
}
|
|
10443
|
+
for (const [key2, child] of Object.entries(record2)) {
|
|
10444
|
+
if (isOpaqueAuthorJson(key2, child, atRoot)) continue;
|
|
10445
|
+
visit(child, path2 ? `${path2}.${key2}` : key2, false);
|
|
10446
|
+
}
|
|
10447
|
+
};
|
|
10448
|
+
visit(descriptor, "", true);
|
|
10449
|
+
return out2;
|
|
10450
|
+
}
|
|
10416
10451
|
function richTextFieldFindings(descriptor) {
|
|
10417
10452
|
const out2 = [];
|
|
10418
10453
|
const visit = (v2, path2, atRoot) => {
|
|
@@ -10552,6 +10587,9 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
10552
10587
|
for (const finding of richTextFieldFindings(descriptor)) {
|
|
10553
10588
|
issues.push({ severity: "error", pass: "rich-text-field", path: finding.path, message: finding.message });
|
|
10554
10589
|
}
|
|
10590
|
+
for (const finding of emptyStateFindings(descriptor)) {
|
|
10591
|
+
issues.push({ severity: "error", pass: "empty-state", path: finding.path, message: finding.message });
|
|
10592
|
+
}
|
|
10555
10593
|
const bindings = collectServiceBindings(descriptor);
|
|
10556
10594
|
const descriptorActions = collectDescriptorActions(descriptor);
|
|
10557
10595
|
const workerActions = descriptorActions.filter(({ actionId }) => actionId.startsWith("tier5."));
|
|
@@ -11049,7 +11087,7 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
11049
11087
|
services: Object.keys(services)
|
|
11050
11088
|
};
|
|
11051
11089
|
}
|
|
11052
|
-
var CRAWL_BLOCKING_PASSES, BOOT_EVAL_TIMEOUT_MS, DRIFT_PROBES, DEVICE_PARITY_WITHHELD, defaultEvaluator, bootEvaluator, actionEvaluator, NATIVE_PROP_ENUMS, KNOWN_PROPS, IN_ARRAY_BINDING_PROPS, SERVICE_SIGIL, INTEGER_PROPS, NATIVE_REQUIRED_PROPS, bareNestedClass, NATIVE_NESTED_CLASSES, NATIVE_MODIFIERS_CLASS, NATIVE_DESCRIPTOR_CLASS, NATIVE_DESCRIPTOR_NESTED, NATIVE_NESTED_PROPS, MODIFIER_KEYS, INTEGER_MODIFIERS, MODIFIER_KINDS, SCHEMA_SCORED_NODES, CORE_PACKAGES, LEGACY_UNSCORED_KEYS, DYNAMIC_PLACEHOLDER, LITERAL_ONLY_PROPS, SERVICE_ONLY_BINDING_PROPS, WHOLE_VALUE_BINDING, EMBEDDED_BINDING, OPTIONS_BINDING_PROPS, EDITOR_SERVICE_NAME;
|
|
11090
|
+
var CRAWL_BLOCKING_PASSES, BOOT_EVAL_TIMEOUT_MS, DRIFT_PROBES, DEVICE_PARITY_WITHHELD, defaultEvaluator, bootEvaluator, actionEvaluator, NATIVE_PROP_ENUMS, KNOWN_PROPS, IN_ARRAY_BINDING_PROPS, SERVICE_SIGIL, INTEGER_PROPS, NATIVE_REQUIRED_PROPS, bareNestedClass, NATIVE_NESTED_CLASSES, NATIVE_MODIFIERS_CLASS, NATIVE_DESCRIPTOR_CLASS, NATIVE_DESCRIPTOR_NESTED, NATIVE_NESTED_PROPS, MODIFIER_KEYS, INTEGER_MODIFIERS, MODIFIER_KINDS, SCHEMA_SCORED_NODES, CORE_PACKAGES, LEGACY_UNSCORED_KEYS, DYNAMIC_PLACEHOLDER, LITERAL_ONLY_PROPS, SERVICE_ONLY_BINDING_PROPS, WHOLE_VALUE_BINDING, EMBEDDED_BINDING, OPTIONS_BINDING_PROPS, EDITOR_SERVICE_NAME, EMPTY_STATE_ACTION_STYLES, EMPTY_STATE_ACTION_SIZES;
|
|
11053
11091
|
var init_validate_descriptor_core = __esm({
|
|
11054
11092
|
"../../core/dev-server/src/validate-descriptor.core.ts"() {
|
|
11055
11093
|
init_validator();
|
|
@@ -11275,7 +11313,17 @@ var init_validate_descriptor_core = __esm({
|
|
|
11275
11313
|
slicesPath: "string",
|
|
11276
11314
|
thickness: "number"
|
|
11277
11315
|
},
|
|
11278
|
-
EmptyState: {
|
|
11316
|
+
EmptyState: {
|
|
11317
|
+
action: "any",
|
|
11318
|
+
actionLabel: "string",
|
|
11319
|
+
actionSize: "string",
|
|
11320
|
+
actionStyle: "string",
|
|
11321
|
+
icon: "string",
|
|
11322
|
+
subtitle: "string",
|
|
11323
|
+
subtitleStyle: "string",
|
|
11324
|
+
title: "string",
|
|
11325
|
+
titleStyle: "string"
|
|
11326
|
+
},
|
|
11279
11327
|
Fab: { action: "any", icon: "string", label: "string", size: "string", tint: "string" },
|
|
11280
11328
|
FieldError: { severity: "string", text: "string", textPath: "string", visible: "boolean" },
|
|
11281
11329
|
FilterChips: {
|
|
@@ -12006,6 +12054,8 @@ var init_validate_descriptor_core = __esm({
|
|
|
12006
12054
|
EMBEDDED_BINDING = /\$service:[A-Za-z0-9_-]+\.[A-Za-z0-9_.[\]]+|\$flag:[A-Za-z0-9_.-]+|\$t:[A-Za-z0-9_.-]+|\$item(?:\.[A-Za-z0-9_.[\]]+)?/;
|
|
12007
12055
|
OPTIONS_BINDING_PROPS = /* @__PURE__ */ new Set(["optionsPath"]);
|
|
12008
12056
|
EDITOR_SERVICE_NAME = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
12057
|
+
EMPTY_STATE_ACTION_STYLES = /* @__PURE__ */ new Set(["primary", "secondary", "plain"]);
|
|
12058
|
+
EMPTY_STATE_ACTION_SIZES = /* @__PURE__ */ new Set(["sm", "md"]);
|
|
12009
12059
|
}
|
|
12010
12060
|
});
|
|
12011
12061
|
|
|
@@ -18048,6 +18098,73 @@ var init_icon2 = __esm({
|
|
|
18048
18098
|
}
|
|
18049
18099
|
});
|
|
18050
18100
|
|
|
18101
|
+
// ../native-config/watch-companion.ts
|
|
18102
|
+
function watchMode(mode) {
|
|
18103
|
+
if (mode === void 0 || mode === "standalone") return "standalone";
|
|
18104
|
+
if (mode === "companion") return "companion";
|
|
18105
|
+
throw new Error(`native-config: watch.mode must be "standalone" or "companion", got "${mode}"`);
|
|
18106
|
+
}
|
|
18107
|
+
function parseIosBundleId(configTs) {
|
|
18108
|
+
return /\bbundleId\s*:\s*["']([^"']+)["']/.exec(configTs)?.[1];
|
|
18109
|
+
}
|
|
18110
|
+
function companionWatchBundleId(iosBundleId) {
|
|
18111
|
+
return `${iosBundleId}.watchkitapp`;
|
|
18112
|
+
}
|
|
18113
|
+
function requireIosBundleId(iosBundleId) {
|
|
18114
|
+
if (!iosBundleId) {
|
|
18115
|
+
throw new Error(`native-config: watch.mode "companion" needs the app's iOS bundleId in config.ts \u2014 the watch app is paired to it`);
|
|
18116
|
+
}
|
|
18117
|
+
return iosBundleId;
|
|
18118
|
+
}
|
|
18119
|
+
function watchPairingInfo(mode, iosBundleId) {
|
|
18120
|
+
if (mode === "standalone") return { WKWatchOnly: true };
|
|
18121
|
+
return {
|
|
18122
|
+
WKCompanionAppBundleIdentifier: requireIosBundleId(iosBundleId),
|
|
18123
|
+
// The watch still launches and renders its last/baked content with the phone out of reach.
|
|
18124
|
+
WKRunsIndependentlyOfCompanionApp: true
|
|
18125
|
+
};
|
|
18126
|
+
}
|
|
18127
|
+
function watchSettingsPlan(mode, iosBundleId, standaloneBundleId) {
|
|
18128
|
+
if (mode === "standalone") {
|
|
18129
|
+
return standaloneBundleId ? { INFOPLIST_KEY_WKWatchOnly: "YES", PRODUCT_BUNDLE_IDENTIFIER: standaloneBundleId } : { INFOPLIST_KEY_WKWatchOnly: "YES" };
|
|
18130
|
+
}
|
|
18131
|
+
return { PRODUCT_BUNDLE_IDENTIFIER: companionWatchBundleId(requireIosBundleId(iosBundleId)) };
|
|
18132
|
+
}
|
|
18133
|
+
function watchTargetBundleId(watchProjectYml) {
|
|
18134
|
+
return /^\s{4}bundleId:\s*(\S+)\s*$/m.exec(watchProjectYml)?.[1];
|
|
18135
|
+
}
|
|
18136
|
+
function watchProjectName(watchProjectYml) {
|
|
18137
|
+
return /^name:\s*(\S+)\s*$/m.exec(watchProjectYml)?.[1];
|
|
18138
|
+
}
|
|
18139
|
+
function watchProjectReferenceLines(mode, watchName) {
|
|
18140
|
+
if (mode === "standalone") return [];
|
|
18141
|
+
return [
|
|
18142
|
+
"projectReferences:",
|
|
18143
|
+
` ${WATCH_PROJECT_REF}:`,
|
|
18144
|
+
` path: ../watchos/${watchName}.xcodeproj`
|
|
18145
|
+
];
|
|
18146
|
+
}
|
|
18147
|
+
function watchEmbedLines(mode, watchName) {
|
|
18148
|
+
if (mode === "standalone") return [];
|
|
18149
|
+
return [
|
|
18150
|
+
`- target: ${WATCH_PROJECT_REF}/${watchName}`,
|
|
18151
|
+
" embed: true",
|
|
18152
|
+
" codeSign: false",
|
|
18153
|
+
" copy:",
|
|
18154
|
+
" destination: productsDirectory",
|
|
18155
|
+
" subpath: $(CONTENTS_FOLDER_PATH)/Watch"
|
|
18156
|
+
];
|
|
18157
|
+
}
|
|
18158
|
+
var LABEL_WATCH_SETTINGS, LABEL_WATCH_PROJECT, LABEL_WATCH_EMBED, WATCH_PROJECT_REF;
|
|
18159
|
+
var init_watch_companion = __esm({
|
|
18160
|
+
"../native-config/watch-companion.ts"() {
|
|
18161
|
+
LABEL_WATCH_SETTINGS = "himalaya:watch:settings";
|
|
18162
|
+
LABEL_WATCH_PROJECT = "himalaya:watch:project";
|
|
18163
|
+
LABEL_WATCH_EMBED = "himalaya:watch:embed";
|
|
18164
|
+
WATCH_PROJECT_REF = "Watch";
|
|
18165
|
+
}
|
|
18166
|
+
});
|
|
18167
|
+
|
|
18051
18168
|
// ../native-config/live-activity.ts
|
|
18052
18169
|
function liveWidgetSource(deferredActions) {
|
|
18053
18170
|
const supportedIds = deferredActions ? "[.refresh, .markRead]" : "[.refresh]";
|
|
@@ -18348,15 +18465,16 @@ function parseStringArray(configTs, field) {
|
|
|
18348
18465
|
return [...body.matchAll(/["']([^"']+)["']/g)].map((x2) => x2[1]);
|
|
18349
18466
|
}
|
|
18350
18467
|
function parseWatchConfig(configTs) {
|
|
18351
|
-
const block = /watch\s*[:=]\s*\{([^}]*)\}
|
|
18468
|
+
const block = /export\s+const\s+watch\s*=\s*\{([^}]*)\}/.exec(configTs) ?? [...configTs.matchAll(/\bwatch\s*[:=]\s*\{([^}]*)\}/g)].find((m2) => /\bmode\s*:/.test(m2[1]));
|
|
18352
18469
|
if (!block) return {};
|
|
18353
18470
|
const body = block[1];
|
|
18354
18471
|
const mode = /mode\s*:\s*["']([^"']+)["']/.exec(body)?.[1];
|
|
18355
18472
|
const serve = /serve\s*:\s*["']([^"']+)["']/.exec(body)?.[1];
|
|
18356
18473
|
return { mode, serve };
|
|
18357
18474
|
}
|
|
18358
|
-
function watchInfoPlan(watch2) {
|
|
18359
|
-
const
|
|
18475
|
+
function watchInfoPlan(watch2, iosBundleId) {
|
|
18476
|
+
const mode = watchMode(watch2.mode);
|
|
18477
|
+
const plan = { HimalayaWatchMode: mode, ...watchPairingInfo(mode, iosBundleId) };
|
|
18360
18478
|
if (watch2.serve) plan.HimalayaWatchServe = watch2.serve;
|
|
18361
18479
|
return plan;
|
|
18362
18480
|
}
|
|
@@ -18599,7 +18717,19 @@ function genNativeConfig(app, opts = {}) {
|
|
|
18599
18717
|
}
|
|
18600
18718
|
const macos = macosPlanFor(ids, withCopy(ov.macos));
|
|
18601
18719
|
const android = androidPlanFor(ids, ov.android);
|
|
18602
|
-
const
|
|
18720
|
+
const watchConfig = parseWatchConfig(configTs);
|
|
18721
|
+
const iosBundleId = parseIosBundleId(configTs);
|
|
18722
|
+
const watch2 = watchInfoPlan(watchConfig, iosBundleId);
|
|
18723
|
+
const watchYml = watchosProjectYml(app);
|
|
18724
|
+
const watchYmlText = existsSync26(watchYml) ? readFileSync26(watchYml, "utf8") : "";
|
|
18725
|
+
const watchSettings = watchSettingsPlan(watchMode(watchConfig.mode), iosBundleId, watchTargetBundleId(watchYmlText));
|
|
18726
|
+
const watchName = existsSync26(watchYml) ? watchProjectName(readFileSync26(watchYml, "utf8")) : void 0;
|
|
18727
|
+
const watchEmbedFor = (lines) => (indent) => {
|
|
18728
|
+
const mode = watchMode(watchConfig.mode);
|
|
18729
|
+
if (mode === "standalone") return [];
|
|
18730
|
+
if (!watchName) throw new Error(`${app}: watch.mode "companion" but ${watchYml} has no \`name:\` to embed`);
|
|
18731
|
+
return lines(mode, watchName).map((line) => indent + line);
|
|
18732
|
+
};
|
|
18603
18733
|
const tv = tvInfoPlan(parseTvConfig(configTs));
|
|
18604
18734
|
const orientation = parseOrientationEnvelope(configTs);
|
|
18605
18735
|
const carCategory = resolveCarCategory(parseCarConfig(configTs), app);
|
|
@@ -18641,6 +18771,10 @@ function genNativeConfig(app, opts = {}) {
|
|
|
18641
18771
|
// watchOS (RFC 0047): the watch runtime mode/serve, declared once in config.ts. A watch
|
|
18642
18772
|
// target opts in by adding the LABEL_WATCH markers; a file without them is skipped.
|
|
18643
18773
|
applyToFile(watchosProjectYml(app), "yaml", LABEL_WATCH, (i2) => renderPlistYaml(watch2, i2), check),
|
|
18774
|
+
applyToFile(watchosProjectYml(app), "yaml", LABEL_WATCH_SETTINGS, (i2) => renderPlistYaml(watchSettings, i2), check),
|
|
18775
|
+
// #3704 — the iOS half of a companion pair (project reference + embed into <App>.app/Watch).
|
|
18776
|
+
applyToFile(iosProjectYml(app), "yaml", LABEL_WATCH_PROJECT, watchEmbedFor(watchProjectReferenceLines), check),
|
|
18777
|
+
applyToFile(iosProjectYml(app), "yaml", LABEL_WATCH_EMBED, watchEmbedFor(watchEmbedLines), check),
|
|
18644
18778
|
// tvOS (RFC 0051): HimalayaTvMode managed block; skipped when markers absent.
|
|
18645
18779
|
applyToFile(tvosProjectYml(app), "yaml", LABEL_TV, (i2) => renderPlistYaml(tv, i2), check),
|
|
18646
18780
|
// Android TV (RFC 0051 WS7): Leanback features on the `*-tv` module; skipped when markers absent.
|
|
@@ -18705,6 +18839,7 @@ var init_gen_native_config = __esm({
|
|
|
18705
18839
|
init_paths2();
|
|
18706
18840
|
init_splash();
|
|
18707
18841
|
init_icon2();
|
|
18842
|
+
init_watch_companion();
|
|
18708
18843
|
init_live_activity();
|
|
18709
18844
|
init_car();
|
|
18710
18845
|
init_localweb();
|
|
@@ -116514,6 +116649,10 @@ function withExtras(name, render) {
|
|
|
116514
116649
|
Wrapped.displayName = name;
|
|
116515
116650
|
return Wrapped;
|
|
116516
116651
|
}
|
|
116652
|
+
function spacingToken(ctx, [name, fallback]) {
|
|
116653
|
+
const v2 = ctx.tokens?.spacing?.[name];
|
|
116654
|
+
return typeof v2 === "number" && Number.isFinite(v2) ? Math.max(0, v2) : fallback;
|
|
116655
|
+
}
|
|
116517
116656
|
function sheetTabStops(root) {
|
|
116518
116657
|
const all = Array.from(root.querySelectorAll(NATIVELY_TABBABLE)).filter((el2) => el2.tabIndex >= 0 && !el2.disabled && !el2.closest('[inert], [hidden], [aria-hidden="true"]'));
|
|
116519
116658
|
const ordered = all.filter((el2) => el2.tabIndex > 0).sort((a2, b2) => a2.tabIndex - b2.tabIndex);
|
|
@@ -117702,12 +117841,7 @@ function renderInner(node, ctx) {
|
|
|
117702
117841
|
return /* @__PURE__ */ jsx9("div", { style: { flex: 1 } });
|
|
117703
117842
|
}
|
|
117704
117843
|
case "EmptyState":
|
|
117705
|
-
return /* @__PURE__ */
|
|
117706
|
-
/* @__PURE__ */ jsx9("div", { style: { width: 46, height: 46, borderRadius: 13, background: C2("surfaceTertiary", "#eee"), display: "grid", placeItems: "center", margin: "0 auto 12px", color: C2("textSecondary", "#9aa2ad") }, children: iconSvg(props.icon, { size: 24 }) }),
|
|
117707
|
-
/* @__PURE__ */ jsx9("div", { style: { fontFamily: bodyFont(ctx), fontWeight: 600, fontSize: pxToRem(16), color: C2("textPrimary", "#111") }, children: asBoundText(props.title, ctx) || "Empty" }),
|
|
117708
|
-
props.subtitle && /* @__PURE__ */ jsx9("div", { style: { fontFamily: bodyFont(ctx), fontSize: pxToRem(13), color: C2("textSecondary", "#888"), marginTop: 3 }, children: txt(props.subtitle, ctx) }),
|
|
117709
|
-
actionTextButton(ctx, props.action, asBoundText(props.actionLabel, ctx) || "Take action", accentTextColor(ctx), { margin: "12px auto 0", textAlign: "center" })
|
|
117710
|
-
] });
|
|
117844
|
+
return /* @__PURE__ */ jsx9(EmptyStateNode, { props, ctx, wrap, nodeId: node.id });
|
|
117711
117845
|
// ───────────── atoms ─────────────
|
|
117712
117846
|
case "Text":
|
|
117713
117847
|
return /* @__PURE__ */ jsx9(TextNode, { props, ctx, wrap });
|
|
@@ -118130,7 +118264,7 @@ function renderInner(node, ctx) {
|
|
|
118130
118264
|
}
|
|
118131
118265
|
}
|
|
118132
118266
|
}
|
|
118133
|
-
var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, REVEAL_ON_FOCUS_ATTR, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids2, rowKidCtx, rowKids, staggeredKids, asTextL10n, asFinalTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, RichContentEditorNode, MediaFieldNode, WorkerSubtreeNode, RichContentNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, withRootStyle, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfDocumentCanvas, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, SELF_RENDERED_LEAF, ROLE_WHEN_NAMED, AUTHORED_ROLE, PENDING_RANGE, RANGE_ROLES, NODE_A11Y_ATTRS, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, TAP_ACTIVATOR_ATTR, TAP_GROUP_ATTR, VISUALLY_HIDDEN, NAME_SKIP_SELECTOR, activatorNameObservers, ACTIVATOR_STATE_ATTRS, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, ANIMATION_LEAF, LottieNode, RiveNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ACTIVITY_DEFAULT_NAME, ActivityIndicatorNode, NATIVELY_TABBABLE, BottomSheetNode, PRESENTED_OVERLAY_ATTR, PopoverNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, initialFocusScheduled, PRESENTED_SCOPE, focusRoots, A11yHintDescription, WebRenderer;
|
|
118267
|
+
var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, REVEAL_ON_FOCUS_ATTR, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids2, rowKidCtx, rowKids, staggeredKids, asTextL10n, asFinalTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, RichContentEditorNode, MediaFieldNode, WorkerSubtreeNode, RichContentNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, withRootStyle, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfDocumentCanvas, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, SELF_RENDERED_LEAF, ROLE_WHEN_NAMED, AUTHORED_ROLE, PENDING_RANGE, RANGE_ROLES, NODE_A11Y_ATTRS, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, TAP_ACTIVATOR_ATTR, TAP_GROUP_ATTR, VISUALLY_HIDDEN, NAME_SKIP_SELECTOR, activatorNameObservers, ACTIVATOR_STATE_ATTRS, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, ANIMATION_LEAF, LottieNode, RiveNode, AvatarNode, IconNode, EMPTY_STATE_SPACING, EmptyStateNode, ButtonNode, OtpInputNode, ProgressBarNode, ACTIVITY_DEFAULT_NAME, ActivityIndicatorNode, NATIVELY_TABBABLE, BottomSheetNode, PRESENTED_OVERLAY_ATTR, PopoverNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, initialFocusScheduled, PRESENTED_SCOPE, focusRoots, A11yHintDescription, WebRenderer;
|
|
118134
118268
|
var init_renderNode = __esm({
|
|
118135
118269
|
"../../core/web-renderer/src/renderNode.tsx"() {
|
|
118136
118270
|
"use strict";
|
|
@@ -120212,6 +120346,49 @@ var init_renderNode = __esm({
|
|
|
120212
120346
|
const a11y = described ? { role: "img", "aria-label": String(contentDescription), [SELF_RENDERED_LEAF]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [SELF_RENDERED_LEAF]: true, [ROLE_WHEN_NAMED]: "img" };
|
|
120213
120347
|
return /* @__PURE__ */ jsx9("span", { ...a11y, style: { display: "inline-grid", placeItems: "center", width: size + 6, height: size + 6, lineHeight: 1, flex: "none", ...wrap }, children: iconSvg(iconName, { size, color: C2(resolveScalarStatic(props.tint, ctx) ?? "textPrimary", "#636b78") }) });
|
|
120214
120348
|
});
|
|
120349
|
+
EMPTY_STATE_SPACING = {
|
|
120350
|
+
padding: ["lg", 16],
|
|
120351
|
+
iconGap: ["md", 12],
|
|
120352
|
+
subtitleGap: ["xs", 4],
|
|
120353
|
+
actionGap: ["lg", 16]
|
|
120354
|
+
};
|
|
120355
|
+
EmptyStateNode = withExtras("EmptyStateNode", ({ props, ctx, wrap, nodeId }) => {
|
|
120356
|
+
const C2 = ctx.color;
|
|
120357
|
+
const subtitleText = useBoundString(props.subtitle, ctx);
|
|
120358
|
+
const titleFont = ctx.font(typeof props.titleStyle === "string" && props.titleStyle ? props.titleStyle : "bodyEmphasis");
|
|
120359
|
+
const subtitleFont = ctx.font(typeof props.subtitleStyle === "string" && props.subtitleStyle ? props.subtitleStyle : "caption");
|
|
120360
|
+
const fontCss = (f2) => ({
|
|
120361
|
+
fontFamily: fontStack(f2.family, ctx.idiom),
|
|
120362
|
+
fontSize: f2.remSize,
|
|
120363
|
+
fontWeight: f2.weight,
|
|
120364
|
+
lineHeight: f2.line,
|
|
120365
|
+
letterSpacing: f2.letterSpacing
|
|
120366
|
+
});
|
|
120367
|
+
const hasIcon2 = typeof props.icon === "string" ? props.icon.length > 0 : props.icon != null;
|
|
120368
|
+
const hasSubtitle = subtitleText.trim().length > 0;
|
|
120369
|
+
const label2 = props.actionLabel;
|
|
120370
|
+
const hasAction = props.action != null && typeof label2 === "string" && label2.trim().length > 0;
|
|
120371
|
+
const padding = spacingToken(ctx, EMPTY_STATE_SPACING.padding);
|
|
120372
|
+
return /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", width: "100%", padding, boxSizing: "border-box", ...wrap }, children: [
|
|
120373
|
+
hasIcon2 && /* @__PURE__ */ jsx9("div", { "data-empty-state-part": "icon", "aria-hidden": "true", style: { width: 46, height: 46, borderRadius: 13, background: C2("surfaceTertiary", "#eee"), display: "grid", placeItems: "center", color: C2("textSecondary", "#9aa2ad"), flexShrink: 0 }, children: iconSvg(props.icon, { size: 24 }) }),
|
|
120374
|
+
/* @__PURE__ */ jsx9("div", { "data-empty-state-part": "title", style: { ...fontCss(titleFont), color: C2("textPrimary", "#111"), marginTop: hasIcon2 ? spacingToken(ctx, EMPTY_STATE_SPACING.iconGap) : 0, overflowWrap: "anywhere" }, children: txt(props.title, ctx) }),
|
|
120375
|
+
hasSubtitle && /* @__PURE__ */ jsx9("div", { "data-empty-state-part": "subtitle", style: { ...fontCss(subtitleFont), color: C2("textSecondary", "#888"), marginTop: spacingToken(ctx, EMPTY_STATE_SPACING.subtitleGap), overflowWrap: "anywhere" }, children: isBinding(props.subtitle) ? subtitleText : txt(props.subtitle, ctx) }),
|
|
120376
|
+
hasAction && /* @__PURE__ */ jsx9("div", { "data-empty-state-part": "action", style: { marginTop: spacingToken(ctx, EMPTY_STATE_SPACING.actionGap), display: "flex", justifyContent: "center" }, children: renderNode({
|
|
120377
|
+
id: `${nodeId ?? "empty_state"}.action`,
|
|
120378
|
+
body: {
|
|
120379
|
+
package: "himalaya",
|
|
120380
|
+
type: "Button",
|
|
120381
|
+
props: {
|
|
120382
|
+
title: label2,
|
|
120383
|
+
action: props.action,
|
|
120384
|
+
style: props.actionStyle ?? "secondary",
|
|
120385
|
+
size: props.actionSize ?? "sm",
|
|
120386
|
+
fullWidth: false
|
|
120387
|
+
}
|
|
120388
|
+
}
|
|
120389
|
+
}, { ...ctx, rowStretch: false }) })
|
|
120390
|
+
] });
|
|
120391
|
+
});
|
|
120215
120392
|
ButtonNode = withExtras("ButtonNode", ({ props, ctx, wrap }) => {
|
|
120216
120393
|
const C2 = ctx.color;
|
|
120217
120394
|
const boundTitle = useResolvedScalar(isBinding(props.title) ? props.title : void 0, ctx);
|
|
@@ -143473,23 +143650,23 @@ var init_preview_assets_generated = __esm({
|
|
|
143473
143650
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
143474
143651
|
init_preview_assets_format();
|
|
143475
143652
|
PREVIEW_ASSET_MANIFEST = [
|
|
143476
|
-
{ key: "assets/index-
|
|
143477
|
-
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset:
|
|
143478
|
-
{ key: "assets/pdfDocument-
|
|
143479
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
143480
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
143481
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
143482
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
143483
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
143484
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
143485
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
143486
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
143487
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
143488
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
143489
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
143490
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
143491
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
143492
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
143653
|
+
{ key: "assets/index-BZS8K4zM.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1192364, sha256: "50d2524148ee0aedb74e5e6a548f269eb75b4a289f7a1de101de410c01e60bf5" },
|
|
143654
|
+
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset: 1192372, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
|
|
143655
|
+
{ key: "assets/pdfDocument-PXxklXbm.js", contentType: "application/javascript; charset=utf-8", offset: 2509406, length: 489166, sha256: "6df079a4bd8eaa2ed5abfb4af8154f2a4c0b8283fb26e1ef2f1964c2d7b6d1ac" },
|
|
143656
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 2998572, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
143657
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3003182, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
143658
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3491766, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
143659
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3582690, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
143660
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3673674, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
143661
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3764654, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
143662
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 3855526, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
143663
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 3946506, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
143664
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4055142, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
143665
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4164226, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
143666
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4273274, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
143667
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4380974, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
143668
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 4469082, length: 4947, sha256: "ec96c9af3b4b5bf3113b3ef80c4a6f16b77f40e28903dd20813ce866207e145d" },
|
|
143669
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4474029, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
|
|
143493
143670
|
];
|
|
143494
143671
|
}
|
|
143495
143672
|
});
|
|
Binary file
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"category": "Core",
|
|
99
99
|
"propsType": "EmptyStateProps",
|
|
100
100
|
"bindings": [],
|
|
101
|
-
"propsSource": "export interface EmptyStateProps {\n title: string;\n subtitle?: string;\n icon?: IconRef;\n action?: Action;\n /** #1059 — CTA label
|
|
101
|
+
"propsSource": "export interface EmptyStateProps {\n title: string;\n subtitle?: string;\n icon?: IconRef;\n /** The CTA. Drawn as a real `Button` (see `actionStyle` / `actionSize`). */\n action?: Action;\n /** #1059 — CTA label, also its accessibility label. REQUIRED when `action` is set:\n * there is no default, `himi validate` reports an error, and no button is drawn. */\n actionLabel?: string;\n /** `typography` token for the title. Default `\"bodyEmphasis\"`. */\n titleStyle?: string;\n /** `typography` token for the subtitle. Default `\"caption\"`. */\n subtitleStyle?: string;\n /** The CTA's Button `style`. Default `\"secondary\"`. */\n actionStyle?: \"primary\" | \"secondary\" | \"plain\";\n /** The CTA's Button `size`. Default `\"sm\"`. */\n actionSize?: \"sm\" | \"md\";\n}"
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
"name": "Text",
|
|
@@ -396,9 +396,19 @@ export interface EmptyStateProps {
|
|
|
396
396
|
title: string;
|
|
397
397
|
subtitle?: string;
|
|
398
398
|
icon?: IconRef;
|
|
399
|
+
/** The CTA. Drawn as a real `Button` (see `actionStyle` / `actionSize`). */
|
|
399
400
|
action?: Action;
|
|
400
|
-
/** #1059 — CTA label
|
|
401
|
+
/** #1059 — CTA label, also its accessibility label. REQUIRED when `action` is set:
|
|
402
|
+
* there is no default, `himi validate` reports an error, and no button is drawn. */
|
|
401
403
|
actionLabel?: string;
|
|
404
|
+
/** `typography` token for the title. Default `"bodyEmphasis"`. */
|
|
405
|
+
titleStyle?: string;
|
|
406
|
+
/** `typography` token for the subtitle. Default `"caption"`. */
|
|
407
|
+
subtitleStyle?: string;
|
|
408
|
+
/** The CTA's Button `style`. Default `"secondary"`. */
|
|
409
|
+
actionStyle?: "primary" | "secondary" | "plain";
|
|
410
|
+
/** The CTA's Button `size`. Default `"sm"`. */
|
|
411
|
+
actionSize?: "sm" | "md";
|
|
402
412
|
}
|
|
403
413
|
```
|
|
404
414
|
|
|
@@ -331,7 +331,7 @@ to drive them:
|
|
|
331
331
|
| State | Compose with | Notes |
|
|
332
332
|
|---|---|---|
|
|
333
333
|
| **Loading** | `Skeleton` (shape of the eventual content) or `StatefulSection` / `ActivityIndicator` | Prefer a content-shaped `Skeleton` over a bare spinner — it previews the layout. The descriptor renders against the state-skeleton, then repaints as worker state lands. |
|
|
334
|
-
| **Empty** | `EmptyState` (`title`,
|
|
334
|
+
| **Empty** | `EmptyState` (`title`, optional `icon` / `subtitle`) **plus a directive action** (`action` + `actionLabel`) | An empty screen is an invitation to act, not a dead end. Give it the next step, for example `"actionLabel": "Add your first item"`. Use `EmptyState` for **every** empty state, so all empty states in the app have the same layout and style. See [Empty states](#empty-states-one-component-one-layout) below. |
|
|
335
335
|
| **Error** | `Banner` (or inline) **with a retry action** | Say what failed and offer recovery; never a blank screen or a raw error string. |
|
|
336
336
|
| **Loaded** | the real content | The one everyone remembers to build. |
|
|
337
337
|
|
|
@@ -340,12 +340,43 @@ Bind visibility to worker state with `hidden_path` (`$service:…`/`$item.` data
|
|
|
340
340
|
components precisely so states are first-class — use them. (Reproducing an existing app? Enumerate
|
|
341
341
|
every state the *original* shows; the same discipline applies to net-new screens.)
|
|
342
342
|
|
|
343
|
+
### Empty states: one component, one layout
|
|
344
|
+
|
|
345
|
+
`EmptyState` draws one standard layout on iOS, Android, macOS and web. Do not build an empty
|
|
346
|
+
state by hand from `Icon`, `Text` and `Button` nodes.
|
|
347
|
+
|
|
348
|
+
- The layout is a centred vertical stack, in this order: icon tile, title, subtitle, button.
|
|
349
|
+
- Only `title` is required. `icon`, `subtitle` and the button are optional. A missing part
|
|
350
|
+
takes no space.
|
|
351
|
+
- The title uses the `typography` token in `titleStyle`. The default is `bodyEmphasis`.
|
|
352
|
+
- The subtitle uses the `typography` token in `subtitleStyle`. The default is `caption`.
|
|
353
|
+
- The padding and the gaps come from the `spacing` tokens `lg`, `md` and `xs`.
|
|
354
|
+
- The button is a real `Button`. It uses the app's button tokens. Set `actionStyle`
|
|
355
|
+
(`primary`, `secondary` or `plain`) and `actionSize` (`sm` or `md`). The defaults are
|
|
356
|
+
`secondary` and `sm`.
|
|
357
|
+
- `actionLabel` is the button text and its accessibility label. It has no default. If you set
|
|
358
|
+
`action` without `actionLabel`, `himi validate` shows an error and no button is drawn.
|
|
359
|
+
|
|
360
|
+
```jsonc
|
|
361
|
+
{ "id": "saved.empty",
|
|
362
|
+
"body": { "package": "himalaya", "type": "EmptyState",
|
|
363
|
+
"props": { "icon": "bookmark", "title": "No saved items",
|
|
364
|
+
"subtitle": "Save a product to see it here.", "subtitleStyle": "footnoteRegular",
|
|
365
|
+
"action": { "actionId": "himi.open", "params": { "screenId": "shop" } },
|
|
366
|
+
"actionLabel": "Browse products" } },
|
|
367
|
+
"modifiers": { "hiddenPath": "$service:saved.notEmpty" } }
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
To show the empty state only when the list is empty, bind `hiddenPath` to a worker boolean
|
|
371
|
+
(see `himi docs recipe-four-state`). Write the title and the subtitle as literal copy or as
|
|
372
|
+
`$t:` keys. Today, iOS and Android do not resolve a `$service:` binding in `title` or `subtitle`.
|
|
373
|
+
|
|
343
374
|
**Loading & empty states are first-class — use the `Skeleton` and `EmptyState` component types.**
|
|
344
375
|
|
|
345
376
|
There is **no builder-DSL package** — the `@wix/himalaya` umbrella exposes `./core`, `./state`,
|
|
346
377
|
`wix-*`, … but no `skRect` / `emptyBlock` helpers. Author these states as the **raw descriptor
|
|
347
378
|
nodes** `himi init` scaffolds: a `Skeleton` node for loading, and an `EmptyState` node (`icon` +
|
|
348
|
-
`title`/`subtitle` +
|
|
379
|
+
`title`/`subtitle` + `action` with its `actionLabel`) for empty. Run `himi components EmptyState` /
|
|
349
380
|
`himi components Skeleton` for the exact props. Written as raw nodes, these states ship over the
|
|
350
381
|
air and render on every current binary.
|
|
351
382
|
|
|
@@ -5,7 +5,8 @@ from **one flat layout** — no conditional trees, no separate loading screen. T
|
|
|
5
5
|
worker computes a **display string per state** (non-empty only in its state) and
|
|
6
6
|
the descriptor binds each to a `Text` with `collapseWhenEmpty: true`. Sections
|
|
7
7
|
that must fully appear/disappear gate with the `hiddenWhen`/`hiddenPath` modifier
|
|
8
|
-
bound to a worker boolean.
|
|
8
|
+
bound to a worker boolean. The empty state is always an `EmptyState` node, gated
|
|
9
|
+
the same way.
|
|
9
10
|
|
|
10
11
|
This is the corpus norm: of the in-repo worker bundles, ~3 in 4 model loading,
|
|
11
12
|
more than half model error, and the reference apps (`apps/himi-owner-lite`,
|
|
@@ -19,8 +20,8 @@ interface State {
|
|
|
19
20
|
status: "loading" | "ready" | "error";
|
|
20
21
|
items: Row[];
|
|
21
22
|
loadingText: string; // "Loading…" only while loading
|
|
22
|
-
emptyText: string; // "No products yet." only when ready + 0 rows
|
|
23
23
|
error: string; // the message only when failed
|
|
24
|
+
notEmpty: boolean; // gates the EmptyState (hiddenPath hides when TRUE)
|
|
24
25
|
notErrored: boolean; // gates the Retry button (hiddenPath hides when TRUE)
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -30,24 +31,29 @@ function shape(s: Partial<State>): State {
|
|
|
30
31
|
return {
|
|
31
32
|
status, items,
|
|
32
33
|
loadingText: status === "loading" ? "Loading products…" : "",
|
|
33
|
-
emptyText: status === "ready" && items.length === 0 ? "No products in this store yet." : "",
|
|
34
34
|
error: s.error ?? "",
|
|
35
|
+
notEmpty: !(status === "ready" && items.length === 0),
|
|
35
36
|
notErrored: status !== "error",
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
Route **every** state change through `shape()` — set `status` + raw data, let it
|
|
41
|
-
recompute the strings. Hand-maintaining
|
|
42
|
-
up loading-and-errored at once.
|
|
42
|
+
recompute the strings and flags. Hand-maintaining them per action is how screens
|
|
43
|
+
end up loading-and-errored at once.
|
|
43
44
|
|
|
44
|
-
## 2. The descriptor: one
|
|
45
|
+
## 2. The descriptor: one node per state + a gated Retry
|
|
45
46
|
|
|
46
47
|
```jsonc
|
|
47
48
|
{ "id": "loading", "…Text": { "text": "$service:products.loadingText",
|
|
48
49
|
"color": "textSecondary", "collapseWhenEmpty": true } },
|
|
49
|
-
{ "id": "empty",
|
|
50
|
-
|
|
50
|
+
{ "id": "empty",
|
|
51
|
+
"body": { "package": "himalaya", "type": "EmptyState",
|
|
52
|
+
"props": { "icon": "bag", "title": "No products in this store yet",
|
|
53
|
+
"subtitle": "Add a product to see it here.",
|
|
54
|
+
"action": { "actionId": "tier5.products.create" },
|
|
55
|
+
"actionLabel": "Add your first product" } },
|
|
56
|
+
"modifiers": { "hiddenPath": "$service:products.notEmpty" } },
|
|
51
57
|
{ "id": "error", "…Text": { "text": "$service:products.error",
|
|
52
58
|
"color": "danger", "collapseWhenEmpty": true } },
|
|
53
59
|
{ "id": "retry",
|
|
@@ -64,6 +70,13 @@ up loading-and-errored at once.
|
|
|
64
70
|
the binding reads without negation.
|
|
65
71
|
- Ready state is simply the data itself (the list rows, the detail fields) — it
|
|
66
72
|
needs no dedicated marker.
|
|
73
|
+
- **Use `EmptyState` for every empty state.** It draws one standard layout on
|
|
74
|
+
every platform: icon, title, subtitle and button, with type and gaps from the
|
|
75
|
+
app's tokens. Only `title` is required. `actionLabel` is required when you set
|
|
76
|
+
`action`: there is no default label, and `himi validate` reports a missing one.
|
|
77
|
+
- Write the `EmptyState` title and subtitle as literal copy or `$t:` keys. Today,
|
|
78
|
+
iOS and Android do not resolve a `$service:` binding in those props, so gate the
|
|
79
|
+
node with `hiddenPath` instead of binding its text.
|
|
67
80
|
|
|
68
81
|
## 3. Which state when
|
|
69
82
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1238.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"artifactId": "himalaya-cli"
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
"falconPackageHash": "
|
|
70
|
+
"falconPackageHash": "fa100c156434113a7befa8bdb97c6f87ee57d27d3e088aa3b2a9752c"
|
|
71
71
|
}
|