@wix/himalaya-cli 0.1317.0 → 0.1319.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/theme/src/index.d.ts +21 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/webview-page/src/capabilities.generated.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/brand-color-math.d.ts +98 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +9 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core/brand-color-math.mjs +183 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/theme.mjs +189 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +8 -0
- package/dist/cli.mjs +475 -372
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/app-config.md +1 -1
- package/guides/importable-sdks.md +1 -0
- package/guides/sdk-reference.json +39 -2
- package/guides/web-page-sdk-reference.md +1 -0
- package/package.json +2 -2
- package/templates/beauty-salon-owner/config.ts +1 -1
- package/templates/beauty-salon-owner/dev/index.ts +125 -24
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/community-club-owner/config.ts +1 -1
- package/templates/community-club-owner/dev/index.ts +125 -24
- package/templates/community-club-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/events-meetups-owner/config.ts +1 -1
- package/templates/events-meetups-owner/dev/index.ts +125 -24
- package/templates/events-meetups-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/gym-fitness-owner/config.ts +1 -1
- package/templates/gym-fitness-owner/dev/index.ts +125 -24
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/nonprofit-cause-owner/config.ts +1 -1
- package/templates/nonprofit-cause-owner/dev/index.ts +125 -24
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/owner-lite/config.ts +1 -1
- package/templates/owner-lite/dev/index.ts +125 -24
- package/templates/owner-lite/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/podcast-creator-owner/config.ts +1 -1
- package/templates/podcast-creator-owner/dev/index.ts +125 -24
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/portfolio-creative-owner/config.ts +1 -1
- package/templates/portfolio-creative-owner/dev/index.ts +125 -24
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/restaurant-owner/config.ts +1 -1
- package/templates/restaurant-owner/dev/index.ts +125 -24
- package/templates/restaurant-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/retail-store-owner/config.ts +1 -1
- package/templates/retail-store-owner/dev/index.ts +125 -24
- package/templates/retail-store-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
- package/templates/yoga-studio-owner/config.ts +1 -1
- package/templates/yoga-studio-owner/dev/index.ts +125 -24
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-attachments.ts +41 -2
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +59 -31
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +154 -13
|
@@ -61,10 +61,11 @@ import {
|
|
|
61
61
|
import {
|
|
62
62
|
ARIA_MAX_ATTACHMENTS,
|
|
63
63
|
ARIA_MAX_IMAGE_BYTES,
|
|
64
|
+
ARIA_MAX_DOCUMENT_BYTES,
|
|
64
65
|
attachmentLine,
|
|
65
66
|
chipIn,
|
|
66
67
|
imageFileName,
|
|
67
|
-
|
|
68
|
+
attachmentMime,
|
|
68
69
|
parseDataUri,
|
|
69
70
|
refusalFor,
|
|
70
71
|
sendBlocker,
|
|
@@ -480,6 +481,9 @@ export interface AriaChatLabels {
|
|
|
480
481
|
/** Send refused while a photo is still uploading, or failed to. */
|
|
481
482
|
attachWaitUploading?: Resolvable<string>;
|
|
482
483
|
attachWaitFailed?: Resolvable<string>;
|
|
484
|
+
/** Send refused by a failed file that cannot be retried (a cold-start chip
|
|
485
|
+
* whose source did not survive): Remove is the only control it offers. */
|
|
486
|
+
attachWaitRemove?: Resolvable<string>;
|
|
483
487
|
/** Send refused with photos and no words. The service requires message text
|
|
484
488
|
* on every turn, so a photo alone is not a sendable message. */
|
|
485
489
|
attachNeedsText?: Resolvable<string>;
|
|
@@ -535,7 +539,7 @@ export interface AriaDictationOptions {
|
|
|
535
539
|
export interface AriaAttachmentPorts {
|
|
536
540
|
/** Let the owner pick (or take) one photo. Resolves the image as a `data:`
|
|
537
541
|
* URI, or null when they cancelled. */
|
|
538
|
-
pick(source: "library" | "camera"): Promise<{ dataUri: string; name?: string; mimeType?: string } | null>;
|
|
542
|
+
pick(source: "library" | "camera" | "document"): Promise<{ dataUri: string; name?: string; mimeType?: string } | null>;
|
|
539
543
|
/** PUT `base64` to a pre-signed url with `contentType`, carrying NO user
|
|
540
544
|
* credentials — the url authorizes itself. */
|
|
541
545
|
put(url: string, base64: string, contentType: string): Promise<{ ok: boolean; status: number }>;
|
|
@@ -1652,23 +1656,28 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
1652
1656
|
const attachUploadingText = () => res(o.labels?.attachUploading ?? "Uploading…");
|
|
1653
1657
|
const attachFailedText = () => res(o.labels?.attachFailed ?? "Couldn't upload");
|
|
1654
1658
|
const chipLabels = () => ({ uploading: attachUploadingText(), failed: attachFailedText() });
|
|
1655
|
-
const refusalText = (why: "type" | "size" | "count"): string =>
|
|
1659
|
+
const refusalText = (why: "type" | "size" | "count", maxBytes = ARIA_MAX_IMAGE_BYTES): string =>
|
|
1656
1660
|
why === "count"
|
|
1657
|
-
? o.labels?.attachTooMany?.(ARIA_MAX_ATTACHMENTS) ?? `You can attach up to ${ARIA_MAX_ATTACHMENTS}
|
|
1661
|
+
? o.labels?.attachTooMany?.(ARIA_MAX_ATTACHMENTS) ?? `You can attach up to ${ARIA_MAX_ATTACHMENTS} files.`
|
|
1658
1662
|
: why === "size"
|
|
1659
|
-
? o.labels?.attachTooLarge?.(
|
|
1660
|
-
?? `That
|
|
1663
|
+
? o.labels?.attachTooLarge?.(maxBytes / (1024 * 1024))
|
|
1664
|
+
?? `That file is too large to attach (up to ${maxBytes / (1024 * 1024)} MB).`
|
|
1661
1665
|
: res(o.labels?.attachUnsupported ?? "That file type can't be attached.");
|
|
1662
|
-
const waitUploadingText = () => res(o.labels?.attachWaitUploading ?? "Wait for your
|
|
1663
|
-
const waitFailedText = () => res(o.labels?.attachWaitFailed ?? "Retry or remove the
|
|
1664
|
-
const
|
|
1666
|
+
const waitUploadingText = () => res(o.labels?.attachWaitUploading ?? "Wait for your file to finish uploading.");
|
|
1667
|
+
const waitFailedText = () => res(o.labels?.attachWaitFailed ?? "Retry or remove the file that didn't upload.");
|
|
1668
|
+
const waitRemoveText = () => res(o.labels?.attachWaitRemove ?? "Remove the file that didn't upload, then add it again.");
|
|
1669
|
+
/** The failed-file notice must name only a control the chips offer: "Retry"
|
|
1670
|
+
* while any failed chip can still retry, otherwise "Remove". */
|
|
1671
|
+
const failedNotice = (): string =>
|
|
1672
|
+
chips.some((c) => c.state === "failed" && !c.retryHidden) ? waitFailedText() : waitRemoveText();
|
|
1673
|
+
const needsTextText = () => res(o.labels?.attachNeedsText ?? "Add a message to send with your file.");
|
|
1665
1674
|
/** Clear the status line if what it says is an attachment notice, and only
|
|
1666
1675
|
* then. Every notice is advice about the composer's photos, so once the owner
|
|
1667
1676
|
* acts on them it is stale — but the same line also carries "Aria is
|
|
1668
1677
|
* typing…", which a photo edit must never erase. */
|
|
1669
1678
|
const withoutNotice = <T extends { statusText: string }>(s: T): T => {
|
|
1670
|
-
const notices = [waitUploadingText(), waitFailedText(), needsTextText(),
|
|
1671
|
-
refusalText("type"), refusalText("size"), refusalText("count")];
|
|
1679
|
+
const notices = [waitUploadingText(), waitFailedText(), waitRemoveText(), needsTextText(),
|
|
1680
|
+
refusalText("type"), refusalText("size"), refusalText("size", ARIA_MAX_DOCUMENT_BYTES), refusalText("count")];
|
|
1672
1681
|
return s.statusText && notices.includes(s.statusText) ? { ...s, statusText: "" } : s;
|
|
1673
1682
|
};
|
|
1674
1683
|
const toolFailedText = () => res(o.labels?.toolFailed ?? `${assistant()} couldn't finish that. Try again.`);
|
|
@@ -2023,16 +2032,20 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
2023
2032
|
chipsSeeded = true;
|
|
2024
2033
|
const persisted = Array.isArray(s.attachments) ? s.attachments : [];
|
|
2025
2034
|
// An upload does not survive the process that ran it, so a chip persisted
|
|
2026
|
-
// mid-upload would say "Uploading…" forever.
|
|
2027
|
-
//
|
|
2035
|
+
// mid-upload would say "Uploading…" forever. Restore it as failed; only a
|
|
2036
|
+
// chip with retained inline bytes can offer Retry until the file-backed follow-up.
|
|
2028
2037
|
chips = persisted
|
|
2029
2038
|
.filter((c) => c && typeof c.id === "string")
|
|
2030
|
-
.map((c) =>
|
|
2039
|
+
.map((c) => {
|
|
2040
|
+
const chip = chipIn(c, c.state === "uploading" ? "failed" : c.state, chipLabels(), c.ref);
|
|
2041
|
+
// Inline bytes were worker-owned. A cold-start document or large image
|
|
2042
|
+
// has no source left: keep Remove available, never offer a dead Retry.
|
|
2043
|
+
return chip.state === "failed" && !chip.thumbUrl ? { ...chip, retryHidden: true } : chip;
|
|
2044
|
+
});
|
|
2031
2045
|
for (const c of chips) {
|
|
2032
2046
|
const n = Number(/^att-(\d+)$/.exec(c.id)?.[1] ?? 0);
|
|
2033
2047
|
if (n > chipSeq) chipSeq = n;
|
|
2034
|
-
// A rehydrated chip
|
|
2035
|
-
// none, so its retry fails honestly rather than sending nothing.
|
|
2048
|
+
// A rehydrated chip can retry only the source it kept inline.
|
|
2036
2049
|
if (c.thumbUrl && !chipBytes.has(c.id)) chipBytes.set(c.id, c.thumbUrl);
|
|
2037
2050
|
}
|
|
2038
2051
|
};
|
|
@@ -2044,21 +2057,21 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
2044
2057
|
if (!chips.length) return null;
|
|
2045
2058
|
const blocker = sendBlocker(chips);
|
|
2046
2059
|
if (blocker === "uploading") return { ...s, statusText: waitUploadingText(), error: "" };
|
|
2047
|
-
if (blocker === "failed") return { ...s, statusText:
|
|
2060
|
+
if (blocker === "failed") return { ...s, statusText: failedNotice(), error: "" };
|
|
2048
2061
|
if (!content) return { ...s, statusText: needsTextText(), error: "" };
|
|
2049
2062
|
return null;
|
|
2050
2063
|
};
|
|
2051
2064
|
|
|
2052
2065
|
/** Keep a "wait for your photo" notice true to the chips as they are NOW. An
|
|
2053
|
-
* upload that FAILED while Send was held on "Wait for your
|
|
2066
|
+
* upload that FAILED while Send was held on "Wait for your file to finish
|
|
2054
2067
|
* uploading" must say to retry or remove it instead, and one that landed,
|
|
2055
2068
|
* with nothing else pending, clears it. Any other status line (the typing
|
|
2056
2069
|
* line above all) is left alone. */
|
|
2057
2070
|
const refreshWaitNotice = (s: AriaChatState): AriaChatState => {
|
|
2058
|
-
const waiting = [waitUploadingText(), waitFailedText()];
|
|
2071
|
+
const waiting = [waitUploadingText(), waitFailedText(), waitRemoveText()];
|
|
2059
2072
|
if (!s.statusText || !waiting.includes(s.statusText)) return s;
|
|
2060
2073
|
const blocker = sendBlocker(chips);
|
|
2061
|
-
const next = blocker === "uploading" ? waitUploadingText() : blocker === "failed" ?
|
|
2074
|
+
const next = blocker === "uploading" ? waitUploadingText() : blocker === "failed" ? failedNotice() : "";
|
|
2062
2075
|
return next === s.statusText ? s : { ...s, statusText: next };
|
|
2063
2076
|
};
|
|
2064
2077
|
|
|
@@ -3794,8 +3807,8 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
3794
3807
|
const atCategories = { ...m, open: true, provider: null, query: "", items: [], itemsLoading: false, itemsFailed: "" };
|
|
3795
3808
|
// Listed once per business. A failed list is asked again: the failure
|
|
3796
3809
|
// may have been the network, and the next open is the retry.
|
|
3797
|
-
if (m.providers !== null) { setMention(atCategories); return s; }
|
|
3798
|
-
if (m.providersLoading) { setMention(atCategories); return s; }
|
|
3810
|
+
if (m.providers !== null) { setMention(atCategories); return committed ?? s; }
|
|
3811
|
+
if (m.providersLoading) { setMention(atCategories); return committed ?? s; }
|
|
3799
3812
|
const site = m.site;
|
|
3800
3813
|
setMention({ ...atCategories, providersLoading: true, providersFailed: "" });
|
|
3801
3814
|
let providers: MentionProvider[] | null = null;
|
|
@@ -4112,7 +4125,8 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
4112
4125
|
// picker whose result will be thrown away wastes the owner's time.
|
|
4113
4126
|
if (chips.length >= ARIA_MAX_ATTACHMENTS) return { ...s, statusText: refusalText("count"), error: "" };
|
|
4114
4127
|
const raw = typeof arg === "string" ? arg : firstString(arg?.source, arg?.value);
|
|
4115
|
-
const source = raw.trim().toLowerCase() === "
|
|
4128
|
+
const source = raw.trim().toLowerCase() === "document" ? "document"
|
|
4129
|
+
: raw.trim().toLowerCase() === "camera" ? "camera" : "library";
|
|
4116
4130
|
// The picker is open for as long as the owner takes, and a poll, a reply or
|
|
4117
4131
|
// another action can commit a NEWER state meanwhile. Returning `{ ...s }`
|
|
4118
4132
|
// afterwards would put this pre-picker snapshot back over it: an older
|
|
@@ -4124,17 +4138,18 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
4124
4138
|
let picked: Awaited<ReturnType<AriaAttachmentPorts["pick"]>>;
|
|
4125
4139
|
try {
|
|
4126
4140
|
picked = await ports.pick(source);
|
|
4127
|
-
} catch {
|
|
4141
|
+
} catch (error) {
|
|
4142
|
+
if (/too large|size limit/i.test(String(error))) return { ...latest(), statusText: refusalText("size", source === "document" ? ARIA_MAX_DOCUMENT_BYTES : ARIA_MAX_IMAGE_BYTES), error: "" };
|
|
4128
4143
|
// A picker that could not open is not the owner's fault and there is no
|
|
4129
4144
|
// file to talk about; say nothing rather than something misleading.
|
|
4130
|
-
return latest();
|
|
4145
|
+
return withoutNotice(latest());
|
|
4131
4146
|
}
|
|
4132
4147
|
if (!picked || !picked.dataUri) return latest(); // cancelled
|
|
4133
4148
|
const parsed = parseDataUri(picked.dataUri);
|
|
4134
|
-
const mimeType =
|
|
4149
|
+
const mimeType = attachmentMime(picked.mimeType || parsed?.mimeType || "", picked.name);
|
|
4135
4150
|
// Re-checked after the await: other picks may have landed meanwhile.
|
|
4136
4151
|
const refused = refusalFor(parsed, mimeType, chips.length);
|
|
4137
|
-
if (refused) return { ...latest(), statusText: refusalText(refused), error: "" };
|
|
4152
|
+
if (refused) return { ...latest(), statusText: refusalText(refused, mimeType.startsWith("image/") ? ARIA_MAX_IMAGE_BYTES : ARIA_MAX_DOCUMENT_BYTES), error: "" };
|
|
4138
4153
|
chipSeq += 1;
|
|
4139
4154
|
const id = `att-${chipSeq}`;
|
|
4140
4155
|
chipBytes.set(id, picked.dataUri);
|
|
@@ -4143,7 +4158,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
4143
4158
|
name: imageFileName(mimeType, chipSeq, picked.name),
|
|
4144
4159
|
mimeType,
|
|
4145
4160
|
// Only a small image rides the state as its own thumbnail; see `chipBytes`.
|
|
4146
|
-
thumbUrl: picked.dataUri.length <= THUMB_INLINE_MAX ? picked.dataUri : "",
|
|
4161
|
+
thumbUrl: mimeType.startsWith("image/") && picked.dataUri.length <= THUMB_INLINE_MAX ? picked.dataUri : "",
|
|
4147
4162
|
}, "uploading", chipLabels());
|
|
4148
4163
|
chips = [...chips, chip];
|
|
4149
4164
|
startUpload(chip);
|
|
@@ -4202,7 +4217,7 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
4202
4217
|
retryAttachment: (s, arg) => {
|
|
4203
4218
|
const id = chipIdOf(arg);
|
|
4204
4219
|
const current = chips.find((c) => c.id === id);
|
|
4205
|
-
if (!current || current.state !== "failed") return s;
|
|
4220
|
+
if (!current || current.state !== "failed" || (!chipBytes.get(id) && !current.thumbUrl)) return s;
|
|
4206
4221
|
// A NEW id for the new attempt, in the same place in the strip. Keeping the
|
|
4207
4222
|
// old one would let the first attempt's outcome, if it is still in the air,
|
|
4208
4223
|
// settle this one.
|
|
@@ -4421,8 +4436,21 @@ export function createAriaChat(o: AriaChatOptions): AriaChatCore {
|
|
|
4421
4436
|
await probeDictation();
|
|
4422
4437
|
return gated(r.listening && !dictationLive ? { ...r, listening: false } : r);
|
|
4423
4438
|
},
|
|
4424
|
-
submit: (s, arg) =>
|
|
4425
|
-
|
|
4439
|
+
submit: async (s, arg) => {
|
|
4440
|
+
const revision = draftSeq;
|
|
4441
|
+
const next = await impl.submit(s, arg);
|
|
4442
|
+
// Refusals preserve a draft; an edit while the async reducer resolved
|
|
4443
|
+
// belongs to the owner, including consuming a selected mention trigger.
|
|
4444
|
+
// Preserve the send result and its pending turn/poll; only rebase the draft.
|
|
4445
|
+
return gated(revision !== draftSeq && next.input === s.input && committed
|
|
4446
|
+
? { ...next, input: committed.input } : next);
|
|
4447
|
+
},
|
|
4448
|
+
submitPrompt: async (s, arg) => {
|
|
4449
|
+
const revision = draftSeq;
|
|
4450
|
+
const next = await impl.submitPrompt(s, arg);
|
|
4451
|
+
return gated(revision !== draftSeq && next.input === s.input && committed
|
|
4452
|
+
? { ...next, input: committed.input } : next);
|
|
4453
|
+
},
|
|
4426
4454
|
newChat: (s) => impl.newChat(s).then(gated),
|
|
4427
4455
|
typing: (s, arg) => gated(impl.typing(s, arg)),
|
|
4428
4456
|
tick: (s) => impl.tick(s).then((r) => (r ? gated(r) : r)),
|
|
@@ -28,7 +28,7 @@ import { defineService } from "@himalaya/state";
|
|
|
28
28
|
import { open } from "@himalaya/open-url";
|
|
29
29
|
import { writeText } from "@himalaya/clipboard";
|
|
30
30
|
import { availability, recognizeOnce, stop as stopSpeech } from "@himalaya/speech";
|
|
31
|
-
import { capturePhoto } from "@himalaya/camera";
|
|
31
|
+
import { capturePhoto, pickDocument } from "@himalaya/camera";
|
|
32
32
|
import { put } from "@himalaya/presigned-upload";
|
|
33
33
|
import { alert } from "@himalaya/ui";
|
|
34
34
|
import { auth } from "@himalaya/wix-platform";
|
|
@@ -250,12 +250,13 @@ const core = createAriaChat({
|
|
|
250
250
|
widgetItemsUnavailable: () => copyParam("ownerAria.widget.itemsUnavailable", "Items aren't available here."),
|
|
251
251
|
attachUploading: () => copyParam("ownerAria.attach.uploading", "Uploading…"),
|
|
252
252
|
attachFailed: () => copyParam("ownerAria.attach.failed", "Couldn't upload"),
|
|
253
|
-
attachTooMany: (max) => copyTemplate("ownerAria.attach.tooMany", "You can attach up to {max}
|
|
253
|
+
attachTooMany: (max) => copyTemplate("ownerAria.attach.tooMany", "You can attach up to {max} files.", { max }),
|
|
254
254
|
attachUnsupported: () => copyParam("ownerAria.attach.unsupported", "That file type can't be attached."),
|
|
255
|
-
attachTooLarge: (mb) => copyTemplate("ownerAria.attach.tooLarge", "That
|
|
256
|
-
attachWaitUploading: () => copyParam("ownerAria.attach.waitUploading", "Wait for your
|
|
257
|
-
attachWaitFailed: () => copyParam("ownerAria.attach.waitFailed", "Retry or remove the
|
|
258
|
-
|
|
255
|
+
attachTooLarge: (mb) => copyTemplate("ownerAria.attach.tooLarge", "That file is too large to attach (up to {mb} MB).", { mb }),
|
|
256
|
+
attachWaitUploading: () => copyParam("ownerAria.attach.waitUploading", "Wait for your file to finish uploading."),
|
|
257
|
+
attachWaitFailed: () => copyParam("ownerAria.attach.waitFailed", "Retry or remove the file that didn't upload."),
|
|
258
|
+
attachWaitRemove: () => copyParam("ownerAria.attach.waitRemove", "Remove the file that didn't upload, then add it again."),
|
|
259
|
+
attachNeedsText: () => copyParam("ownerAria.attach.needsText", "Add a message to send with your file."),
|
|
259
260
|
toolFailed: () => copyParam("ownerAria.toolFailed", "Aria couldn't finish that. Try again."),
|
|
260
261
|
},
|
|
261
262
|
clientTools: { confirm: confirmWithOwner, userAgent },
|
|
@@ -305,6 +306,10 @@ const core = createAriaChat({
|
|
|
305
306
|
// which go to a self-authorizing url with no Wix credential attached.
|
|
306
307
|
attachments: {
|
|
307
308
|
pick: async (source) => {
|
|
309
|
+
if (source === "document") {
|
|
310
|
+
const file = await pickDocument();
|
|
311
|
+
return file ? { dataUri: file.uri, name: file.name, mimeType: file.mime } : null;
|
|
312
|
+
}
|
|
308
313
|
const asset = await capturePhoto({ source, maxEdgePixels: 2048 });
|
|
309
314
|
return asset ? { dataUri: asset.uri, mimeType: asset.mime } : null;
|
|
310
315
|
},
|
|
@@ -318,6 +323,92 @@ const core = createAriaChat({
|
|
|
318
323
|
},
|
|
319
324
|
});
|
|
320
325
|
|
|
326
|
+
// Focused native TextFields keep their local non-empty edit rather than adopting
|
|
327
|
+
// worker normalization (the shared shouldAdoptWorkerValue rule). Remember only
|
|
328
|
+
// prefixes where THIS draft actually selected a reference, so later editor echoes and
|
|
329
|
+
// the Form.message submission cannot restore those triggers into the wire text.
|
|
330
|
+
// Email addresses and newly authored @ characters are never blanket-stripped.
|
|
331
|
+
let mentionTriggerPrefixes: string[] = [];
|
|
332
|
+
let pendingMentionTrigger: { rawPrefix: string; prefix: string } | null = null;
|
|
333
|
+
let mentionDraftRevision = 0;
|
|
334
|
+
let previousMentionRaw = "";
|
|
335
|
+
// Set by a selection that consumed a typed trigger: the normalized draft the
|
|
336
|
+
// worker now holds. A field that blurs adopts that value WITHOUT dispatching
|
|
337
|
+
// typing, so the next keystroke is an edit of it, not of previousMentionRaw.
|
|
338
|
+
// The first typing after a selection whose raw value is byte-identical to the
|
|
339
|
+
// pre-selection one cannot be an edit of the focused raw text (nothing changed),
|
|
340
|
+
// so it is read as an edit of the adopted draft: that field holds no consumed
|
|
341
|
+
// marker any more, and a standalone @ there is a new trigger.
|
|
342
|
+
let adoptedMentionDraft: string | null = null;
|
|
343
|
+
function reconcileMentionDraft(raw: string): string {
|
|
344
|
+
// Move consumed trigger positions with an edit anywhere in the focused field.
|
|
345
|
+
// A replaced/deleted trigger loses its marker, so newly authored @ text stays literal.
|
|
346
|
+
let start = 0;
|
|
347
|
+
while (start < previousMentionRaw.length && start < raw.length && previousMentionRaw[start] === raw[start]) start += 1;
|
|
348
|
+
let suffix = 0;
|
|
349
|
+
while (suffix < previousMentionRaw.length - start && suffix < raw.length - start
|
|
350
|
+
&& previousMentionRaw[previousMentionRaw.length - suffix - 1] === raw[raw.length - suffix - 1]) suffix += 1;
|
|
351
|
+
const end = previousMentionRaw.length - suffix;
|
|
352
|
+
const delta = raw.length - previousMentionRaw.length;
|
|
353
|
+
const move = (position: number): number | null => position < start ? position : position >= end ? position + delta : null;
|
|
354
|
+
mentionTriggerPrefixes = mentionTriggerPrefixes.flatMap(prefix => {
|
|
355
|
+
let position = move(prefix.length);
|
|
356
|
+
// A whole-draft replacement ("Ask @" → "New @") shares only whitespace and the @
|
|
357
|
+
// with the old text, so the common suffix lines the NEW @ up with the old marker.
|
|
358
|
+
// When every word before the marker was replaced, its context is gone: the @ is
|
|
359
|
+
// newly authored and must stay (and may open the picker again).
|
|
360
|
+
if (position !== null && start === 0 && prefix.length >= end && prefix.trim()
|
|
361
|
+
&& !previousMentionRaw.slice(end, prefix.length).trim()) return [];
|
|
362
|
+
// Coalesced edits may add text on both sides of the marker. Keep it when
|
|
363
|
+
// its complete previous context still occurs exactly once in the new value.
|
|
364
|
+
if (position === null && prefix) {
|
|
365
|
+
const anchor = `${prefix}@`; const found = raw.indexOf(anchor);
|
|
366
|
+
if (found >= 0 && raw.indexOf(anchor, found + 1) < 0) position = found + prefix.length;
|
|
367
|
+
}
|
|
368
|
+
// A coalesced focused-field edit can replace context on both sides of a
|
|
369
|
+
// selected marker. If this is the sole consumed marker and the new draft
|
|
370
|
+
// has one standalone @, its position is unambiguous even without the old
|
|
371
|
+
// prefix. Email addresses and authored @suffixes are never candidates.
|
|
372
|
+
if (position === null && mentionTriggerPrefixes.length === 1) {
|
|
373
|
+
const candidates = [...raw.matchAll(/(^|\s)@(?=\s|$)/g)].map(match => match.index! + match[1].length);
|
|
374
|
+
if (candidates.length === 1) position = candidates[0];
|
|
375
|
+
}
|
|
376
|
+
// Only the standalone trigger that opened the picker is consumed. Adding
|
|
377
|
+
// a literal suffix (or joining it to the preceding word) authors ordinary
|
|
378
|
+
// @ text even when the focused editor retains the selected trigger.
|
|
379
|
+
const standalone = position !== null && raw[position] === "@"
|
|
380
|
+
&& (position === 0 || /\s/.test(raw[position - 1]))
|
|
381
|
+
&& (position + 1 === raw.length || /\s/.test(raw[position + 1]));
|
|
382
|
+
return standalone ? [raw.slice(0, position!)] : [];
|
|
383
|
+
});
|
|
384
|
+
if (pendingMentionTrigger) {
|
|
385
|
+
const position = move(pendingMentionTrigger.rawPrefix.length);
|
|
386
|
+
const standalone = position !== null && raw[position] === "@"
|
|
387
|
+
&& (position === 0 || /\s/.test(raw[position - 1]))
|
|
388
|
+
&& (position + 1 === raw.length || /\s/.test(raw[position + 1]));
|
|
389
|
+
pendingMentionTrigger = standalone
|
|
390
|
+
? { rawPrefix: raw.slice(0, position!), prefix: raw.slice(0, position!) } : null;
|
|
391
|
+
if (pendingMentionTrigger) {
|
|
392
|
+
for (const prefix of [...mentionTriggerPrefixes].sort((a, b) => b.length - a.length)) {
|
|
393
|
+
if (prefix.length < pendingMentionTrigger.rawPrefix.length) pendingMentionTrigger.prefix = pendingMentionTrigger.prefix.slice(0, prefix.length) + pendingMentionTrigger.prefix.slice(prefix.length + 1);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
previousMentionRaw = raw;
|
|
398
|
+
let text = raw;
|
|
399
|
+
for (const prefix of [...mentionTriggerPrefixes].sort((a, b) => b.length - a.length)) {
|
|
400
|
+
text = text.slice(0, prefix.length) + text.slice(prefix.length + 1);
|
|
401
|
+
}
|
|
402
|
+
return text;
|
|
403
|
+
}
|
|
404
|
+
function reconciledMentionArg(arg?: AriaActionArg): AriaActionArg | undefined {
|
|
405
|
+
if (typeof arg === "string") return reconcileMentionDraft(arg);
|
|
406
|
+
if (!arg) return arg;
|
|
407
|
+
const keys: Array<"message" | "text" | "value" | "intent" | "id"> = ["message", "text", "value", "intent", "id"];
|
|
408
|
+
const key = keys.find(k => typeof arg[k] === "string" && arg[k]);
|
|
409
|
+
return key ? { ...arg, [key]: reconcileMentionDraft(String(arg[key])) } : arg;
|
|
410
|
+
}
|
|
411
|
+
|
|
321
412
|
const svc = defineService<AriaChatState, {
|
|
322
413
|
load: (s: AriaChatState, arg?: AriaActionArg) => Promise<AriaChatState>;
|
|
323
414
|
submit: (s: AriaChatState, arg?: AriaActionArg) => Promise<AriaChatState>;
|
|
@@ -374,13 +465,51 @@ const svc = defineService<AriaChatState, {
|
|
|
374
465
|
state: core.initialState,
|
|
375
466
|
actions: {
|
|
376
467
|
// `load` is the onAppear dispatch, so it is where the copy pack arrives.
|
|
377
|
-
load: (s, arg) => { stashCopy(arg); stashTargets(arg); stashRealtimeUrl(arg); return core.load(s); },
|
|
378
|
-
submit:
|
|
379
|
-
|
|
380
|
-
|
|
468
|
+
load: (s, arg) => { mentionDraftRevision += 1; mentionTriggerPrefixes = []; pendingMentionTrigger = null; previousMentionRaw = ""; adoptedMentionDraft = null; stashCopy(arg); stashTargets(arg); stashRealtimeUrl(arg); return core.load(s); },
|
|
469
|
+
submit: async (s, arg) => {
|
|
470
|
+
const normalized = reconciledMentionArg(arg);
|
|
471
|
+
const previousPrefixes = mentionTriggerPrefixes; const previousTrigger = pendingMentionTrigger;
|
|
472
|
+
const revision = mentionDraftRevision;
|
|
473
|
+
const next = await core.submit(s, normalized);
|
|
474
|
+
// A refusal keeps this draft; a later keystroke/new-chat belongs to its own.
|
|
475
|
+
if (revision === mentionDraftRevision) {
|
|
476
|
+
if (next.input && next.input === s.input) { mentionTriggerPrefixes = previousPrefixes; pendingMentionTrigger = previousTrigger; }
|
|
477
|
+
else { mentionTriggerPrefixes = []; pendingMentionTrigger = null; previousMentionRaw = ""; adoptedMentionDraft = null; }
|
|
478
|
+
}
|
|
479
|
+
return next;
|
|
480
|
+
},
|
|
481
|
+
submitPrompt: async (s, arg) => {
|
|
482
|
+
const previousPrefixes = mentionTriggerPrefixes; const previousTrigger = pendingMentionTrigger;
|
|
483
|
+
const revision = mentionDraftRevision;
|
|
484
|
+
const next = await core.submitPrompt(s, arg);
|
|
485
|
+
if (revision === mentionDraftRevision) {
|
|
486
|
+
if (next.input && next.input === s.input) { mentionTriggerPrefixes = previousPrefixes; pendingMentionTrigger = previousTrigger; }
|
|
487
|
+
else { mentionTriggerPrefixes = []; pendingMentionTrigger = null; previousMentionRaw = ""; adoptedMentionDraft = null; }
|
|
488
|
+
}
|
|
489
|
+
return next;
|
|
490
|
+
},
|
|
491
|
+
newChat: (s) => { mentionDraftRevision += 1; mentionTriggerPrefixes = []; pendingMentionTrigger = null; previousMentionRaw = ""; adoptedMentionDraft = null; return core.newChat(s); },
|
|
381
492
|
// The composer's onChange. Mirrors the draft into state so `submit` can
|
|
382
493
|
// empty it and the field actually clears.
|
|
383
|
-
typing:
|
|
494
|
+
typing: (s, arg) => {
|
|
495
|
+
mentionDraftRevision += 1;
|
|
496
|
+
const raw = typeof arg === "string" ? arg : ([arg?.value, arg?.text, arg?.message].find((v): v is string => typeof v === "string") ?? "");
|
|
497
|
+
if (adoptedMentionDraft !== null) {
|
|
498
|
+
if (raw === previousMentionRaw) { mentionTriggerPrefixes = []; previousMentionRaw = adoptedMentionDraft; }
|
|
499
|
+
adoptedMentionDraft = null;
|
|
500
|
+
}
|
|
501
|
+
const next = core.typing(s, { value: reconcileMentionDraft(raw) });
|
|
502
|
+
// A standalone @ asks for a reference; emails and embedded @ characters
|
|
503
|
+
// remain ordinary text. A successful selection consumes its trigger.
|
|
504
|
+
if (next.input !== s.input && /(?:^|\s)@$/.test(next.input) && !next.mention.openHidden) {
|
|
505
|
+
// Keep the fragment editable until a reference is selected. Cancelling
|
|
506
|
+
// the picker must not turn a literal @example.com into example.com.
|
|
507
|
+
pendingMentionTrigger = { rawPrefix: raw.slice(0, -1), prefix: next.input.slice(0, -1) };
|
|
508
|
+
void svc.mentionOpen();
|
|
509
|
+
return next;
|
|
510
|
+
}
|
|
511
|
+
return next;
|
|
512
|
+
},
|
|
384
513
|
// Named by the `_poll` directive above. A name that does not resolve here is
|
|
385
514
|
// a `poll-action-missing` error in `himi test --content`.
|
|
386
515
|
tick: core.tick,
|
|
@@ -419,11 +548,23 @@ const svc = defineService<AriaChatState, {
|
|
|
419
548
|
// chips above the composer. Every one is named by the descriptor, so every
|
|
420
549
|
// one has to be exported here — see the note on the picker family above.
|
|
421
550
|
mentionOpen: core.mentionOpen,
|
|
422
|
-
mentionClose: core.mentionClose,
|
|
551
|
+
mentionClose: (s) => { pendingMentionTrigger = null; return core.mentionClose(s); },
|
|
423
552
|
mentionBack: core.mentionBack,
|
|
424
553
|
mentionProvider: core.mentionProvider,
|
|
425
554
|
mentionQuery: core.mentionQuery,
|
|
426
|
-
mentionPick:
|
|
555
|
+
mentionPick: (s, arg) => {
|
|
556
|
+
const next = core.mentionPick(s, arg);
|
|
557
|
+
const trigger = pendingMentionTrigger;
|
|
558
|
+
if (trigger && !s.mention.hidden && next.mention.hidden && next.input.startsWith(`${trigger.prefix}@`)) {
|
|
559
|
+
mentionDraftRevision += 1;
|
|
560
|
+
pendingMentionTrigger = null;
|
|
561
|
+
if (!mentionTriggerPrefixes.includes(trigger.rawPrefix)) mentionTriggerPrefixes.push(trigger.rawPrefix);
|
|
562
|
+
const normalized = next.input.slice(0, trigger.prefix.length) + next.input.slice(trigger.prefix.length + 1);
|
|
563
|
+
adoptedMentionDraft = normalized;
|
|
564
|
+
return core.typing(next, { value: normalized });
|
|
565
|
+
}
|
|
566
|
+
return next;
|
|
567
|
+
},
|
|
427
568
|
mentionRemove: core.mentionRemove,
|
|
428
569
|
// The composer's photos. `attachmentSettled` is dispatched by the upload
|
|
429
570
|
// itself (see `attachments.settled` above), never by the descriptor.
|
|
@@ -37,7 +37,7 @@ export default defineApp({
|
|
|
37
37
|
actions: "http://localhost:8190/v1/actions",
|
|
38
38
|
sync: "http://localhost:8190/v1/sync",
|
|
39
39
|
},
|
|
40
|
-
capabilities: ["live_activity","push","share","secure_storage","open_url","local_database","clipboard","ui","speech","camera","presigned_upload","app_info","biometrics"],
|
|
40
|
+
capabilities: ["live_activity","push","share","secure_storage","open_url","local_database","clipboard","ui","speech","camera","presigned_upload","app_info","biometrics","wix_platform"],
|
|
41
41
|
designTokensPath: "./tokens.json",
|
|
42
42
|
navigation: {
|
|
43
43
|
"navKind": "responsive",
|
|
@@ -61615,6 +61615,65 @@ const SCREENS = runtimeSetting({
|
|
|
61615
61615
|
},
|
|
61616
61616
|
{
|
|
61617
61617
|
"id": "",
|
|
61618
|
+
"body": {
|
|
61619
|
+
"package": "himalaya",
|
|
61620
|
+
"type": "VStack",
|
|
61621
|
+
"props": {
|
|
61622
|
+
"spacing": 4,
|
|
61623
|
+
"children": [
|
|
61624
|
+
{
|
|
61625
|
+
"id": "",
|
|
61626
|
+
"body": {
|
|
61627
|
+
"package": "himalaya",
|
|
61628
|
+
"type": "Icon",
|
|
61629
|
+
"props": {
|
|
61630
|
+
"name": "doc",
|
|
61631
|
+
"size": 24,
|
|
61632
|
+
"tint": "textSecondary"
|
|
61633
|
+
}
|
|
61634
|
+
},
|
|
61635
|
+
"modifiers": {
|
|
61636
|
+
"accessibilityRole": "decorative"
|
|
61637
|
+
}
|
|
61638
|
+
},
|
|
61639
|
+
{
|
|
61640
|
+
"id": "",
|
|
61641
|
+
"body": {
|
|
61642
|
+
"package": "himalaya",
|
|
61643
|
+
"type": "Text",
|
|
61644
|
+
"props": {
|
|
61645
|
+
"text": "$item.name",
|
|
61646
|
+
"style": "caption",
|
|
61647
|
+
"color": "textPrimary",
|
|
61648
|
+
"maxLines": 2
|
|
61649
|
+
}
|
|
61650
|
+
},
|
|
61651
|
+
"modifiers": {
|
|
61652
|
+
"height": 44
|
|
61653
|
+
}
|
|
61654
|
+
},
|
|
61655
|
+
{
|
|
61656
|
+
"id": "",
|
|
61657
|
+
"body": {
|
|
61658
|
+
"package": "himalaya",
|
|
61659
|
+
"type": "Text",
|
|
61660
|
+
"props": {
|
|
61661
|
+
"text": "$item.typeLabel",
|
|
61662
|
+
"style": "caption",
|
|
61663
|
+
"color": "textSecondary",
|
|
61664
|
+
"maxLines": 1
|
|
61665
|
+
}
|
|
61666
|
+
}
|
|
61667
|
+
}
|
|
61668
|
+
]
|
|
61669
|
+
}
|
|
61670
|
+
},
|
|
61671
|
+
"modifiers": {
|
|
61672
|
+
"hiddenPath": "$item.documentHidden"
|
|
61673
|
+
}
|
|
61674
|
+
},
|
|
61675
|
+
{
|
|
61676
|
+
"id": "himi_owner_lite_aria.attachment_status_$item.id",
|
|
61618
61677
|
"body": {
|
|
61619
61678
|
"package": "himalaya",
|
|
61620
61679
|
"type": "Text",
|
|
@@ -61626,6 +61685,7 @@ const SCREENS = runtimeSetting({
|
|
|
61626
61685
|
}
|
|
61627
61686
|
},
|
|
61628
61687
|
"modifiers": {
|
|
61688
|
+
"height": 44,
|
|
61629
61689
|
"hiddenPath": "$item.statusHidden"
|
|
61630
61690
|
}
|
|
61631
61691
|
},
|
|
@@ -61641,21 +61701,22 @@ const SCREENS = runtimeSetting({
|
|
|
61641
61701
|
"id": "himi_owner_lite_aria.attachment_retry_$item.id",
|
|
61642
61702
|
"body": {
|
|
61643
61703
|
"package": "himalaya",
|
|
61644
|
-
"type": "
|
|
61704
|
+
"type": "Button",
|
|
61645
61705
|
"props": {
|
|
61646
|
-
"
|
|
61647
|
-
"
|
|
61648
|
-
|
|
61649
|
-
|
|
61706
|
+
"title": "Retry",
|
|
61707
|
+
"action": {
|
|
61708
|
+
"actionId": "tier5.himiOwnerLiteAria.retryAttachment",
|
|
61709
|
+
"params": {
|
|
61710
|
+
"id": "$item.id"
|
|
61711
|
+
}
|
|
61712
|
+
},
|
|
61713
|
+
"style": "tertiary",
|
|
61714
|
+
"size": "sm"
|
|
61650
61715
|
}
|
|
61651
61716
|
},
|
|
61652
61717
|
"modifiers": {
|
|
61653
|
-
"
|
|
61654
|
-
|
|
61655
|
-
"params": {
|
|
61656
|
-
"id": "$item.id"
|
|
61657
|
-
}
|
|
61658
|
-
},
|
|
61718
|
+
"width": 92,
|
|
61719
|
+
"height": 48,
|
|
61659
61720
|
"hiddenPath": "$item.retryHidden"
|
|
61660
61721
|
}
|
|
61661
61722
|
},
|
|
@@ -61663,32 +61724,51 @@ const SCREENS = runtimeSetting({
|
|
|
61663
61724
|
"id": "himi_owner_lite_aria.attachment_remove_$item.id",
|
|
61664
61725
|
"body": {
|
|
61665
61726
|
"package": "himalaya",
|
|
61666
|
-
"type": "
|
|
61727
|
+
"type": "Button",
|
|
61667
61728
|
"props": {
|
|
61668
|
-
"
|
|
61669
|
-
"
|
|
61670
|
-
|
|
61729
|
+
"title": "Remove attachment",
|
|
61730
|
+
"action": {
|
|
61731
|
+
"actionId": "tier5.himiOwnerLiteAria.removeAttachment",
|
|
61732
|
+
"params": {
|
|
61733
|
+
"id": "$item.id"
|
|
61734
|
+
}
|
|
61735
|
+
},
|
|
61736
|
+
"style": "tertiary",
|
|
61737
|
+
"iconOnly": true,
|
|
61738
|
+
"leadingIcon": "close",
|
|
61739
|
+
"cornerRadius": 24,
|
|
61740
|
+
"minHeight": 48
|
|
61671
61741
|
}
|
|
61672
61742
|
},
|
|
61673
61743
|
"modifiers": {
|
|
61674
|
-
"
|
|
61675
|
-
|
|
61676
|
-
|
|
61677
|
-
|
|
61678
|
-
}
|
|
61679
|
-
},
|
|
61680
|
-
"accessibilityLabel": "Remove photo"
|
|
61744
|
+
"width": 48,
|
|
61745
|
+
"height": 48,
|
|
61746
|
+
"accessibilityLabel": "Remove attachment",
|
|
61747
|
+
"accessibilityRole": "button"
|
|
61681
61748
|
}
|
|
61682
61749
|
}
|
|
61683
61750
|
]
|
|
61684
61751
|
}
|
|
61752
|
+
},
|
|
61753
|
+
"modifiers": {
|
|
61754
|
+
"height": 48
|
|
61685
61755
|
}
|
|
61686
61756
|
}
|
|
61687
61757
|
]
|
|
61688
61758
|
}
|
|
61689
61759
|
},
|
|
61690
61760
|
"modifiers": {
|
|
61691
|
-
"width":
|
|
61761
|
+
"width": 160,
|
|
61762
|
+
"padding": {
|
|
61763
|
+
"top": 8,
|
|
61764
|
+
"bottom": 8,
|
|
61765
|
+
"leading": 8,
|
|
61766
|
+
"trailing": 8
|
|
61767
|
+
},
|
|
61768
|
+
"background": {
|
|
61769
|
+
"token": "surfaceSecondary"
|
|
61770
|
+
},
|
|
61771
|
+
"cornerRadius": 12
|
|
61692
61772
|
}
|
|
61693
61773
|
}
|
|
61694
61774
|
]
|
|
@@ -61700,7 +61780,7 @@ const SCREENS = runtimeSetting({
|
|
|
61700
61780
|
"leading": 0,
|
|
61701
61781
|
"trailing": 0,
|
|
61702
61782
|
"top": 8,
|
|
61703
|
-
"bottom":
|
|
61783
|
+
"bottom": 8
|
|
61704
61784
|
}
|
|
61705
61785
|
}
|
|
61706
61786
|
},
|
|
@@ -61753,6 +61833,27 @@ const SCREENS = runtimeSetting({
|
|
|
61753
61833
|
},
|
|
61754
61834
|
"accessibilityLabel": "Take a photo"
|
|
61755
61835
|
}
|
|
61836
|
+
},
|
|
61837
|
+
{
|
|
61838
|
+
"id": "himi_owner_lite_aria.attach.document",
|
|
61839
|
+
"body": {
|
|
61840
|
+
"package": "himalaya",
|
|
61841
|
+
"type": "Icon",
|
|
61842
|
+
"props": {
|
|
61843
|
+
"name": "document",
|
|
61844
|
+
"size": 22,
|
|
61845
|
+
"tint": "accentPrimary"
|
|
61846
|
+
}
|
|
61847
|
+
},
|
|
61848
|
+
"modifiers": {
|
|
61849
|
+
"onTap": {
|
|
61850
|
+
"actionId": "tier5.himiOwnerLiteAria.attach",
|
|
61851
|
+
"params": {
|
|
61852
|
+
"source": "document"
|
|
61853
|
+
}
|
|
61854
|
+
},
|
|
61855
|
+
"accessibilityLabel": "Add files"
|
|
61856
|
+
}
|
|
61756
61857
|
}
|
|
61757
61858
|
]
|
|
61758
61859
|
}
|