@wix/himalaya-cli 0.1027.0 → 0.1029.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 (29) hide show
  1. package/dist/cli.mjs +176 -31
  2. package/dist/preview-assets.generated.bin +0 -0
  3. package/package.json +2 -2
  4. package/templates/beauty-salon/dev/index.ts +15 -3
  5. package/templates/beauty-salon-owner/dev/index.ts +22 -27
  6. package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +23 -3
  7. package/templates/branded-lite/dev/index.ts +32 -4
  8. package/templates/community-club-owner/dev/index.ts +22 -27
  9. package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +23 -3
  10. package/templates/events-meetups-owner/dev/index.ts +22 -27
  11. package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +23 -3
  12. package/templates/gym-fitness/dev/index.ts +15 -3
  13. package/templates/gym-fitness-owner/dev/index.ts +22 -27
  14. package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +23 -3
  15. package/templates/nonprofit-cause-owner/dev/index.ts +22 -27
  16. package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +23 -3
  17. package/templates/owner-lite/dev/index.ts +22 -27
  18. package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +23 -3
  19. package/templates/podcast-creator-owner/dev/index.ts +22 -27
  20. package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +23 -3
  21. package/templates/portfolio-creative-owner/dev/index.ts +22 -27
  22. package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +23 -3
  23. package/templates/restaurant-owner/dev/index.ts +22 -27
  24. package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +23 -3
  25. package/templates/retail-store-owner/dev/index.ts +22 -27
  26. package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +23 -3
  27. package/templates/yoga-studio/dev/index.ts +15 -1
  28. package/templates/yoga-studio-owner/dev/index.ts +22 -27
  29. package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +23 -3
