@clubmed/trident-ui 2.0.0-beta.74 → 2.0.0-beta.76

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.
Files changed (59) hide show
  1. package/examples/chapters-demo.d.ts +1 -0
  2. package/examples/chapters-demo.js +46 -0
  3. package/examples/chapters-demo.js.map +1 -0
  4. package/examples/criteria-transports-b2b-demo.d.ts +1 -1
  5. package/examples/criteria-transports-b2b-demo.js +100 -33
  6. package/examples/criteria-transports-b2b-demo.js.map +1 -1
  7. package/examples/criteria-transports-demo.js +209 -20
  8. package/examples/criteria-transports-demo.js.map +1 -1
  9. package/examples/promises-demo.d.ts +1 -0
  10. package/examples/promises-demo.js +50 -0
  11. package/examples/promises-demo.js.map +1 -0
  12. package/examples/sparkle-wrapper-demo.d.ts +1 -0
  13. package/examples/sparkle-wrapper-demo.js +34 -0
  14. package/examples/sparkle-wrapper-demo.js.map +1 -0
  15. package/package.json +1 -1
  16. package/styles/animate.css +19 -0
  17. package/styles/theme.css +1 -0
  18. package/ui/Chapters/Chapter.d.ts +7 -0
  19. package/ui/Chapters/Chapter.js +36 -0
  20. package/ui/Chapters/Chapter.js.map +1 -0
  21. package/ui/Chapters/ChapterTitle.d.ts +14 -0
  22. package/ui/Chapters/ChapterTitle.js +35 -0
  23. package/ui/Chapters/ChapterTitle.js.map +1 -0
  24. package/ui/Chapters/Chapters.d.ts +15 -0
  25. package/ui/Chapters/Chapters.js +42 -0
  26. package/ui/Chapters/Chapters.js.map +1 -0
  27. package/ui/Chapters/Chapters.themes.d.ts +9 -0
  28. package/ui/Chapters/Chapters.themes.js +65 -0
  29. package/ui/Chapters/Chapters.themes.js.map +1 -0
  30. package/ui/Chapters/ChaptersSummary.d.ts +17 -0
  31. package/ui/Chapters/ChaptersSummary.js +29 -0
  32. package/ui/Chapters/ChaptersSummary.js.map +1 -0
  33. package/ui/ElasticHeight.js +1 -0
  34. package/ui/ElasticHeight.js.map +1 -1
  35. package/ui/Promises/Promises.d.ts +26 -0
  36. package/ui/Promises/Promises.js +42 -0
  37. package/ui/Promises/Promises.js.map +1 -0
  38. package/ui/Promises/PromisesMedia.d.ts +12 -0
  39. package/ui/Promises/PromisesMedia.js +64 -0
  40. package/ui/Promises/PromisesMedia.js.map +1 -0
  41. package/ui/Promises/PromisesMenu.d.ts +11 -0
  42. package/ui/Promises/PromisesMenu.js +154 -0
  43. package/ui/Promises/PromisesMenu.js.map +1 -0
  44. package/ui/SparkleWrapper.d.ts +5 -0
  45. package/ui/SparkleWrapper.js +56 -0
  46. package/ui/SparkleWrapper.js.map +1 -0
  47. package/ui/criteria/CriteriaTransports.d.ts +36 -55
  48. package/ui/criteria/CriteriaTransports.js +256 -206
  49. package/ui/criteria/CriteriaTransports.js.map +1 -1
  50. package/ui/forms/NumberField.d.ts +23 -23
  51. package/examples/criteria-transports-b2c-demo.d.ts +0 -1
  52. package/examples/criteria-transports-b2c-demo.js +0 -37
  53. package/examples/criteria-transports-b2c-demo.js.map +0 -1
  54. package/examples/criteria-transports-data.d.ts +0 -7
  55. package/examples/criteria-transports-data.js +0 -151
  56. package/examples/criteria-transports-data.js.map +0 -1
  57. package/examples/criteria-transports-error-demo.d.ts +0 -1
  58. package/examples/criteria-transports-error-demo.js +0 -29
  59. package/examples/criteria-transports-error-demo.js.map +0 -1
