@bacano/sdk 1.0.1 → 1.1.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/README.md +342 -7
- package/STOREFRONT_CLARITY.md +140 -0
- package/STOREFRONT_CONSTRUCTION.md +92 -0
- package/STOREFRONT_LEADS.md +130 -0
- package/STOREFRONT_LEGAL.md +66 -0
- package/STOREFRONT_MARKETING.md +286 -0
- package/STOREFRONT_PERFORMANCE.md +265 -0
- package/STOREFRONT_PREVIEW.md +474 -0
- package/client.d.ts +7 -1
- package/errors.d.ts +9 -1
- package/graphql.cjs +63 -0
- package/graphql.d.ts +2 -2
- package/graphql.js +63 -0
- package/index.cjs +1542 -192
- package/index.d.ts +8 -6
- package/index.js +1542 -192
- package/marketing/attribution.d.ts +51 -0
- package/marketing/clarity.d.ts +3 -0
- package/marketing/domain.d.ts +1 -0
- package/marketing/ga4.d.ts +2 -0
- package/marketing/index.d.ts +5 -0
- package/marketing/runtime.d.ts +2 -0
- package/marketing/sanitize.d.ts +2 -0
- package/marketing/types.d.ts +109 -0
- package/media.d.ts +45 -2
- package/modules/auth.d.ts +3 -2
- package/modules/availability.d.ts +2 -2
- package/modules/cart-session.d.ts +2 -2
- package/modules/cart.d.ts +3 -3
- package/modules/catalog.d.ts +15 -3
- package/modules/content.d.ts +2 -2
- package/modules/marketing.d.ts +5 -0
- package/modules/orders.d.ts +2 -2
- package/modules/profile.d.ts +1 -1
- package/modules/static-catalog.d.ts +13 -0
- package/modules/website.d.ts +7 -1
- package/package.json +14 -3
- package/react/context-registry.d.ts +9 -0
- package/react/context.d.ts +1 -1
- package/react/hooks.d.ts +23 -2
- package/react/marketing-context.d.ts +3 -0
- package/react/marketing-provider.d.ts +10 -0
- package/react/preview/cache.d.ts +23 -0
- package/react/preview/context.d.ts +5 -0
- package/react/preview/navigation.d.ts +9 -0
- package/react/preview/provider.d.ts +3 -0
- package/react/preview/shell.d.ts +3 -0
- package/react/preview/toolbar.d.ts +3 -0
- package/react/preview/types.d.ts +60 -0
- package/react/preview.cjs +742 -0
- package/react/preview.d.ts +14 -0
- package/react/preview.js +730 -0
- package/react/website-gate.d.ts +22 -0
- package/react.cjs +3432 -1780
- package/react.d.ts +8 -4
- package/react.js +3428 -1772
- package/skills/bacano-web/SKILL.md +109 -0
- package/skills/bacano-web/agents/openai.yaml +4 -0
- package/skills/bacano-web/references/common.md +91 -0
- package/skills/bacano-web/references/informational.md +39 -0
- package/skills/bacano-web/references/report.md +52 -0
- package/skills/bacano-web/references/storefront.md +116 -0
- package/skills/bacano-web/scripts/audit-http.mjs +247 -0
- package/skills/bacano-web/scripts/cli.mjs +222 -0
- package/skills/bacano-web/scripts/postinstall.mjs +8 -0
- package/transport/documents.d.ts +8 -6
- package/transport/graphql.d.ts +13 -1
- package/types.d.ts +202 -0
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/sdk/src/react/preview.ts
|
|
21
|
+
var preview_exports = {};
|
|
22
|
+
__export(preview_exports, {
|
|
23
|
+
BacanoPreviewContext: () => BacanoPreviewContext,
|
|
24
|
+
BacanoPreviewModeContext: () => BacanoPreviewModeContext,
|
|
25
|
+
BacanoPreviewProvider: () => BacanoPreviewProvider,
|
|
26
|
+
BacanoPreviewShell: () => BacanoPreviewShell,
|
|
27
|
+
BacanoPreviewToolbar: () => BacanoPreviewToolbar,
|
|
28
|
+
interceptPreviewLink: () => interceptPreviewLink,
|
|
29
|
+
normalizePreviewRoute: () => normalizePreviewRoute,
|
|
30
|
+
useBacanoPreview: () => useBacanoPreview,
|
|
31
|
+
useBacanoPreviewMode: () => useBacanoPreviewMode
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(preview_exports);
|
|
34
|
+
|
|
35
|
+
// libs/sdk/src/react/preview/context.ts
|
|
36
|
+
var import_react2 = require("react");
|
|
37
|
+
|
|
38
|
+
// libs/sdk/src/react/context-registry.ts
|
|
39
|
+
var import_react = require("react");
|
|
40
|
+
var REACT_CONTEXT_REGISTRY = /* @__PURE__ */ Symbol.for(
|
|
41
|
+
"@bacano/sdk/react-context-registry/v1"
|
|
42
|
+
);
|
|
43
|
+
function getReactContextRegistry() {
|
|
44
|
+
const globalRegistry = globalThis;
|
|
45
|
+
const existing = globalRegistry[REACT_CONTEXT_REGISTRY];
|
|
46
|
+
if (existing instanceof Map) {
|
|
47
|
+
return existing;
|
|
48
|
+
}
|
|
49
|
+
const registry = /* @__PURE__ */ new Map();
|
|
50
|
+
globalRegistry[REACT_CONTEXT_REGISTRY] = registry;
|
|
51
|
+
return registry;
|
|
52
|
+
}
|
|
53
|
+
function getOrCreateReactContext(key, defaultValue) {
|
|
54
|
+
const registry = getReactContextRegistry();
|
|
55
|
+
const existing = registry.get(key);
|
|
56
|
+
if (existing) {
|
|
57
|
+
return existing;
|
|
58
|
+
}
|
|
59
|
+
const context = (0, import_react.createContext)(defaultValue);
|
|
60
|
+
registry.set(key, context);
|
|
61
|
+
return context;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// libs/sdk/src/react/preview/context.ts
|
|
65
|
+
var BacanoPreviewModeContext = getOrCreateReactContext(
|
|
66
|
+
"bacano-preview-mode-v1",
|
|
67
|
+
false
|
|
68
|
+
);
|
|
69
|
+
var BacanoPreviewContext = getOrCreateReactContext(
|
|
70
|
+
"bacano-preview-state-v1",
|
|
71
|
+
null
|
|
72
|
+
);
|
|
73
|
+
function useBacanoPreview() {
|
|
74
|
+
const context = (0, import_react2.useContext)(BacanoPreviewContext);
|
|
75
|
+
if (!context) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"useBacanoPreview must be used inside BacanoPreviewProvider."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return context;
|
|
81
|
+
}
|
|
82
|
+
function useBacanoPreviewMode() {
|
|
83
|
+
return (0, import_react2.useContext)(BacanoPreviewModeContext);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// libs/sdk/src/react/preview/navigation.ts
|
|
87
|
+
function normalizePreviewRoute(value) {
|
|
88
|
+
if (!value) return "/";
|
|
89
|
+
let decoded = value.trim();
|
|
90
|
+
try {
|
|
91
|
+
decoded = decodeURIComponent(decoded);
|
|
92
|
+
} catch {
|
|
93
|
+
return "/";
|
|
94
|
+
}
|
|
95
|
+
if (!decoded.startsWith("/") || decoded.startsWith("//")) return "/";
|
|
96
|
+
const [pathname] = decoded.split(/[?#]/, 1);
|
|
97
|
+
if (!pathname || pathname.includes("\\") || Array.from(pathname).some((character) => character.charCodeAt(0) < 32)) {
|
|
98
|
+
return "/";
|
|
99
|
+
}
|
|
100
|
+
return pathname === "/" ? pathname : pathname.replace(/\/+$/, "");
|
|
101
|
+
}
|
|
102
|
+
function interceptPreviewLink(event, options) {
|
|
103
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || typeof Element === "undefined") {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (!(event.target instanceof Element)) return false;
|
|
107
|
+
const anchor = event.target.closest("a");
|
|
108
|
+
if (!(anchor instanceof HTMLAnchorElement) || anchor.target === "_blank" || anchor.hasAttribute("download")) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const currentOrigin = options.origin ?? (typeof window === "undefined" ? void 0 : window.location.origin);
|
|
112
|
+
if (!currentOrigin) return false;
|
|
113
|
+
const url = new URL(anchor.href, currentOrigin);
|
|
114
|
+
if (url.origin !== currentOrigin) return false;
|
|
115
|
+
const normalize = options.normalizeRoute ?? normalizePreviewRoute;
|
|
116
|
+
const route = normalize(url.pathname);
|
|
117
|
+
if (options.isPreviewableRoute?.(route) === false) return false;
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
options.navigate(route);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// libs/sdk/src/react/preview/provider.tsx
|
|
124
|
+
var import_react3 = require("react");
|
|
125
|
+
|
|
126
|
+
// libs/sdk/src/react/context.ts
|
|
127
|
+
var BacanoReactContext = getOrCreateReactContext("bacano-client-v1", {
|
|
128
|
+
client: null,
|
|
129
|
+
loading: true,
|
|
130
|
+
error: null
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// libs/sdk/src/react/marketing-context.ts
|
|
134
|
+
var NOOP_MARKETING_RUNTIME = {
|
|
135
|
+
enabled: false,
|
|
136
|
+
track: () => void 0,
|
|
137
|
+
captureAttribution: () => null,
|
|
138
|
+
getAttribution: () => null,
|
|
139
|
+
destroy: () => void 0
|
|
140
|
+
};
|
|
141
|
+
var BacanoMarketingContext = getOrCreateReactContext(
|
|
142
|
+
"bacano-marketing-v1",
|
|
143
|
+
NOOP_MARKETING_RUNTIME
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// libs/sdk/src/react/preview/cache.ts
|
|
147
|
+
var PreviewRouteCache = class {
|
|
148
|
+
constructor(maxEntries) {
|
|
149
|
+
this.maxEntries = maxEntries;
|
|
150
|
+
}
|
|
151
|
+
maxEntries;
|
|
152
|
+
values = /* @__PURE__ */ new Map();
|
|
153
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
154
|
+
load(input) {
|
|
155
|
+
const pending = this.inFlight.get(input.route);
|
|
156
|
+
if (pending) return pending;
|
|
157
|
+
if (!input.force) {
|
|
158
|
+
const cached = this.values.get(input.route);
|
|
159
|
+
if (cached) {
|
|
160
|
+
this.values.delete(input.route);
|
|
161
|
+
this.values.set(input.route, cached);
|
|
162
|
+
return Promise.resolve(cached);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const request = input.loader({
|
|
166
|
+
route: input.route,
|
|
167
|
+
force: input.force,
|
|
168
|
+
client: input.client
|
|
169
|
+
}).then((document) => {
|
|
170
|
+
if (document === null || document === void 0) {
|
|
171
|
+
throw new EmptyPreviewDocumentError();
|
|
172
|
+
}
|
|
173
|
+
const value = { document, refreshedAt: /* @__PURE__ */ new Date() };
|
|
174
|
+
this.values.delete(input.route);
|
|
175
|
+
this.values.set(input.route, value);
|
|
176
|
+
this.trim();
|
|
177
|
+
return value;
|
|
178
|
+
});
|
|
179
|
+
this.inFlight.set(input.route, request);
|
|
180
|
+
const clearInFlight = () => {
|
|
181
|
+
if (this.inFlight.get(input.route) === request) {
|
|
182
|
+
this.inFlight.delete(input.route);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
void request.then(clearInFlight, clearInFlight);
|
|
186
|
+
return request;
|
|
187
|
+
}
|
|
188
|
+
clear() {
|
|
189
|
+
this.values.clear();
|
|
190
|
+
this.inFlight.clear();
|
|
191
|
+
}
|
|
192
|
+
trim() {
|
|
193
|
+
while (this.values.size > this.maxEntries) {
|
|
194
|
+
const oldestKey = this.values.keys().next().value;
|
|
195
|
+
if (typeof oldestKey !== "string") return;
|
|
196
|
+
this.values.delete(oldestKey);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
var EmptyPreviewDocumentError = class extends Error {
|
|
201
|
+
constructor() {
|
|
202
|
+
super("Preview loader returned an empty document.");
|
|
203
|
+
this.name = "EmptyPreviewDocumentError";
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// libs/sdk/src/react/preview/provider.tsx
|
|
208
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
209
|
+
var DEFAULT_CACHE_MAX_ENTRIES = 50;
|
|
210
|
+
function createInitialState() {
|
|
211
|
+
return {
|
|
212
|
+
status: "idle",
|
|
213
|
+
document: null,
|
|
214
|
+
error: null,
|
|
215
|
+
refreshedAt: null
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function getStorageKey(websiteSlug) {
|
|
219
|
+
return `@bacano/sdk:preview:${encodeURIComponent(websiteSlug)}:ui:v1`;
|
|
220
|
+
}
|
|
221
|
+
function isToolbarPosition(value) {
|
|
222
|
+
return value === "top-left" || value === "top-right" || value === "bottom-left" || value === "bottom-right";
|
|
223
|
+
}
|
|
224
|
+
function readPersistedToolbarState(websiteSlug) {
|
|
225
|
+
if (typeof window === "undefined") return null;
|
|
226
|
+
try {
|
|
227
|
+
const raw = window.sessionStorage.getItem(getStorageKey(websiteSlug));
|
|
228
|
+
if (!raw) return null;
|
|
229
|
+
const value = JSON.parse(raw);
|
|
230
|
+
return {
|
|
231
|
+
expanded: typeof value.expanded === "boolean" ? value.expanded : void 0,
|
|
232
|
+
position: isToolbarPosition(value.position) ? value.position : void 0
|
|
233
|
+
};
|
|
234
|
+
} catch {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function persistToolbarState(websiteSlug, state) {
|
|
239
|
+
if (typeof window === "undefined") return;
|
|
240
|
+
try {
|
|
241
|
+
window.sessionStorage.setItem(
|
|
242
|
+
getStorageKey(websiteSlug),
|
|
243
|
+
JSON.stringify(state)
|
|
244
|
+
);
|
|
245
|
+
} catch {
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function safeLoaderError(error) {
|
|
249
|
+
if (error instanceof EmptyPreviewDocumentError) {
|
|
250
|
+
return {
|
|
251
|
+
code: "EMPTY_DOCUMENT",
|
|
252
|
+
message: "No encontramos contenido publicado para esta ruta."
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
code: "LOADER_FAILED",
|
|
257
|
+
message: "No pudimos consultar el contenido publicado de Bacano."
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function BacanoPreviewProvider({
|
|
261
|
+
websiteSlug,
|
|
262
|
+
route: requestedRoute,
|
|
263
|
+
loadRoute,
|
|
264
|
+
navigate: navigateStorefront,
|
|
265
|
+
normalizeRoute = normalizePreviewRoute,
|
|
266
|
+
isPreviewableRoute,
|
|
267
|
+
initialExpanded = true,
|
|
268
|
+
initialPosition = "top-right",
|
|
269
|
+
cacheMaxEntries = DEFAULT_CACHE_MAX_ENTRIES,
|
|
270
|
+
children
|
|
271
|
+
}) {
|
|
272
|
+
const clientState = (0, import_react3.useContext)(BacanoReactContext);
|
|
273
|
+
const route = (0, import_react3.useMemo)(
|
|
274
|
+
() => normalizeRoute(requestedRoute),
|
|
275
|
+
[normalizeRoute, requestedRoute]
|
|
276
|
+
);
|
|
277
|
+
const [state, setState] = (0, import_react3.useState)(createInitialState);
|
|
278
|
+
const [isExpanded, setExpandedState] = (0, import_react3.useState)(initialExpanded);
|
|
279
|
+
const [position, setPositionState] = (0, import_react3.useState)(initialPosition);
|
|
280
|
+
const mountedRef = (0, import_react3.useRef)(false);
|
|
281
|
+
const requestSequenceRef = (0, import_react3.useRef)(0);
|
|
282
|
+
const cacheRef = (0, import_react3.useRef)(null);
|
|
283
|
+
const cacheSizeRef = (0, import_react3.useRef)(cacheMaxEntries);
|
|
284
|
+
if (!cacheRef.current || cacheSizeRef.current !== cacheMaxEntries) {
|
|
285
|
+
cacheRef.current = new PreviewRouteCache(
|
|
286
|
+
Math.max(1, cacheMaxEntries)
|
|
287
|
+
);
|
|
288
|
+
cacheSizeRef.current = cacheMaxEntries;
|
|
289
|
+
}
|
|
290
|
+
(0, import_react3.useEffect)(() => {
|
|
291
|
+
mountedRef.current = true;
|
|
292
|
+
return () => {
|
|
293
|
+
mountedRef.current = false;
|
|
294
|
+
requestSequenceRef.current += 1;
|
|
295
|
+
};
|
|
296
|
+
}, []);
|
|
297
|
+
(0, import_react3.useEffect)(() => {
|
|
298
|
+
const persisted = readPersistedToolbarState(websiteSlug);
|
|
299
|
+
setExpandedState(persisted?.expanded ?? initialExpanded);
|
|
300
|
+
setPositionState(persisted?.position ?? initialPosition);
|
|
301
|
+
}, [initialExpanded, initialPosition, websiteSlug]);
|
|
302
|
+
const load = (0, import_react3.useCallback)(
|
|
303
|
+
async (force, preserveDocument) => {
|
|
304
|
+
const client = clientState.client;
|
|
305
|
+
if (!client) {
|
|
306
|
+
if (!clientState.loading) {
|
|
307
|
+
setState({
|
|
308
|
+
status: "error",
|
|
309
|
+
document: null,
|
|
310
|
+
error: {
|
|
311
|
+
code: "CLIENT_UNAVAILABLE",
|
|
312
|
+
message: "No pudimos inicializar la conexi\xF3n con Bacano."
|
|
313
|
+
},
|
|
314
|
+
refreshedAt: null
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (isPreviewableRoute?.(route) === false) {
|
|
320
|
+
setState({
|
|
321
|
+
status: "error",
|
|
322
|
+
document: null,
|
|
323
|
+
error: {
|
|
324
|
+
code: "ROUTE_NOT_PREVIEWABLE",
|
|
325
|
+
message: "Esta ruta no est\xE1 disponible en la vista previa."
|
|
326
|
+
},
|
|
327
|
+
refreshedAt: null
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const sequence = ++requestSequenceRef.current;
|
|
332
|
+
setState((current) => ({
|
|
333
|
+
...current,
|
|
334
|
+
status: "loading",
|
|
335
|
+
document: preserveDocument ? current.document : null,
|
|
336
|
+
error: null
|
|
337
|
+
}));
|
|
338
|
+
try {
|
|
339
|
+
const cache = cacheRef.current;
|
|
340
|
+
if (!cache) return;
|
|
341
|
+
const result = await cache.load({
|
|
342
|
+
route,
|
|
343
|
+
force,
|
|
344
|
+
client,
|
|
345
|
+
loader: loadRoute
|
|
346
|
+
});
|
|
347
|
+
if (!mountedRef.current || sequence !== requestSequenceRef.current) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
setState({
|
|
351
|
+
status: "ready",
|
|
352
|
+
document: result.document,
|
|
353
|
+
error: null,
|
|
354
|
+
refreshedAt: result.refreshedAt
|
|
355
|
+
});
|
|
356
|
+
} catch (error) {
|
|
357
|
+
if (!mountedRef.current || sequence !== requestSequenceRef.current)
|
|
358
|
+
return;
|
|
359
|
+
setState((current) => ({
|
|
360
|
+
...current,
|
|
361
|
+
status: "error",
|
|
362
|
+
document: preserveDocument ? current.document : null,
|
|
363
|
+
error: safeLoaderError(error)
|
|
364
|
+
}));
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
[
|
|
368
|
+
clientState.client,
|
|
369
|
+
clientState.loading,
|
|
370
|
+
isPreviewableRoute,
|
|
371
|
+
loadRoute,
|
|
372
|
+
route
|
|
373
|
+
]
|
|
374
|
+
);
|
|
375
|
+
(0, import_react3.useEffect)(() => {
|
|
376
|
+
if (clientState.loading) {
|
|
377
|
+
setState((current) => ({ ...current, status: "idle", error: null }));
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
void load(false, false);
|
|
381
|
+
return () => {
|
|
382
|
+
requestSequenceRef.current += 1;
|
|
383
|
+
};
|
|
384
|
+
}, [clientState.loading, load]);
|
|
385
|
+
const refresh = (0, import_react3.useCallback)(() => load(true, true), [load]);
|
|
386
|
+
const navigate = (0, import_react3.useCallback)(
|
|
387
|
+
(nextRoute) => {
|
|
388
|
+
const normalized = normalizeRoute(nextRoute);
|
|
389
|
+
if (isPreviewableRoute?.(normalized) === false) {
|
|
390
|
+
setState((current) => ({
|
|
391
|
+
...current,
|
|
392
|
+
status: "error",
|
|
393
|
+
error: {
|
|
394
|
+
code: "ROUTE_NOT_PREVIEWABLE",
|
|
395
|
+
message: "Esta ruta no est\xE1 disponible en la vista previa."
|
|
396
|
+
}
|
|
397
|
+
}));
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
navigateStorefront(normalized);
|
|
401
|
+
},
|
|
402
|
+
[isPreviewableRoute, navigateStorefront, normalizeRoute]
|
|
403
|
+
);
|
|
404
|
+
const setExpanded = (0, import_react3.useCallback)(
|
|
405
|
+
(expanded) => {
|
|
406
|
+
setExpandedState(expanded);
|
|
407
|
+
persistToolbarState(websiteSlug, { expanded, position });
|
|
408
|
+
},
|
|
409
|
+
[position, websiteSlug]
|
|
410
|
+
);
|
|
411
|
+
const setPosition = (0, import_react3.useCallback)(
|
|
412
|
+
(nextPosition) => {
|
|
413
|
+
setPositionState(nextPosition);
|
|
414
|
+
persistToolbarState(websiteSlug, {
|
|
415
|
+
expanded: isExpanded,
|
|
416
|
+
position: nextPosition
|
|
417
|
+
});
|
|
418
|
+
},
|
|
419
|
+
[isExpanded, websiteSlug]
|
|
420
|
+
);
|
|
421
|
+
const value = (0, import_react3.useMemo)(
|
|
422
|
+
() => ({
|
|
423
|
+
isPreview: true,
|
|
424
|
+
websiteSlug,
|
|
425
|
+
route,
|
|
426
|
+
...state,
|
|
427
|
+
isExpanded,
|
|
428
|
+
position,
|
|
429
|
+
refresh,
|
|
430
|
+
navigate,
|
|
431
|
+
setExpanded,
|
|
432
|
+
setPosition
|
|
433
|
+
}),
|
|
434
|
+
[
|
|
435
|
+
isExpanded,
|
|
436
|
+
navigate,
|
|
437
|
+
position,
|
|
438
|
+
refresh,
|
|
439
|
+
route,
|
|
440
|
+
setExpanded,
|
|
441
|
+
setPosition,
|
|
442
|
+
state,
|
|
443
|
+
websiteSlug
|
|
444
|
+
]
|
|
445
|
+
);
|
|
446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BacanoPreviewModeContext.Provider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BacanoMarketingContext.Provider, { value: NOOP_MARKETING_RUNTIME, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
447
|
+
BacanoPreviewContext.Provider,
|
|
448
|
+
{
|
|
449
|
+
value,
|
|
450
|
+
children
|
|
451
|
+
}
|
|
452
|
+
) }) });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// libs/sdk/src/react/preview/toolbar.tsx
|
|
456
|
+
var import_react4 = require("react");
|
|
457
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
458
|
+
var positionOptions = [
|
|
459
|
+
{ value: "top-left", label: "Arriba a la izquierda", symbol: "\u2196" },
|
|
460
|
+
{ value: "top-right", label: "Arriba a la derecha", symbol: "\u2197" },
|
|
461
|
+
{ value: "bottom-left", label: "Abajo a la izquierda", symbol: "\u2199" },
|
|
462
|
+
{ value: "bottom-right", label: "Abajo a la derecha", symbol: "\u2198" }
|
|
463
|
+
];
|
|
464
|
+
function BacanoPreviewToolbar({
|
|
465
|
+
websiteName,
|
|
466
|
+
logo,
|
|
467
|
+
primaryColor = "#172033",
|
|
468
|
+
accentColor = "#2f80ed",
|
|
469
|
+
backgroundColor = "#ffffff",
|
|
470
|
+
locale = "es-CO",
|
|
471
|
+
zIndex = 2147483e3,
|
|
472
|
+
suggestedRoutes = []
|
|
473
|
+
}) {
|
|
474
|
+
const preview = useBacanoPreview();
|
|
475
|
+
const [routeInput, setRouteInput] = (0, import_react4.useState)(preview.route);
|
|
476
|
+
const [positionMenuOpen, setPositionMenuOpen] = (0, import_react4.useState)(false);
|
|
477
|
+
const controlsId = (0, import_react4.useId)();
|
|
478
|
+
const positionMenuId = (0, import_react4.useId)();
|
|
479
|
+
const routesListId = (0, import_react4.useId)();
|
|
480
|
+
const style = {
|
|
481
|
+
"--bacano-preview-primary": primaryColor,
|
|
482
|
+
"--bacano-preview-accent": accentColor,
|
|
483
|
+
"--bacano-preview-background": backgroundColor,
|
|
484
|
+
zIndex
|
|
485
|
+
};
|
|
486
|
+
(0, import_react4.useEffect)(() => setRouteInput(preview.route), [preview.route]);
|
|
487
|
+
if (!preview.isExpanded) {
|
|
488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: previewToolbarStyles }),
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
className: "bacano-preview-root bacano-preview-root--collapsed",
|
|
494
|
+
"data-position": preview.position,
|
|
495
|
+
style,
|
|
496
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
497
|
+
"button",
|
|
498
|
+
{
|
|
499
|
+
type: "button",
|
|
500
|
+
className: "bacano-preview-tab",
|
|
501
|
+
"aria-controls": controlsId,
|
|
502
|
+
"aria-expanded": "false",
|
|
503
|
+
"aria-label": `Mostrar vista previa de ${preview.route}`,
|
|
504
|
+
title: "Mostrar barra de vista previa",
|
|
505
|
+
onClick: () => preview.setExpanded(true),
|
|
506
|
+
children: [
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PreviewIcon, {}),
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Vista previa" }),
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronIcon, { direction: "down" })
|
|
510
|
+
]
|
|
511
|
+
}
|
|
512
|
+
)
|
|
513
|
+
}
|
|
514
|
+
)
|
|
515
|
+
] });
|
|
516
|
+
}
|
|
517
|
+
const statusMessage = getStatusMessage(
|
|
518
|
+
preview.status,
|
|
519
|
+
preview.error?.message
|
|
520
|
+
);
|
|
521
|
+
function submitRoute(event) {
|
|
522
|
+
event.preventDefault();
|
|
523
|
+
preview.navigate(routeInput);
|
|
524
|
+
}
|
|
525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
526
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: previewToolbarStyles }),
|
|
527
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
528
|
+
"div",
|
|
529
|
+
{
|
|
530
|
+
className: "bacano-preview-root",
|
|
531
|
+
"data-position": preview.position,
|
|
532
|
+
style,
|
|
533
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
534
|
+
"section",
|
|
535
|
+
{
|
|
536
|
+
id: controlsId,
|
|
537
|
+
className: "bacano-preview-toolbar",
|
|
538
|
+
"aria-label": "Controles de vista previa de Bacano",
|
|
539
|
+
children: [
|
|
540
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bacano-preview-summary", children: [
|
|
541
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
542
|
+
"span",
|
|
543
|
+
{
|
|
544
|
+
className: "bacano-preview-logo",
|
|
545
|
+
"aria-hidden": logo ? void 0 : true,
|
|
546
|
+
children: logo ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PreviewIcon, {})
|
|
547
|
+
}
|
|
548
|
+
),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "bacano-preview-copy", children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
|
|
551
|
+
"Vista en vivo",
|
|
552
|
+
websiteName ? ` \xB7 ${websiteName}` : "",
|
|
553
|
+
":",
|
|
554
|
+
" ",
|
|
555
|
+
preview.route
|
|
556
|
+
] }),
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { role: "status", "aria-live": "polite", children: preview.refreshedAt && preview.status !== "error" ? `Contenido p\xFAblico consultado a las ${formatTime(
|
|
558
|
+
preview.refreshedAt,
|
|
559
|
+
locale
|
|
560
|
+
)}.` : statusMessage })
|
|
561
|
+
] })
|
|
562
|
+
] }),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { className: "bacano-preview-route", onSubmit: submitRoute, children: [
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: `${controlsId}-route`, children: "Ruta para visualizar" }),
|
|
565
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
566
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
567
|
+
"input",
|
|
568
|
+
{
|
|
569
|
+
id: `${controlsId}-route`,
|
|
570
|
+
type: "text",
|
|
571
|
+
value: routeInput,
|
|
572
|
+
list: suggestedRoutes.length > 0 ? routesListId : void 0,
|
|
573
|
+
autoComplete: "off",
|
|
574
|
+
onChange: (event) => setRouteInput(event.target.value)
|
|
575
|
+
}
|
|
576
|
+
),
|
|
577
|
+
suggestedRoutes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("datalist", { id: routesListId, children: suggestedRoutes.map((route) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: route }, route)) }) : null,
|
|
578
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "submit", "aria-label": "Abrir ruta", title: "Abrir ruta", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ArrowIcon, {}) })
|
|
579
|
+
] })
|
|
580
|
+
] }),
|
|
581
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "bacano-preview-actions", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
582
|
+
"button",
|
|
583
|
+
{
|
|
584
|
+
type: "button",
|
|
585
|
+
disabled: preview.status === "loading",
|
|
586
|
+
onClick: () => void preview.refresh(),
|
|
587
|
+
children: [
|
|
588
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RefreshIcon, { spinning: preview.status === "loading" }),
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: preview.status === "loading" ? "Actualizando" : "Actualizar" })
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
) }),
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bacano-preview-corner-actions", children: [
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
595
|
+
"button",
|
|
596
|
+
{
|
|
597
|
+
type: "button",
|
|
598
|
+
"aria-label": "Cambiar posici\xF3n de la barra",
|
|
599
|
+
"aria-controls": positionMenuId,
|
|
600
|
+
"aria-expanded": positionMenuOpen,
|
|
601
|
+
title: "Cambiar posici\xF3n",
|
|
602
|
+
onClick: () => setPositionMenuOpen((current) => !current),
|
|
603
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MoveIcon, {})
|
|
604
|
+
}
|
|
605
|
+
),
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
607
|
+
"button",
|
|
608
|
+
{
|
|
609
|
+
type: "button",
|
|
610
|
+
"aria-label": "Ocultar barra de vista previa",
|
|
611
|
+
"aria-controls": controlsId,
|
|
612
|
+
"aria-expanded": "true",
|
|
613
|
+
title: "Ocultar barra",
|
|
614
|
+
onClick: () => {
|
|
615
|
+
setPositionMenuOpen(false);
|
|
616
|
+
preview.setExpanded(false);
|
|
617
|
+
},
|
|
618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronIcon, { direction: "up" })
|
|
619
|
+
}
|
|
620
|
+
)
|
|
621
|
+
] }),
|
|
622
|
+
positionMenuOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
623
|
+
"div",
|
|
624
|
+
{
|
|
625
|
+
id: positionMenuId,
|
|
626
|
+
className: "bacano-preview-position-menu",
|
|
627
|
+
role: "group",
|
|
628
|
+
"aria-label": "Posici\xF3n de la barra",
|
|
629
|
+
onKeyDown: (event) => {
|
|
630
|
+
if (event.key === "Escape") setPositionMenuOpen(false);
|
|
631
|
+
},
|
|
632
|
+
children: positionOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
633
|
+
"button",
|
|
634
|
+
{
|
|
635
|
+
type: "button",
|
|
636
|
+
"aria-label": option.label,
|
|
637
|
+
"aria-pressed": preview.position === option.value,
|
|
638
|
+
title: option.label,
|
|
639
|
+
onClick: () => {
|
|
640
|
+
preview.setPosition(option.value);
|
|
641
|
+
setPositionMenuOpen(false);
|
|
642
|
+
},
|
|
643
|
+
children: option.symbol
|
|
644
|
+
},
|
|
645
|
+
option.value
|
|
646
|
+
))
|
|
647
|
+
}
|
|
648
|
+
) : null
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
}
|
|
653
|
+
)
|
|
654
|
+
] });
|
|
655
|
+
}
|
|
656
|
+
function getStatusMessage(status, error) {
|
|
657
|
+
if (status === "error") return error ?? "No pudimos actualizar el contenido.";
|
|
658
|
+
if (status === "loading") return "Consultando el contenido p\xFAblico actual.";
|
|
659
|
+
if (status === "ready") return "Contenido p\xFAblico actualizado.";
|
|
660
|
+
return "Preparando la conexi\xF3n con Bacano.";
|
|
661
|
+
}
|
|
662
|
+
function formatTime(value, locale) {
|
|
663
|
+
try {
|
|
664
|
+
return new Intl.DateTimeFormat(locale, {
|
|
665
|
+
hour: "numeric",
|
|
666
|
+
minute: "2-digit",
|
|
667
|
+
second: "2-digit"
|
|
668
|
+
}).format(value);
|
|
669
|
+
} catch {
|
|
670
|
+
return value.toLocaleTimeString();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
function SvgIcon(props) {
|
|
674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", ...props, children: props.children });
|
|
675
|
+
}
|
|
676
|
+
function PreviewIcon() {
|
|
677
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(SvgIcon, { "aria-hidden": "true", children: [
|
|
678
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z" }),
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "2.5" })
|
|
680
|
+
] });
|
|
681
|
+
}
|
|
682
|
+
function RefreshIcon({ spinning }) {
|
|
683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
684
|
+
SvgIcon,
|
|
685
|
+
{
|
|
686
|
+
"aria-hidden": "true",
|
|
687
|
+
className: spinning ? "is-spinning" : void 0,
|
|
688
|
+
children: [
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M20 6v5h-5M4 18v-5h5" }),
|
|
690
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 9a7 7 0 0 0-12-2L4 11M6 15a7 7 0 0 0 12 2l2-4" })
|
|
691
|
+
]
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
function ArrowIcon() {
|
|
696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SvgIcon, { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M5 12h14M13 6l6 6-6 6" }) });
|
|
697
|
+
}
|
|
698
|
+
function MoveIcon() {
|
|
699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SvgIcon, { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m12 2 3 3-3 3M12 2 9 5M22 12l-3-3-3 3M22 12l-3 3M12 22l3-3-3-3M12 22l-3-3M2 12l3-3 3 3M2 12l3 3" }) });
|
|
700
|
+
}
|
|
701
|
+
function ChevronIcon({ direction }) {
|
|
702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SvgIcon, { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: direction === "up" ? "m6 15 6-6 6 6" : "m6 9 6 6 6-6" }) });
|
|
703
|
+
}
|
|
704
|
+
var previewToolbarStyles = `
|
|
705
|
+
.bacano-preview-root{position:fixed;pointer-events:none;width:calc(100% - 24px);max-width:1240px;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:var(--bacano-preview-primary);line-height:1.35}
|
|
706
|
+
.bacano-preview-root[data-position="top-left"]{top:12px;left:12px}.bacano-preview-root[data-position="top-right"]{top:12px;right:12px}.bacano-preview-root[data-position="bottom-left"]{bottom:12px;left:12px}.bacano-preview-root[data-position="bottom-right"]{right:12px;bottom:12px}
|
|
707
|
+
.bacano-preview-root--collapsed{width:auto;max-width:calc(100% - 24px)}
|
|
708
|
+
.bacano-preview-toolbar,.bacano-preview-tab{pointer-events:auto;border:1px solid color-mix(in srgb,var(--bacano-preview-accent) 34%,transparent);background:color-mix(in srgb,var(--bacano-preview-background) 96%,transparent);box-shadow:0 16px 42px color-mix(in srgb,var(--bacano-preview-primary) 18%,transparent);backdrop-filter:blur(16px)}
|
|
709
|
+
.bacano-preview-toolbar{position:relative;display:grid;grid-template-columns:minmax(220px,1fr) minmax(280px,460px) auto;align-items:center;gap:12px;border-radius:16px;padding:14px 92px 14px 16px}
|
|
710
|
+
.bacano-preview-summary{display:flex;min-width:0;align-items:center;gap:10px}.bacano-preview-logo{display:grid;width:34px;height:34px;flex:0 0 auto;place-items:center;overflow:hidden;border-radius:10px;background:color-mix(in srgb,var(--bacano-preview-accent) 12%,transparent);color:var(--bacano-preview-accent)}.bacano-preview-logo>svg{width:20px;height:20px;stroke-width:1.8}.bacano-preview-logo img{display:block;max-width:100%;max-height:100%;object-fit:contain}
|
|
711
|
+
.bacano-preview-copy{display:flex;min-width:0;flex-direction:column;gap:2px}.bacano-preview-copy strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px}.bacano-preview-copy span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;opacity:.68}
|
|
712
|
+
.bacano-preview-route label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bacano-preview-route>div{display:flex;gap:6px}.bacano-preview-route input{min-width:0;min-height:42px;flex:1;border:1px solid color-mix(in srgb,var(--bacano-preview-primary) 20%,transparent);border-radius:10px;background:var(--bacano-preview-background);padding:0 12px;color:var(--bacano-preview-primary);font:inherit;font-size:14px}.bacano-preview-route button,.bacano-preview-actions button,.bacano-preview-corner-actions button,.bacano-preview-position-menu button,.bacano-preview-tab{border:0;font:inherit;cursor:pointer}
|
|
713
|
+
.bacano-preview-route button{display:grid;width:42px;height:42px;flex:0 0 auto;place-items:center;border-radius:10px;background:var(--bacano-preview-primary);color:var(--bacano-preview-background)}.bacano-preview-route svg,.bacano-preview-actions svg,.bacano-preview-corner-actions svg,.bacano-preview-tab svg{width:18px;height:18px;stroke-width:1.8}
|
|
714
|
+
.bacano-preview-actions button{display:flex;min-height:42px;align-items:center;justify-content:center;gap:8px;border-radius:10px;background:var(--bacano-preview-accent);padding:0 16px;color:var(--bacano-preview-background);font-weight:700}.bacano-preview-actions button:disabled{cursor:wait;opacity:.68}
|
|
715
|
+
.bacano-preview-corner-actions{position:absolute;top:8px;right:8px;display:flex;gap:2px}.bacano-preview-corner-actions button{display:grid;width:36px;height:36px;place-items:center;border-radius:9px;background:transparent;color:var(--bacano-preview-primary)}.bacano-preview-corner-actions button:hover{background:color-mix(in srgb,var(--bacano-preview-primary) 7%,transparent)}
|
|
716
|
+
.bacano-preview-position-menu{position:absolute;right:48px;top:48px;display:grid;grid-template-columns:repeat(2,44px);gap:4px;border:1px solid color-mix(in srgb,var(--bacano-preview-primary) 16%,transparent);border-radius:12px;background:var(--bacano-preview-background);padding:6px;box-shadow:0 12px 30px color-mix(in srgb,var(--bacano-preview-primary) 18%,transparent)}.bacano-preview-root[data-position^="bottom"] .bacano-preview-position-menu{top:auto;bottom:48px}.bacano-preview-position-menu button{width:44px;height:40px;border-radius:8px;background:transparent;color:var(--bacano-preview-primary);font-size:18px}.bacano-preview-position-menu button[aria-pressed="true"]{background:color-mix(in srgb,var(--bacano-preview-accent) 14%,transparent);color:var(--bacano-preview-accent)}
|
|
717
|
+
.bacano-preview-tab{display:flex;min-height:44px;max-width:100%;align-items:center;gap:8px;border-radius:999px;padding:0 16px;color:var(--bacano-preview-primary);font-weight:750}.bacano-preview-tab span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
718
|
+
.bacano-preview-root button:focus-visible,.bacano-preview-root input:focus-visible{outline:3px solid color-mix(in srgb,var(--bacano-preview-accent) 42%,transparent);outline-offset:2px}.bacano-preview-root svg.is-spinning{animation:bacano-preview-spin .8s linear infinite}@keyframes bacano-preview-spin{to{transform:rotate(360deg)}}
|
|
719
|
+
@media(max-width:900px){.bacano-preview-toolbar{grid-template-columns:1fr auto;padding-right:88px}.bacano-preview-route{grid-column:1/-1;grid-row:2}.bacano-preview-actions{grid-column:2;grid-row:1}.bacano-preview-copy span{white-space:normal}.bacano-preview-actions button span{display:none}}
|
|
720
|
+
@media(max-width:520px){.bacano-preview-root{width:calc(100% - 16px)}.bacano-preview-root[data-position="top-left"],.bacano-preview-root[data-position="top-right"]{top:8px;left:8px;right:auto}.bacano-preview-root[data-position="bottom-left"],.bacano-preview-root[data-position="bottom-right"]{bottom:8px;left:8px;right:auto}.bacano-preview-toolbar{grid-template-columns:minmax(0,1fr);gap:10px;border-radius:14px;padding:12px 80px 12px 12px}.bacano-preview-actions{grid-column:1;grid-row:3}.bacano-preview-actions button{width:100%}.bacano-preview-actions button span{display:inline}.bacano-preview-route{grid-column:1;grid-row:2}}
|
|
721
|
+
@media(prefers-reduced-motion:reduce){.bacano-preview-root *{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}
|
|
722
|
+
`;
|
|
723
|
+
|
|
724
|
+
// libs/sdk/src/react/preview/shell.tsx
|
|
725
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
726
|
+
function BacanoPreviewShell({
|
|
727
|
+
toolbar = {},
|
|
728
|
+
children,
|
|
729
|
+
...providerProps
|
|
730
|
+
}) {
|
|
731
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BacanoPreviewProvider, { ...providerProps, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BacanoPreviewShellContent, { toolbar, render: children }) });
|
|
732
|
+
}
|
|
733
|
+
function BacanoPreviewShellContent({
|
|
734
|
+
toolbar,
|
|
735
|
+
render
|
|
736
|
+
}) {
|
|
737
|
+
const preview = useBacanoPreview();
|
|
738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
739
|
+
toolbar === false ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BacanoPreviewToolbar, { ...toolbar }),
|
|
740
|
+
render(preview)
|
|
741
|
+
] });
|
|
742
|
+
}
|