@wix/himalaya-cli 0.1612.0 → 0.1614.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.
Files changed (35) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +5 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/ui/src/index.d.ts +53 -13
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +15 -1
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +4 -2
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/ui.mjs +31 -5
  6. package/dist/cli.mjs +2189 -1377
  7. package/dist/preview-assets.generated.bin +0 -0
  8. package/fixtures/wix-canned.json +4 -0
  9. package/guides/component-reference.json +7 -4
  10. package/guides/component-reference.md +16 -2
  11. package/guides/designing-himi-screens.md +4 -1
  12. package/guides/getting-started.md +3 -2
  13. package/guides/hhp.md +2 -2
  14. package/guides/himi-json-output.md +3 -0
  15. package/guides/himi-skill.md +3 -2
  16. package/guides/himi-test.md +65 -2
  17. package/guides/one-app-to-himi-app.md +1 -1
  18. package/guides/recipe-form-submit.md +9 -0
  19. package/guides/sdk-reference.json +28 -4
  20. package/package.json +2 -2
  21. package/stdlib/fonts/catalog.json +141 -0
  22. package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +178 -12
  23. package/templates/branded-lite/dev/index.ts +192 -0
  24. package/templates/branded-lite/l10n/en.json +1 -1
  25. package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +178 -12
  26. package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +178 -12
  27. package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +178 -12
  28. package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +178 -12
  29. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +178 -12
  30. package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +178 -12
  31. package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +178 -12
  32. package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +178 -12
  33. package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +178 -12
  34. package/templates/yoga-studio/dev/index.ts +192 -0
  35. package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +178 -12