package/dist/cli.mjs CHANGED
@@ -5378,6 +5378,7 @@ function resolveTranslation(value, catalog, sourceCatalog) {
5378
5378
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
5379
5379
  var init_bindings = __esm({
5380
5380
  "../../core/ts/src/bindings.ts"() {
5381
+ "use strict";
5381
5382
  BINDING_SIGILS = ["service", "flag", "item", "t"];
5382
5383
  BINDING_SIGIL_RE = new RegExp(
5383
5384
  `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
@@ -22579,6 +22580,75 @@ var init_icons = __esm({
22579
22580
  }
22580
22581
  });
22581
22582
 
22583
+ // ../../core/web-renderer/src/webviewFrame.ts
22584
+ function currentOrigin() {
22585
+ try {
22586
+ const origin = typeof window !== "undefined" ? window.location?.origin : void 0;
22587
+ return origin && origin !== "null" ? origin : null;
22588
+ } catch {
22589
+ return null;
22590
+ }
22591
+ }
22592
+ function webviewFrameSandbox(url, grants2 = [], pageOrigin = currentOrigin()) {
22593
+ const target = classifyEmbedUrl(url, pageOrigin);
22594
+ if (!target || !NETWORK_SCHEMES.has(target.protocol)) return null;
22595
+ const tokens = ["allow-scripts", ...grants2.filter((g) => g !== "allow-scripts" && g !== "allow-same-origin")];
22596
+ if (target.crossOrigin) tokens.splice(1, 0, "allow-same-origin");
22597
+ return { src: target.crossOrigin ? target.href : url, sandbox: tokens.join(" ") };
22598
+ }
22599
+ function classifyEmbedUrl(url, pageOrigin = currentOrigin()) {
22600
+ const parsed = url.replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, "").replace(/[\t\n\r]/g, "");
22601
+ const absolute = /^[a-z][a-z0-9+.-]*:/i.test(parsed);
22602
+ const schemeRelative = !absolute && /^[\\/]{2}/.test(parsed);
22603
+ let target;
22604
+ try {
22605
+ target = new URL(parsed, pageOrigin ?? "http://relative.invalid");
22606
+ } catch {
22607
+ return null;
22608
+ }
22609
+ const crossOrigin = pageOrigin !== null && target.origin !== pageOrigin;
22610
+ return { protocol: target.protocol, href: target.href, absolute, schemeRelative, crossOrigin };
22611
+ }
22612
+ function isWebviewUrlAllowed(url) {
22613
+ return webviewFrameSandbox(url, [], null) !== null;
22614
+ }
22615
+ var NETWORK_SCHEMES;
22616
+ var init_webviewFrame = __esm({
22617
+ "../../core/web-renderer/src/webviewFrame.ts"() {
22618
+ NETWORK_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:"]);
22619
+ }
22620
+ });
22621
+
22622
+ // ../../core/web-renderer/src/pdfSource.ts
22623
+ function pdfEmbedPlan(url, pageOrigin = currentOrigin()) {
22624
+ const target = classifyEmbedUrl(url, pageOrigin);
22625
+ if (!target) return null;
22626
+ if (target.protocol === "http:" || target.protocol === "https:") {
22627
+ if (pageOrigin === null) {
22628
+ if (target.absolute) return { mode: "direct", src: target.href };
22629
+ if (target.schemeRelative) return { mode: "direct", src: target.href.replace(/^https?:/, "") };
22630
+ return null;
22631
+ }
22632
+ return { mode: target.crossOrigin ? "direct" : "retype", src: target.href };
22633
+ }
22634
+ if (target.protocol === "blob:" && pageOrigin !== null && !target.crossOrigin) {
22635
+ return { mode: "retype", src: target.href };
22636
+ }
22637
+ return null;
22638
+ }
22639
+ async function retypeAsPdf(src, fetchImpl = fetch) {
22640
+ const res = await fetchImpl(src, { credentials: "same-origin" });
22641
+ if (!res.ok) return null;
22642
+ if (/html|xml/i.test(res.headers.get("content-type") ?? "")) return null;
22643
+ const body = await res.blob();
22644
+ return URL.createObjectURL(body.slice(0, body.size, "application/pdf"));
22645
+ }
22646
+ var init_pdfSource = __esm({
22647
+ "../../core/web-renderer/src/pdfSource.ts"() {
22648
+ init_webviewFrame();
22649
+ }
22650
+ });
22651
+
22582
22652
  // ../../core/web-renderer/src/a11y/controls.tsx
22583
22653
  import React3 from "react";
22584
22654
  import { jsx as jsx4, jsxs } from "react/jsx-runtime";
@@ -24281,6 +24351,14 @@ function useResolvedMediaItems(items, ctx) {
24281
24351
  return out ?? it;
24282
24352
  }), [items, values, ctx]);
24283
24353
  }
24354
+ function sourceFragment(src) {
24355
+ if (!src) return "";
24356
+ try {
24357
+ return new URL(src).hash;
24358
+ } catch {
24359
+ return "";
24360
+ }
24361
+ }
24284
24362
  function isNativeInteractiveElement(el) {
24285
24363
  const props = el.props;
24286
24364
  return typeof el.type === "string" && (["button", "input", "select", "textarea"].includes(el.type) || el.type === "a" && typeof props.href === "string");
@@ -24321,9 +24399,10 @@ function withExtras(name, render) {
24321
24399
  const additive = addIntrinsicPadding(el.props.style, wrap ?? {});
24322
24400
  const inferredDecorative = el.props[INFERRED_DECORATIVE] === true;
24323
24401
  const iconGlyph2 = el.props[ICON_GLYPH] === true;
24402
+ const roleWhenNamed = el.props[ROLE_WHEN_NAMED];
24324
24403
  if (!Object.keys(pass).length) {
24325
- if (inferredDecorative || iconGlyph2) {
24326
- return React5.cloneElement(el, { [INFERRED_DECORATIVE]: void 0, [ICON_GLYPH]: void 0, ...additive ? { style: additive } : {} });
24404
+ if (inferredDecorative || iconGlyph2 || roleWhenNamed != null) {
24405
+ return React5.cloneElement(el, { [INFERRED_DECORATIVE]: void 0, [ICON_GLYPH]: void 0, [ROLE_WHEN_NAMED]: void 0, ...additive ? { style: additive } : {} });
24327
24406
  }
24328
24407
  return additive ? React5.cloneElement(el, { style: additive }) : /* @__PURE__ */ jsx6(Fragment3, { children: el });
24329
24408
  }
@@ -24335,6 +24414,14 @@ function withExtras(name, render) {
24335
24414
  const nodeSpeaksForItself = pass["aria-label"] != null || passRole != null && passRole !== "presentation" && passRole !== "none" || typeof pass.onClick === "function" || typeof pass.onDoubleClick === "function";
24336
24415
  if (pass["aria-hidden"] == null && nodeSpeaksForItself) next["aria-hidden"] = void 0;
24337
24416
  }
24417
+ if (roleWhenNamed != null) {
24418
+ next[ROLE_WHEN_NAMED] = void 0;
24419
+ const isControl = typeof pass.onClick === "function" || typeof pass.onDoubleClick === "function";
24420
+ const roleAuthored = pass[AUTHORED_ROLE] === true;
24421
+ if (typeof roleWhenNamed === "string" && pass["aria-label"] != null && pass.role == null && prev.role == null && !isControl && !roleAuthored) {
24422
+ next.role = roleWhenNamed;
24423
+ }
24424
+ }
24338
24425
  if (iconGlyph2) {
24339
24426
  next[ICON_GLYPH] = void 0;
24340
24427
  if (pass.role === "presentation" && typeof pass.onClick !== "function" && typeof pass.onDoubleClick !== "function") {
@@ -24348,6 +24435,7 @@ function withExtras(name, render) {
24348
24435
  delete next[SYNTHETIC_TAP_ROLE];
24349
24436
  const tabIndexIsSynthetic = next[SYNTHETIC_TABINDEX] === true;
24350
24437
  delete next[SYNTHETIC_TABINDEX];
24438
+ delete next[AUTHORED_ROLE];
24351
24439
  if (additive) next.style = additive;
24352
24440
  const ownsInteractiveSemantics = isNativeInteractiveElement(el) || hasInteractiveReactDescendant(el);
24353
24441
  if (ownsInteractiveSemantics) {
@@ -24896,6 +24984,7 @@ function applyA11ySemantics(node, ctx, extra) {
24896
24984
  if (typeof headingLevel === "number" && headingLevel >= 1 && headingLevel <= 6) {
24897
24985
  extra["aria-level"] = String(headingLevel);
24898
24986
  }
24987
+ if (role != null && Object.prototype.hasOwnProperty.call(ARIA_ROLE, role)) extra[AUTHORED_ROLE] = true;
24899
24988
  const hint = str7(m.accessibilityHint ?? m.accessibility_hint);
24900
24989
  const value = str7(m.accessibilityValue ?? m.accessibility_value);
24901
24990
  if (value) extra["aria-valuetext"] = value;
@@ -25091,7 +25180,10 @@ function renderNodeInner(node, ctx) {
25091
25180
  if (composed) extra.style = composed;
25092
25181
  }
25093
25182
  }
25094
- if (typeof el.type === "string") delete extra[SYNTHETIC_TABINDEX];
25183
+ if (typeof el.type === "string") {
25184
+ delete extra[SYNTHETIC_TABINDEX];
25185
+ delete extra[AUTHORED_ROLE];
25186
+ }
25095
25187
  let out = Object.keys(extra).length ? React5.cloneElement(el, extra) : el;
25096
25188
  if (a11yHint) {
25097
25189
  out = /* @__PURE__ */ jsx6(A11yHintDescription, { hint: a11yHint, idBase: componentId, children: out });
@@ -25812,7 +25904,7 @@ function renderInner(node, ctx) {
25812
25904
  }
25813
25905
  }
25814
25906
  }
25815
- var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, 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, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, ICON_GLYPH, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, 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, initialFocusSeen, PRESENTED_SCOPE, presentedOpeners, presentedObserver, A11yHintDescription, WebRenderer;
25907
+ var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, 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, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, ICON_GLYPH, ROLE_WHEN_NAMED, AUTHORED_ROLE, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, 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, initialFocusSeen, PRESENTED_SCOPE, presentedOpeners, presentedObserver, A11yHintDescription, WebRenderer;
25816
25908
  var init_renderNode = __esm({
25817
25909
  "../../core/web-renderer/src/renderNode.tsx"() {
25818
25910
  "use strict";
@@ -25829,6 +25921,8 @@ var init_renderNode = __esm({
25829
25921
  init_env();
25830
25922
  init_actionParams();
25831
25923
  init_icons();
25924
+ init_webviewFrame();
25925
+ init_pdfSource();
25832
25926
  init_icon_catalog_generated();
25833
25927
  init_controls();
25834
25928
  init_modalStack();
@@ -27006,8 +27100,32 @@ var init_renderNode = __esm({
27006
27100
  PdfViewNode = withExtras("PdfViewNode", ({ props, ctx, wrap }) => {
27007
27101
  const boundUrl = useResolvedScalar(props.url != null && isBinding(props.url) ? props.url : void 0, ctx);
27008
27102
  const url = props.url != null && isBinding(props.url) ? boundUrl : props.url;
27009
- const rawUrl = typeof url === "string" && !isBinding(url) ? url.trim() : "";
27010
- const ok = /^(https?:|blob:|\/)/i.test(rawUrl);
27103
+ const rawUrl = typeof url === "string" && !isBinding(url) ? url : "";
27104
+ const plan = rawUrl ? pdfEmbedPlan(rawUrl) : null;
27105
+ const retypeSrc = plan?.mode === "retype" ? plan.src : null;
27106
+ const [retyped, setRetyped] = React5.useState(null);
27107
+ React5.useEffect(() => {
27108
+ if (!retypeSrc) return;
27109
+ let live2 = true;
27110
+ let made = null;
27111
+ const settle = (u) => {
27112
+ made = u;
27113
+ if (!live2) {
27114
+ if (u) URL.revokeObjectURL(u);
27115
+ return;
27116
+ }
27117
+ setRetyped({ from: retypeSrc, url: u });
27118
+ };
27119
+ retypeAsPdf(retypeSrc).then(settle, () => settle(null));
27120
+ return () => {
27121
+ live2 = false;
27122
+ if (made) URL.revokeObjectURL(made);
27123
+ setRetyped((cur) => cur?.from === retypeSrc ? null : cur);
27124
+ };
27125
+ }, [retypeSrc]);
27126
+ const settled = retyped && retyped.from === retypeSrc ? retyped : null;
27127
+ const src = plan?.mode === "direct" ? plan.src : settled?.url ?? null;
27128
+ const loading = plan?.mode === "retype" && !settled;
27011
27129
  const ph = typeof props.height === "number" && props.height > 0 ? props.height : void 0;
27012
27130
  const frame = {
27013
27131
  width: "100%",
@@ -27018,7 +27136,19 @@ var init_renderNode = __esm({
27018
27136
  overflow: "hidden",
27019
27137
  ...wrap
27020
27138
  };
27021
- if (!ok) {
27139
+ if (loading) {
27140
+ return /* @__PURE__ */ jsx6(
27141
+ "div",
27142
+ {
27143
+ "data-himalaya-pdf": "loading",
27144
+ role: "img",
27145
+ "aria-label": "loading document",
27146
+ "aria-busy": "true",
27147
+ style: { ...frame, background: "#f4f4f4" }
27148
+ }
27149
+ );
27150
+ }
27151
+ if (!src) {
27022
27152
  return /* @__PURE__ */ jsx6(
27023
27153
  "div",
27024
27154
  {
@@ -27034,7 +27164,7 @@ var init_renderNode = __esm({
27034
27164
  "object",
27035
27165
  {
27036
27166
  "data-himalaya-pdf": "document",
27037
- data: rawUrl + startPage,
27167
+ data: src + (plan?.mode === "retype" ? startPage || sourceFragment(retypeSrc) : startPage),
27038
27168
  type: "application/pdf",
27039
27169
  "aria-label": typeof props.title === "string" && props.title ? props.title : "PDF document",
27040
27170
  style: frame
@@ -27048,13 +27178,14 @@ var init_renderNode = __esm({
27048
27178
  const inlineHtml = props.inlineHtml != null && isBinding(props.inlineHtml) ? boundHtml : props.inlineHtml;
27049
27179
  const urlStr = typeof url === "string" && url.length > 0 && !isBinding(url) ? url : void 0;
27050
27180
  const htmlStr = typeof inlineHtml === "string" && inlineHtml.length > 0 && !isBinding(inlineHtml) ? inlineHtml : void 0;
27181
+ const urlFrame = urlStr ? webviewFrameSandbox(urlStr) : null;
27051
27182
  const h = typeof props.height === "number" && props.height > 0 ? props.height : void 0;
27052
27183
  const ar = typeof props.aspectRatio === "number" && props.aspectRatio > 0 ? props.aspectRatio : void 0;
27053
27184
  const frameStyle = { width: "100%", boxSizing: "border-box", border: "none", borderRadius: ctx.radius("md", 8), background: "#fff", ...h ? { height: h } : ar ? { aspectRatio: String(ar) } : { height: 200 } };
27054
27185
  const bandColor = typeof props.coverBandColor === "string" && props.coverBandColor.length > 0 ? props.coverBandColor : void 0;
27055
27186
  return /* @__PURE__ */ jsxs3("div", { style: { width: "100%", position: "relative", ...bandColor ? { background: bandColor, borderRadius: ctx.radius("md", 8), overflow: "hidden" } : {}, ...wrap }, children: [
27056
27187
  bandColor ? /* @__PURE__ */ jsx6("div", { "data-testid": "webview-cover-band", style: { height: 8, background: bandColor } }) : null,
27057
- htmlStr ? /* @__PURE__ */ jsx6("iframe", { title: "webview", srcDoc: htmlStr, sandbox: "allow-scripts", style: frameStyle }) : urlStr ? /* @__PURE__ */ jsx6("iframe", { title: "webview", src: urlStr, sandbox: "allow-scripts allow-same-origin", style: frameStyle }) : /* @__PURE__ */ jsx6("div", { style: { ...frameStyle, display: "grid", placeItems: "center", color: "#999", fontFamily: "ui-monospace, monospace", fontSize: 11, border: "1px dashed #ccc" }, children: "WebView (no url)" })
27188
+ htmlStr ? /* @__PURE__ */ jsx6("iframe", { title: "webview", srcDoc: htmlStr, sandbox: "allow-scripts", style: frameStyle }) : urlFrame ? /* @__PURE__ */ jsx6("iframe", { title: "webview", src: urlFrame.src, sandbox: urlFrame.sandbox, style: frameStyle }) : /* @__PURE__ */ jsx6("div", { style: { ...frameStyle, display: "grid", placeItems: "center", color: "#999", fontFamily: "ui-monospace, monospace", fontSize: 11, border: "1px dashed #ccc" }, children: urlStr ? "WebView (url not allowed)" : "WebView (no url)" })
27058
27189
  ] });
27059
27190
  });
27060
27191
  InteractivePicker = withExtras("InteractivePicker", ({ props, ctx, wrap }) => {
@@ -27332,6 +27463,8 @@ var init_renderNode = __esm({
27332
27463
  SYNTHETIC_TABINDEX = "data-hm-synthetic-tabindex";
27333
27464
  INFERRED_DECORATIVE = "data-hm-inferred-decorative";
27334
27465
  ICON_GLYPH = "data-hm-icon-glyph";
27466
+ ROLE_WHEN_NAMED = "data-hm-role-when-named";
27467
+ AUTHORED_ROLE = "data-hm-authored-role";
27335
27468
  INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
27336
27469
  "button",
27337
27470
  "checkbox",
@@ -27539,7 +27672,7 @@ var init_renderNode = __esm({
27539
27672
  const iconName = isBinding(props.name) ? String(bound ?? "") : props.name;
27540
27673
  const contentDescription = useResolvedScalar(props.contentDescription, ctx);
27541
27674
  const described = contentDescription != null && String(contentDescription).trim() !== "";
27542
- const a11y = described ? { role: "img", "aria-label": String(contentDescription), [ICON_GLYPH]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [ICON_GLYPH]: true };
27675
+ const a11y = described ? { role: "img", "aria-label": String(contentDescription), [ICON_GLYPH]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [ICON_GLYPH]: true, [ROLE_WHEN_NAMED]: "img" };
27543
27676
  return /* @__PURE__ */ jsx6("span", { ...a11y, style: { display: "inline-grid", placeItems: "center", width: size + 6, height: size + 6, lineHeight: 1, flex: "none", ...wrap }, children: iconSvg(iconName, { size, color: C(resolveScalarStatic(props.tint, ctx) ?? "textPrimary", "#636b78") }) });
27544
27677
  });
27545
27678
  ButtonNode = withExtras("ButtonNode", ({ props, ctx, wrap }) => {
@@ -27675,11 +27808,13 @@ var init_renderNode = __esm({
27675
27808
  const thick = Math.max(3, Math.round(size / 8));
27676
27809
  const bound = useResolvedScalar(props.valuePath, ctx);
27677
27810
  const aiRaw = props.valuePath != null ? bound : props.value;
27678
- const determinate = !props.indeterminate && typeof aiRaw === "number";
27811
+ const aiNum = typeof aiRaw === "number" ? aiRaw : typeof aiRaw === "string" && aiRaw.trim() !== "" ? Number(aiRaw) : void 0;
27812
+ const determinate = !props.indeterminate && aiNum !== void 0 && Number.isFinite(aiNum);
27679
27813
  if (determinate) {
27680
- const pct = Math.max(0, Math.min(1, aiRaw));
27814
+ const pct = Math.max(0, Math.min(1, aiNum));
27681
27815
  const ringMask = `radial-gradient(farthest-side, transparent calc(100% - ${thick}px), #000 calc(100% - ${thick}px))`;
27682
- return /* @__PURE__ */ jsx6("div", { role: "progressbar", style: { width: size, height: size, borderRadius: "50%", flex: "none", background: `conic-gradient(${tint} ${pct * 360}deg, ${track} 0deg)`, WebkitMask: ringMask, mask: ringMask, ...wrap } });
27816
+ const a11y = { "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(pct * 100) };
27817
+ return /* @__PURE__ */ jsx6("div", { role: "progressbar", ...a11y, style: { width: size, height: size, borderRadius: "50%", flex: "none", background: `conic-gradient(${tint} ${pct * 360}deg, ${track} 0deg)`, WebkitMask: ringMask, mask: ringMask, ...wrap } });
27683
27818
  }
27684
27819
  ensureSpinKeyframes();
27685
27820
  return /* @__PURE__ */ jsx6("div", { role: "progressbar", style: { width: size, height: size, borderRadius: "50%", border: `${thick}px solid ${track}`, borderTopColor: tint, boxSizing: "border-box", flex: "none", animation: ctx.empty ? void 0 : "himalaya-spin 0.8s linear infinite", ...wrap } });
@@ -29374,6 +29509,7 @@ __export(src_exports, {
29374
29509
  isBinding: () => isBinding,
29375
29510
  isNodeLike: () => isNodeLike,
29376
29511
  isSerifFamily: () => isSerifFamily,
29512
+ isWebviewUrlAllowed: () => isWebviewUrlAllowed,
29377
29513
  makeCtx: () => makeCtx,
29378
29514
  makeModStyle: () => makeModStyle,
29379
29515
  makeTokenResolvers: () => makeTokenResolvers,
@@ -29382,7 +29518,8 @@ __export(src_exports, {
29382
29518
  renderDescriptorToHtml: () => renderDescriptorToHtml,
29383
29519
  renderNode: () => renderNode,
29384
29520
  servicePath: () => servicePath,
29385
- useBoundValue: () => useBoundValue
29521
+ useBoundValue: () => useBoundValue,
29522
+ webviewFrameSandbox: () => webviewFrameSandbox
29386
29523
  });
29387
29524
  var init_src3 = __esm({
29388
29525
  "../../core/web-renderer/src/index.ts"() {
@@ -29396,6 +29533,7 @@ var init_src3 = __esm({
29396
29533
  init_AppRegistry();
29397
29534
  init_helpers();
29398
29535
  init_icons();
29536
+ init_webviewFrame();
29399
29537
  }
29400
29538
  });
29401
29539
 
@@ -48891,7 +49029,14 @@ function indexHtml(asset, pathname, creds, handoverAttempted = false) {
48891
49029
  headers: {
48892
49030
  "content-type": asset.contentType || "text/html; charset=utf-8",
48893
49031
  "cache-control": creds || handoverAttempted ? "no-store" : "public, max-age=60, stale-while-revalidate=600",
48894
- "content-security-policy": previewCsp(nonce)
49032
+ "content-security-policy": previewCsp(nonce),
49033
+ // This document's URL can name a credential: `?pvt=` (still accepted from an embedder such
49034
+ // as the dashboard frame) or a `?h=` code before the inline script strips it. The browser
49035
+ // default sends the FULL URL as `Referer` on same-origin requests, so every `/v1/*` read,
49036
+ // the gateway's request log and the Tier-5 frame's `document.referrer` would carry it.
49037
+ // `strict-origin` sends the origin alone. Not `no-referrer`: that also turns a same-origin
49038
+ // POST's `Origin` header into `null`, and `/v1/telemetry/ingest` is one (#2386).
49039
+ "referrer-policy": "strict-origin"
48895
49040
  }
48896
49041
  });
48897
49042
  }
@@ -48925,7 +49070,7 @@ function previewResponse(pathname, assets, mount = "/preview", creds, handoverAt
48925
49070
  var T5_FRAME_CSP, PREVIEW_BASE_JS, PREVIEW_ENTRY_RECOVERY_JS, MOUNT_STRIP;
48926
49071
  var init_preview2 = __esm({
48927
49072
  "../../packages/serve/src/preview.ts"() {
48928
- T5_FRAME_CSP = "default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; connect-src 'none'; img-src 'none'; media-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'";
49073
+ T5_FRAME_CSP = "default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; connect-src 'none'; img-src 'none'; media-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; sandbox allow-scripts";
48929
49074
  PREVIEW_BASE_JS = // Both serve mounts (/preview framed + /app unframed — RFC 0051 track D) serve the SAME
48930
49075
  // embedded artifact, so one shim derives whichever mount the browser is on. Non-greedy:
48931
49076
  // the EARLIEST mount segment wins, mirroring the SPA's own deployBase (an app literally
@@ -49178,21 +49323,21 @@ var init_preview_assets_generated = __esm({
49178
49323
  "../../packages/serve/src/preview-assets.generated.ts"() {
49179
49324
  init_preview_assets_format();
49180
49325
  PREVIEW_ASSET_MANIFEST = [
49181
- { key: "assets/index-BvsDhZYW.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1043409, sha256: "98882914dcb360867c5f265e3d6542774f18c0b0c8f18813b66b304a122c1b01" },
49182
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1043417, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
49183
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1048027, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
49184
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1536611, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
49185
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1627535, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
49186
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1718519, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
49187
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1809499, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
49188
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1900371, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
49189
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1991351, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
49190
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2099987, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
49191
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2209071, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
49192
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2318119, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
49193
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2425819, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
49194
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2513927, length: 4947, sha256: "3dd02534fef5e0c2bb40b6c6a6c994641728fde306921e66ffab3e9a7dfa6bbe" },
49195
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2518874, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
49326
+ { key: "assets/index---zsKTyk.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1046198, sha256: "4ca35bb22d26776fdb371a4cfb2137ecbb7bd03924695269ac6364171187fe89" },
49327
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1046206, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
49328
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1050816, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
49329
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1539400, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
49330
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1630324, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
49331
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1721308, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
49332
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1812288, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
49333
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1903160, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
49334
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1994140, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
49335
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2102776, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
49336
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2211860, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
49337
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2320908, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
49338
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2428608, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
49339
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2516716, length: 4947, sha256: "684c954fbc5b82e4513932286c45f00f08b2d988c71614f0700f3cc57716fa84" },
49340
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2521663, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
49196
49341
  ];
49197
49342
  }
49198
49343
  });
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1027.0",
3
+ "version": "0.1029.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": [
@@ -65,5 +65,5 @@
65
65
  "artifactId": "himalaya-cli"
66
66
  }
67
67
  },
68
- "falconPackageHash": "9ce64db92bfef4391297f6111f02ad23a382a5e206bd732aae1df4b1"
68
+ "falconPackageHash": "785b6d68758b001717f983ccbdad398a5765dced9bf5544af3865811"
69
69
  }
@@ -144,10 +144,22 @@ const SCREENS = runtimeSetting({
144
144
  }
145
145
  },
146
146
  "cornerRadius": 8,
147
- "hiddenPath": "$service:himiBrandedHome.hideHeroSkeleton",
148
- "padding": {
149
- "bottom": 16
147
+ "hiddenPath": "$service:himiBrandedHome.hideHeroSkeleton"
148
+ }
149
+ },
150
+ {
151
+ "id": "himi_branded_home.salon.hero_skeleton.gap",
152
+ "body": {
153
+ "package": "himalaya",
154
+ "type": "VStack",
155
+ "props": {
156
+ "children": []
150
157
  }
158
+ },
159
+ "modifiers": {
160
+ "height": 16,
161
+ "fillMaxWidth": true,
162
+ "hiddenPath": "$service:himiBrandedHome.hideHeroSkeleton"
151
163
  }
152
164
  },
153
165
  {
@@ -55191,7 +55191,7 @@ const SCREENS = runtimeSetting({
55191
55191
  "spacing": 3,
55192
55192
  "children": [
55193
55193
  {
55194
- "id": "himi_owner_lite_aria.msg_$item.id.who",
55194
+ "id": "himi_owner_lite_aria.msg_$item.id.content",
55195
55195
  "body": {
55196
55196
  "package": "himalaya",
55197
55197
  "type": "HStack",
@@ -55210,43 +55210,34 @@ const SCREENS = runtimeSetting({
55210
55210
  }
55211
55211
  },
55212
55212
  {
55213
- "id": "",
55213
+ "id": "himi_owner_lite_aria.msg_$item.id.bubble",
55214
55214
  "body": {
55215
55215
  "package": "himalaya",
55216
55216
  "type": "Text",
55217
55217
  "props": {
55218
- "text": "$item.who",
55219
- "style": "footnote",
55220
- "color": "textSecondary",
55221
- "maxLines": 1
55218
+ "text": "$item.content",
55219
+ "style": "body",
55220
+ "maxLines": 50
55222
55221
  }
55223
- }
55224
- }
55225
- ]
55226
- }
55227
- }
55228
- },
55229
- {
55230
- "id": "himi_owner_lite_aria.msg_$item.id.content",
55231
- "body": {
55232
- "package": "himalaya",
55233
- "type": "HStack",
55234
- "props": {
55235
- "spacing": 0,
55236
- "children": [
55237
- {
55238
- "id": "",
55239
- "body": {
55240
- "package": "himalaya",
55241
- "type": "Spacer",
55242
- "props": {}
55243
55222
  },
55244
55223
  "modifiers": {
55224
+ "accessibilityLabel": "$item.spoken",
55225
+ "padding": {
55226
+ "leading": 16,
55227
+ "trailing": 16,
55228
+ "top": 8,
55229
+ "bottom": 8
55230
+ },
55231
+ "background": {
55232
+ "token": "surfaceSecondary"
55233
+ },
55234
+ "cornerRadius": 20,
55235
+ "maxWidth": 300,
55245
55236
  "hiddenPath": "$item.notUser"
55246
55237
  }
55247
55238
  },
55248
55239
  {
55249
- "id": "",
55240
+ "id": "himi_owner_lite_aria.msg_$item.id.text",
55250
55241
  "body": {
55251
55242
  "package": "himalaya",
55252
55243
  "type": "Text",
@@ -55255,6 +55246,10 @@ const SCREENS = runtimeSetting({
55255
55246
  "style": "body",
55256
55247
  "maxLines": 50
55257
55248
  }
55249
+ },
55250
+ "modifiers": {
55251
+ "accessibilityLabel": "$item.spoken",
55252
+ "hiddenPath": "$item.notAria"
55258
55253
  }
55259
55254
  }
55260
55255
  ]
@@ -83,6 +83,11 @@ export interface AriaBubble {
83
83
  * that right-aligns the owner renders two templates and collapses one. */
84
84
  notUser: boolean;
85
85
  notAria: boolean;
86
+ /** What a screen reader says for the row: the author, then the words. A
87
+ * screen that draws the speaker only as a bubble and a side of the screen
88
+ * (`messageStyle: 'userBubble'`) has no visible author line to read, and
89
+ * without this the owner's question and Aria's reply sound the same. */
90
+ spoken: string;
86
91
  link1Label: string; link1Url: string; link1Hidden: boolean;
87
92
  link2Label: string; link2Url: string; link2Hidden: boolean;
88
93
  link3Label: string; link3Url: string; link3Hidden: boolean;
@@ -561,9 +566,23 @@ export function disclosedLabel(link: { label: string; url: string }): string {
561
566
  * machinery dies. (Measured: 20 tests, every one of them about polling.) */
562
567
  export { stripMarkdown };
563
568
 
569
+ /** The screen-reader line for a bubble — see `AriaBubble.spoken`. */
570
+ export function spokenOf(who: string, content: string): string {
571
+ return who ? `${who}: ${content}` : content;
572
+ }
573
+
574
+ /** A persisted transcript from before `spoken` existed, made whole. A `$item.`
575
+ * path missing on a row does not substitute, so a row without the field would
576
+ * announce the literal binding until the next rebuild replaced it. */
577
+ export function withSpoken(bubbles: AriaBubble[]): AriaBubble[] {
578
+ return bubbles.every((b) => typeof b.spoken === "string")
579
+ ? bubbles
580
+ : bubbles.map((b) => (typeof b.spoken === "string" ? b : { ...b, spoken: spokenOf(b.who, b.content) }));
581
+ }
582
+
564
583
  /** A greeting or optimistic bubble: no links, all slots defaulted. */
565
584
  export function plainBubble(id: string, role: string, who: string, content: string): AriaBubble {
566
- return { id, role, who, content, notUser: role !== "USER", notAria: role === "USER", ...linkFieldsOf("", role) };
585
+ return { id, role, who, content, notUser: role !== "USER", notAria: role === "USER", spoken: spokenOf(who, content), ...linkFieldsOf("", role) };
567
586
  }
568
587
 
569
588
  /** Server transcript → bubbles. USER text is literal; ASSISTANT replies are
@@ -644,6 +663,7 @@ function bubbleOf(id: string, role: string, who: string, raw: string, writing: b
644
663
  content,
645
664
  notUser: role !== "USER",
646
665
  notAria: role === "USER",
666
+ spoken: spokenOf(who, content),
647
667
  ...linkFieldsOf(prose, role),
648
668
  };
649
669
  }
@@ -2004,7 +2024,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
2004
2024
  // a rehydrated turn there was no ladder at all, leaving "Aria is
2005
2025
  // typing…" on screen with nothing ever fetching the answer.
2006
2026
  if (s._pending || s.status === "sending") {
2007
- const held: AriaChatState = { ...s, status: "sending", prompts: [] };
2027
+ const held: AriaChatState = { ...s, status: "sending", prompts: [], messages: withSpoken(s.messages) };
2008
2028
  return cadence(held, o.poll ? o.poll.fastMs : null, null);
2009
2029
  }
2010
2030
  // …but the self-kick pass runs BEFORE the pack is stashed, so the
@@ -2013,7 +2033,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
2013
2033
  // still the only thing on screen — `prompts` is already recomputed
2014
2034
  // here, and a chip pack that localizes beside a greeting that does not
2015
2035
  // is the visible half of the same bug.
2016
- const messages = isGreetingOnly(s.messages) ? greetingOnly() : s.messages;
2036
+ const messages = isGreetingOnly(s.messages) ? greetingOnly() : withSpoken(s.messages);
2017
2037
  return { ...s, status: "ready", messages, prompts: promptsFor(messages, promptList()) };
2018
2038
  }
2019
2039
  try {
@@ -190,10 +190,22 @@ const SCREENS = runtimeSetting({
190
190
  }
191
191
  },
192
192
  "cornerRadius": 8,
193
- "hiddenPath": "$service:himiBrandedHome.hideHeroSkeleton",
194
- "padding": {
195
- "bottom": 16
193
+ "hiddenPath": "$service:himiBrandedHome.hideHeroSkeleton"
194
+ }
195
+ },
196
+ {
197
+ "id": "himi_branded_home.hero_skeleton.gap",
198
+ "body": {
199
+ "package": "himalaya",
200
+ "type": "VStack",
201
+ "props": {
202
+ "children": []
196
203
  }
204
+ },
205
+ "modifiers": {
206
+ "height": 16,
207
+ "fillMaxWidth": true,
208
+ "hiddenPath": "$service:himiBrandedHome.hideHeroSkeleton"
197
209
  }
198
210
  },
199
211
  {
@@ -294,8 +306,24 @@ const SCREENS = runtimeSetting({
294
306
  "leading": 24,
295
307
  "trailing": 24,
296
308
  "top": 24,
297
- "bottom": 16
309
+ "bottom": 24
298
310
  },
311
+ "fillMaxWidth": true,
312
+ "hiddenPath": "$service:himiBrandedHome.hideHeroFallback"
313
+ }
314
+ },
315
+ {
316
+ "id": "himi_branded_home.hero.gap",
317
+ "body": {
318
+ "package": "himalaya",
319
+ "type": "VStack",
320
+ "props": {
321
+ "children": []
322
+ }
323
+ },
324
+ "modifiers": {
325
+ "height": 16,
326
+ "fillMaxWidth": true,
299
327
  "hiddenPath": "$service:himiBrandedHome.hideHeroFallback"
300
328
  }
301
329
  },