@wix/himalaya-cli 0.1237.0 → 0.1239.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 +208 -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
|
@@ -6878,6 +6878,7 @@ function resolveTranslation(value, catalog, sourceCatalog) {
|
|
|
6878
6878
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
6879
6879
|
var init_bindings = __esm({
|
|
6880
6880
|
"../../core/ts/src/bindings.ts"() {
|
|
6881
|
+
"use strict";
|
|
6881
6882
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
6882
6883
|
BINDING_SIGIL_RE = new RegExp(
|
|
6883
6884
|
`^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -10413,6 +10414,41 @@ function mediaFieldFindings(descriptor) {
|
|
|
10413
10414
|
visit(descriptor, "", true);
|
|
10414
10415
|
return out2;
|
|
10415
10416
|
}
|
|
10417
|
+
function emptyStateFindings(descriptor) {
|
|
10418
|
+
const out2 = [];
|
|
10419
|
+
const visit = (v2, path2, atRoot) => {
|
|
10420
|
+
if (Array.isArray(v2)) {
|
|
10421
|
+
v2.forEach((x2, i2) => visit(x2, `${path2}[${i2}]`, false));
|
|
10422
|
+
return;
|
|
10423
|
+
}
|
|
10424
|
+
if (!v2 || typeof v2 !== "object") return;
|
|
10425
|
+
const record2 = v2;
|
|
10426
|
+
const body = record2.body;
|
|
10427
|
+
if (body?.package === "himalaya" && body.type === "EmptyState") {
|
|
10428
|
+
const p2 = body.props ?? {};
|
|
10429
|
+
const base = path2 ? `${path2}.body.props` : "body.props";
|
|
10430
|
+
const label2 = p2.actionLabel;
|
|
10431
|
+
if (p2.action != null && (typeof label2 !== "string" || label2.trim() === "")) {
|
|
10432
|
+
out2.push({
|
|
10433
|
+
path: `${base}.actionLabel`,
|
|
10434
|
+
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`"
|
|
10435
|
+
});
|
|
10436
|
+
}
|
|
10437
|
+
if (p2.actionStyle !== void 0 && !(typeof p2.actionStyle === "string" && EMPTY_STATE_ACTION_STYLES.has(p2.actionStyle))) {
|
|
10438
|
+
out2.push({ path: `${base}.actionStyle`, message: `EmptyState.actionStyle must be "primary", "secondary" or "plain", got ${JSON.stringify(p2.actionStyle)}` });
|
|
10439
|
+
}
|
|
10440
|
+
if (p2.actionSize !== void 0 && !(typeof p2.actionSize === "string" && EMPTY_STATE_ACTION_SIZES.has(p2.actionSize))) {
|
|
10441
|
+
out2.push({ path: `${base}.actionSize`, message: `EmptyState.actionSize must be "sm" or "md", got ${JSON.stringify(p2.actionSize)}` });
|
|
10442
|
+
}
|
|
10443
|
+
}
|
|
10444
|
+
for (const [key2, child] of Object.entries(record2)) {
|
|
10445
|
+
if (isOpaqueAuthorJson(key2, child, atRoot)) continue;
|
|
10446
|
+
visit(child, path2 ? `${path2}.${key2}` : key2, false);
|
|
10447
|
+
}
|
|
10448
|
+
};
|
|
10449
|
+
visit(descriptor, "", true);
|
|
10450
|
+
return out2;
|
|
10451
|
+
}
|
|
10416
10452
|
function richTextFieldFindings(descriptor) {
|
|
10417
10453
|
const out2 = [];
|
|
10418
10454
|
const visit = (v2, path2, atRoot) => {
|
|
@@ -10552,6 +10588,9 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
10552
10588
|
for (const finding of richTextFieldFindings(descriptor)) {
|
|
10553
10589
|
issues.push({ severity: "error", pass: "rich-text-field", path: finding.path, message: finding.message });
|
|
10554
10590
|
}
|
|
10591
|
+
for (const finding of emptyStateFindings(descriptor)) {
|
|
10592
|
+
issues.push({ severity: "error", pass: "empty-state", path: finding.path, message: finding.message });
|
|
10593
|
+
}
|
|
10555
10594
|
const bindings = collectServiceBindings(descriptor);
|
|
10556
10595
|
const descriptorActions = collectDescriptorActions(descriptor);
|
|
10557
10596
|
const workerActions = descriptorActions.filter(({ actionId }) => actionId.startsWith("tier5."));
|
|
@@ -11049,7 +11088,7 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
11049
11088
|
services: Object.keys(services)
|
|
11050
11089
|
};
|
|
11051
11090
|
}
|
|
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;
|
|
11091
|
+
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
11092
|
var init_validate_descriptor_core = __esm({
|
|
11054
11093
|
"../../core/dev-server/src/validate-descriptor.core.ts"() {
|
|
11055
11094
|
init_validator();
|
|
@@ -11275,7 +11314,17 @@ var init_validate_descriptor_core = __esm({
|
|
|
11275
11314
|
slicesPath: "string",
|
|
11276
11315
|
thickness: "number"
|
|
11277
11316
|
},
|
|
11278
|
-
EmptyState: {
|
|
11317
|
+
EmptyState: {
|
|
11318
|
+
action: "any",
|
|
11319
|
+
actionLabel: "string",
|
|
11320
|
+
actionSize: "string",
|
|
11321
|
+
actionStyle: "string",
|
|
11322
|
+
icon: "string",
|
|
11323
|
+
subtitle: "string",
|
|
11324
|
+
subtitleStyle: "string",
|
|
11325
|
+
title: "string",
|
|
11326
|
+
titleStyle: "string"
|
|
11327
|
+
},
|
|
11279
11328
|
Fab: { action: "any", icon: "string", label: "string", size: "string", tint: "string" },
|
|
11280
11329
|
FieldError: { severity: "string", text: "string", textPath: "string", visible: "boolean" },
|
|
11281
11330
|
FilterChips: {
|
|
@@ -12006,6 +12055,8 @@ var init_validate_descriptor_core = __esm({
|
|
|
12006
12055
|
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
12056
|
OPTIONS_BINDING_PROPS = /* @__PURE__ */ new Set(["optionsPath"]);
|
|
12008
12057
|
EDITOR_SERVICE_NAME = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
12058
|
+
EMPTY_STATE_ACTION_STYLES = /* @__PURE__ */ new Set(["primary", "secondary", "plain"]);
|
|
12059
|
+
EMPTY_STATE_ACTION_SIZES = /* @__PURE__ */ new Set(["sm", "md"]);
|
|
12009
12060
|
}
|
|
12010
12061
|
});
|
|
12011
12062
|
|
|
@@ -18048,6 +18099,73 @@ var init_icon2 = __esm({
|
|
|
18048
18099
|
}
|
|
18049
18100
|
});
|
|
18050
18101
|
|
|
18102
|
+
// ../native-config/watch-companion.ts
|
|
18103
|
+
function watchMode(mode) {
|
|
18104
|
+
if (mode === void 0 || mode === "standalone") return "standalone";
|
|
18105
|
+
if (mode === "companion") return "companion";
|
|
18106
|
+
throw new Error(`native-config: watch.mode must be "standalone" or "companion", got "${mode}"`);
|
|
18107
|
+
}
|
|
18108
|
+
function parseIosBundleId(configTs) {
|
|
18109
|
+
return /\bbundleId\s*:\s*["']([^"']+)["']/.exec(configTs)?.[1];
|
|
18110
|
+
}
|
|
18111
|
+
function companionWatchBundleId(iosBundleId) {
|
|
18112
|
+
return `${iosBundleId}.watchkitapp`;
|
|
18113
|
+
}
|
|
18114
|
+
function requireIosBundleId(iosBundleId) {
|
|
18115
|
+
if (!iosBundleId) {
|
|
18116
|
+
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`);
|
|
18117
|
+
}
|
|
18118
|
+
return iosBundleId;
|
|
18119
|
+
}
|
|
18120
|
+
function watchPairingInfo(mode, iosBundleId) {
|
|
18121
|
+
if (mode === "standalone") return { WKWatchOnly: true };
|
|
18122
|
+
return {
|
|
18123
|
+
WKCompanionAppBundleIdentifier: requireIosBundleId(iosBundleId),
|
|
18124
|
+
// The watch still launches and renders its last/baked content with the phone out of reach.
|
|
18125
|
+
WKRunsIndependentlyOfCompanionApp: true
|
|
18126
|
+
};
|
|
18127
|
+
}
|
|
18128
|
+
function watchSettingsPlan(mode, iosBundleId, standaloneBundleId) {
|
|
18129
|
+
if (mode === "standalone") {
|
|
18130
|
+
return standaloneBundleId ? { INFOPLIST_KEY_WKWatchOnly: "YES", PRODUCT_BUNDLE_IDENTIFIER: standaloneBundleId } : { INFOPLIST_KEY_WKWatchOnly: "YES" };
|
|
18131
|
+
}
|
|
18132
|
+
return { PRODUCT_BUNDLE_IDENTIFIER: companionWatchBundleId(requireIosBundleId(iosBundleId)) };
|
|
18133
|
+
}
|
|
18134
|
+
function watchTargetBundleId(watchProjectYml) {
|
|
18135
|
+
return /^\s{4}bundleId:\s*(\S+)\s*$/m.exec(watchProjectYml)?.[1];
|
|
18136
|
+
}
|
|
18137
|
+
function watchProjectName(watchProjectYml) {
|
|
18138
|
+
return /^name:\s*(\S+)\s*$/m.exec(watchProjectYml)?.[1];
|
|
18139
|
+
}
|
|
18140
|
+
function watchProjectReferenceLines(mode, watchName) {
|
|
18141
|
+
if (mode === "standalone") return [];
|
|
18142
|
+
return [
|
|
18143
|
+
"projectReferences:",
|
|
18144
|
+
` ${WATCH_PROJECT_REF}:`,
|
|
18145
|
+
` path: ../watchos/${watchName}.xcodeproj`
|
|
18146
|
+
];
|
|
18147
|
+
}
|
|
18148
|
+
function watchEmbedLines(mode, watchName) {
|
|
18149
|
+
if (mode === "standalone") return [];
|
|
18150
|
+
return [
|
|
18151
|
+
`- target: ${WATCH_PROJECT_REF}/${watchName}`,
|
|
18152
|
+
" embed: true",
|
|
18153
|
+
" codeSign: false",
|
|
18154
|
+
" copy:",
|
|
18155
|
+
" destination: productsDirectory",
|
|
18156
|
+
" subpath: $(CONTENTS_FOLDER_PATH)/Watch"
|
|
18157
|
+
];
|
|
18158
|
+
}
|
|
18159
|
+
var LABEL_WATCH_SETTINGS, LABEL_WATCH_PROJECT, LABEL_WATCH_EMBED, WATCH_PROJECT_REF;
|
|
18160
|
+
var init_watch_companion = __esm({
|
|
18161
|
+
"../native-config/watch-companion.ts"() {
|
|
18162
|
+
LABEL_WATCH_SETTINGS = "himalaya:watch:settings";
|
|
18163
|
+
LABEL_WATCH_PROJECT = "himalaya:watch:project";
|
|
18164
|
+
LABEL_WATCH_EMBED = "himalaya:watch:embed";
|
|
18165
|
+
WATCH_PROJECT_REF = "Watch";
|
|
18166
|
+
}
|
|
18167
|
+
});
|
|
18168
|
+
|
|
18051
18169
|
// ../native-config/live-activity.ts
|
|
18052
18170
|
function liveWidgetSource(deferredActions) {
|
|
18053
18171
|
const supportedIds = deferredActions ? "[.refresh, .markRead]" : "[.refresh]";
|
|
@@ -18348,15 +18466,16 @@ function parseStringArray(configTs, field) {
|
|
|
18348
18466
|
return [...body.matchAll(/["']([^"']+)["']/g)].map((x2) => x2[1]);
|
|
18349
18467
|
}
|
|
18350
18468
|
function parseWatchConfig(configTs) {
|
|
18351
|
-
const block = /watch\s*[:=]\s*\{([^}]*)\}
|
|
18469
|
+
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
18470
|
if (!block) return {};
|
|
18353
18471
|
const body = block[1];
|
|
18354
18472
|
const mode = /mode\s*:\s*["']([^"']+)["']/.exec(body)?.[1];
|
|
18355
18473
|
const serve = /serve\s*:\s*["']([^"']+)["']/.exec(body)?.[1];
|
|
18356
18474
|
return { mode, serve };
|
|
18357
18475
|
}
|
|
18358
|
-
function watchInfoPlan(watch2) {
|
|
18359
|
-
const
|
|
18476
|
+
function watchInfoPlan(watch2, iosBundleId) {
|
|
18477
|
+
const mode = watchMode(watch2.mode);
|
|
18478
|
+
const plan = { HimalayaWatchMode: mode, ...watchPairingInfo(mode, iosBundleId) };
|
|
18360
18479
|
if (watch2.serve) plan.HimalayaWatchServe = watch2.serve;
|
|
18361
18480
|
return plan;
|
|
18362
18481
|
}
|
|
@@ -18599,7 +18718,19 @@ function genNativeConfig(app, opts = {}) {
|
|
|
18599
18718
|
}
|
|
18600
18719
|
const macos = macosPlanFor(ids, withCopy(ov.macos));
|
|
18601
18720
|
const android = androidPlanFor(ids, ov.android);
|
|
18602
|
-
const
|
|
18721
|
+
const watchConfig = parseWatchConfig(configTs);
|
|
18722
|
+
const iosBundleId = parseIosBundleId(configTs);
|
|
18723
|
+
const watch2 = watchInfoPlan(watchConfig, iosBundleId);
|
|
18724
|
+
const watchYml = watchosProjectYml(app);
|
|
18725
|
+
const watchYmlText = existsSync26(watchYml) ? readFileSync26(watchYml, "utf8") : "";
|
|
18726
|
+
const watchSettings = watchSettingsPlan(watchMode(watchConfig.mode), iosBundleId, watchTargetBundleId(watchYmlText));
|
|
18727
|
+
const watchName = existsSync26(watchYml) ? watchProjectName(readFileSync26(watchYml, "utf8")) : void 0;
|
|
18728
|
+
const watchEmbedFor = (lines) => (indent) => {
|
|
18729
|
+
const mode = watchMode(watchConfig.mode);
|
|
18730
|
+
if (mode === "standalone") return [];
|
|
18731
|
+
if (!watchName) throw new Error(`${app}: watch.mode "companion" but ${watchYml} has no \`name:\` to embed`);
|
|
18732
|
+
return lines(mode, watchName).map((line) => indent + line);
|
|
18733
|
+
};
|
|
18603
18734
|
const tv = tvInfoPlan(parseTvConfig(configTs));
|
|
18604
18735
|
const orientation = parseOrientationEnvelope(configTs);
|
|
18605
18736
|
const carCategory = resolveCarCategory(parseCarConfig(configTs), app);
|
|
@@ -18641,6 +18772,10 @@ function genNativeConfig(app, opts = {}) {
|
|
|
18641
18772
|
// watchOS (RFC 0047): the watch runtime mode/serve, declared once in config.ts. A watch
|
|
18642
18773
|
// target opts in by adding the LABEL_WATCH markers; a file without them is skipped.
|
|
18643
18774
|
applyToFile(watchosProjectYml(app), "yaml", LABEL_WATCH, (i2) => renderPlistYaml(watch2, i2), check),
|
|
18775
|
+
applyToFile(watchosProjectYml(app), "yaml", LABEL_WATCH_SETTINGS, (i2) => renderPlistYaml(watchSettings, i2), check),
|
|
18776
|
+
// #3704 — the iOS half of a companion pair (project reference + embed into <App>.app/Watch).
|
|
18777
|
+
applyToFile(iosProjectYml(app), "yaml", LABEL_WATCH_PROJECT, watchEmbedFor(watchProjectReferenceLines), check),
|
|
18778
|
+
applyToFile(iosProjectYml(app), "yaml", LABEL_WATCH_EMBED, watchEmbedFor(watchEmbedLines), check),
|
|
18644
18779
|
// tvOS (RFC 0051): HimalayaTvMode managed block; skipped when markers absent.
|
|
18645
18780
|
applyToFile(tvosProjectYml(app), "yaml", LABEL_TV, (i2) => renderPlistYaml(tv, i2), check),
|
|
18646
18781
|
// Android TV (RFC 0051 WS7): Leanback features on the `*-tv` module; skipped when markers absent.
|
|
@@ -18705,6 +18840,7 @@ var init_gen_native_config = __esm({
|
|
|
18705
18840
|
init_paths2();
|
|
18706
18841
|
init_splash();
|
|
18707
18842
|
init_icon2();
|
|
18843
|
+
init_watch_companion();
|
|
18708
18844
|
init_live_activity();
|
|
18709
18845
|
init_car();
|
|
18710
18846
|
init_localweb();
|
|
@@ -116514,6 +116650,10 @@ function withExtras(name, render) {
|
|
|
116514
116650
|
Wrapped.displayName = name;
|
|
116515
116651
|
return Wrapped;
|
|
116516
116652
|
}
|
|
116653
|
+
function spacingToken(ctx, [name, fallback]) {
|
|
116654
|
+
const v2 = ctx.tokens?.spacing?.[name];
|
|
116655
|
+
return typeof v2 === "number" && Number.isFinite(v2) ? Math.max(0, v2) : fallback;
|
|
116656
|
+
}
|
|
116517
116657
|
function sheetTabStops(root) {
|
|
116518
116658
|
const all = Array.from(root.querySelectorAll(NATIVELY_TABBABLE)).filter((el2) => el2.tabIndex >= 0 && !el2.disabled && !el2.closest('[inert], [hidden], [aria-hidden="true"]'));
|
|
116519
116659
|
const ordered = all.filter((el2) => el2.tabIndex > 0).sort((a2, b2) => a2.tabIndex - b2.tabIndex);
|
|
@@ -117702,12 +117842,7 @@ function renderInner(node, ctx) {
|
|
|
117702
117842
|
return /* @__PURE__ */ jsx9("div", { style: { flex: 1 } });
|
|
117703
117843
|
}
|
|
117704
117844
|
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
|
-
] });
|
|
117845
|
+
return /* @__PURE__ */ jsx9(EmptyStateNode, { props, ctx, wrap, nodeId: node.id });
|
|
117711
117846
|
// ───────────── atoms ─────────────
|
|
117712
117847
|
case "Text":
|
|
117713
117848
|
return /* @__PURE__ */ jsx9(TextNode, { props, ctx, wrap });
|
|
@@ -118130,7 +118265,7 @@ function renderInner(node, ctx) {
|
|
|
118130
118265
|
}
|
|
118131
118266
|
}
|
|
118132
118267
|
}
|
|
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;
|
|
118268
|
+
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
118269
|
var init_renderNode = __esm({
|
|
118135
118270
|
"../../core/web-renderer/src/renderNode.tsx"() {
|
|
118136
118271
|
"use strict";
|
|
@@ -120212,6 +120347,49 @@ var init_renderNode = __esm({
|
|
|
120212
120347
|
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
120348
|
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
120349
|
});
|
|
120350
|
+
EMPTY_STATE_SPACING = {
|
|
120351
|
+
padding: ["lg", 16],
|
|
120352
|
+
iconGap: ["md", 12],
|
|
120353
|
+
subtitleGap: ["xs", 4],
|
|
120354
|
+
actionGap: ["lg", 16]
|
|
120355
|
+
};
|
|
120356
|
+
EmptyStateNode = withExtras("EmptyStateNode", ({ props, ctx, wrap, nodeId }) => {
|
|
120357
|
+
const C2 = ctx.color;
|
|
120358
|
+
const subtitleText = useBoundString(props.subtitle, ctx);
|
|
120359
|
+
const titleFont = ctx.font(typeof props.titleStyle === "string" && props.titleStyle ? props.titleStyle : "bodyEmphasis");
|
|
120360
|
+
const subtitleFont = ctx.font(typeof props.subtitleStyle === "string" && props.subtitleStyle ? props.subtitleStyle : "caption");
|
|
120361
|
+
const fontCss = (f2) => ({
|
|
120362
|
+
fontFamily: fontStack(f2.family, ctx.idiom),
|
|
120363
|
+
fontSize: f2.remSize,
|
|
120364
|
+
fontWeight: f2.weight,
|
|
120365
|
+
lineHeight: f2.line,
|
|
120366
|
+
letterSpacing: f2.letterSpacing
|
|
120367
|
+
});
|
|
120368
|
+
const hasIcon2 = typeof props.icon === "string" ? props.icon.length > 0 : props.icon != null;
|
|
120369
|
+
const hasSubtitle = subtitleText.trim().length > 0;
|
|
120370
|
+
const label2 = props.actionLabel;
|
|
120371
|
+
const hasAction = props.action != null && typeof label2 === "string" && label2.trim().length > 0;
|
|
120372
|
+
const padding = spacingToken(ctx, EMPTY_STATE_SPACING.padding);
|
|
120373
|
+
return /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", width: "100%", padding, boxSizing: "border-box", ...wrap }, children: [
|
|
120374
|
+
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 }) }),
|
|
120375
|
+
/* @__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) }),
|
|
120376
|
+
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) }),
|
|
120377
|
+
hasAction && /* @__PURE__ */ jsx9("div", { "data-empty-state-part": "action", style: { marginTop: spacingToken(ctx, EMPTY_STATE_SPACING.actionGap), display: "flex", justifyContent: "center" }, children: renderNode({
|
|
120378
|
+
id: `${nodeId ?? "empty_state"}.action`,
|
|
120379
|
+
body: {
|
|
120380
|
+
package: "himalaya",
|
|
120381
|
+
type: "Button",
|
|
120382
|
+
props: {
|
|
120383
|
+
title: label2,
|
|
120384
|
+
action: props.action,
|
|
120385
|
+
style: props.actionStyle ?? "secondary",
|
|
120386
|
+
size: props.actionSize ?? "sm",
|
|
120387
|
+
fullWidth: false
|
|
120388
|
+
}
|
|
120389
|
+
}
|
|
120390
|
+
}, { ...ctx, rowStretch: false }) })
|
|
120391
|
+
] });
|
|
120392
|
+
});
|
|
120215
120393
|
ButtonNode = withExtras("ButtonNode", ({ props, ctx, wrap }) => {
|
|
120216
120394
|
const C2 = ctx.color;
|
|
120217
120395
|
const boundTitle = useResolvedScalar(isBinding(props.title) ? props.title : void 0, ctx);
|
|
@@ -143473,23 +143651,23 @@ var init_preview_assets_generated = __esm({
|
|
|
143473
143651
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
143474
143652
|
init_preview_assets_format();
|
|
143475
143653
|
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:
|
|
143654
|
+
{ key: "assets/index-BZS8K4zM.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1192364, sha256: "50d2524148ee0aedb74e5e6a548f269eb75b4a289f7a1de101de410c01e60bf5" },
|
|
143655
|
+
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset: 1192372, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
|
|
143656
|
+
{ key: "assets/pdfDocument-PXxklXbm.js", contentType: "application/javascript; charset=utf-8", offset: 2509406, length: 489166, sha256: "6df079a4bd8eaa2ed5abfb4af8154f2a4c0b8283fb26e1ef2f1964c2d7b6d1ac" },
|
|
143657
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 2998572, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
143658
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3003182, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
143659
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3491766, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
143660
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3582690, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
143661
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3673674, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
143662
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3764654, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
143663
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 3855526, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
143664
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 3946506, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
143665
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4055142, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
143666
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4164226, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
143667
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4273274, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
143668
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4380974, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
143669
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 4469082, length: 4947, sha256: "ec96c9af3b4b5bf3113b3ef80c4a6f16b77f40e28903dd20813ce866207e145d" },
|
|
143670
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4474029, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
|
|
143493
143671
|
];
|
|
143494
143672
|
}
|
|
143495
143673
|
});
|
|
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.1239.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": "7c4036664e3989c5654ed281a7f34ceaa99b28fc6c6747a6d4bcdc06"
|
|
71
71
|
}
|