@swift-food-services/catering-widget 0.2.0-beta.5 → 0.2.0-beta.7
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/index.cjs +149 -201
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +151 -203
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5292,9 +5292,6 @@ styleInject(`/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
|
|
|
5292
5292
|
.swift-catering-widget .pt-8 {
|
|
5293
5293
|
padding-top: calc(var(--spacing) * 8);
|
|
5294
5294
|
}
|
|
5295
|
-
.swift-catering-widget .pt-14 {
|
|
5296
|
-
padding-top: calc(var(--spacing) * 14);
|
|
5297
|
-
}
|
|
5298
5295
|
.swift-catering-widget .pr-1 {
|
|
5299
5296
|
padding-right: calc(var(--spacing) * 1);
|
|
5300
5297
|
}
|
|
@@ -5355,6 +5352,9 @@ styleInject(`/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
|
|
|
5355
5352
|
.swift-catering-widget .pl-4 {
|
|
5356
5353
|
padding-left: calc(var(--spacing) * 4);
|
|
5357
5354
|
}
|
|
5355
|
+
.swift-catering-widget .pl-6 {
|
|
5356
|
+
padding-left: calc(var(--spacing) * 6);
|
|
5357
|
+
}
|
|
5358
5358
|
.swift-catering-widget .pl-9 {
|
|
5359
5359
|
padding-left: calc(var(--spacing) * 9);
|
|
5360
5360
|
}
|
|
@@ -9465,7 +9465,7 @@ function MenuItemModal({
|
|
|
9465
9465
|
onClick: () => handleSaveAiPick(true),
|
|
9466
9466
|
disabled: isMinSelectionsUnmet,
|
|
9467
9467
|
className: `w-full py-3 rounded-lg font-medium transition-all text-sm ${isMinSelectionsUnmet ? "bg-base-300 text-base-content/50 cursor-not-allowed" : "bg-primary hover:opacity-90 text-white"}`,
|
|
9468
|
-
children: isPickedInAiMenu ? "Save selections" : "Pick \xB7 Save selections"
|
|
9468
|
+
children: addButtonLabel ?? (isPickedInAiMenu ? "Save selections" : "Pick \xB7 Save selections")
|
|
9469
9469
|
}
|
|
9470
9470
|
),
|
|
9471
9471
|
isPickedInAiMenu && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -13491,7 +13491,7 @@ function ChatSessionProvider({
|
|
|
13491
13491
|
if (!chat.sessionId) setActiveViewedPreview(null);
|
|
13492
13492
|
}, [chat.sessionId]);
|
|
13493
13493
|
const hasResults = react.useMemo(
|
|
13494
|
-
() => chat.latestMealSessionParts.length > 0,
|
|
13494
|
+
() => chat.latestMealSessionParts.some((p) => p.intentBlocks.length > 0),
|
|
13495
13495
|
[chat.latestMealSessionParts]
|
|
13496
13496
|
);
|
|
13497
13497
|
const prevPartsRef = react.useRef(chat.latestMealSessionParts);
|
|
@@ -16282,7 +16282,8 @@ var FIELD_LABEL = {
|
|
|
16282
16282
|
sessionDate: "Date",
|
|
16283
16283
|
eventTime: "Food arrives by",
|
|
16284
16284
|
deliveryLocation: "Location",
|
|
16285
|
-
guestCount: "Guests"
|
|
16285
|
+
guestCount: "Guests",
|
|
16286
|
+
budget: "Budget"
|
|
16286
16287
|
};
|
|
16287
16288
|
function MissingFieldsClarifier({
|
|
16288
16289
|
missing,
|
|
@@ -16340,6 +16341,26 @@ function getOverlayRoot() {
|
|
|
16340
16341
|
}
|
|
16341
16342
|
return document.querySelector("[data-swift-overlay-root]") ?? document.body;
|
|
16342
16343
|
}
|
|
16344
|
+
function swapOptionToMenuItem(o, restaurantId) {
|
|
16345
|
+
return {
|
|
16346
|
+
id: o.menuItemId,
|
|
16347
|
+
menuItemName: o.name,
|
|
16348
|
+
description: o.description ?? void 0,
|
|
16349
|
+
price: String(o.unitPrice),
|
|
16350
|
+
discountPrice: o.discountPrice != null ? String(o.discountPrice) : void 0,
|
|
16351
|
+
isDiscount: o.isDiscount,
|
|
16352
|
+
image: o.imageUrl ?? void 0,
|
|
16353
|
+
allergens: o.allergens,
|
|
16354
|
+
dietaryFilters: o.dietaryFilters,
|
|
16355
|
+
cateringQuantityUnit: o.cateringQuantityUnit,
|
|
16356
|
+
feedsPerUnit: o.feedsPerUnit,
|
|
16357
|
+
minOrderQuantity: o.minOrderQuantity,
|
|
16358
|
+
restaurantId,
|
|
16359
|
+
groupTitle: o.groupTitle ?? void 0,
|
|
16360
|
+
itemDisplayOrder: 0,
|
|
16361
|
+
addons: o.addons ?? []
|
|
16362
|
+
};
|
|
16363
|
+
}
|
|
16343
16364
|
function SwapModal({
|
|
16344
16365
|
open,
|
|
16345
16366
|
sessionId,
|
|
@@ -16357,10 +16378,12 @@ function SwapModal({
|
|
|
16357
16378
|
const [options, setOptions] = react.useState(null);
|
|
16358
16379
|
const [loading, setLoading] = react.useState(false);
|
|
16359
16380
|
const [error, setError] = react.useState(null);
|
|
16381
|
+
const [selected, setSelected] = react.useState(null);
|
|
16360
16382
|
react.useEffect(() => {
|
|
16361
16383
|
if (!open || !restaurantId || !category) {
|
|
16362
16384
|
setOptions(null);
|
|
16363
16385
|
setError(null);
|
|
16386
|
+
setSelected(null);
|
|
16364
16387
|
return;
|
|
16365
16388
|
}
|
|
16366
16389
|
let cancelled = false;
|
|
@@ -16385,6 +16408,24 @@ function SwapModal({
|
|
|
16385
16408
|
};
|
|
16386
16409
|
}, [open, sessionId, restaurantId, category, excludeIds.join(","), intentPhrase]);
|
|
16387
16410
|
if (typeof document === "undefined") return null;
|
|
16411
|
+
if (selected && restaurantId) {
|
|
16412
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16413
|
+
MenuItemModal,
|
|
16414
|
+
{
|
|
16415
|
+
item: swapOptionToMenuItem(selected, restaurantId),
|
|
16416
|
+
isOpen: true,
|
|
16417
|
+
onClose: () => setSelected(null),
|
|
16418
|
+
viewOnly: true,
|
|
16419
|
+
aiAddonMode: true,
|
|
16420
|
+
addButtonLabel: "Confirm Swap",
|
|
16421
|
+
isPickedInAiMenu: false,
|
|
16422
|
+
onSaveAiPickAddons: (selections) => {
|
|
16423
|
+
onPick(selected, selections);
|
|
16424
|
+
setSelected(null);
|
|
16425
|
+
}
|
|
16426
|
+
}
|
|
16427
|
+
);
|
|
16428
|
+
}
|
|
16388
16429
|
const modal = /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16389
16430
|
react$1.motion.div,
|
|
16390
16431
|
{
|
|
@@ -16466,7 +16507,7 @@ function SwapModal({
|
|
|
16466
16507
|
visible: { transition: { staggerChildren: 0.04, delayChildren: 0.02 } }
|
|
16467
16508
|
},
|
|
16468
16509
|
style: { display: "flex", flexDirection: "column" },
|
|
16469
|
-
children: options.map((opt, i) => /* @__PURE__ */ jsxRuntime.jsx(SwapCard, { option: opt, onPick: () =>
|
|
16510
|
+
children: options.map((opt, i) => /* @__PURE__ */ jsxRuntime.jsx(SwapCard, { option: opt, onPick: () => setSelected(opt), showDivider: i < options.length - 1 }, opt.menuItemId))
|
|
16470
16511
|
}
|
|
16471
16512
|
)
|
|
16472
16513
|
] })
|
|
@@ -16658,6 +16699,15 @@ var GOOGLE_MAPS_CONFIG = {
|
|
|
16658
16699
|
"name"
|
|
16659
16700
|
]
|
|
16660
16701
|
};
|
|
16702
|
+
var LONDON_DELIVERY_BOUNDS = {
|
|
16703
|
+
north: 51.75,
|
|
16704
|
+
south: 51.2,
|
|
16705
|
+
east: 0.35,
|
|
16706
|
+
west: -0.55
|
|
16707
|
+
};
|
|
16708
|
+
function isWithinLondonBounds(lat, lng) {
|
|
16709
|
+
return lat >= LONDON_DELIVERY_BOUNDS.south && lat <= LONDON_DELIVERY_BOUNDS.north && lng >= LONDON_DELIVERY_BOUNDS.west && lng <= LONDON_DELIVERY_BOUNDS.east;
|
|
16710
|
+
}
|
|
16661
16711
|
|
|
16662
16712
|
// src/utils/google-maps-loader.ts
|
|
16663
16713
|
var isLoading = false;
|
|
@@ -16702,8 +16752,10 @@ function loadGoogleMapsScript(apiKey) {
|
|
|
16702
16752
|
}
|
|
16703
16753
|
|
|
16704
16754
|
// src/hooks/useAddressAutocomplete.ts
|
|
16755
|
+
var OUT_OF_ZONE_MESSAGE = "We only deliver inside London right now \u2014 please pick a London address.";
|
|
16705
16756
|
function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
16706
16757
|
const countryRestriction = options.countryRestriction === void 0 ? GOOGLE_MAPS_CONFIG.COUNTRY_RESTRICTION : options.countryRestriction;
|
|
16758
|
+
const restrictToDeliveryZone = options.restrictToDeliveryZone ?? true;
|
|
16707
16759
|
const { googleMapsApiKey } = useCateringConfig();
|
|
16708
16760
|
const inputRef = react.useRef(null);
|
|
16709
16761
|
const containerRef = react.useRef(null);
|
|
@@ -16715,6 +16767,7 @@ function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
|
16715
16767
|
const [predictions, setPredictions] = react.useState([]);
|
|
16716
16768
|
const [open, setOpen] = react.useState(false);
|
|
16717
16769
|
const [activeIndex, setActiveIndex] = react.useState(-1);
|
|
16770
|
+
const [outOfZoneError, setOutOfZoneError] = react.useState(null);
|
|
16718
16771
|
react.useEffect(() => {
|
|
16719
16772
|
loadGoogleMapsScript(googleMapsApiKey).then(() => {
|
|
16720
16773
|
if (!window.google?.maps?.places) return;
|
|
@@ -16725,6 +16778,7 @@ function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
|
16725
16778
|
}, [googleMapsApiKey]);
|
|
16726
16779
|
react.useEffect(() => {
|
|
16727
16780
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
16781
|
+
setOutOfZoneError(null);
|
|
16728
16782
|
if (justSelectedRef.current) {
|
|
16729
16783
|
justSelectedRef.current = false;
|
|
16730
16784
|
return;
|
|
@@ -16739,7 +16793,14 @@ function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
|
16739
16793
|
autocompleteServiceRef.current.getPlacePredictions(
|
|
16740
16794
|
{
|
|
16741
16795
|
input: query,
|
|
16742
|
-
...countryRestriction ? { componentRestrictions: { country: countryRestriction } } : {}
|
|
16796
|
+
...countryRestriction ? { componentRestrictions: { country: countryRestriction } } : {},
|
|
16797
|
+
// Delivery pickers bias predictions toward the London box so
|
|
16798
|
+
// local results rank first. NB: this is `bounds` (a bias the
|
|
16799
|
+
// legacy getPlacePredictions honors), NOT `locationRestriction`
|
|
16800
|
+
// — that field is silently rejected here and kills the dropdown.
|
|
16801
|
+
// The hard out-of-zone rejection lives on the on-select
|
|
16802
|
+
// coordinate guard below + the backend bbox.
|
|
16803
|
+
...restrictToDeliveryZone ? { bounds: LONDON_DELIVERY_BOUNDS } : {}
|
|
16743
16804
|
},
|
|
16744
16805
|
(results, status) => {
|
|
16745
16806
|
if (status === google.maps.places.PlacesServiceStatus.OK && results) {
|
|
@@ -16768,6 +16829,13 @@ function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
|
16768
16829
|
{ placeId: prediction.place_id, fields: GOOGLE_MAPS_CONFIG.FIELDS },
|
|
16769
16830
|
(place, status) => {
|
|
16770
16831
|
if (status === google.maps.places.PlacesServiceStatus.OK && place?.geometry) {
|
|
16832
|
+
const lat = place.geometry.location?.lat();
|
|
16833
|
+
const lng = place.geometry.location?.lng();
|
|
16834
|
+
if (restrictToDeliveryZone && typeof lat === "number" && typeof lng === "number" && !isWithinLondonBounds(lat, lng)) {
|
|
16835
|
+
setOutOfZoneError(OUT_OF_ZONE_MESSAGE);
|
|
16836
|
+
return;
|
|
16837
|
+
}
|
|
16838
|
+
setOutOfZoneError(null);
|
|
16771
16839
|
onPlaceSelect(place);
|
|
16772
16840
|
}
|
|
16773
16841
|
}
|
|
@@ -16805,6 +16873,7 @@ function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
|
16805
16873
|
setPredictions([]);
|
|
16806
16874
|
setActiveIndex(-1);
|
|
16807
16875
|
setOpen(false);
|
|
16876
|
+
setOutOfZoneError(null);
|
|
16808
16877
|
};
|
|
16809
16878
|
return {
|
|
16810
16879
|
inputRef,
|
|
@@ -16817,7 +16886,8 @@ function useAddressAutocomplete(onPlaceSelect, options = {}) {
|
|
|
16817
16886
|
setActiveIndex,
|
|
16818
16887
|
handleSelect,
|
|
16819
16888
|
handleKeyDown,
|
|
16820
|
-
clear
|
|
16889
|
+
clear,
|
|
16890
|
+
outOfZoneError
|
|
16821
16891
|
};
|
|
16822
16892
|
}
|
|
16823
16893
|
function ChatAddressInput({
|
|
@@ -16839,7 +16909,8 @@ function ChatAddressInput({
|
|
|
16839
16909
|
activeIndex,
|
|
16840
16910
|
setActiveIndex,
|
|
16841
16911
|
handleSelect,
|
|
16842
|
-
handleKeyDown
|
|
16912
|
+
handleKeyDown,
|
|
16913
|
+
outOfZoneError
|
|
16843
16914
|
} = useAddressAutocomplete(onPlaceSelect);
|
|
16844
16915
|
react.useEffect(() => {
|
|
16845
16916
|
if (initialQuery) setQuery(initialQuery);
|
|
@@ -16918,6 +16989,7 @@ function ChatAddressInput({
|
|
|
16918
16989
|
}
|
|
16919
16990
|
)
|
|
16920
16991
|
] }),
|
|
16992
|
+
outOfZoneError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 pl-6 text-xs text-red-500", children: outOfZoneError }),
|
|
16921
16993
|
open && predictions.length > 0 && dropdownRect && typeof document !== "undefined" && reactDom.createPortal(
|
|
16922
16994
|
/* Portal to the widget's shared overlay root so the
|
|
16923
16995
|
dropdown escapes the bar pill's overflow-hidden +
|
|
@@ -16975,135 +17047,8 @@ function ChatAddressInput({
|
|
|
16975
17047
|
)
|
|
16976
17048
|
] });
|
|
16977
17049
|
}
|
|
16978
|
-
var GATE_PROMPT = "What is the code to use the AI chat and test our beta version?";
|
|
16979
|
-
function AIChatBetaGate({ onUnlock }) {
|
|
16980
|
-
const textareaRef = react.useRef(null);
|
|
16981
|
-
const [input, setInput] = react.useState("");
|
|
16982
|
-
const [error, setError] = react.useState(null);
|
|
16983
|
-
function submit() {
|
|
16984
|
-
const trimmed = input.trim();
|
|
16985
|
-
if (!trimmed) return;
|
|
16986
|
-
if (onUnlock(trimmed)) return;
|
|
16987
|
-
setError("Incorrect code. Try again.");
|
|
16988
|
-
setInput("");
|
|
16989
|
-
textareaRef.current?.focus();
|
|
16990
|
-
}
|
|
16991
|
-
function handleSubmit(e) {
|
|
16992
|
-
e.preventDefault();
|
|
16993
|
-
submit();
|
|
16994
|
-
}
|
|
16995
|
-
function handleKeyDown(e) {
|
|
16996
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
16997
|
-
e.preventDefault();
|
|
16998
|
-
submit();
|
|
16999
|
-
}
|
|
17000
|
-
}
|
|
17001
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "swift-chat-design bg-white rounded-xl shadow-sm border border-base-200 flex h-full min-h-0 flex-col overflow-hidden", children: [
|
|
17002
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2.5 flex items-center gap-3 border-b border-base-200", children: [
|
|
17003
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-9 h-9 rounded-full bg-primary flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4 text-white" }) }),
|
|
17004
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
17005
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-gray-800", children: "AI Assistant" }),
|
|
17006
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: "Beta access" })
|
|
17007
|
-
] })
|
|
17008
|
-
] }),
|
|
17009
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-h-0 overflow-y-auto p-3", children: [
|
|
17010
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextBubble, { sender: "bot", text: GATE_PROMPT }),
|
|
17011
|
-
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17012
|
-
"p",
|
|
17013
|
-
{
|
|
17014
|
-
role: "alert",
|
|
17015
|
-
className: "mt-2 text-xs text-red-600",
|
|
17016
|
-
children: error
|
|
17017
|
-
}
|
|
17018
|
-
)
|
|
17019
|
-
] }),
|
|
17020
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-base-200 p-2.5", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17021
|
-
"form",
|
|
17022
|
-
{
|
|
17023
|
-
onSubmit: handleSubmit,
|
|
17024
|
-
className: "flex items-end gap-2 rounded-xl border border-base-300 bg-white px-3 py-2 focus-within:border-primary transition-colors",
|
|
17025
|
-
children: [
|
|
17026
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17027
|
-
"textarea",
|
|
17028
|
-
{
|
|
17029
|
-
ref: textareaRef,
|
|
17030
|
-
rows: 1,
|
|
17031
|
-
value: input,
|
|
17032
|
-
onChange: (e) => {
|
|
17033
|
-
setInput(e.target.value);
|
|
17034
|
-
if (error) setError(null);
|
|
17035
|
-
},
|
|
17036
|
-
onKeyDown: handleKeyDown,
|
|
17037
|
-
placeholder: "Enter access code\u2026",
|
|
17038
|
-
"aria-label": "Beta access code",
|
|
17039
|
-
autoFocus: true,
|
|
17040
|
-
className: "flex-1 bg-transparent text-sm text-gray-800 placeholder:text-gray-400 outline-none resize-none leading-snug py-1 overflow-hidden"
|
|
17041
|
-
}
|
|
17042
|
-
),
|
|
17043
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17044
|
-
"button",
|
|
17045
|
-
{
|
|
17046
|
-
type: "submit",
|
|
17047
|
-
disabled: !input.trim(),
|
|
17048
|
-
className: "flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full bg-primary text-white transition-colors hover:bg-primary/90 disabled:opacity-50",
|
|
17049
|
-
title: "Submit code",
|
|
17050
|
-
"aria-label": "Submit code",
|
|
17051
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-3.5 h-3.5" })
|
|
17052
|
-
}
|
|
17053
|
-
)
|
|
17054
|
-
]
|
|
17055
|
-
}
|
|
17056
|
-
) })
|
|
17057
|
-
] });
|
|
17058
|
-
}
|
|
17059
|
-
var STORAGE_KEY3 = "swift-food-chat-beta-unlocked";
|
|
17060
|
-
var BETA_CODE = "1423";
|
|
17061
|
-
function readUnlocked() {
|
|
17062
|
-
if (typeof window === "undefined") return false;
|
|
17063
|
-
try {
|
|
17064
|
-
return window.localStorage.getItem(STORAGE_KEY3) === "1";
|
|
17065
|
-
} catch {
|
|
17066
|
-
return false;
|
|
17067
|
-
}
|
|
17068
|
-
}
|
|
17069
|
-
var unlockedValue = readUnlocked();
|
|
17070
|
-
var subscribers = /* @__PURE__ */ new Set();
|
|
17071
|
-
function setUnlocked(next) {
|
|
17072
|
-
if (unlockedValue === next) return;
|
|
17073
|
-
unlockedValue = next;
|
|
17074
|
-
subscribers.forEach((cb) => cb());
|
|
17075
|
-
}
|
|
17076
|
-
function subscribe(cb) {
|
|
17077
|
-
subscribers.add(cb);
|
|
17078
|
-
return () => {
|
|
17079
|
-
subscribers.delete(cb);
|
|
17080
|
-
};
|
|
17081
|
-
}
|
|
17082
|
-
function useBetaUnlock() {
|
|
17083
|
-
const unlocked = react.useSyncExternalStore(
|
|
17084
|
-
subscribe,
|
|
17085
|
-
() => unlockedValue,
|
|
17086
|
-
() => false
|
|
17087
|
-
);
|
|
17088
|
-
const tryUnlock = react.useCallback((code) => {
|
|
17089
|
-
if (code.trim() !== BETA_CODE) return false;
|
|
17090
|
-
setUnlocked(true);
|
|
17091
|
-
if (typeof window !== "undefined") {
|
|
17092
|
-
try {
|
|
17093
|
-
window.localStorage.setItem(STORAGE_KEY3, "1");
|
|
17094
|
-
} catch {
|
|
17095
|
-
}
|
|
17096
|
-
}
|
|
17097
|
-
return true;
|
|
17098
|
-
}, []);
|
|
17099
|
-
return { unlocked, tryUnlock };
|
|
17100
|
-
}
|
|
17101
17050
|
var MAX_INPUT_HEIGHT = 140;
|
|
17102
17051
|
function AIChat() {
|
|
17103
|
-
const { unlocked, tryUnlock } = useBetaUnlock();
|
|
17104
|
-
if (!unlocked) {
|
|
17105
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AIChatBetaGate, { onUnlock: tryUnlock });
|
|
17106
|
-
}
|
|
17107
17052
|
return /* @__PURE__ */ jsxRuntime.jsx(AIChatBody, {});
|
|
17108
17053
|
}
|
|
17109
17054
|
function AIChatBody() {
|
|
@@ -17114,6 +17059,9 @@ function AIChatBody() {
|
|
|
17114
17059
|
sessionId,
|
|
17115
17060
|
latestChips,
|
|
17116
17061
|
missingFields,
|
|
17062
|
+
latestMealSessions,
|
|
17063
|
+
latestActiveMealSessionIndex,
|
|
17064
|
+
latestSummary,
|
|
17117
17065
|
sendText,
|
|
17118
17066
|
applyEditField,
|
|
17119
17067
|
handleChip,
|
|
@@ -17182,6 +17130,24 @@ function AIChatBody() {
|
|
|
17182
17130
|
setPendingInputFocus(false);
|
|
17183
17131
|
}, [pendingInputFocus, gateActive, pillEditing, bootstrapping, sessionId]);
|
|
17184
17132
|
const inFeedbackMode = feedbackTarget !== null;
|
|
17133
|
+
const activeMeal = latestMealSessions[latestActiveMealSessionIndex];
|
|
17134
|
+
const derivedMissing = [];
|
|
17135
|
+
if (latestMealSessions.length > 0) {
|
|
17136
|
+
for (const f of activeMeal?.missingFields ?? []) {
|
|
17137
|
+
if (f === "sessionDate" || f === "eventTime" || f === "guestCount") {
|
|
17138
|
+
derivedMissing.push(f);
|
|
17139
|
+
}
|
|
17140
|
+
}
|
|
17141
|
+
if ((latestSummary?.taxonomy?.budget ?? null) == null) {
|
|
17142
|
+
derivedMissing.push("budget");
|
|
17143
|
+
}
|
|
17144
|
+
if (!hasAddress) derivedMissing.push("deliveryLocation");
|
|
17145
|
+
}
|
|
17146
|
+
const effectiveMissingFields = missingFields && missingFields.fields.length > 0 ? missingFields : derivedMissing.length > 0 ? {
|
|
17147
|
+
fields: derivedMissing,
|
|
17148
|
+
reason: missingFields?.reason ?? "Add these and I'll build your menu."
|
|
17149
|
+
} : null;
|
|
17150
|
+
const mandatoryFieldsLocked = !inFeedbackMode && !!effectiveMissingFields && effectiveMissingFields.fields.length > 0;
|
|
17185
17151
|
const RATING_LABELS = ["Terrible", "Poor", "Okay", "Good", "Great"];
|
|
17186
17152
|
react.useEffect(() => {
|
|
17187
17153
|
if (!feedbackTarget) return;
|
|
@@ -17259,6 +17225,7 @@ function AIChatBody() {
|
|
|
17259
17225
|
}
|
|
17260
17226
|
if (sending || bootstrapping || !sessionId || !input.trim()) return;
|
|
17261
17227
|
if (gateActive && !hasAddress) return;
|
|
17228
|
+
if (mandatoryFieldsLocked) return;
|
|
17262
17229
|
void sendText(input, buildChatAddress());
|
|
17263
17230
|
setInput("");
|
|
17264
17231
|
}
|
|
@@ -17426,10 +17393,10 @@ function AIChatBody() {
|
|
|
17426
17393
|
) })
|
|
17427
17394
|
] }),
|
|
17428
17395
|
actionChips.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 border-t border-base-200 px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(ChipGroup, { chips: actionChips, onAction: handleChipClick }) }),
|
|
17429
|
-
|
|
17396
|
+
effectiveMissingFields && effectiveMissingFields.fields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17430
17397
|
MissingFieldsClarifier,
|
|
17431
17398
|
{
|
|
17432
|
-
missing:
|
|
17399
|
+
missing: effectiveMissingFields,
|
|
17433
17400
|
onEditField: (field) => {
|
|
17434
17401
|
if (field === "deliveryLocation") {
|
|
17435
17402
|
setPillEditing(true);
|
|
@@ -17576,7 +17543,7 @@ function AIChatBody() {
|
|
|
17576
17543
|
value: inFeedbackMode ? feedbackNote : input,
|
|
17577
17544
|
onChange: (e) => inFeedbackMode ? setFeedbackNote(e.target.value) : setInput(e.target.value),
|
|
17578
17545
|
onKeyDown: handleKeyDown,
|
|
17579
|
-
placeholder: inFeedbackMode ? feedbackRating <= 2 ? "What went wrong? (optional)" : "Add a note (optional)" : "Ask for menu suggestions...",
|
|
17546
|
+
placeholder: inFeedbackMode ? feedbackRating <= 2 ? "What went wrong? (optional)" : "Add a note (optional)" : mandatoryFieldsLocked ? "Add the details above to continue\u2026" : "Ask for menu suggestions...",
|
|
17580
17547
|
disabled: inFeedbackMode ? feedbackState === "sending" : bootstrapping || !sessionId,
|
|
17581
17548
|
className: "flex-1 bg-transparent text-sm text-gray-800 placeholder:text-gray-400 outline-none resize-none leading-snug py-1 overflow-hidden"
|
|
17582
17549
|
}
|
|
@@ -17585,7 +17552,7 @@ function AIChatBody() {
|
|
|
17585
17552
|
"button",
|
|
17586
17553
|
{
|
|
17587
17554
|
type: "submit",
|
|
17588
|
-
disabled: inFeedbackMode ? feedbackRating < 1 || feedbackState === "sending" : sending || bootstrapping || !input.trim() || !sessionId,
|
|
17555
|
+
disabled: inFeedbackMode ? feedbackRating < 1 || feedbackState === "sending" : sending || bootstrapping || !input.trim() || !sessionId || mandatoryFieldsLocked,
|
|
17589
17556
|
className: "flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full bg-primary text-white transition-colors hover:bg-primary/90 disabled:opacity-50",
|
|
17590
17557
|
title: inFeedbackMode ? "Submit feedback" : "Send",
|
|
17591
17558
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-3.5 h-3.5" })
|
|
@@ -17610,7 +17577,7 @@ function AIChatBody() {
|
|
|
17610
17577
|
intentExcludes: swapTarget?.intentExcludes ?? null,
|
|
17611
17578
|
itemName: swapTarget?.itemName ?? "",
|
|
17612
17579
|
onClose: () => setSwapTarget(null),
|
|
17613
|
-
onPick: (replacement) => {
|
|
17580
|
+
onPick: (replacement, addonSelections) => {
|
|
17614
17581
|
const target = swapTarget;
|
|
17615
17582
|
if (!target) return;
|
|
17616
17583
|
setSwapTarget(null);
|
|
@@ -17627,10 +17594,15 @@ function AIChatBody() {
|
|
|
17627
17594
|
allergens: replacement.allergens,
|
|
17628
17595
|
dietaryFilters: replacement.dietaryFilters,
|
|
17629
17596
|
feedsPerUnit: replacement.feedsPerUnit,
|
|
17630
|
-
cateringQuantityUnit:
|
|
17631
|
-
minOrderQuantity:
|
|
17632
|
-
addons:
|
|
17597
|
+
cateringQuantityUnit: replacement.cateringQuantityUnit,
|
|
17598
|
+
minOrderQuantity: replacement.minOrderQuantity,
|
|
17599
|
+
addons: replacement.addons
|
|
17633
17600
|
});
|
|
17601
|
+
cart.setAddonSelections(
|
|
17602
|
+
target.intentId,
|
|
17603
|
+
replacement.menuItemId,
|
|
17604
|
+
addonSelections
|
|
17605
|
+
);
|
|
17634
17606
|
}
|
|
17635
17607
|
}
|
|
17636
17608
|
)
|
|
@@ -17653,7 +17625,8 @@ function MobileAddressPickerSurface({
|
|
|
17653
17625
|
activeIndex,
|
|
17654
17626
|
setActiveIndex,
|
|
17655
17627
|
handleSelect,
|
|
17656
|
-
handleKeyDown
|
|
17628
|
+
handleKeyDown,
|
|
17629
|
+
outOfZoneError
|
|
17657
17630
|
} = useAddressAutocomplete(onPlaceSelect);
|
|
17658
17631
|
react.useEffect(() => {
|
|
17659
17632
|
if (initialQuery) setQuery(initialQuery);
|
|
@@ -17779,6 +17752,7 @@ function MobileAddressPickerSurface({
|
|
|
17779
17752
|
] })
|
|
17780
17753
|
}
|
|
17781
17754
|
),
|
|
17755
|
+
outOfZoneError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 flex-shrink-0 text-center text-xs text-red-600", children: outOfZoneError }),
|
|
17782
17756
|
predictions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17783
17757
|
react$1.motion.div,
|
|
17784
17758
|
{
|
|
@@ -20135,7 +20109,9 @@ function EmptyIntentState({ message }) {
|
|
|
20135
20109
|
var MISSING_FIELD_LABELS = {
|
|
20136
20110
|
guestCount: "guest count",
|
|
20137
20111
|
sessionDate: "date",
|
|
20138
|
-
eventTime: "time"
|
|
20112
|
+
eventTime: "time",
|
|
20113
|
+
deliveryLocation: "delivery location",
|
|
20114
|
+
budget: "budget"
|
|
20139
20115
|
};
|
|
20140
20116
|
function formatMissingFieldList(fields) {
|
|
20141
20117
|
const labels = fields.map((f) => MISSING_FIELD_LABELS[f] ?? f);
|
|
@@ -21087,7 +21063,8 @@ function InlineAddressInput({
|
|
|
21087
21063
|
activeIndex,
|
|
21088
21064
|
setActiveIndex,
|
|
21089
21065
|
handleSelect,
|
|
21090
|
-
handleKeyDown
|
|
21066
|
+
handleKeyDown,
|
|
21067
|
+
outOfZoneError
|
|
21091
21068
|
} = useAddressAutocomplete(onPlaceSelect);
|
|
21092
21069
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: "relative mt-1.5 pt-1.5 border-t border-base-200", children: [
|
|
21093
21070
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -21125,7 +21102,8 @@ function InlineAddressInput({
|
|
|
21125
21102
|
]
|
|
21126
21103
|
},
|
|
21127
21104
|
p.place_id
|
|
21128
|
-
)) })
|
|
21105
|
+
)) }),
|
|
21106
|
+
outOfZoneError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[10px] text-red-500", children: outOfZoneError })
|
|
21129
21107
|
] });
|
|
21130
21108
|
}
|
|
21131
21109
|
function PricingSummary({
|
|
@@ -24705,8 +24683,10 @@ function AddressAutocomplete({
|
|
|
24705
24683
|
setActiveIndex,
|
|
24706
24684
|
handleSelect,
|
|
24707
24685
|
handleKeyDown,
|
|
24708
|
-
clear
|
|
24686
|
+
clear,
|
|
24687
|
+
outOfZoneError
|
|
24709
24688
|
} = useAddressAutocomplete(onPlaceSelect);
|
|
24689
|
+
const shownError = error || outOfZoneError || void 0;
|
|
24710
24690
|
const handleClear = () => {
|
|
24711
24691
|
clear();
|
|
24712
24692
|
if (onClearAddress) onClearAddress();
|
|
@@ -24727,7 +24707,7 @@ function AddressAutocomplete({
|
|
|
24727
24707
|
onKeyDown: handleKeyDown,
|
|
24728
24708
|
placeholder: "Start typing an address...",
|
|
24729
24709
|
autoComplete: "new-password",
|
|
24730
|
-
className: `address-search-input w-full bg-gray-50 border rounded-lg px-4 py-2.5 text-base text-base-content placeholder:text-base-content/50 focus:outline-none focus:ring-2 focus:ring-dark-pink/20 focus:border-dark-pink transition-all ${
|
|
24710
|
+
className: `address-search-input w-full bg-gray-50 border rounded-lg px-4 py-2.5 text-base text-base-content placeholder:text-base-content/50 focus:outline-none focus:ring-2 focus:ring-dark-pink/20 focus:border-dark-pink transition-all ${shownError ? "border-error" : hasValidAddress ? "border-success" : "border-base-300"}`
|
|
24731
24711
|
}
|
|
24732
24712
|
),
|
|
24733
24713
|
hasValidAddress && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -24760,9 +24740,9 @@ function AddressAutocomplete({
|
|
|
24760
24740
|
p.place_id
|
|
24761
24741
|
)) })
|
|
24762
24742
|
] }),
|
|
24763
|
-
|
|
24764
|
-
hasValidAddress && !
|
|
24765
|
-
!hasValidAddress && !
|
|
24743
|
+
shownError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-error", children: shownError }),
|
|
24744
|
+
hasValidAddress && !shownError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-success", children: "Address selected" }),
|
|
24745
|
+
!hasValidAddress && !shownError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-base-content/60", children: "Please select an address from the dropdown" })
|
|
24766
24746
|
] });
|
|
24767
24747
|
}
|
|
24768
24748
|
function DeliveryAddressForm({
|
|
@@ -24900,7 +24880,11 @@ function BillingAddressAutocomplete({
|
|
|
24900
24880
|
setActiveIndex,
|
|
24901
24881
|
handleSelect,
|
|
24902
24882
|
handleKeyDown
|
|
24903
|
-
} = useAddressAutocomplete(onPlaceSelect, {
|
|
24883
|
+
} = useAddressAutocomplete(onPlaceSelect, {
|
|
24884
|
+
countryRestriction: null,
|
|
24885
|
+
// Billing can be anywhere — only delivery is London-restricted.
|
|
24886
|
+
restrictToDeliveryZone: false
|
|
24887
|
+
});
|
|
24904
24888
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-full", ref: containerRef, children: [
|
|
24905
24889
|
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block text-[10px] font-bold text-base-content/60 uppercase tracking-widest mb-1.5", children: [
|
|
24906
24890
|
"Search Address",
|
|
@@ -27646,7 +27630,6 @@ function CateringOrderBuilder() {
|
|
|
27646
27630
|
const [mobileAIInput, setMobileAIInput] = react.useState("");
|
|
27647
27631
|
const [mobileAIInputHeight, setMobileAIInputHeight] = react.useState(44);
|
|
27648
27632
|
const mobileAIInputRef = react.useRef(null);
|
|
27649
|
-
const [mobileGateError, setMobileGateError] = react.useState(null);
|
|
27650
27633
|
const mobileChatScrollRef = react.useRef(null);
|
|
27651
27634
|
const [mobileAddressPillEditing, setMobileAddressPillEditing] = react.useState(false);
|
|
27652
27635
|
const buildChatAddress = useChatAddressFromContext();
|
|
@@ -27841,20 +27824,6 @@ function CateringOrderBuilder() {
|
|
|
27841
27824
|
});
|
|
27842
27825
|
setMobileAddressPillEditing(false);
|
|
27843
27826
|
};
|
|
27844
|
-
const handleMobileGateSubmit = () => {
|
|
27845
|
-
const code = mobileAIInput.trim();
|
|
27846
|
-
if (!code) return;
|
|
27847
|
-
if (tryUnlockAiBeta(code)) {
|
|
27848
|
-
setMobileAIInput("");
|
|
27849
|
-
resetMobileAIInputHeight();
|
|
27850
|
-
setMobileGateError(null);
|
|
27851
|
-
return;
|
|
27852
|
-
}
|
|
27853
|
-
setMobileGateError("Incorrect code. Try again.");
|
|
27854
|
-
setMobileAIInput("");
|
|
27855
|
-
resetMobileAIInputHeight();
|
|
27856
|
-
mobileAIInputRef.current?.focus();
|
|
27857
|
-
};
|
|
27858
27827
|
const closeMobileAIChat = () => {
|
|
27859
27828
|
mobileAIInputRef.current?.blur();
|
|
27860
27829
|
setTimeout(() => {
|
|
@@ -27951,9 +27920,8 @@ function CateringOrderBuilder() {
|
|
|
27951
27920
|
setExpandedItemId(item.id);
|
|
27952
27921
|
};
|
|
27953
27922
|
const { stickyTopOffset = 0, publishableKey, aiEnabled = false } = useCateringConfig();
|
|
27954
|
-
const
|
|
27955
|
-
const
|
|
27956
|
-
const mobileAddressEditorOpen = mobileAddressGateActive || aiBetaUnlocked && mobileAddressPillEditing;
|
|
27923
|
+
const mobileAddressGateActive = isMobileAIChatOpen && !hasChatAddress;
|
|
27924
|
+
const mobileAddressEditorOpen = mobileAddressGateActive || mobileAddressPillEditing;
|
|
27957
27925
|
const effectiveRightPanelTab = aiEnabled ? rightPanelTab : "cart";
|
|
27958
27926
|
const [overlayVisible, setOverlayVisible] = react.useState(false);
|
|
27959
27927
|
const basketColumnRef = react.useRef(null);
|
|
@@ -29040,7 +29008,7 @@ function CateringOrderBuilder() {
|
|
|
29040
29008
|
transition: { duration: 0.18, ease: "easeOut" },
|
|
29041
29009
|
className: "absolute inset-0",
|
|
29042
29010
|
children: [
|
|
29043
|
-
|
|
29011
|
+
hasChatAddress && mobileChatView === "chat" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29044
29012
|
react$1.motion.button,
|
|
29045
29013
|
{
|
|
29046
29014
|
type: "button",
|
|
@@ -29080,16 +29048,7 @@ function CateringOrderBuilder() {
|
|
|
29080
29048
|
"data-allow-touch": true,
|
|
29081
29049
|
className: "absolute inset-x-0 top-0 overflow-y-auto overscroll-contain",
|
|
29082
29050
|
style: { bottom: 64 },
|
|
29083
|
-
children:
|
|
29084
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29085
|
-
TextBubble,
|
|
29086
|
-
{
|
|
29087
|
-
sender: "bot",
|
|
29088
|
-
text: "What is the code to use the AI chat and test our beta version?"
|
|
29089
|
-
}
|
|
29090
|
-
),
|
|
29091
|
-
mobileGateError && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-xs text-red-600", children: mobileGateError })
|
|
29092
|
-
] }) : mobileChatView === "results" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
29051
|
+
children: mobileChatView === "results" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
29093
29052
|
MobileResultsView,
|
|
29094
29053
|
{
|
|
29095
29054
|
onBack: () => setMobileChatView("chat")
|
|
@@ -29097,12 +29056,12 @@ function CateringOrderBuilder() {
|
|
|
29097
29056
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
29098
29057
|
MobileChatThread,
|
|
29099
29058
|
{
|
|
29100
|
-
hasAddressTopPill: hasChatAddress
|
|
29059
|
+
hasAddressTopPill: hasChatAddress
|
|
29101
29060
|
}
|
|
29102
29061
|
)
|
|
29103
29062
|
}
|
|
29104
29063
|
),
|
|
29105
|
-
|
|
29064
|
+
mobileChatView === "chat" && /* @__PURE__ */ jsxRuntime.jsx(MobileChatFloatingChips, { bottomOffset: 64 + 8, inputRef: mobileAIInputRef })
|
|
29106
29065
|
]
|
|
29107
29066
|
},
|
|
29108
29067
|
"chat-surface"
|
|
@@ -29265,10 +29224,7 @@ function CateringOrderBuilder() {
|
|
|
29265
29224
|
{
|
|
29266
29225
|
inputRef: mobileAIInputRef,
|
|
29267
29226
|
value: mobileAIInput,
|
|
29268
|
-
onChange:
|
|
29269
|
-
setMobileAIInput(v);
|
|
29270
|
-
if (mobileGateError) setMobileGateError(null);
|
|
29271
|
-
},
|
|
29227
|
+
onChange: setMobileAIInput,
|
|
29272
29228
|
onInputResize: handleMobileAIInput,
|
|
29273
29229
|
onResetHeight: resetMobileAIInputHeight,
|
|
29274
29230
|
tabbable: isMobileAIChatOpen,
|
|
@@ -29278,8 +29234,6 @@ function CateringOrderBuilder() {
|
|
|
29278
29234
|
setChatInputFocused(true);
|
|
29279
29235
|
},
|
|
29280
29236
|
onBlur: () => setChatInputFocused(false),
|
|
29281
|
-
gateMode: !aiBetaUnlocked,
|
|
29282
|
-
onGateSubmit: handleMobileGateSubmit,
|
|
29283
29237
|
buildAddress: buildChatAddress
|
|
29284
29238
|
}
|
|
29285
29239
|
)
|
|
@@ -29770,8 +29724,6 @@ function MobileAIInput({
|
|
|
29770
29724
|
isOpen,
|
|
29771
29725
|
onFocus,
|
|
29772
29726
|
onBlur,
|
|
29773
|
-
gateMode = false,
|
|
29774
|
-
onGateSubmit,
|
|
29775
29727
|
buildAddress,
|
|
29776
29728
|
submitBlocked = false
|
|
29777
29729
|
}) {
|
|
@@ -29788,7 +29740,7 @@ function MobileAIInput({
|
|
|
29788
29740
|
}, [feedbackTarget]);
|
|
29789
29741
|
const chatDisabled = sending || bootstrapping || !sessionId;
|
|
29790
29742
|
const inputDisabled = inFeedbackMode ? feedbackState === "sending" : bootstrapping || !sessionId;
|
|
29791
|
-
const sendDisabled = inFeedbackMode ? feedbackState === "sending" : submitBlocked || (
|
|
29743
|
+
const sendDisabled = inFeedbackMode ? feedbackState === "sending" : submitBlocked || (chatDisabled || !value.trim());
|
|
29792
29744
|
function submit() {
|
|
29793
29745
|
if (inFeedbackMode) {
|
|
29794
29746
|
void handleFeedbackSubmit();
|
|
@@ -29796,10 +29748,6 @@ function MobileAIInput({
|
|
|
29796
29748
|
}
|
|
29797
29749
|
if (!value.trim()) return;
|
|
29798
29750
|
if (submitBlocked) return;
|
|
29799
|
-
if (gateMode) {
|
|
29800
|
-
onGateSubmit?.();
|
|
29801
|
-
return;
|
|
29802
|
-
}
|
|
29803
29751
|
if (chatDisabled) return;
|
|
29804
29752
|
void sendText(value, buildAddress?.() ?? void 0);
|
|
29805
29753
|
onChange("");
|
|
@@ -29836,9 +29784,9 @@ function MobileAIInput({
|
|
|
29836
29784
|
onKeyDown: handleKeyDown,
|
|
29837
29785
|
onFocus,
|
|
29838
29786
|
onBlur,
|
|
29839
|
-
placeholder: inFeedbackMode ? "Add a note (optional)" :
|
|
29787
|
+
placeholder: inFeedbackMode ? "Add a note (optional)" : "How can I help?",
|
|
29840
29788
|
tabIndex: tabbable ? 0 : -1,
|
|
29841
|
-
disabled:
|
|
29789
|
+
disabled: inputDisabled,
|
|
29842
29790
|
autoComplete: "off",
|
|
29843
29791
|
autoCorrect: "off",
|
|
29844
29792
|
autoCapitalize: "off",
|