@@ -910,6 +910,7 @@ export declare function segmentedControl(props: {
910
910
  export declare function carousel(props: {
911
911
  items: Component[];
912
912
  paged?: boolean;
913
+ /** #4673 — `$service:` page index, two-way with onChange (literal or `paged` bound pages). */
913
914
  currentIndexPath?: string;
914
915
  currentIndex?: number;
915
916
  onChange?: ActionShape;
@@ -925,6 +926,10 @@ export declare function pager(props: {
925
926
  onChange?: ActionShape;
926
927
  showIndicator?: boolean;
927
928
  liveWindow?: number;
929
+ /** #4673 — `$service:` page index, two-way with onChange. */
930
+ currentIndexPath?: string;
931
+ /** #4673 — `$service:` array; pages[0] is the page template ($item.* substitution). */
932
+ pagesPath?: string;
928
933
  }, opts?: {
929
934
  id?: string;
930
935
  }): Component;
@@ -39,37 +39,77 @@ export declare function alert(options: AlertOptions): Promise<AlertResult>;
39
39
  * `warning`, `danger`). Use `danger` for errors; the hosts also accept `error` as an alias of it. */
40
40
  export type SnackbarTone = "info" | "success" | "warning" | "danger";
41
41
  export interface SnackbarOptions {
42
+ /** At most two lines on screen; a longer message is ellipsised. */
42
43
  message: string;
43
44
  /** Default "info". */
44
45
  tone?: SnackbarTone;
45
- /** Auto-dismiss delay in ms, on every host. Default 3000; 0 or less also means 3000. */
46
+ /** Auto-dismiss delay in ms, clamped on every host to {@link SNACKBAR_LIMITS} (2–10 s, at least
47
+ * 4 s with an `action` so it can be reached by VoiceOver / TalkBack before it goes). Absent, 0 or
48
+ * less: the default, 3000 (4000 with an `action`). */
46
49
  durationMs?: number;
47
- /** One action button ("Undo", "View"). Tapping it runs `actionId` with `args`, then dismisses the
48
- * snackbar. The id must be a worker action:
50
+ /** A thumbnail of the thing the toast is about: a 40 pt square at the leading edge. `https:` on
51
+ * every host; a local `file:` URL on iOS and macOS only, whose image pipeline already reads local
52
+ * files. Any other URL is ignored (the toast shows without it), and an image that fails to load
53
+ * just hides. */
54
+ imageUrl?: string;
55
+ /** One action button ("Undo", "View"). Tapping it dismisses the snackbar and resolves the call
56
+ * `{ actionTapped: true }`. With an `actionId` the tap also runs that action with `args`. The id
57
+ * must be a worker action:
49
58
  * - one of this bundle's own `tier5.<svc>.<action>` ids — run on THIS worker, never another
50
59
  * screen's or the app-level worker's;
51
60
  * - an app service's `app.<svc>.<action>` — needs `app_services` and an exported action (an app
52
61
  * service's own id needs neither). The web host refuses it until it hosts app services.
53
62
  * Any other id (`capability.*`, `himi.*`, a registered handler) is refused when the snackbar is
54
63
  * requested: the call rejects and nothing is shown. A host that cannot tell which worker asked
55
- * (React Native, an embedded web region) refuses every `action` the same way. */
64
+ * (React Native, an embedded web region) refuses every `action` the same way. An APP SERVICE
65
+ * must name an `actionId`: an awaited result carries no gesture credit (RFC 0074 §7), so its
66
+ * View has to run as an action of its own. */
56
67
  action?: SnackbarAction;
57
68
  }
58
69
  export interface SnackbarAction {
59
- /** The button's text — also its VoiceOver / TalkBack / screen-reader label. */
70
+ /** The button's text — also its VoiceOver / TalkBack / screen-reader label. At most 24
71
+ * characters; a longer label is ellipsised. */
60
72
  label: string;
61
- /** What the tap runs: one of this bundle's own `tier5.<svc>.<action>` ids, or `app.<svc>.<action>`. */
62
- actionId: string;
73
+ /** What the tap runs, if anything: one of this bundle's own `tier5.<svc>.<action>` ids, or
74
+ * `app.<svc>.<action>`. A screen worker may leave it out and branch on `actionTapped` instead
75
+ * ("Undo"); an app service may not. */
76
+ actionId?: string;
63
77
  /** The action's arguments, which the reducer receives as typed JSON. */
64
78
  args?: Record<string, unknown>;
65
79
  }
80
+ /** What a snackbar call resolves with. */
81
+ export interface SnackbarResult {
82
+ /** The user tapped the action. Always false for a snackbar without one (resolved on
83
+ * presentation); with one, false when it was dismissed any other way — timed out, swiped, closed,
84
+ * or replaced by a newer snackbar. */
85
+ actionTapped: boolean;
86
+ }
87
+ /** #4661 — the constraints that keep a snackbar a toast, enforced here and again by every host. */
88
+ export declare const SNACKBAR_LIMITS: {
89
+ readonly messageLines: 2;
90
+ readonly labelChars: 24;
91
+ readonly minDurationMs: 2000;
92
+ /** The floor with an action: long enough to reach it with a screen reader. */
93
+ readonly minActionDurationMs: 4000;
94
+ readonly maxDurationMs: 10000;
95
+ /** The thumbnail's side, in pt / dp / CSS px. */
96
+ readonly imageSize: 40;
97
+ };
98
+ /** The duration a host shows a snackbar for: absent / non-finite / 0 or less → undefined (the host
99
+ * default applies), else clamped to {@link SNACKBAR_LIMITS}. */
100
+ export declare function snackbarDurationMs(durationMs: number | undefined, hasAction: boolean): number | undefined;
101
+ /** An action label as every host draws it: at most {@link SNACKBAR_LIMITS}.labelChars characters
102
+ * (by code point, so an emoji is never cut in half), the last one an ellipsis when it was cut. */
103
+ export declare function snackbarLabel(label: string): string;
66
104
  /** Show a transient snackbar toast: it floats above the tab bar, slides and fades in and out
67
- * (fades only under reduced motion), queues behind one that is already showing, and is read
68
- * by VoiceOver / TalkBack. Resolves once it is PRESENTED (not after it auto-dismisses).
105
+ * (fades only under reduced motion), queues behind one that is already showing, and is announced
106
+ * by VoiceOver / TalkBack / the screen reader. Without an `action` it resolves
107
+ * `{ actionTapped: false }` once it is queued, as before; with one it resolves when the snackbar
108
+ * goes, `{ actionTapped: true }` only if the action was tapped (see {@link SnackbarResult}).
69
109
  * Rejects with `no_ui_host` if no presenter is attached; with an `action`, also with
70
- * `invalid_action` (empty label or id), `action_not_allowed` (not one of this bundle's
71
- * actions), or, for an `app.*` id, `undeclared` (no `app_services`), `not_exported`, `no_service`,
72
- * `no_action`, `not_booted` or `unavailable`. */
73
- export declare function snackbar(options: SnackbarOptions): Promise<void>;
110
+ * `invalid_action` (empty label), `action_id_required` (an app service with no `actionId`),
111
+ * `action_not_allowed` (not one of this bundle's actions), or, for an `app.*` id, `undeclared` (no
112
+ * `app_services`), `not_exported`, `no_service`, `no_action`, `not_booted` or `unavailable`. */
113
+ export declare function snackbar(options: SnackbarOptions): Promise<SnackbarResult>;
74
114
  /** Capability version, for bundles that gate on min binary version. */
75
115
  export declare const version = 1;
@@ -1278,7 +1278,12 @@ export interface SegmentedControlProps {
1278
1278
  export interface CarouselProps {
1279
1279
  /** Opt-in paging for itemsPath; absent preserves the horizontal card rail. */
1280
1280
  paged?: boolean;
1281
- /** Worker-driven page index; clamped to the current page count. */
1281
+ /** #4673 — `$service:` path to the page index, two-way with `onChange`: a CHANGE of the resolved
1282
+ * value animates the carousel there (instantly under reduced motion); a swipe still fires
1283
+ * `onChange` with `args.index`, which the worker writes back. Out of range ⇒ clamped; not an
1284
+ * integer ⇒ ignored; equal to the current page ⇒ nothing; a move the binding made fires no
1285
+ * `onChange`. Drives literal `items` and `paged` bound ones; inside a bound row a substituted
1286
+ * literal places the page like `currentIndex`. A rail (`itemsPath` without `paged`) ignores it. */
1282
1287
  currentIndexPath?: string;
1283
1288
  items: Component[];
1284
1289
  currentIndex?: number;
@@ -1296,6 +1301,12 @@ export interface PagerProps {
1296
1301
  showIndicator?: boolean;
1297
1302
  /** RFC 0073 §4.5 — as {@link CarouselProps.liveWindow}. */
1298
1303
  liveWindow?: number;
1304
+ /** #4673 — as {@link CarouselProps.currentIndexPath}: a worker-driven page, two-way with `onChange`. */
1305
+ currentIndexPath?: string;
1306
+ /** #4673 — `$service:` path to an array: `pages[0]` is the page TEMPLATE, instantiated once per
1307
+ * element with `$item.` substitution (as `Carousel.itemsPath`). Pages are keyed by `$item.id`, so
1308
+ * the page on screen stays on screen when items are inserted before it. */
1309
+ pagesPath?: string;
1299
1310
  }
1300
1311
  export interface StepIndicatorProps {
1301
1312
  steps: string[];
@@ -1321,6 +1332,9 @@ export interface SnackbarProps {
1321
1332
  severity?: Severity;
1322
1333
  /** #1059 — action label; overridable for localized hosts. Default "Take action". */
1323
1334
  actionLabel?: string;
1335
+ /** #4661 — a 40 pt/dp thumbnail at the leading edge (`https:` or a local file/asset URL; any
1336
+ * other is ignored), drawn by the same presenter as a worker's `ui.snackbar({ imageUrl })`. */
1337
+ imageUrl?: string;
1324
1338
  }
1325
1339
  export interface AlertDialogProps {
1326
1340
  title: string;
@@ -14883,6 +14883,7 @@ var propsOf = (c) => {
14883
14883
  return isRec(p) ? p : {};
14884
14884
  };
14885
14885
  var hasItemsPath = (props) => typeof props.itemsPath === "string" && props.itemsPath !== "";
14886
+ var hasPagesPath = (props) => typeof props.pagesPath === "string" && /^\$(service|app):/.test(props.pagesPath);
14886
14887
  function childComponents(value, path, inTemplate, out) {
14887
14888
  if (Array.isArray(value)) {
14888
14889
  value.forEach((v, i) => childComponents(v, `${path}[${i}]`, inTemplate, out));
@@ -14899,9 +14900,10 @@ function childrenOf(c, path, inTemplate) {
14899
14900
  const props = propsOf(c);
14900
14901
  const type = typeOf(c);
14901
14902
  const boundList = (type === "LazyList" || type === "Grid" || type === "Carousel") && hasItemsPath(props);
14903
+ const boundPages = type === "Pager" && hasPagesPath(props);
14902
14904
  const out = [];
14903
14905
  for (const [k, v] of Object.entries(props)) {
14904
- const templ = inTemplate || /Template$/.test(k) || boundList && k === "items";
14906
+ const templ = inTemplate || /Template$/.test(k) || boundList && k === "items" || boundPages && k === "pages";
14905
14907
  childComponents(v, `${path}.body.props.${k}`, templ, out);
14906
14908
  }
14907
14909
  return out;
@@ -14949,7 +14951,7 @@ function mountable(c, inTemplate = false) {
14949
14951
  const pages = type === "Carousel" ? props.items : props.pages;
14950
14952
  const perPage = Array.isArray(pages) ? pages.map((p) => isComponent(p) ? mountable(p) : 0) : [];
14951
14953
  const window = typeof props.liveWindow === "number" && props.liveWindow > 0 ? Math.floor(props.liveWindow) : 0;
14952
- const bound = type === "Carousel" && hasItemsPath(props);
14954
+ const bound = type === "Carousel" ? hasItemsPath(props) : hasPagesPath(props);
14953
14955
  if (bound) {
14954
14956
  const template = perPage[0] ?? 0;
14955
14957
  if (template === 0) return 0;
@@ -28,22 +28,48 @@ async function alert(options) {
28
28
  const r = await dispatch("capability.ui.alert", params);
29
29
  return { confirmed: r?.confirmed === true || r?.confirmed === "true" };
30
30
  }
31
+ var SNACKBAR_LIMITS = {
32
+ messageLines: 2,
33
+ labelChars: 24,
34
+ minDurationMs: 2e3,
35
+ /** The floor with an action: long enough to reach it with a screen reader. */
36
+ minActionDurationMs: 4e3,
37
+ maxDurationMs: 1e4,
38
+ /** The thumbnail's side, in pt / dp / CSS px. */
39
+ imageSize: 40
40
+ };
41
+ function snackbarDurationMs(durationMs, hasAction) {
42
+ if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs <= 0) return void 0;
43
+ const min = hasAction ? SNACKBAR_LIMITS.minActionDurationMs : SNACKBAR_LIMITS.minDurationMs;
44
+ return Math.min(SNACKBAR_LIMITS.maxDurationMs, Math.max(min, Math.trunc(durationMs)));
45
+ }
46
+ function snackbarLabel(label) {
47
+ const chars = Array.from(label ?? "");
48
+ return chars.length <= SNACKBAR_LIMITS.labelChars ? chars.join("") : `${chars.slice(0, SNACKBAR_LIMITS.labelChars - 1).join("")}\u2026`;
49
+ }
31
50
  async function snackbar(options) {
32
51
  const params = { message: options.message ?? "" };
33
52
  if (options.tone) params.tone = options.tone;
34
- if (typeof options.durationMs === "number" && Number.isFinite(options.durationMs)) {
35
- params.durationMs = Math.min(2147483647, Math.max(0, Math.trunc(options.durationMs)));
36
- }
53
+ const durationMs = snackbarDurationMs(options.durationMs, !!options.action);
54
+ if (durationMs !== void 0) params.durationMs = durationMs;
55
+ if (typeof options.imageUrl === "string" && options.imageUrl.trim()) params.imageUrl = options.imageUrl.trim();
37
56
  if (options.action) {
38
57
  const { label, actionId, args } = options.action;
39
- params.action = JSON.stringify(args === void 0 ? { label, actionId } : { label, actionId, args });
58
+ const action = { label: snackbarLabel(label) };
59
+ if (actionId) action.actionId = actionId;
60
+ if (args !== void 0) action.args = args;
61
+ params.action = JSON.stringify(action);
40
62
  }
41
- await dispatch("capability.ui.snackbar", params);
63
+ const r = await dispatch("capability.ui.snackbar", params);
64
+ return { actionTapped: r?.actionTapped === true || r?.actionTapped === "true" };
42
65
  }
43
66
  var version = 1;
44
67
  export {
68
+ SNACKBAR_LIMITS,
45
69
  alert,
46
70
  snackbar,
71
+ snackbarDurationMs,
72
+ snackbarLabel,
47
73
  version
48
74
  };
49
75
  //# sourceMappingURL=ui.mjs.map