@quikturn/logos-react 1.0.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/index.cjs ADDED
@@ -0,0 +1,675 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var logos = require('@quikturn/logos');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefault(React);
10
+
11
+ // src/context.tsx
12
+ var QuikturnContext = React.createContext(null);
13
+ function useQuikturnContext() {
14
+ return React.useContext(QuikturnContext);
15
+ }
16
+ function QuikturnProvider({
17
+ token,
18
+ baseUrl,
19
+ children
20
+ }) {
21
+ return /* @__PURE__ */ jsxRuntime.jsx(QuikturnContext.Provider, { value: { token, baseUrl }, children });
22
+ }
23
+ function useLogoUrl(domain, options) {
24
+ const ctx = useQuikturnContext();
25
+ const token = options?.token ?? ctx?.token;
26
+ const baseUrl = options?.baseUrl ?? ctx?.baseUrl;
27
+ return React.useMemo(
28
+ () => logos.logoUrl(domain, {
29
+ token,
30
+ baseUrl,
31
+ size: options?.size,
32
+ format: options?.format,
33
+ greyscale: options?.greyscale,
34
+ theme: options?.theme
35
+ }),
36
+ [domain, token, baseUrl, options?.size, options?.format, options?.greyscale, options?.theme]
37
+ );
38
+ }
39
+ var fired = /* @__PURE__ */ new Set();
40
+ function fireBeacon(token) {
41
+ if (typeof window === "undefined") return;
42
+ if (!token || token.startsWith("sk_")) return;
43
+ if (fired.has(token)) return;
44
+ fired.add(token);
45
+ const img = new Image();
46
+ img.src = `${logos.BASE_URL}/_beacon?token=${token}&page=${encodeURIComponent(location.href)}`;
47
+ }
48
+ function QuikturnLogo({
49
+ domain,
50
+ token,
51
+ baseUrl,
52
+ size,
53
+ format,
54
+ greyscale,
55
+ theme,
56
+ alt,
57
+ href,
58
+ className,
59
+ style,
60
+ loading = "lazy",
61
+ onError,
62
+ onLoad
63
+ }) {
64
+ const ctx = useQuikturnContext();
65
+ const effectiveToken = token ?? ctx?.token ?? "";
66
+ const effectiveBaseUrl = baseUrl ?? ctx?.baseUrl;
67
+ const src = React.useMemo(
68
+ () => logos.logoUrl(domain, {
69
+ token: effectiveToken || void 0,
70
+ size,
71
+ format,
72
+ greyscale,
73
+ theme,
74
+ baseUrl: effectiveBaseUrl
75
+ }),
76
+ [domain, effectiveToken, effectiveBaseUrl, size, format, greyscale, theme]
77
+ );
78
+ React.useEffect(() => {
79
+ if (effectiveToken) fireBeacon(effectiveToken);
80
+ }, [effectiveToken]);
81
+ const imgEl = /* @__PURE__ */ jsxRuntime.jsx(
82
+ "img",
83
+ {
84
+ src,
85
+ alt: alt ?? `${domain} logo`,
86
+ loading,
87
+ onError,
88
+ onLoad
89
+ }
90
+ );
91
+ if (href) {
92
+ return /* @__PURE__ */ jsxRuntime.jsx(
93
+ "a",
94
+ {
95
+ href,
96
+ target: "_blank",
97
+ rel: "noopener noreferrer",
98
+ className,
99
+ style,
100
+ children: imgEl
101
+ }
102
+ );
103
+ }
104
+ if (className || style) {
105
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style, children: imgEl });
106
+ }
107
+ return imgEl;
108
+ }
109
+ var ANIMATION_CONFIG = {
110
+ SMOOTH_TAU: 0.25,
111
+ MIN_COPIES: 2,
112
+ COPY_HEADROOM: 2
113
+ };
114
+ function useResizeObserver(callback, refs, deps) {
115
+ React.useEffect(() => {
116
+ if (typeof window === "undefined") return;
117
+ if (!window.ResizeObserver) {
118
+ const handle = () => callback();
119
+ window.addEventListener("resize", handle);
120
+ callback();
121
+ return () => window.removeEventListener("resize", handle);
122
+ }
123
+ const observers = refs.map((ref) => {
124
+ if (!ref.current) return null;
125
+ const observer = new ResizeObserver(callback);
126
+ observer.observe(ref.current);
127
+ return observer;
128
+ });
129
+ callback();
130
+ return () => {
131
+ observers.forEach((o) => o?.disconnect());
132
+ };
133
+ }, deps);
134
+ }
135
+ function useImageLoader(listRef, onLoad, deps) {
136
+ React.useEffect(() => {
137
+ const images = listRef.current?.querySelectorAll("img") ?? [];
138
+ if (images.length === 0) {
139
+ onLoad();
140
+ return;
141
+ }
142
+ let remaining = images.length;
143
+ const done = () => {
144
+ remaining -= 1;
145
+ if (remaining === 0) onLoad();
146
+ };
147
+ images.forEach((img) => {
148
+ const el = img;
149
+ if (el.complete) {
150
+ done();
151
+ } else {
152
+ el.addEventListener("load", done, { once: true });
153
+ el.addEventListener("error", done, { once: true });
154
+ }
155
+ });
156
+ return () => {
157
+ images.forEach((img) => {
158
+ img.removeEventListener("load", done);
159
+ img.removeEventListener("error", done);
160
+ });
161
+ };
162
+ }, deps);
163
+ }
164
+ function useAnimationLoop(trackRef, targetVelocity, seqWidth, seqHeight, isHovered, hoverSpeed, isVertical) {
165
+ const rafRef = React.useRef(null);
166
+ const lastTsRef = React.useRef(null);
167
+ const offsetRef = React.useRef(0);
168
+ const velocityRef = React.useRef(0);
169
+ React.useEffect(() => {
170
+ const track = trackRef.current;
171
+ if (!track) return;
172
+ const prefersReduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
173
+ const seqSize = isVertical ? seqHeight : seqWidth;
174
+ if (seqSize > 0) {
175
+ offsetRef.current = (offsetRef.current % seqSize + seqSize) % seqSize;
176
+ track.style.transform = isVertical ? `translate3d(0, ${-offsetRef.current}px, 0)` : `translate3d(${-offsetRef.current}px, 0, 0)`;
177
+ }
178
+ if (prefersReduced) {
179
+ track.style.transform = "translate3d(0, 0, 0)";
180
+ return () => {
181
+ lastTsRef.current = null;
182
+ };
183
+ }
184
+ const animate = (ts) => {
185
+ if (lastTsRef.current === null) lastTsRef.current = ts;
186
+ const dt = Math.max(0, ts - lastTsRef.current) / 1e3;
187
+ lastTsRef.current = ts;
188
+ const target = isHovered && hoverSpeed !== void 0 ? hoverSpeed : targetVelocity;
189
+ const ease = 1 - Math.exp(-dt / ANIMATION_CONFIG.SMOOTH_TAU);
190
+ velocityRef.current += (target - velocityRef.current) * ease;
191
+ if (seqSize > 0) {
192
+ let next = offsetRef.current + velocityRef.current * dt;
193
+ next = (next % seqSize + seqSize) % seqSize;
194
+ offsetRef.current = next;
195
+ track.style.transform = isVertical ? `translate3d(0, ${-offsetRef.current}px, 0)` : `translate3d(${-offsetRef.current}px, 0, 0)`;
196
+ }
197
+ rafRef.current = requestAnimationFrame(animate);
198
+ };
199
+ rafRef.current = requestAnimationFrame(animate);
200
+ return () => {
201
+ if (rafRef.current !== null) {
202
+ cancelAnimationFrame(rafRef.current);
203
+ rafRef.current = null;
204
+ }
205
+ lastTsRef.current = null;
206
+ };
207
+ }, [targetVelocity, seqWidth, seqHeight, isHovered, hoverSpeed, isVertical]);
208
+ }
209
+ function toCssLength(value) {
210
+ return typeof value === "number" ? `${value}px` : value ?? void 0;
211
+ }
212
+ function FadeOverlays({
213
+ isVertical,
214
+ fadeColor = "#ffffff"
215
+ }) {
216
+ const base = {
217
+ position: "absolute",
218
+ pointerEvents: "none",
219
+ zIndex: 1
220
+ };
221
+ if (isVertical) {
222
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
223
+ /* @__PURE__ */ jsxRuntime.jsx(
224
+ "div",
225
+ {
226
+ "aria-hidden": "true",
227
+ "data-testid": "fade-overlay",
228
+ style: {
229
+ ...base,
230
+ top: 0,
231
+ left: 0,
232
+ right: 0,
233
+ height: "clamp(24px, 8%, 120px)",
234
+ background: `linear-gradient(to bottom, ${fadeColor} 0%, transparent 100%)`
235
+ }
236
+ }
237
+ ),
238
+ /* @__PURE__ */ jsxRuntime.jsx(
239
+ "div",
240
+ {
241
+ "aria-hidden": "true",
242
+ "data-testid": "fade-overlay",
243
+ style: {
244
+ ...base,
245
+ bottom: 0,
246
+ left: 0,
247
+ right: 0,
248
+ height: "clamp(24px, 8%, 120px)",
249
+ background: `linear-gradient(to top, ${fadeColor} 0%, transparent 100%)`
250
+ }
251
+ }
252
+ )
253
+ ] });
254
+ }
255
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
256
+ /* @__PURE__ */ jsxRuntime.jsx(
257
+ "div",
258
+ {
259
+ "aria-hidden": "true",
260
+ "data-testid": "fade-overlay",
261
+ style: {
262
+ ...base,
263
+ top: 0,
264
+ bottom: 0,
265
+ left: 0,
266
+ width: "clamp(24px, 8%, 120px)",
267
+ background: `linear-gradient(to right, ${fadeColor} 0%, transparent 100%)`
268
+ }
269
+ }
270
+ ),
271
+ /* @__PURE__ */ jsxRuntime.jsx(
272
+ "div",
273
+ {
274
+ "aria-hidden": "true",
275
+ "data-testid": "fade-overlay",
276
+ style: {
277
+ ...base,
278
+ top: 0,
279
+ bottom: 0,
280
+ right: 0,
281
+ width: "clamp(24px, 8%, 120px)",
282
+ background: `linear-gradient(to left, ${fadeColor} 0%, transparent 100%)`
283
+ }
284
+ }
285
+ )
286
+ ] });
287
+ }
288
+ function DefaultLogoItem({
289
+ logo,
290
+ logoHeight,
291
+ scaleOnHover
292
+ }) {
293
+ const [hovered, setHovered] = React.useState(false);
294
+ const imgStyle = {
295
+ height: `${logoHeight}px`,
296
+ width: "auto",
297
+ display: "block",
298
+ objectFit: "contain",
299
+ userSelect: "none",
300
+ pointerEvents: "none",
301
+ transform: scaleOnHover && hovered ? "scale(1.2)" : void 0,
302
+ transition: scaleOnHover ? "transform 300ms cubic-bezier(0.4, 0, 0.2, 1)" : void 0
303
+ };
304
+ const handlers = scaleOnHover ? {
305
+ onMouseEnter: () => setHovered(true),
306
+ onMouseLeave: () => setHovered(false)
307
+ } : {};
308
+ const img = /* @__PURE__ */ jsxRuntime.jsx(
309
+ "img",
310
+ {
311
+ src: logo.url,
312
+ alt: logo.alt,
313
+ loading: "lazy",
314
+ decoding: "async",
315
+ draggable: false,
316
+ style: imgStyle
317
+ }
318
+ );
319
+ if (logo.href) {
320
+ return /* @__PURE__ */ jsxRuntime.jsx(
321
+ "a",
322
+ {
323
+ href: logo.href,
324
+ target: "_blank",
325
+ rel: "noopener noreferrer",
326
+ "aria-label": logo.alt,
327
+ style: {
328
+ display: "inline-flex",
329
+ alignItems: "center",
330
+ textDecoration: "none"
331
+ },
332
+ ...handlers,
333
+ children: img
334
+ }
335
+ );
336
+ }
337
+ return /* @__PURE__ */ jsxRuntime.jsx(
338
+ "span",
339
+ {
340
+ style: { display: "inline-flex", alignItems: "center" },
341
+ ...handlers,
342
+ children: img
343
+ }
344
+ );
345
+ }
346
+ var QuikturnLogoCarousel = React__default.default.memo(
347
+ function QuikturnLogoCarousel2({
348
+ domains,
349
+ logos: logos$1,
350
+ token,
351
+ baseUrl,
352
+ speed = 120,
353
+ direction = "left",
354
+ pauseOnHover,
355
+ hoverSpeed,
356
+ logoHeight = 28,
357
+ gap = 32,
358
+ width = "100%",
359
+ fadeOut = false,
360
+ fadeOutColor,
361
+ scaleOnHover = false,
362
+ logoSize,
363
+ logoFormat,
364
+ logoGreyscale,
365
+ logoTheme,
366
+ renderItem,
367
+ className,
368
+ style,
369
+ ariaLabel = "Company logos"
370
+ }) {
371
+ const ctx = useQuikturnContext();
372
+ const effectiveToken = token ?? ctx?.token ?? "";
373
+ const effectiveBaseUrl = baseUrl ?? ctx?.baseUrl;
374
+ const containerRef = React.useRef(null);
375
+ const trackRef = React.useRef(null);
376
+ const seqRef = React.useRef(null);
377
+ const [seqWidth, setSeqWidth] = React.useState(0);
378
+ const [seqHeight, setSeqHeight] = React.useState(0);
379
+ const [copyCount, setCopyCount] = React.useState(ANIMATION_CONFIG.MIN_COPIES);
380
+ const [isHovered, setIsHovered] = React.useState(false);
381
+ const isVertical = direction === "up" || direction === "down";
382
+ const resolvedLogos = React.useMemo(() => {
383
+ const items = logos$1 ?? (domains ?? []).map((d) => ({ domain: d }));
384
+ return items.map((item) => ({
385
+ domain: item.domain,
386
+ alt: item.alt ?? `${item.domain} logo`,
387
+ href: item.href,
388
+ url: logos.logoUrl(item.domain, {
389
+ token: effectiveToken || void 0,
390
+ size: item.size ?? logoSize,
391
+ format: item.format ?? logoFormat,
392
+ greyscale: item.greyscale ?? logoGreyscale,
393
+ theme: item.theme ?? logoTheme,
394
+ baseUrl: effectiveBaseUrl
395
+ })
396
+ }));
397
+ }, [
398
+ domains,
399
+ logos$1,
400
+ effectiveToken,
401
+ effectiveBaseUrl,
402
+ logoSize,
403
+ logoFormat,
404
+ logoGreyscale,
405
+ logoTheme
406
+ ]);
407
+ React.useEffect(() => {
408
+ if (effectiveToken) fireBeacon(effectiveToken);
409
+ }, [effectiveToken]);
410
+ const effectiveHoverSpeed = React.useMemo(() => {
411
+ if (hoverSpeed !== void 0) return hoverSpeed;
412
+ if (pauseOnHover === true) return 0;
413
+ return void 0;
414
+ }, [hoverSpeed, pauseOnHover]);
415
+ const targetVelocity = React.useMemo(() => {
416
+ const mag = Math.abs(speed);
417
+ const dirMul = isVertical ? direction === "up" ? 1 : -1 : direction === "left" ? 1 : -1;
418
+ const signMul = speed < 0 ? -1 : 1;
419
+ return mag * dirMul * signMul;
420
+ }, [speed, direction, isVertical]);
421
+ const updateDimensions = React.useCallback(() => {
422
+ const containerEl = containerRef.current;
423
+ const seqRect = seqRef.current?.getBoundingClientRect();
424
+ const sw = seqRect?.width ?? 0;
425
+ const sh = seqRect?.height ?? 0;
426
+ if (isVertical) {
427
+ const parentH = containerEl?.parentElement?.clientHeight ?? 0;
428
+ if (containerEl && parentH > 0) {
429
+ containerEl.style.height = `${Math.ceil(parentH)}px`;
430
+ }
431
+ if (sh > 0) {
432
+ setSeqHeight(Math.ceil(sh));
433
+ const viewport = containerEl?.clientHeight ?? parentH ?? sh;
434
+ const copies = Math.ceil(viewport / sh) + ANIMATION_CONFIG.COPY_HEADROOM;
435
+ setCopyCount(Math.max(ANIMATION_CONFIG.MIN_COPIES, copies));
436
+ }
437
+ } else if (sw > 0) {
438
+ setSeqWidth(Math.ceil(sw));
439
+ const containerW = containerEl?.clientWidth ?? 0;
440
+ const copies = Math.ceil(containerW / sw) + ANIMATION_CONFIG.COPY_HEADROOM;
441
+ setCopyCount(Math.max(ANIMATION_CONFIG.MIN_COPIES, copies));
442
+ }
443
+ }, [isVertical]);
444
+ useResizeObserver(updateDimensions, [containerRef, seqRef], [
445
+ resolvedLogos,
446
+ gap,
447
+ logoHeight,
448
+ isVertical
449
+ ]);
450
+ useImageLoader(seqRef, updateDimensions, [
451
+ resolvedLogos,
452
+ gap,
453
+ logoHeight,
454
+ isVertical
455
+ ]);
456
+ useAnimationLoop(
457
+ trackRef,
458
+ targetVelocity,
459
+ seqWidth,
460
+ seqHeight,
461
+ isHovered,
462
+ effectiveHoverSpeed,
463
+ isVertical
464
+ );
465
+ const handleMouseEnter = React.useCallback(() => {
466
+ if (effectiveHoverSpeed !== void 0) setIsHovered(true);
467
+ }, [effectiveHoverSpeed]);
468
+ const handleMouseLeave = React.useCallback(() => {
469
+ if (effectiveHoverSpeed !== void 0) setIsHovered(false);
470
+ }, [effectiveHoverSpeed]);
471
+ const logoLists = React.useMemo(
472
+ () => Array.from({ length: copyCount }, (_, ci) => /* @__PURE__ */ jsxRuntime.jsx(
473
+ "ul",
474
+ {
475
+ ref: ci === 0 ? seqRef : void 0,
476
+ role: "list",
477
+ "aria-hidden": ci > 0 ? true : void 0,
478
+ style: {
479
+ display: "flex",
480
+ flexDirection: isVertical ? "column" : "row",
481
+ alignItems: "center",
482
+ listStyle: "none",
483
+ margin: 0,
484
+ padding: 0
485
+ },
486
+ children: resolvedLogos.map((logo, i) => /* @__PURE__ */ jsxRuntime.jsx(
487
+ "li",
488
+ {
489
+ role: "listitem",
490
+ style: {
491
+ flex: "none",
492
+ ...isVertical ? { marginBottom: `${gap}px` } : { marginRight: `${gap}px` }
493
+ },
494
+ children: renderItem ? renderItem(logo, i) : /* @__PURE__ */ jsxRuntime.jsx(
495
+ DefaultLogoItem,
496
+ {
497
+ logo,
498
+ logoHeight,
499
+ scaleOnHover
500
+ }
501
+ )
502
+ },
503
+ `${ci}-${i}`
504
+ ))
505
+ },
506
+ ci
507
+ )),
508
+ [
509
+ copyCount,
510
+ resolvedLogos,
511
+ isVertical,
512
+ gap,
513
+ logoHeight,
514
+ scaleOnHover,
515
+ renderItem
516
+ ]
517
+ );
518
+ const cssWidth = toCssLength(width);
519
+ return /* @__PURE__ */ jsxRuntime.jsxs(
520
+ "div",
521
+ {
522
+ ref: containerRef,
523
+ role: "region",
524
+ "aria-label": ariaLabel,
525
+ className,
526
+ style: {
527
+ position: "relative",
528
+ overflow: "hidden",
529
+ width: isVertical ? void 0 : cssWidth ?? "100%",
530
+ height: isVertical ? "100%" : void 0,
531
+ display: isVertical ? "inline-block" : void 0,
532
+ ...style
533
+ },
534
+ children: [
535
+ fadeOut && /* @__PURE__ */ jsxRuntime.jsx(FadeOverlays, { isVertical, fadeColor: fadeOutColor }),
536
+ /* @__PURE__ */ jsxRuntime.jsx(
537
+ "div",
538
+ {
539
+ ref: trackRef,
540
+ style: {
541
+ display: "flex",
542
+ flexDirection: isVertical ? "column" : "row",
543
+ width: isVertical ? "100%" : "max-content",
544
+ willChange: "transform",
545
+ userSelect: "none",
546
+ position: "relative",
547
+ zIndex: 0
548
+ },
549
+ onMouseEnter: handleMouseEnter,
550
+ onMouseLeave: handleMouseLeave,
551
+ children: logoLists
552
+ }
553
+ )
554
+ ]
555
+ }
556
+ );
557
+ }
558
+ );
559
+ function QuikturnLogoGrid({
560
+ domains,
561
+ logos: logos$1,
562
+ token,
563
+ baseUrl,
564
+ columns = 4,
565
+ gap = 24,
566
+ logoSize,
567
+ logoFormat,
568
+ logoGreyscale,
569
+ logoTheme,
570
+ renderItem,
571
+ className,
572
+ style,
573
+ ariaLabel = "Company logos"
574
+ }) {
575
+ const ctx = useQuikturnContext();
576
+ const effectiveToken = token ?? ctx?.token ?? "";
577
+ const effectiveBaseUrl = baseUrl ?? ctx?.baseUrl;
578
+ const resolvedLogos = React.useMemo(() => {
579
+ const items = logos$1 ?? (domains ?? []).map((d) => ({ domain: d }));
580
+ return items.map((item) => ({
581
+ domain: item.domain,
582
+ alt: item.alt ?? `${item.domain} logo`,
583
+ href: item.href,
584
+ url: logos.logoUrl(item.domain, {
585
+ token: effectiveToken || void 0,
586
+ size: item.size ?? logoSize,
587
+ format: item.format ?? logoFormat,
588
+ greyscale: item.greyscale ?? logoGreyscale,
589
+ theme: item.theme ?? logoTheme,
590
+ baseUrl: effectiveBaseUrl
591
+ })
592
+ }));
593
+ }, [
594
+ domains,
595
+ logos$1,
596
+ effectiveToken,
597
+ effectiveBaseUrl,
598
+ logoSize,
599
+ logoFormat,
600
+ logoGreyscale,
601
+ logoTheme
602
+ ]);
603
+ React.useEffect(() => {
604
+ if (effectiveToken) fireBeacon(effectiveToken);
605
+ }, [effectiveToken]);
606
+ return /* @__PURE__ */ jsxRuntime.jsx(
607
+ "div",
608
+ {
609
+ role: "region",
610
+ "aria-label": ariaLabel,
611
+ className,
612
+ style: {
613
+ display: "grid",
614
+ gridTemplateColumns: `repeat(${columns}, 1fr)`,
615
+ gap: `${gap}px`,
616
+ alignItems: "center",
617
+ justifyItems: "center",
618
+ ...style
619
+ },
620
+ children: resolvedLogos.map(
621
+ (logo, i) => renderItem ? /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: renderItem(logo, i) }, logo.domain) : /* @__PURE__ */ jsxRuntime.jsx(
622
+ "div",
623
+ {
624
+ style: {
625
+ display: "flex",
626
+ alignItems: "center",
627
+ justifyContent: "center"
628
+ },
629
+ children: logo.href ? /* @__PURE__ */ jsxRuntime.jsx(
630
+ "a",
631
+ {
632
+ href: logo.href,
633
+ target: "_blank",
634
+ rel: "noopener noreferrer",
635
+ "aria-label": logo.alt,
636
+ children: /* @__PURE__ */ jsxRuntime.jsx(
637
+ "img",
638
+ {
639
+ src: logo.url,
640
+ alt: logo.alt,
641
+ loading: "lazy",
642
+ style: {
643
+ maxWidth: "100%",
644
+ height: "auto",
645
+ display: "block"
646
+ }
647
+ }
648
+ )
649
+ }
650
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
651
+ "img",
652
+ {
653
+ src: logo.url,
654
+ alt: logo.alt,
655
+ loading: "lazy",
656
+ style: {
657
+ maxWidth: "100%",
658
+ height: "auto",
659
+ display: "block"
660
+ }
661
+ }
662
+ )
663
+ },
664
+ logo.domain
665
+ )
666
+ )
667
+ }
668
+ );
669
+ }
670
+
671
+ exports.QuikturnLogo = QuikturnLogo;
672
+ exports.QuikturnLogoCarousel = QuikturnLogoCarousel;
673
+ exports.QuikturnLogoGrid = QuikturnLogoGrid;
674
+ exports.QuikturnProvider = QuikturnProvider;
675
+ exports.useLogoUrl = useLogoUrl;