@@ -0,0 +1,154 @@
1
+ "use client";
2
+ import { t as e } from "../../chunks/clsx.js";
3
+ import { Button as t } from "../buttons/Button.js";
4
+ import { n } from "../../chunks/Carousel.context.js";
5
+ import { Carousel as r } from "../carousel/Carousel.js";
6
+ import { CarouselBody as i } from "../carousel/CarouselBody.js";
7
+ import { CarouselItem as a } from "../carousel/CarouselItem.js";
8
+ import { useEffect as o, useId as s, useLayoutEffect as c, useMemo as l, useRef as u } from "react";
9
+ import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
10
+ //#region lib/ui/Promises/PromisesMenu.tsx
11
+ var m = ({ anchorLabel: n, anchorName: r, isActive: i, labelNode: a }) => {
12
+ let o = u(null), s = u(null);
13
+ return c(() => {
14
+ if (!o.current || !s.current) return;
15
+ let e = new ResizeObserver(() => {
16
+ s.current && o.current && (s.current.style.height = `${o.current.offsetHeight}px`);
17
+ });
18
+ return e.observe(o.current), () => e.disconnect();
19
+ }, []), /* @__PURE__ */ f("li", {
20
+ className: e("relative isolate transition-[opacity,height,margin-inline-start] ms-0 duration-300 overflow-hidden rounded-32 bg-white p-20", { "@3xl/promises:ms-52": !i }),
21
+ children: /* @__PURE__ */ p("div", {
22
+ ref: s,
23
+ className: "flex justify-between items-start overflow-hidden",
24
+ style: { anchorName: r },
25
+ children: [/* @__PURE__ */ f("div", {
26
+ ref: o,
27
+ className: "pe-40",
28
+ children: a
29
+ }), i && /* @__PURE__ */ f(t, {
30
+ "aria-hidden": !0,
31
+ className: "opacity-0 pointer-events-none",
32
+ icon: "ArrowDefaultRight",
33
+ inert: !0,
34
+ tabIndex: -1,
35
+ variant: "pill",
36
+ children: n
37
+ })]
38
+ })
39
+ });
40
+ }, h = ({ activeIndex: e, onSelect: t }) => {
41
+ let { api: r, snapped: i } = n(), a = u(t);
42
+ a.current = t;
43
+ let s = i[0];
44
+ return o(() => {
45
+ s !== void 0 && a.current(s);
46
+ }, [s]), o(() => {
47
+ r?.scrollTo(e);
48
+ }, [r, e]), null;
49
+ }, g = ({ activeIndex: t, className: n, onSelect: o, sliderItems: s }) => {
50
+ let c = u(t), m = l(() => ({
51
+ active: s.length > 1,
52
+ align: "center",
53
+ startIndex: c.current
54
+ }), [s.length]);
55
+ return /* @__PURE__ */ f(d, { children: /* @__PURE__ */ p(r, {
56
+ className: e("relative isolate flex h-full items-center", n),
57
+ options: m,
58
+ children: [/* @__PURE__ */ f(h, {
59
+ activeIndex: t,
60
+ onSelect: o
61
+ }), /* @__PURE__ */ f(i, {
62
+ className: "w-full px-20",
63
+ scrollClassName: "gap-12 md:gap-40 auto-cols-full",
64
+ children: s.map((t, n) => /* @__PURE__ */ f(a, {
65
+ index: n,
66
+ children: /* @__PURE__ */ f("div", {
67
+ "aria-label": `${n + 1}/${s.length}`,
68
+ className: e("rounded-16 overflow-hidden bg-white"),
69
+ children: t
70
+ })
71
+ }, n))
72
+ })]
73
+ }) });
74
+ }, _ = ({ activeIndex: n, className: r, items: i, labels: a, onClickMenu: o }) => {
75
+ let c = s(), u = c.replace(/[^a-zA-Z0-9_-]/g, ""), { menuItems: h, sliderItems: _ } = l(() => {
76
+ let r = i.map(({ href: t, id: r, title: i }, a) => {
77
+ let s = a === n, l = r ?? `${c}_${a}`;
78
+ return {
79
+ anchorName: `--promises-${u}-${a}`,
80
+ href: t,
81
+ id: r,
82
+ isActive: s,
83
+ itemId: l,
84
+ labelNode: /* @__PURE__ */ f("button", {
85
+ id: l,
86
+ "aria-label": i,
87
+ className: e("text-start hover:underline text-h4 text-center font-serif @3xl/promises:text-h4 @5xl/promises:text-h2 @6xl/promises:text-h1 @3xl/promises:text-start"),
88
+ onClick: () => o(a),
89
+ type: "button",
90
+ children: i
91
+ }),
92
+ title: i
93
+ };
94
+ });
95
+ return {
96
+ menuItems: r,
97
+ sliderItems: r.map(({ labelNode: e, href: n, itemId: r }) => /* @__PURE__ */ p("div", {
98
+ className: "rounded-32 p-16",
99
+ children: [e, /* @__PURE__ */ f(t, {
100
+ "aria-describedby": r,
101
+ "aria-label": a.anchor.continue,
102
+ href: n,
103
+ icon: "ArrowDefaultRight",
104
+ variant: "pill",
105
+ children: a.anchor.continue
106
+ })]
107
+ }))
108
+ };
109
+ }, [
110
+ n,
111
+ i,
112
+ a,
113
+ c,
114
+ o,
115
+ u
116
+ ]), v = h[n];
117
+ return /* @__PURE__ */ p(d, { children: [
118
+ /* @__PURE__ */ f("ul", {
119
+ className: e("hidden @3xl/promises:block", "absolute bottom-0 inset-x-0 overflow-hidden @3xl/promises:-ms-52 text-black w-full", "@3xl/promises:pointer-events-auto @3xl/promises:static @3xl/promises:p-0 @3xl/promises:pt-40", r),
120
+ children: h.map(({ anchorName: e, id: t, isActive: n, labelNode: r, title: i }, o) => /* @__PURE__ */ f(m, {
121
+ anchorLabel: a.anchor.continue,
122
+ anchorName: e,
123
+ isActive: n,
124
+ labelNode: r
125
+ }, t ?? `${i}-${o}`))
126
+ }),
127
+ v && /* @__PURE__ */ f(t, {
128
+ "aria-describedby": v.itemId,
129
+ "aria-label": a.anchor.continue,
130
+ className: "hidden @3xl/promises:inline-flex transition-[top] duration-200 ease-out-quad absolute z-1",
131
+ href: v.href,
132
+ icon: "ArrowDefaultRight",
133
+ style: {
134
+ positionAnchor: v.anchorName,
135
+ top: "anchor(top)",
136
+ right: "anchor(right)"
137
+ },
138
+ variant: "pill",
139
+ children: a.anchor.continue
140
+ }),
141
+ /* @__PURE__ */ f("div", {
142
+ className: "@3xl/promises:hidden absolute inset-x-0 bottom-20",
143
+ children: /* @__PURE__ */ f(g, {
144
+ activeIndex: n,
145
+ onSelect: o,
146
+ sliderItems: _
147
+ })
148
+ })
149
+ ] });
150
+ };
151
+ //#endregion
152
+ export { _ as PromisesMenu };
153
+
154
+ //# sourceMappingURL=PromisesMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromisesMenu.js","names":[],"sources":["../../../lib/ui/Promises/PromisesMenu.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport type { FunctionComponent, ReactNode } from 'react';\nimport { useEffect, useId, useMemo, useRef, useLayoutEffect } from 'react';\nimport { useCarousel } from '../carousel/Carousel.context';\n\nimport { Carousel } from '../carousel/Carousel';\nimport { CarouselBody } from '../carousel/CarouselBody';\nimport { CarouselItem } from '../carousel/CarouselItem';\nimport { Button } from '../buttons/Button';\nimport type { PromisesItem, PromisesLabels } from './Promises';\n\ninterface MenuItemProps {\n anchorLabel: string;\n anchorName: string;\n isActive: boolean;\n labelNode: ReactNode;\n}\n\nconst PromisesMenuItem: FunctionComponent<MenuItemProps> = ({\n anchorLabel,\n anchorName,\n isActive,\n labelNode,\n}) => {\n const labelRef = useRef<HTMLDivElement>(null);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!labelRef.current || !containerRef.current) return;\n const resizeObserver = new ResizeObserver(() => {\n if (containerRef.current && labelRef.current) {\n containerRef.current.style.height = `${labelRef.current.offsetHeight}px`;\n }\n });\n resizeObserver.observe(labelRef.current);\n return () => resizeObserver.disconnect();\n }, []);\n\n return (\n <li\n className={clsx(\n 'relative isolate transition-[opacity,height,margin-inline-start] ms-0 duration-300 overflow-hidden rounded-32 bg-white p-20',\n { '@3xl/promises:ms-52': !isActive },\n )}\n >\n <div\n ref={containerRef}\n className=\"flex justify-between items-start overflow-hidden\"\n style={{ anchorName } as unknown as React.CSSProperties}\n >\n <div ref={labelRef} className=\"pe-40\">\n {labelNode}\n </div>\n {isActive && (\n <Button\n aria-hidden\n className=\"opacity-0 pointer-events-none\"\n icon=\"ArrowDefaultRight\"\n inert\n tabIndex={-1}\n variant=\"pill\"\n >\n {anchorLabel}\n </Button>\n )}\n </div>\n </li>\n );\n};\n\ninterface Props {\n activeIndex: number;\n className?: string;\n items: PromisesItem[];\n labels: PromisesLabels;\n onClickMenu: (index: number) => void;\n}\n\ninterface PromisesItemSliderProps {\n activeIndex: number;\n className?: string;\n onSelect: (index: number) => void;\n sliderItems: ReactNode[];\n}\n\nconst CarouselSync: FunctionComponent<{\n activeIndex: number;\n onSelect: (index: number) => void;\n}> = ({ activeIndex, onSelect }) => {\n const { api, snapped } = useCarousel();\n const onSelectRef = useRef(onSelect);\n onSelectRef.current = onSelect;\n\n const snappedIndex = snapped[0];\n useEffect(() => {\n if (snappedIndex !== undefined) onSelectRef.current(snappedIndex);\n }, [snappedIndex]);\n\n useEffect(() => {\n api?.scrollTo(activeIndex);\n }, [api, activeIndex]);\n\n return null;\n};\n\nconst PromisesItemSlider: FunctionComponent<PromisesItemSliderProps> = ({\n activeIndex,\n className,\n onSelect,\n sliderItems,\n}) => {\n const initialIndex = useRef(activeIndex);\n const carouselOptions = useMemo(\n () => ({\n active: sliderItems.length > 1,\n align: 'center' as const,\n startIndex: initialIndex.current,\n }),\n [sliderItems.length],\n );\n\n return (\n <>\n <Carousel\n className={clsx('relative isolate flex h-full items-center', className)}\n options={carouselOptions}\n >\n <CarouselSync activeIndex={activeIndex} onSelect={onSelect} />\n <CarouselBody className=\"w-full px-20\" scrollClassName=\"gap-12 md:gap-40 auto-cols-full\">\n {sliderItems.map((item, i) => (\n <CarouselItem index={i} key={i}>\n <div\n aria-label={`${i + 1}/${sliderItems.length}`}\n className={clsx('rounded-16 overflow-hidden bg-white')}\n >\n {item}\n </div>\n </CarouselItem>\n ))}\n </CarouselBody>\n </Carousel>\n </>\n );\n};\n\nexport const PromisesMenu: FunctionComponent<Props> = ({\n activeIndex,\n className,\n items,\n labels,\n onClickMenu,\n}) => {\n const menuId = useId();\n const safeMenuId = menuId.replace(/[^a-zA-Z0-9_-]/g, '');\n\n const { menuItems, sliderItems } = useMemo(() => {\n const mItems = items.map(({ href, id, title }, index) => {\n const isActive = index === activeIndex;\n const itemId = id ?? `${menuId}_${index}`;\n const anchorName = `--promises-${safeMenuId}-${index}`;\n\n const labelNode = (\n <button\n id={itemId}\n aria-label={title}\n className={clsx(\n 'text-start hover:underline text-h4 text-center font-serif @3xl/promises:text-h4 @5xl/promises:text-h2 @6xl/promises:text-h1 @3xl/promises:text-start',\n )}\n onClick={() => onClickMenu(index)}\n type=\"button\"\n >\n {title}\n </button>\n );\n\n return { anchorName, href, id, isActive, itemId, labelNode, title };\n });\n\n const sItems = mItems.map(({ labelNode, href, itemId }) => (\n <div className=\"rounded-32 p-16\">\n {labelNode}\n <Button\n aria-describedby={itemId}\n aria-label={labels.anchor.continue}\n href={href}\n icon=\"ArrowDefaultRight\"\n variant=\"pill\"\n >\n {labels.anchor.continue}\n </Button>\n </div>\n ));\n\n return { menuItems: mItems, sliderItems: sItems };\n }, [activeIndex, items, labels, menuId, onClickMenu, safeMenuId]);\n\n const activeItem = menuItems[activeIndex];\n\n return (\n <>\n <ul\n className={clsx(\n 'hidden @3xl/promises:block',\n 'absolute bottom-0 inset-x-0 overflow-hidden @3xl/promises:-ms-52 text-black w-full',\n '@3xl/promises:pointer-events-auto @3xl/promises:static @3xl/promises:p-0 @3xl/promises:pt-40',\n className,\n )}\n >\n {menuItems.map(({ anchorName, id, isActive, labelNode, title }, index) => (\n <PromisesMenuItem\n anchorLabel={labels.anchor.continue}\n anchorName={anchorName}\n isActive={isActive}\n key={id ?? `${title}-${index}`}\n labelNode={labelNode}\n />\n ))}\n </ul>\n {activeItem && (\n <Button\n aria-describedby={activeItem.itemId}\n aria-label={labels.anchor.continue}\n className=\"hidden @3xl/promises:inline-flex transition-[top] duration-200 ease-out-quad absolute z-1\"\n href={activeItem.href}\n icon=\"ArrowDefaultRight\"\n style={\n {\n positionAnchor: activeItem.anchorName,\n top: 'anchor(top)',\n right: 'anchor(right)',\n } as React.CSSProperties\n }\n variant=\"pill\"\n >\n {labels.anchor.continue}\n </Button>\n )}\n <div className=\"@3xl/promises:hidden absolute inset-x-0 bottom-20\">\n <PromisesItemSlider\n activeIndex={activeIndex}\n onSelect={onClickMenu}\n sliderItems={sliderItems}\n />\n </div>\n </>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { HTMLAttributes, PropsWithChildren } from 'react';
2
+ export interface SparkleWrapperProps extends HTMLAttributes<HTMLDivElement> {
3
+ count?: number;
4
+ }
5
+ export declare function SparkleWrapper({ children, className, count, ...props }: PropsWithChildren<SparkleWrapperProps>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { t as e } from "../chunks/clsx.js";
3
+ import { useLayoutEffect as t, useRef as n, useState as r } from "react";
4
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
5
+ import { Icon as o } from "@clubmed/trident-icons";
6
+ //#region lib/ui/SparkleWrapper.tsx
7
+ function s(e, t) {
8
+ return e + Math.random() * (t - e);
9
+ }
10
+ function c(e) {
11
+ return Array.from({ length: e }, () => ({
12
+ angle: Math.random() * 360,
13
+ distance: s(60, 110),
14
+ delay: Math.round(s(0, 150)),
15
+ size: Math.round(s(8, 20))
16
+ }));
17
+ }
18
+ function l(e, t, n, r) {
19
+ return Math.abs(e) < 1e-6 ? r / Math.abs(t) : Math.abs(t) < 1e-6 ? n / Math.abs(e) : Math.min(n / Math.abs(e), r / Math.abs(t));
20
+ }
21
+ function u({ children: u, className: d, count: f = 7, ...p }) {
22
+ let m = n(null), [h, g] = r([0, 0]), [_] = r(() => c(Math.round(s(f, f + 3))));
23
+ return t(() => {
24
+ if (!m.current) return;
25
+ let { width: e, height: t } = m.current.getBoundingClientRect();
26
+ g([e / 2, t / 2]);
27
+ }, []), /* @__PURE__ */ a("div", {
28
+ ...p,
29
+ className: e("relative inline-flex items-center justify-center", d),
30
+ children: [_.map(({ angle: e, distance: t, delay: n, size: r }, a) => {
31
+ let s = e * Math.PI / 180, c = Math.cos(s), u = Math.sin(s), [d, f] = h, p = d > 0 || f > 0 ? l(c, u, d, f) : 0;
32
+ return /* @__PURE__ */ i(o, {
33
+ name: "Diamond",
34
+ "aria-hidden": "true",
35
+ className: "absolute top-1/2 left-1/2 animate-sparkle-fly pointer-events-none",
36
+ style: {
37
+ "--sparkle-start-x": `${Math.round(c * p)}px`,
38
+ "--sparkle-start-y": `${Math.round(u * p)}px`,
39
+ "--sparkle-end-x": `${Math.round(c * (p + t))}px`,
40
+ "--sparkle-end-y": `${Math.round(u * (p + t))}px`,
41
+ animationDelay: `${n}ms`,
42
+ width: `${r}px`,
43
+ height: `${r}px`
44
+ }
45
+ }, a);
46
+ }), /* @__PURE__ */ i("div", {
47
+ ref: m,
48
+ className: "relative z-10 animate-bounce-enter",
49
+ children: u
50
+ })]
51
+ });
52
+ }
53
+ //#endregion
54
+ export { u as SparkleWrapper };
55
+
56
+ //# sourceMappingURL=SparkleWrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SparkleWrapper.js","names":[],"sources":["../../lib/ui/SparkleWrapper.tsx"],"sourcesContent":["'use client';\n\nimport { Icon } from '@clubmed/trident-icons';\nimport type { HTMLAttributes, PropsWithChildren } from 'react';\nimport { useLayoutEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\n\nfunction randomBetween(min: number, max: number) {\n return min + Math.random() * (max - min);\n}\n\nfunction generateSparkles(count: number) {\n return Array.from({ length: count }, () => ({\n angle: Math.random() * 360,\n distance: randomBetween(60, 110),\n delay: Math.round(randomBetween(0, 150)),\n size: Math.round(randomBetween(8, 20)),\n }));\n}\n\nfunction edgeT(cos: number, sin: number, hw: number, hh: number): number {\n if (Math.abs(cos) < 1e-6) return hh / Math.abs(sin);\n if (Math.abs(sin) < 1e-6) return hw / Math.abs(cos);\n return Math.min(hw / Math.abs(cos), hh / Math.abs(sin));\n}\n\nexport interface SparkleWrapperProps extends HTMLAttributes<HTMLDivElement> {\n count?: number;\n}\n\nexport function SparkleWrapper({\n children,\n className,\n count = 7,\n ...props\n}: PropsWithChildren<SparkleWrapperProps>) {\n const childRef = useRef<HTMLDivElement>(null);\n const [halfSize, setHalfSize] = useState<[number, number]>([0, 0]);\n const [sparkles] = useState(() => generateSparkles(Math.round(randomBetween(count, count + 3))));\n\n useLayoutEffect(() => {\n if (!childRef.current) return;\n const { width, height } = childRef.current.getBoundingClientRect();\n setHalfSize([width / 2, height / 2]);\n }, []);\n\n return (\n <div {...props} className={clsx('relative inline-flex items-center justify-center', className)}>\n {sparkles.map(({ angle, distance, delay, size }, i) => {\n const rad = (angle * Math.PI) / 180;\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const [hw, hh] = halfSize;\n const t = hw > 0 || hh > 0 ? edgeT(cos, sin, hw, hh) : 0;\n\n return (\n <Icon\n key={i}\n name=\"Diamond\"\n aria-hidden=\"true\"\n className=\"absolute top-1/2 left-1/2 animate-sparkle-fly pointer-events-none\"\n style={\n {\n '--sparkle-start-x': `${Math.round(cos * t)}px`,\n '--sparkle-start-y': `${Math.round(sin * t)}px`,\n '--sparkle-end-x': `${Math.round(cos * (t + distance))}px`,\n '--sparkle-end-y': `${Math.round(sin * (t + distance))}px`,\n animationDelay: `${delay}ms`,\n width: `${size}px`,\n height: `${size}px`,\n } as React.CSSProperties\n }\n />\n );\n })}\n <div ref={childRef} className=\"relative z-10 animate-bounce-enter\">\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAOA,SAAS,EAAc,GAAa,GAAa;AAC/C,QAAO,IAAM,KAAK,QAAQ,IAAI,IAAM;;AAGtC,SAAS,EAAiB,GAAe;AACvC,QAAO,MAAM,KAAK,EAAE,QAAQ,GAAO,SAAS;EAC1C,OAAO,KAAK,QAAQ,GAAG;EACvB,UAAU,EAAc,IAAI,IAAI;EAChC,OAAO,KAAK,MAAM,EAAc,GAAG,IAAI,CAAC;EACxC,MAAM,KAAK,MAAM,EAAc,GAAG,GAAG,CAAA;EACtC,EAAE;;AAGL,SAAS,EAAM,GAAa,GAAa,GAAY,GAAoB;AAGvE,QAFI,KAAK,IAAI,EAAI,GAAG,OAAa,IAAK,KAAK,IAAI,EAAI,GAC/C,KAAK,IAAI,EAAI,GAAG,OAAa,IAAK,KAAK,IAAI,EAAI,GAC5C,KAAK,IAAI,IAAK,KAAK,IAAI,EAAI,EAAE,IAAK,KAAK,IAAI,EAAI,CAAC;;AAOzD,SAAgB,EAAe,EAC7B,aACA,cACA,WAAQ,GACR,GAAG,KACsC;CACzC,IAAM,IAAW,EAAuB,KAAK,EACvC,CAAC,GAAU,KAAe,EAA2B,CAAC,GAAG,EAAE,CAAC,EAC5D,CAAC,KAAY,QAAe,EAAiB,KAAK,MAAM,EAAc,GAAO,IAAQ,EAAE,CAAC,CAAC,CAAC;AAQhG,QANA,QAAsB;AACpB,MAAI,CAAC,EAAS,QAAS;EACvB,IAAM,EAAE,UAAO,cAAW,EAAS,QAAQ,uBAAuB;AAClE,IAAY,CAAC,IAAQ,GAAG,IAAS,EAAE,CAAC;IACnC,EAAE,CAAC,EAGJ,kBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,EAAK,oDAAoD,EAAU;YAA9F,CACG,EAAS,KAAK,EAAE,UAAO,aAAU,UAAO,WAAQ,MAAM;GACrD,IAAM,IAAO,IAAQ,KAAK,KAAM,KAC1B,IAAM,KAAK,IAAI,EAAI,EACnB,IAAM,KAAK,IAAI,EAAI,EACnB,CAAC,GAAI,KAAM,GACX,IAAI,IAAK,KAAK,IAAK,IAAI,EAAM,GAAK,GAAK,GAAI,EAAG,GAAG;AAEvD,UACE,kBAAC,GAAD;IAEE,MAAK;IACL,eAAY;IACZ,WAAU;IACV,OACE;KACE,qBAAqB,GAAG,KAAK,MAAM,IAAM,EAAE,CAAC;KAC5C,qBAAqB,GAAG,KAAK,MAAM,IAAM,EAAE,CAAC;KAC5C,mBAAmB,GAAG,KAAK,MAAM,KAAO,IAAI,GAAU,CAAC;KACvD,mBAAmB,GAAG,KAAK,MAAM,KAAO,IAAI,GAAU,CAAC;KACvD,gBAAgB,GAAG,EAAM;KACzB,OAAO,GAAG,EAAK;KACf,QAAQ,GAAG,EAAK;;IAGpB,EAfK,EAeL;IAEJ,EACF,kBAAC,OAAD;GAAK,KAAK;GAAU,WAAU;GAC3B;GACG,CAAA,CAAA"}
@@ -1,72 +1,53 @@
1
- import { Dispatch, FunctionComponent } from 'react';
2
- export interface TransportOption {
3
- id: string;
4
- label: string;
5
- }
6
- export interface TransportSection {
7
- title: string;
8
- options: TransportOption[];
9
- }
10
- export interface TransportPromotionalCard {
11
- icon?: string;
12
- title: string;
13
- description: string;
1
+ import { FunctionComponent } from 'react';
2
+ import { RadioSelectOption } from '../forms/RadioSelect';
3
+ export interface Airport {
4
+ code: string;
5
+ name: string;
14
6
  }
15
7
  export interface CriteriaTransportsLabels {
16
- addTransportationFrom: string;
8
+ toggleLabel: string;
9
+ topCitiesLabel: string;
10
+ otherCitiesLabel: string;
11
+ clubMedTransportTitle: string;
12
+ clubMedTransportDescription: string;
17
13
  reset?: string;
18
14
  apply?: string;
19
15
  }
20
- export type CriteriaTransportsAction = {
21
- type: 'enabled';
22
- payload: boolean;
23
- } | {
24
- type: 'select';
25
- payload: string | null;
26
- } | {
27
- type: 'flightType';
28
- payload: 'round-trip' | 'one-way';
29
- } | {
30
- type: 'flightClass';
31
- payload: string;
32
- } | {
33
- type: 'fromQuery';
34
- payload: string;
35
- };
16
+ export interface CriteriaTransportsB2BLabels {
17
+ roundTripLabel: string;
18
+ oneWayLabel: string;
19
+ cabinClassLabel: string;
20
+ departureDateLabel: string;
21
+ }
36
22
  export interface CriteriaTransportsProps {
37
23
  labels: CriteriaTransportsLabels;
38
24
  title?: string;
39
- /** card (default): white outer card with sand inner. flat: no background, content rendered directly */
25
+ /** card (default): white outer card with sand inner. flat: no background, fields rendered directly */
40
26
  variant?: 'card' | 'flat';
41
- /** b2c (default): large items + promotional card. b2b: compact items + flight controls */
27
+ /** Switches between B2C (default) and B2B mode. B2B mode adds flight type, cabin class, and departure selectors. */
42
28
  mode?: 'b2c' | 'b2b';
43
29
  enabled: boolean;
44
- sections: TransportSection[];
45
- selectedId: string | null;
30
+ topCities: Airport[];
31
+ otherCities: Airport[];
32
+ selectedAirportCode?: string | null;
46
33
  className?: string;
47
- onChange: Dispatch<CriteriaTransportsAction>;
34
+ onToggle: (enabled: boolean) => void;
35
+ onSelect: (code: string | null) => void;
48
36
  onReset?: () => void;
49
37
  onApply?: () => void;
50
- /** B2C: promotional card shown in the sand area when enabled=false */
51
- promotionalCard?: TransportPromotionalCard;
52
- /** Error message — shown instead of sections when enabled=true */
38
+ b2bLabels?: CriteriaTransportsB2BLabels;
39
+ /** Currently selected flight type (B2B mode). Defaults to 'roundtrip'. */
40
+ flightType?: 'roundtrip' | 'oneway';
41
+ onFlightTypeChange?: (type: 'roundtrip' | 'oneway') => void;
42
+ /** Currently selected cabin class value (B2B mode). */
43
+ cabinClass?: string;
44
+ /** Options for the cabin class RadioSelect (B2B mode). */
45
+ cabinClassOptions?: RadioSelectOption<string>[];
46
+ onCabinClassChange?: (event: Event, value: string) => void;
47
+ /** Controlled value for the departure airport TextField; also used to filter the airport list. */
48
+ departureQuery?: string;
49
+ onDepartureQueryChange?: (event: Event, value: string) => void;
50
+ /** Error message shown in B2B mode when a prerequisite (e.g. resort selection) is missing. */
53
51
  error?: string;
54
- /** B2B: controlled flight type */
55
- flightType?: 'round-trip' | 'one-way';
56
- /** B2B: labels for the round-trip/one-way radio row */
57
- flightTypeLabels?: {
58
- roundTrip: string;
59
- oneWay: string;
60
- };
61
- /** B2B: controlled selected class label */
62
- flightClass?: string;
63
- /** B2B: label for the class selector field */
64
- flightClassLabel?: string;
65
- /** B2B: available class options */
66
- flightClasses?: string[];
67
- /** B2B: controlled from/search query */
68
- fromQuery?: string;
69
- /** B2B: label for the from search field */
70
- fromQueryLabel?: string;
71
52
  }
72
53
  export declare const CriteriaTransports: FunctionComponent<CriteriaTransportsProps>;