@wix/himalaya-cli 0.1201.0 → 0.1203.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.
@@ -610,6 +610,8 @@ export declare function formField(props: {
610
610
  * opens the device photo picker; the renderer uploads the bytes to Wix Media and
611
611
  * calls `<uploadService>.genUpload`/`setMedia` on the screen's worker so the well
612
612
  * previews the photo and the worker can attach it on save. Generic (any app).
613
+ * Declared in core.proto as `media_field = 163` (#3744); `label` also names the
614
+ * well for assistive technology, so pass one.
613
615
  */
614
616
  export declare function mediaField(props: {
615
617
  valuePath: string;
@@ -1549,6 +1549,22 @@ export interface RichContentEditorProps {
1549
1549
  /** Rendered when the engine page is unavailable (not bundled / missing / failed / 15 s timeout). */
1550
1550
  fallback?: Component;
1551
1551
  }
1552
+ /**
1553
+ * #3744 — an image well bound to a `$service:` image URL. Tapping it opens the platform photo
1554
+ * picker (PhotosPicker on iOS, the Android photo picker, a file chooser on web); the renderer
1555
+ * then runs the upload contract against the screen's worker: `<uploadService>.genUpload({fileName,
1556
+ * mimeType})` → PUT the bytes to `<uploadService>.uploadUrl` + `?filename=<fileName>` →
1557
+ * `<uploadService>.setMedia({mediaId, imageUrl})`. The well previews whatever `valuePath`
1558
+ * resolves to, so the worker updating that value in `setMedia` is what shows the new photo.
1559
+ */
1560
+ export interface MediaFieldProps {
1561
+ /** `$service:<svc>.<path>` → the current image URL; empty ⇒ the empty well with `label`. */
1562
+ valuePath: string;
1563
+ /** The worker service exposing `genUpload` / `setMedia` and the `uploadUrl` value. */
1564
+ uploadService: string;
1565
+ /** Empty-well copy (a message key or literal). Default "Add a photo". */
1566
+ label?: string;
1567
+ }
1552
1568
  /**
1553
1569
  * RFC 0063 — a Wix Ricos rich-content document rendered natively: headings, lists, links,
1554
1570
  * images, galleries, video, tables and link cards (never a WebView). The document travels as a
@@ -2379,6 +2395,10 @@ export type CoreComponentBody = {
2379
2395
  package: "himalaya";
2380
2396
  type: "RichContentEditor";
2381
2397
  props: RichContentEditorProps;
2398
+ } | {
2399
+ package: "himalaya";
2400
+ type: "MediaField";
2401
+ props: MediaFieldProps;
2382
2402
  } | {
2383
2403
  package: "himalaya";
2384
2404
  type: "VoiceNote";
@@ -193,7 +193,7 @@ function errorMessageFor(args) {
193
193
  if (worker) return worker;
194
194
  const failure = validate(args.rule, args.value);
195
195
  if (!failure) return null;
196
- if (args.rule?.message) return args.rule.message;
196
+ if (typeof args.rule?.message === "string" && args.rule.message.trim()) return args.rule.message;
197
197
  return defaultMessage(failure, args.catalog);
198
198
  }
199
199
  function shouldRevealError(args) {
@@ -8774,6 +8774,8 @@ var CORE_COMPONENTS = /* @__PURE__ */ new Set([
8774
8774
  "himalaya.RichContent",
8775
8775
  // Rich content editor — RFC 0063 §6
8776
8776
  "himalaya.RichContentEditor",
8777
+ // Image well + Wix Media upload — #3744
8778
+ "himalaya.MediaField",
8777
8779
  // Recorded-audio bubble — messenger design G4
8778
8780
  "himalaya.VoiceNote",
8779
8781
  "himalaya.Marquee",
@@ -9251,7 +9253,7 @@ function errorMessageFor(args) {
9251
9253
  if (worker) return worker;
9252
9254
  const failure = validate(args.rule, args.value);
9253
9255
  if (!failure) return null;
9254
- if (args.rule?.message) return args.rule.message;
9256
+ if (typeof args.rule?.message === "string" && args.rule.message.trim()) return args.rule.message;
9255
9257
  return defaultMessage(failure, args.catalog);
9256
9258
  }
9257
9259
  function shouldRevealError(args) {
@@ -155,7 +155,7 @@ function errorMessageFor(args) {
155
155
  if (worker) return worker;
156
156
  const failure = validate(args.rule, args.value);
157
157
  if (!failure) return null;
158
- if (args.rule?.message) return args.rule.message;
158
+ if (typeof args.rule?.message === "string" && args.rule.message.trim()) return args.rule.message;
159
159
  return defaultMessage(failure, args.catalog);
160
160
  }
161
161
  var nonEmpty = (type) => (v) => typeof v === "string" && v.length > 0 && isValid({ type }, v);
package/dist/cli.mjs CHANGED
@@ -6818,6 +6818,7 @@ function walk(node, registry, path2, out2) {
6818
6818
  var SYSTEM_FONT_FAMILY, TONAL_ELEVATION_ALPHA, COLOR_TOKEN_PROPS, TYPOGRAPHY_TOKEN_PROPS;
6819
6819
  var init_tokens = __esm({
6820
6820
  "../../core/ts/src/tokens.ts"() {
6821
+ "use strict";
6821
6822
  SYSTEM_FONT_FAMILY = "$system";
6822
6823
  TONAL_ELEVATION_ALPHA = [0, 0.05, 0.08, 0.11, 0.12, 0.14];
6823
6824
  COLOR_TOKEN_PROPS = {
@@ -6868,6 +6869,7 @@ function resolveTranslation(value, catalog, sourceCatalog) {
6868
6869
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
6869
6870
  var init_bindings = __esm({
6870
6871
  "../../core/ts/src/bindings.ts"() {
6872
+ "use strict";
6871
6873
  BINDING_SIGILS = ["service", "flag", "item", "t"];
6872
6874
  BINDING_SIGIL_RE = new RegExp(
6873
6875
  `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
@@ -7825,6 +7827,8 @@ var init_validator = __esm({
7825
7827
  "himalaya.RichContent",
7826
7828
  // Rich content editor — RFC 0063 §6
7827
7829
  "himalaya.RichContentEditor",
7830
+ // Image well + Wix Media upload — #3744
7831
+ "himalaya.MediaField",
7828
7832
  // Recorded-audio bubble — messenger design G4
7829
7833
  "himalaya.VoiceNote",
7830
7834
  "himalaya.Marquee",
@@ -8265,6 +8269,9 @@ var init_a11y_contract = __esm({
8265
8269
  VoiceNote: { role: "group", name: "required", state: ["playing", "duration/position"], decorative: false },
8266
8270
  Map: { role: "image", name: "required", state: [], decorative: false },
8267
8271
  WebView: { role: "group", name: "required", state: [], decorative: false },
8272
+ // #3744 — the image well is a BUTTON (it opens the photo picker), named by its `label` on every
8273
+ // renderer — including once a photo fills the well and the label is no longer drawn.
8274
+ MediaField: { role: "button", name: "required", state: ["photo set / empty", "uploading"], decorative: false },
8268
8275
  // ---- Interactive controls -----------------------------------------------------------
8269
8276
  Button: { role: "button", name: "required", state: ["disabled"], decorative: false },
8270
8277
  Fab: { role: "button", name: "required", state: ["disabled"], decorative: false },
@@ -10359,6 +10366,33 @@ function richContentEditorFindings(descriptor) {
10359
10366
  visit(descriptor, "", true, false);
10360
10367
  return out2;
10361
10368
  }
10369
+ function mediaFieldFindings(descriptor) {
10370
+ const out2 = [];
10371
+ const visit = (v, path2, atRoot) => {
10372
+ if (Array.isArray(v)) {
10373
+ v.forEach((x, i) => visit(x, `${path2}[${i}]`, false));
10374
+ return;
10375
+ }
10376
+ if (!v || typeof v !== "object") return;
10377
+ const record2 = v;
10378
+ const body = record2.body;
10379
+ if (body?.package === "himalaya" && body.type === "MediaField") {
10380
+ const p = body.props ?? {};
10381
+ if (typeof p.valuePath !== "string" || !p.valuePath.startsWith("$service:") || !WHOLE_VALUE_BINDING.test(p.valuePath)) {
10382
+ out2.push({ path: path2, message: `MediaField.valuePath must be a "$service:<service>.<field>" binding to the current image URL, got ${JSON.stringify(p.valuePath ?? null)} \u2014 every renderer reads it only as a binding to one field, so the well would stay empty` });
10383
+ }
10384
+ if (typeof p.uploadService !== "string" || !EDITOR_SERVICE_NAME.test(p.uploadService)) {
10385
+ out2.push({ path: path2, message: `MediaField.uploadService must name a worker service (letters, digits, "_" or "-") exposing genUpload / setMedia, got ${JSON.stringify(p.uploadService ?? null)}` });
10386
+ }
10387
+ }
10388
+ for (const [key2, child] of Object.entries(record2)) {
10389
+ if (isOpaqueAuthorJson(key2, child, atRoot)) continue;
10390
+ visit(child, path2 ? `${path2}.${key2}` : key2, false);
10391
+ }
10392
+ };
10393
+ visit(descriptor, "", true);
10394
+ return out2;
10395
+ }
10362
10396
  function renderedWixMediaReferences(descriptor) {
10363
10397
  const record2 = descriptor && typeof descriptor === "object" ? descriptor : null;
10364
10398
  const regions = record2 && "payload" in record2 ? [
@@ -10468,6 +10502,9 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
10468
10502
  for (const finding of richContentEditorFindings(descriptor)) {
10469
10503
  issues.push({ severity: "error", pass: "rich-content-editor", path: finding.path, message: finding.message });
10470
10504
  }
10505
+ for (const finding of mediaFieldFindings(descriptor)) {
10506
+ issues.push({ severity: "error", pass: "media-field", path: finding.path, message: finding.message });
10507
+ }
10471
10508
  const bindings = collectServiceBindings(descriptor);
10472
10509
  const descriptorActions = collectDescriptorActions(descriptor);
10473
10510
  const workerActions = descriptorActions.filter(({ actionId }) => actionId.startsWith("tier5."));
@@ -11316,6 +11353,7 @@ var init_validate_descriptor_core = __esm({
11316
11353
  zoom: "number"
11317
11354
  },
11318
11355
  Marquee: { color: "string", durationMs: "number", style: "string", text: "string" },
11356
+ MediaField: { label: "string", uploadService: "string", valuePath: "string" },
11319
11357
  MediaPlayer: {
11320
11358
  allowCellular: "boolean",
11321
11359
  appearance: "any",
@@ -11691,6 +11729,7 @@ var init_validate_descriptor_core = __esm({
11691
11729
  Form: ["id", "submitButton"],
11692
11730
  FragmentSlot: ["casePath", "defaultCase"],
11693
11731
  Icon: ["name"],
11732
+ MediaField: ["valuePath", "uploadService"],
11694
11733
  ProgressBar: ["progress"],
11695
11734
  SegmentedControl: ["selectedId"],
11696
11735
  Snackbar: ["message"],
@@ -25205,7 +25244,7 @@ function errorMessageFor(args) {
25205
25244
  if (worker) return worker;
25206
25245
  const failure = validate(args.rule, args.value);
25207
25246
  if (!failure) return null;
25208
- if (args.rule?.message) return args.rule.message;
25247
+ if (typeof args.rule?.message === "string" && args.rule.message.trim()) return args.rule.message;
25209
25248
  return defaultMessage(failure, args.catalog);
25210
25249
  }
25211
25250
  function shouldRevealError(args) {
@@ -32628,6 +32667,181 @@ var init_richContentEditor = __esm({
32628
32667
  }
32629
32668
  });
32630
32669
 
32670
+ // ../../core/web-host/src/actions/presigned-upload-policy.ts
32671
+ function hostMatches(host) {
32672
+ const h = host.toLowerCase().split(":")[0];
32673
+ return PRESIGNED_UPLOAD_HOST_ROOTS.some((r) => h === r || h.endsWith(`.${r}`));
32674
+ }
32675
+ function isPresignedUploadTarget(raw) {
32676
+ if (!raw) return false;
32677
+ let u;
32678
+ try {
32679
+ u = new URL(raw);
32680
+ } catch {
32681
+ return false;
32682
+ }
32683
+ if (u.protocol !== "https:") return false;
32684
+ if (u.username || u.password) return false;
32685
+ return hostMatches(u.hostname);
32686
+ }
32687
+ var PRESIGNED_UPLOAD_HOST_ROOTS, MAX_INLINE_BASE64_BYTES, MAX_UPLOAD_BYTES;
32688
+ var init_presigned_upload_policy = __esm({
32689
+ "../../core/web-host/src/actions/presigned-upload-policy.ts"() {
32690
+ PRESIGNED_UPLOAD_HOST_ROOTS = ["wixmp.com"];
32691
+ MAX_INLINE_BASE64_BYTES = 8 * 1024 * 1024;
32692
+ MAX_UPLOAD_BYTES = 32 * 1024 * 1024;
32693
+ }
32694
+ });
32695
+
32696
+ // ../../core/web-renderer/src/mediaFieldUpload.ts
32697
+ function mediaFieldName(label2) {
32698
+ return typeof label2 === "string" && label2.trim() !== "" ? label2 : MEDIA_FIELD_DEFAULT_LABEL;
32699
+ }
32700
+ function mediaFieldState(uploading, hasPhoto, failed2 = false) {
32701
+ if (uploading) return "Uploading";
32702
+ if (failed2) return MEDIA_FIELD_UPLOAD_FAILED;
32703
+ return hasPhoto ? "Photo added" : void 0;
32704
+ }
32705
+ function mediaFieldServicePath(valuePath) {
32706
+ if (typeof valuePath !== "string" || !valuePath.startsWith("$service:")) return null;
32707
+ const p = valuePath.slice("$service:".length);
32708
+ return p === "" ? null : p;
32709
+ }
32710
+ function mediaFieldFileName(sizeBytes, mimeType) {
32711
+ const ext = /png/i.test(mimeType) ? "png" : /gif/i.test(mimeType) ? "gif" : /webp/i.test(mimeType) ? "webp" : /hei[cf]/i.test(mimeType) ? "heic" : "jpg";
32712
+ return `photo-${Math.max(0, Math.floor(sizeBytes))}.${ext}`;
32713
+ }
32714
+ function isMediaFieldUploadTarget(url) {
32715
+ return typeof url === "string" && isPresignedUploadTarget(url);
32716
+ }
32717
+ async function runMediaFieldUpload(o) {
32718
+ const { uploadService: svc, file, deps } = o;
32719
+ if (!svc) return { ok: false, reason: "no_service" };
32720
+ const t = deps.timers ?? { setTimeout: (fn, ms) => setTimeout(fn, ms), clearTimeout: (h) => clearTimeout(h) };
32721
+ const controller = typeof AbortController === "function" ? new AbortController() : null;
32722
+ let expired = false;
32723
+ let onExpire = [];
32724
+ const timer = t.setTimeout(() => {
32725
+ expired = true;
32726
+ controller?.abort();
32727
+ for (const fn of onExpire) fn();
32728
+ onExpire = [];
32729
+ }, o.timeoutMs ?? MEDIA_FIELD_UPLOAD_TIMEOUT_MS);
32730
+ const bounded2 = (p) => {
32731
+ if (expired) return Promise.reject(new Deadline());
32732
+ return new Promise((resolve57, reject) => {
32733
+ const stop = () => reject(new Deadline());
32734
+ onExpire.push(stop);
32735
+ p.then(resolve57, reject).finally(() => {
32736
+ onExpire = onExpire.filter((f) => f !== stop);
32737
+ });
32738
+ });
32739
+ };
32740
+ const dispatchedAs = async (action) => {
32741
+ try {
32742
+ const r = deps.dispatch(action);
32743
+ if (r && typeof r.then === "function") {
32744
+ const v = await bounded2(Promise.resolve(r));
32745
+ return v === null ? "rejected" : "settled";
32746
+ }
32747
+ return "unknown";
32748
+ } catch {
32749
+ return "rejected";
32750
+ }
32751
+ };
32752
+ const dispatched = async (action) => await dispatchedAs(action) !== "rejected";
32753
+ try {
32754
+ const urlPath = `${svc}.uploadUrl`;
32755
+ const before = deps.value(urlPath);
32756
+ let uploadUrl;
32757
+ try {
32758
+ uploadUrl = await bounded2(new Promise((resolve57, reject) => {
32759
+ let done = false;
32760
+ let unsub = () => {
32761
+ };
32762
+ unsub = deps.subscribe(urlPath, (v) => {
32763
+ if (done || typeof v !== "string" || v === "" || v === before) return;
32764
+ done = true;
32765
+ queueMicrotask(() => unsub());
32766
+ resolve57(v);
32767
+ });
32768
+ onExpire.push(() => {
32769
+ if (!done) {
32770
+ done = true;
32771
+ queueMicrotask(() => unsub());
32772
+ }
32773
+ });
32774
+ void dispatchedAs({ actionId: `tier5.${svc}.genUpload`, args: { fileName: file.fileName, mimeType: file.mimeType } }).then((how) => {
32775
+ if (done || how === "unknown") return;
32776
+ if (how === "settled") {
32777
+ const now = deps.value(urlPath);
32778
+ if (typeof now === "string" && now !== "" && now !== before) {
32779
+ done = true;
32780
+ queueMicrotask(() => unsub());
32781
+ resolve57(now);
32782
+ return;
32783
+ }
32784
+ }
32785
+ done = true;
32786
+ queueMicrotask(() => unsub());
32787
+ reject(new ActionRejected());
32788
+ });
32789
+ }));
32790
+ } catch (e) {
32791
+ return { ok: false, reason: e instanceof ActionRejected ? "gen_upload" : "timeout" };
32792
+ }
32793
+ if (!isMediaFieldUploadTarget(uploadUrl)) return { ok: false, reason: "bad_target" };
32794
+ let body;
32795
+ try {
32796
+ body = await bounded2(Promise.resolve(typeof file.body === "function" ? file.body() : file.body));
32797
+ } catch (e) {
32798
+ return { ok: false, reason: e instanceof Deadline ? "timeout" : "read" };
32799
+ }
32800
+ const sep19 = uploadUrl.includes("?") ? "&" : "?";
32801
+ let res;
32802
+ try {
32803
+ res = await bounded2(deps.fetch(`${uploadUrl}${sep19}filename=${encodeURIComponent(file.fileName)}`, {
32804
+ method: "PUT",
32805
+ headers: { "Content-Type": file.mimeType },
32806
+ body,
32807
+ ...controller ? { signal: controller.signal } : {}
32808
+ }));
32809
+ } catch (e) {
32810
+ return { ok: false, reason: e instanceof Deadline || expired ? "timeout" : "put" };
32811
+ }
32812
+ if (!res.ok) return { ok: false, reason: "put" };
32813
+ let json6;
32814
+ try {
32815
+ json6 = await bounded2(res.json());
32816
+ } catch (e) {
32817
+ return { ok: false, reason: e instanceof Deadline || expired ? "timeout" : "bad_descriptor" };
32818
+ }
32819
+ const root = json6 && typeof json6 === "object" ? json6 : {};
32820
+ const d = root.file && typeof root.file === "object" ? root.file : root;
32821
+ const mediaId = typeof d.id === "string" ? d.id : "";
32822
+ if (!mediaId) return { ok: false, reason: "bad_descriptor" };
32823
+ const imageUrl = typeof d.url === "string" ? d.url : "";
32824
+ if (!await dispatched({ actionId: `tier5.${svc}.setMedia`, args: { mediaId, imageUrl } })) return { ok: false, reason: "set_media" };
32825
+ return { ok: true, mediaId, imageUrl };
32826
+ } finally {
32827
+ t.clearTimeout(timer);
32828
+ onExpire = [];
32829
+ }
32830
+ }
32831
+ var MEDIA_FIELD_DEFAULT_LABEL, MEDIA_FIELD_UPLOAD_TIMEOUT_MS, MEDIA_FIELD_UPLOAD_FAILED, Deadline, ActionRejected;
32832
+ var init_mediaFieldUpload = __esm({
32833
+ "../../core/web-renderer/src/mediaFieldUpload.ts"() {
32834
+ init_presigned_upload_policy();
32835
+ MEDIA_FIELD_DEFAULT_LABEL = "Add a photo";
32836
+ MEDIA_FIELD_UPLOAD_TIMEOUT_MS = 3e4;
32837
+ MEDIA_FIELD_UPLOAD_FAILED = "Upload failed";
32838
+ Deadline = class extends Error {
32839
+ };
32840
+ ActionRejected = class extends Error {
32841
+ };
32842
+ }
32843
+ });
32844
+
32631
32845
  // ../../core/web-renderer/src/pdfSource.ts
32632
32846
  function pdfEmbedPlan(url, pageOrigin = currentOrigin()) {
32633
32847
  const target = classifyEmbedUrl(url, pageOrigin);
@@ -35832,9 +36046,10 @@ function renderInner(node, ctx) {
35832
36046
  return /* @__PURE__ */ jsx8(IconNode, { props, ctx, wrap });
35833
36047
  case "Button":
35834
36048
  return /* @__PURE__ */ jsx8(ButtonNode, { props, ctx, wrap });
36049
+ case "MediaField":
36050
+ return /* @__PURE__ */ jsx8(MediaFieldNode, { props, ctx, wrap });
35835
36051
  case "TextField":
35836
36052
  case "RichTextField":
35837
- case "MediaField":
35838
36053
  return /* @__PURE__ */ jsx8(EditableField, { props, ctx, wrap, multiline: type === "RichTextField" });
35839
36054
  case "Toggle":
35840
36055
  return /* @__PURE__ */ jsx8(ToggleNode, { props, ctx, wrap });
@@ -36214,7 +36429,7 @@ function renderInner(node, ctx) {
36214
36429
  }
36215
36430
  }
36216
36431
  }
36217
- 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, kids2, rowKidCtx, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, RichContentEditorNode, 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, 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, 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;
36432
+ 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, 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, 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, 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;
36218
36433
  var init_renderNode = __esm({
36219
36434
  "../../core/web-renderer/src/renderNode.tsx"() {
36220
36435
  "use strict";
@@ -36233,6 +36448,7 @@ var init_renderNode = __esm({
36233
36448
  init_icons();
36234
36449
  init_webviewFrame();
36235
36450
  init_richContentEditor();
36451
+ init_mediaFieldUpload();
36236
36452
  init_pdfSource();
36237
36453
  init_icon_catalog_generated();
36238
36454
  init_controls();
@@ -36369,6 +36585,7 @@ var init_renderNode = __esm({
36369
36585
  return React7.cloneElement(el, { key: n?.id ?? i, style: { ...prev, animationDelay: `${i * staggerMs}ms` } });
36370
36586
  }) : null;
36371
36587
  asTextL10n = (v, ctx) => typeof v === "string" && v.startsWith(TRANSLATION_PREFIX) ? asText2(resolveTranslation(v, ctx.catalog)) : asText2(v);
36588
+ asFinalTextL10n = (v, ctx) => typeof v === "string" ? v.startsWith(TRANSLATION_PREFIX) ? asText2(resolveTranslation(v, ctx.catalog)) : v : asText2(v);
36372
36589
  asBoundText = (v, ctx) => isBinding(v) ? asTextL10n(resolveScalarStatic(v, ctx) ?? "", ctx) : asText2(v);
36373
36590
  useBoundString = (v, ctx) => {
36374
36591
  const resolved2 = useResolvedScalar(v, ctx);
@@ -36471,6 +36688,78 @@ var init_renderNode = __esm({
36471
36688
  return fragmentSlotContent({ props, ctx, discriminator, slotId: nodeId, extra: wrap });
36472
36689
  });
36473
36690
  RichContentEditorNode = withExtras("RichContentEditorNode", ({ props, ctx, wrap, nodeId }) => /* @__PURE__ */ jsx8(RichContentEditorView, { props, ctx, wrap, nodeId, renderChild: (n) => renderNode(n, ctx) }));
36691
+ MediaFieldNode = withExtras("MediaFieldNode", ({ props, ctx, wrap }) => {
36692
+ const C = ctx.color;
36693
+ const servicePathStr = mediaFieldServicePath(props.valuePath);
36694
+ const bound = useBoundValue(ctx, servicePathStr ? String(props.valuePath) : "");
36695
+ const imageUrl = typeof bound === "string" ? bound : "";
36696
+ const [uploading, setUploading] = React7.useState(false);
36697
+ const [failed2, setFailed] = React7.useState(false);
36698
+ const fileRef = React7.useRef(null);
36699
+ const uploadService = typeof props.uploadService === "string" ? props.uploadService : "";
36700
+ const resolvedLabel = asText2(resolveScalarStatic(props.label, ctx));
36701
+ const name = mediaFieldName(resolvedLabel);
36702
+ const state = mediaFieldState(uploading, imageUrl !== "", failed2);
36703
+ const open = () => {
36704
+ if (!uploading) fileRef.current?.click();
36705
+ };
36706
+ const onPick = async (e) => {
36707
+ const input = e.currentTarget;
36708
+ const file = input.files?.[0];
36709
+ input.value = "";
36710
+ if (!file || !ctx.onAction || !ctx.provider || !uploadService) return;
36711
+ const provider = ctx.provider;
36712
+ const mimeType = file.type || "image/jpeg";
36713
+ setUploading(true);
36714
+ setFailed(false);
36715
+ try {
36716
+ const r = await runMediaFieldUpload({
36717
+ uploadService,
36718
+ file: { mimeType, fileName: mediaFieldFileName(file.size, mimeType), body: file },
36719
+ deps: {
36720
+ dispatch: (action) => ctx.onAction?.(action),
36721
+ value: (p) => provider.value(p),
36722
+ subscribe: (p, cb) => provider.subscribe(p, cb),
36723
+ fetch: (url, init) => fetch(url, init)
36724
+ }
36725
+ });
36726
+ if (!r.ok) setFailed(true);
36727
+ } catch {
36728
+ setFailed(true);
36729
+ } finally {
36730
+ setUploading(false);
36731
+ }
36732
+ };
36733
+ const f = ctx.font("bodyEmphasis");
36734
+ const radius = 12;
36735
+ return /* @__PURE__ */ jsxs5(
36736
+ "div",
36737
+ {
36738
+ role: "button",
36739
+ tabIndex: 0,
36740
+ "aria-label": state ? `${name}, ${state}` : name,
36741
+ "aria-busy": uploading || void 0,
36742
+ "data-media-service": uploadService,
36743
+ onClick: open,
36744
+ onKeyDown: (e) => {
36745
+ if (e.key === "Enter" || e.key === " ") {
36746
+ e.preventDefault();
36747
+ open();
36748
+ }
36749
+ },
36750
+ style: { position: "relative", display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: 160, borderRadius: radius, overflow: "hidden", background: C("surfaceSecondary", "#F2F3F5"), cursor: "pointer", boxSizing: "border-box", ...wrap },
36751
+ children: [
36752
+ /* @__PURE__ */ jsx8("input", { ref: fileRef, type: "file", accept: "image/*", tabIndex: -1, "aria-hidden": "true", onChange: onPick, onClick: (e) => e.stopPropagation(), style: { display: "none" } }),
36753
+ imageUrl ? /* @__PURE__ */ jsx8("img", { src: resolveAssetUrl(imageUrl, ctx.assetBaseUrl), alt: "", "aria-hidden": "true", style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", display: "block" } }) : /* @__PURE__ */ jsxs5("div", { "aria-hidden": "true", style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, color: accentTextColor(ctx) }, children: [
36754
+ iconSvg("camera", { size: 28, color: accentTextColor(ctx) }),
36755
+ /* @__PURE__ */ jsx8("span", { style: { fontFamily: fontStack(f.family, ctx.idiom), fontWeight: f.weight, fontSize: f.remSize }, children: name })
36756
+ ] }),
36757
+ uploading ? /* @__PURE__ */ jsx8("div", { "aria-hidden": "true", "data-media-uploading": "true", style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.35)" } }) : null,
36758
+ failed2 && !uploading ? /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", "data-media-upload-error": "true", style: { position: "absolute", left: 8, right: 8, bottom: 8, textAlign: "center", fontSize: pxToRem(13), color: C("danger", "#E62214") }, children: MEDIA_FIELD_UPLOAD_FAILED }) : null
36759
+ ]
36760
+ }
36761
+ );
36762
+ });
36474
36763
  WorkerSubtreeNode = withExtras("WorkerSubtreeNode", ({ props, ctx, wrap, nodeId }) => {
36475
36764
  const slotId = nodeId;
36476
36765
  const extra = wrap;
@@ -36690,12 +36979,20 @@ var init_renderNode = __esm({
36690
36979
  () => ctx.catalog ? new Proxy({}, { get: (_t, k) => typeof k === "string" ? ctx.catalog.get(k) : void 0 }) : void 0,
36691
36980
  [ctx.catalog]
36692
36981
  );
36693
- const rawMessage = errorMessageFor({ rule, value: local, workerError, catalog: validationCatalog });
36694
- const resolvedMessage = useBoundString(rawMessage ?? "", ctx);
36695
- const message = rawMessage === null || !resolvedMessage.trim() ? null : resolvedMessage;
36982
+ const translateOnly = (v) => asFinalTextL10n(v, ctx);
36983
+ const ruleMessageRaw = typeof rule?.message === "string" || rule?.message !== null && typeof rule?.message === "object" ? rule?.message : void 0;
36984
+ const ruleMessageBound = typeof ruleMessageRaw === "string" && isBinding(ruleMessageRaw) && !ruleMessageRaw.startsWith(TRANSLATION_PREFIX);
36985
+ const ruleMessageResolved = useResolvedScalar(ruleMessageBound ? ruleMessageRaw : void 0, ctx);
36986
+ const ruleMessageText = ruleMessageRaw == null ? "" : ruleMessageBound ? ruleMessageResolved == null ? "" : translateOnly(ruleMessageResolved) : translateOnly(ruleMessageRaw);
36987
+ const ruleMessagePending = ruleMessageBound && !ruleMessageText.trim() && ruleMessageRaw.startsWith("$service:") && !!ctx.provider && !(formBag?.submitAttempted ?? false);
36988
+ const effectiveRule = !rule || ruleMessageRaw == null ? rule : { ...rule, message: ruleMessageText };
36989
+ const rawMessage = errorMessageFor({ rule: effectiveRule, value: local, workerError, catalog: validationCatalog });
36990
+ const hasWorkerError = Boolean(workerError && workerError.trim());
36991
+ const painted2 = rawMessage === null ? "" : translateOnly(rawMessage);
36992
+ const message = !painted2.trim() || ruleMessagePending && !hasWorkerError ? null : painted2;
36696
36993
  const revealed = message !== null && shouldRevealError({
36697
36994
  rule,
36698
- hasWorkerError: Boolean(workerError && workerError.trim()),
36995
+ hasWorkerError,
36699
36996
  touched,
36700
36997
  focused: isFocused,
36701
36998
  submitAttempted: formBag?.submitAttempted ?? false
@@ -40401,6 +40698,10 @@ function buildRenderTree(node, path2 = "$", provider = null, itemScope = void 0,
40401
40698
  }
40402
40699
  }
40403
40700
  if (type === "OtpInput" && props.secure === true) delete values.value;
40701
+ if (type === "MediaField" && typeof props.valuePath === "string" && props.valuePath.startsWith("$service:")) {
40702
+ const photo = resolveTreeScalar(props.valuePath, provider, itemScope);
40703
+ if (typeof photo === "string" && photo !== "") delete values.label;
40704
+ }
40404
40705
  collectComponentMediaValues(type, props, { provider, itemScope, values, insideMediaProperty: false });
40405
40706
  collectResolvedMediaValues(modifiers, "modifiers", {
40406
40707
  provider,
@@ -56151,8 +56452,8 @@ function allowed(url, declared) {
56151
56452
  if (declaredPort !== void 0 && (!/^\d+$/.test(declaredPort) || Number(declaredPort) > 65535)) return false;
56152
56453
  const defaultPort = url.protocol === "https:" ? "443" : "80";
56153
56454
  const portMatches = declaredPort !== void 0 ? String(Number(declaredPort)) === actualPort : actualPort === defaultPort;
56154
- const hostMatches = wildcard ? value !== normalized && value.endsWith(`.${normalized}`) : value === normalized || value.endsWith(`.${normalized}`);
56155
- return portMatches && hostMatches;
56455
+ const hostMatches2 = wildcard ? value !== normalized && value.endsWith(`.${normalized}`) : value === normalized || value.endsWith(`.${normalized}`);
56456
+ return portMatches && hostMatches2;
56156
56457
  });
56157
56458
  }
56158
56459
  function ipv4Private(address) {
@@ -61368,21 +61669,21 @@ var init_preview_assets_generated = __esm({
61368
61669
  "../../packages/serve/src/preview-assets.generated.ts"() {
61369
61670
  init_preview_assets_format();
61370
61671
  PREVIEW_ASSET_MANIFEST = [
61371
- { key: "assets/index-Bj2h2VLm.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1140295, sha256: "4501893b27a6121e14d79939efd53d5c88fd923cddab4314ecb5eb41de3233b9" },
61372
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1140303, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
61373
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1144913, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
61374
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1633497, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
61375
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1724421, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
61376
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1815405, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
61377
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1906385, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
61378
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1997257, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
61379
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 2088237, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
61380
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2196873, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
61381
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2305957, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
61382
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2415005, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
61383
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2522705, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
61384
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2610813, length: 4947, sha256: "4bb31d3503d8874f0c8b90db2fafd58b0229ff64adeec94b2debf5ace8151c7a" },
61385
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2615760, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
61672
+ { key: "assets/index-CPRJc_Hj.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1145737, sha256: "5e9c570a5baa2ef39ccf2d357c78631a2d5f9190acfb01dcc77ccce17538457a" },
61673
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1145745, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
61674
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1150355, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
61675
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1638939, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
61676
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1729863, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
61677
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1820847, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
61678
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1911827, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
61679
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 2002699, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
61680
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 2093679, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
61681
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2202315, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
61682
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2311399, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
61683
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2420447, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
61684
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2528147, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
61685
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2616255, length: 4947, sha256: "20678191da952eca3f3fb8fb8b137db4cbb11dc84d0a8e59146cb669c5aa26b9" },
61686
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2621202, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
61386
61687
  ];
61387
61688
  }
61388
61689
  });
Binary file
@@ -2,7 +2,7 @@
2
2
  "_comment": "GENERATED by core/web-embed/authoring/gen-reference.mjs from core/ts/src/schema.ts — do not hand-edit. The schema is the source of truth; regenerate on schema changes.",
3
3
  "schemaSource": "core/ts/src/schema.ts",
4
4
  "bindingGrammar": "$service:<service>.<path> (worker state) · $item.<field> (list row) · $flag:<key> (feature flag) · $env:<key> (client environment — #1056). Bindings resolve in the text/value props marked 'binding-aware' below — INCLUDING Modifiers token refs — but only `background` and `border.color`, which are the two whose token a binding actually fills: a worker can drive per-item theming (e.g. a game board's per-square color), not just text. `shadow` is NOT binding-aware on any renderer, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref — so `shadow: { token: \"$item.x\" }` and `backgroundGradient: { token: \"$item.x\" }` keep the sentinel and silently lose the per-item styling. Colour slots split by LEVEL, not by component: inside modifiers a colour is a TokenRef OBJECT ({ token: \"…\" }), inside props it is a bare TokenName STRING — there is no modifiers.color or modifiers.tint (see the 'Token slots' section in component-reference.md). A few input props render the LITERAL and are NOT binding-aware — notably SearchField.placeholder and Chip.label; SearchField.value is live and binding-aware like other content props. Bindings also CANNOT target strict-enum fields (style, size, alignment, severity, presentation, contentMode, …) — those fail at render, not validation. $env: is client-resolved (no worker) and valid in modifiers.hiddenPath and FragmentSlot.casePath ONLY — keys reduceMotion/colorScheme/sizeClass/isRTL, e.g. hiddenPath:\"$env:reduceMotion\" or hiddenPath:\"$env:colorScheme==light\", casePath:\"$env:colorScheme\"; unknown key fails open (shown / defaultCase).",
5
- "componentCount": 84,
5
+ "componentCount": 85,
6
6
  "notImplementedComponents": [
7
7
  "Text",
8
8
  "Carousel",
@@ -1057,6 +1057,15 @@
1057
1057
  ],
1058
1058
  "propsSource": "export interface RichContentEditorProps {\n /** Form-bag key. Required inside a Form (validator). */\n name?: string;\n /** `$service:<svc>.<path>` → the document JSON string. Seeds ONCE (the first non-empty value). */\n documentPath?: string;\n /** Literal seed document JSON. At most one of documentPath / documentJson. */\n documentJson?: string;\n placeholder?: string;\n /** Empty ⇒ all, minus \"image\" unless uploadService is set. \"image\" requires uploadService. */\n tools?: RichContentEditorTool[];\n /** Debounced ≥ 500 ms; args = { dirty: \"true\" } — never the document. */\n onChange?: Action;\n /** Worker service made by `ricosUploadService` (@himalaya/wix-rich-content-editor). Enables \"image\". */\n uploadService?: string;\n /** Take the remaining height of a bounded parent; else `minHeight`. */\n fillAvailable?: boolean;\n /** Default 240. */\n minHeight?: number;\n /** Rendered when the engine page is unavailable (not bundled / missing / failed / 15 s timeout). */\n fallback?: Component;\n}"
1059
1059
  },
1060
+ {
1061
+ "name": "MediaField",
1062
+ "category": "Image well + Wix Media upload (#3744)",
1063
+ "propsType": "MediaFieldProps",
1064
+ "bindings": [
1065
+ "valuePath"
1066
+ ],
1067
+ "propsSource": "export interface MediaFieldProps {\n /** `$service:<svc>.<path>` → the current image URL; empty ⇒ the empty well with `label`. */\n valuePath: string;\n /** The worker service exposing `genUpload` / `setMedia` and the `uploadUrl` value. */\n uploadService: string;\n /** Empty-well copy (a message key or literal). Default \"Add a photo\". */\n label?: string;\n}"
1068
+ },
1060
1069
  {
1061
1070
  "name": "VoiceNote",
1062
1071
  "category": "Recorded-audio bubble (messenger design G4)",
@@ -3,7 +3,7 @@
3
3
  > GENERATED from `core/ts/src/schema.ts` by `core/web-embed/authoring/gen-reference.mjs`.
4
4
  > The schema is the source of truth — regenerate on schema changes; do not hand-edit.
5
5
 
6
- **84 core component types.** Every component body is `{ "package": "himalaya", "type": "<Type>", "props": { … } }`.
6
+ **85 core component types.** Every component body is `{ "package": "himalaya", "type": "<Type>", "props": { … } }`.
7
7
  Binding grammar: `$service:<service>.<path>` (worker state) · `$item.<field>` (list row template) · `$flag:<key>` (feature flag) · `$env:<key>` (client environment — #1056).
8
8
  Bindings resolve in the text/value props marked **binding-aware** below — **including two `Modifiers` token refs**, `background` and `border.color`, which are the only two whose token a binding actually fills: a worker can drive per-item **theming** (e.g. a game board's per-square color, `background: { token: "$item.bg" }`), not just text content. `shadow` and `backgroundGradient` are `TokenRef`s but are **not** binding-aware on any renderer — `shadow: { token: "$item.x" }` keeps the sentinel as a literal token name and silently loses the per-item styling, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref.
9
9
  `$env:` is **client-resolved** (no worker) and valid in `modifiers.hiddenPath` and `FragmentSlot.casePath` **only** — keys `reduceMotion` / `colorScheme` / `sizeClass` / `isRTL`, with an optional `==`/`!=` comparison (e.g. `hiddenPath: "$env:reduceMotion"`, `hiddenPath: "$env:colorScheme==light"`, `casePath: "$env:colorScheme"`). An unknown key fails open (shown / `defaultCase`).
@@ -94,6 +94,7 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
94
94
  | `DataTable` | Analytics data-viz | `rowsPath`, `totalsPath` |
95
95
  | `RichContent` | Rich content | `documentJsonPath` |
96
96
  | `RichContentEditor` | Rich content editor | `documentPath` |
97
+ | `MediaField` | Image well + Wix Media upload (#3744) | `valuePath` |
97
98
  | `VoiceNote` | Recorded-audio bubble (messenger design G4) | `waveformPath`, `durationMsPath`, `positionMsPath`, `statePath`, `deliveryPath`, `ratePath` |
98
99
  | `Marquee` | Recorded-audio bubble (messenger design G4) | — |
99
100
  | `Timeline` | Recorded-audio bubble (messenger design G4) | `entriesPath` |
@@ -116,7 +117,7 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
116
117
 
117
118
  These props are accepted by the schema and pass validation, but the named platform's renderer never reads them — they silently do nothing (no warning, no log). Prefer a prop NOT listed here, or drive the behaviour from a worker.
118
119
 
119
- **Scope: 20 of 84 components, all of them web / android / ios-only** — every other component/platform pair reads every prop it decodes. The list splits in two, and the halves mean different things:
120
+ **Scope: 20 of 85 components, all of them web / android / ios-only** — every other component/platform pair reads every prop it decodes. The list splits in two, and the halves mean different things:
120
121
 
121
122
  - **`category` (7: `Menu`, `Tooltip`, `Popover`, `ChipsInput`, `OtpInput`, `MediaPlayer`, `TimeGrid`)** — the prop changes the component's *kind*. These genuinely are **not implemented**: an overlay renders always-visible inline, so the component does not do the job its name implies. Check the row's note for a working alternative.
122
123
  - **`styling` (13: `Text`, `Carousel`, `CollapsingHeader`, `Banner`, `Snackbar`, `WebView`, `Slider`, `SelectionControl`, `ActivityIndicator`, `Map`, `Video`, `PdfView`, `Agenda`)** — the component itself **works**; only the listed prop is inert. `Slider` on iOS is a working slider whose `debounceMs` does not throttle — not a broken `Slider`. Use the component; just do not depend on that one prop.
@@ -1667,6 +1668,21 @@ export interface RichContentEditorProps {
1667
1668
 
1668
1669
  > ⚠️ **`onChange` on ios + android — DIVERGES:** renders `fallback` only — no editor exists yet, so nothing dispatches on_change. The editor has not reached these renderers yet, so they show the descriptor's `fallback`; the editor runs on the web and in React Native hosts that register its adapter.
1669
1670
 
1671
+ ### Image well + Wix Media upload (#3744)
1672
+
1673
+ #### MediaField
1674
+
1675
+ ```ts
1676
+ export interface MediaFieldProps {
1677
+ /** `$service:<svc>.<path>` → the current image URL; empty ⇒ the empty well with `label`. */
1678
+ valuePath: string;
1679
+ /** The worker service exposing `genUpload` / `setMedia` and the `uploadUrl` value. */
1680
+ uploadService: string;
1681
+ /** Empty-well copy (a message key or literal). Default "Add a photo". */
1682
+ label?: string;
1683
+ }
1684
+ ```
1685
+
1670
1686
  ### Recorded-audio bubble (messenger design G4)
1671
1687
 
1672
1688
  #### VoiceNote
package/guides/index.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "AUTO-GENERATED by tools/authoring-kit/bundle.mjs — DO NOT EDIT. Regenerate with: npm run authoring:gen",
3
3
  "schemaStamp": {
4
- "componentCount": 84,
4
+ "componentCount": 85,
5
5
  "schemaSource": "core/ts/src/schema.ts"
6
6
  },
7
7
  "portalUrl": "https://apps.wix.com/_api/himi-serve/docs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1201.0",
3
+ "version": "0.1203.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": "da789b2bd209029f397baa8fd5f1d53d0cd64549c3eb4006ffb204d0"
70
+ "falconPackageHash": "36a72891777611eef63e609aa328947ea7a30540e4e0f9e4bc5e90ae"
71
71
  }