@clubmed/trident-ui 2.0.0-beta.60 → 2.0.0-beta.62
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/examples/page-navigation-demo.d.ts +1 -0
- package/examples/page-navigation-demo.js +53 -0
- package/examples/page-navigation-demo.js.map +1 -0
- package/package.json +1 -1
- package/ui/ChatButton.js +1 -1
- package/ui/ChatButton.js.map +1 -1
- package/ui/PageNavigation.d.ts +13 -0
- package/ui/PageNavigation.js +71 -0
- package/ui/PageNavigation.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function PageNavigationDemo(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { PageNavigation as e } from "../ui/PageNavigation.js";
|
|
3
|
+
import { useState as t } from "react";
|
|
4
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
5
|
+
//#region lib/examples/page-navigation-demo.tsx
|
|
6
|
+
var r = [
|
|
7
|
+
{
|
|
8
|
+
id: "accommodation",
|
|
9
|
+
label: "Accommodation",
|
|
10
|
+
href: "#accommodation",
|
|
11
|
+
icon: "Home"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: "transport",
|
|
15
|
+
label: "Transport",
|
|
16
|
+
href: "#transport",
|
|
17
|
+
icon: "PlaneDefault"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "people",
|
|
21
|
+
label: "People",
|
|
22
|
+
href: "#people",
|
|
23
|
+
icon: "PeopleSingle"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "activities",
|
|
27
|
+
label: "Activities",
|
|
28
|
+
href: "#activities",
|
|
29
|
+
icon: "Multisports"
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
function i() {
|
|
33
|
+
let [i, a] = t("accommodation");
|
|
34
|
+
return /* @__PURE__ */ n("nav", {
|
|
35
|
+
"aria-label": "Demo wrapper",
|
|
36
|
+
onClick: (e) => {
|
|
37
|
+
let t = e.target.closest("a");
|
|
38
|
+
if (t) {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
let n = t.getAttribute("href")?.replace("#", "");
|
|
41
|
+
n && a(n);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
children: /* @__PURE__ */ n(e, {
|
|
45
|
+
items: r,
|
|
46
|
+
activeItem: i
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { i as default };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=page-navigation-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-navigation-demo.js","names":[],"sources":["../../lib/examples/page-navigation-demo.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { PageNavigation } from '@/ui/PageNavigation';\n\nconst items = [\n { id: 'accommodation', label: 'Accommodation', href: '#accommodation', icon: 'Home' as const },\n { id: 'transport', label: 'Transport', href: '#transport', icon: 'PlaneDefault' as const },\n { id: 'people', label: 'People', href: '#people', icon: 'PeopleSingle' as const },\n { id: 'activities', label: 'Activities', href: '#activities', icon: 'Multisports' as const },\n];\n\nexport default function PageNavigationDemo() {\n const [active, setActive] = useState('accommodation');\n\n return (\n <nav\n aria-label=\"Demo wrapper\"\n onClick={(e) => {\n const anchor = (e.target as HTMLElement).closest('a');\n if (anchor) {\n e.preventDefault();\n const id = anchor.getAttribute('href')?.replace('#', '');\n if (id) setActive(id);\n }\n }}\n >\n <PageNavigation items={items} activeItem={active} />\n </nav>\n );\n}\n"],"mappings":";;;;;AAKA,IAAM,IAAQ;CACZ;EAAE,IAAI;EAAiB,OAAO;EAAiB,MAAM;EAAkB,MAAM;EAAiB;CAC9F;EAAE,IAAI;EAAa,OAAO;EAAa,MAAM;EAAc,MAAM;EAAyB;CAC1F;EAAE,IAAI;EAAU,OAAO;EAAU,MAAM;EAAW,MAAM;EAAyB;CACjF;EAAE,IAAI;EAAc,OAAO;EAAc,MAAM;EAAe,MAAM;;CACrE;AAED,SAAwB,IAAqB;CAC3C,IAAM,CAAC,GAAQ,KAAa,EAAS,gBAAgB;AAErD,QACE,kBAAC,OAAD;EACE,cAAW;EACX,UAAU,MAAM;GACd,IAAM,IAAU,EAAE,OAAuB,QAAQ,IAAI;AACrD,OAAI,GAAQ;AACV,MAAE,gBAAgB;IAClB,IAAM,IAAK,EAAO,aAAa,OAAO,EAAE,QAAQ,KAAK,GAAG;AACxD,IAAI,KAAI,EAAU,EAAG;;;YAIzB,kBAAC,GAAD;GAAuB;GAAO,YAAY;GAAU,CAAA;EAChD,CAAA"}
|
package/package.json
CHANGED
package/ui/ChatButton.js
CHANGED
|
@@ -2,7 +2,7 @@ import { twMerge as e } from "./helpers/twMerge.js";
|
|
|
2
2
|
import { Icon as t } from "@clubmed/trident-icons";
|
|
3
3
|
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
4
|
//#region lib/ui/ChatButton.tsx
|
|
5
|
-
var i = "
|
|
5
|
+
var i = "AI Agent: Have you got a question?", a = "Chat with your assistant";
|
|
6
6
|
function o({ children: o = i, className: s, type: c = "button", "aria-label": l, tabIndex: u, offset: d, unfoldOn: f = "hover", ...p }) {
|
|
7
7
|
let m = l ?? (typeof o == "string" && o.trim().length > 0 ? o.trim() : a);
|
|
8
8
|
return /* @__PURE__ */ r("button", {
|
package/ui/ChatButton.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatButton.js","names":[],"sources":["../../lib/ui/ChatButton.tsx"],"sourcesContent":["import { Icon } from '@clubmed/trident-icons';\nimport type { ButtonHTMLAttributes } from 'react';\nimport { twMerge } from './helpers/twMerge';\n\nconst DEFAULT_TEASER_COPY = '
|
|
1
|
+
{"version":3,"file":"ChatButton.js","names":[],"sources":["../../lib/ui/ChatButton.tsx"],"sourcesContent":["import { Icon } from '@clubmed/trident-icons';\nimport type { ButtonHTMLAttributes } from 'react';\nimport { twMerge } from './helpers/twMerge';\n\nconst DEFAULT_TEASER_COPY = 'AI Agent: Have you got a question?';\nconst FALLBACK_ARIA_LABEL = 'Chat with your assistant';\n\nexport type ChatButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n offset?: boolean;\n unfoldOn?: 'hover' | 'active';\n};\n\nexport function ChatButton({\n children = DEFAULT_TEASER_COPY,\n className,\n type = 'button',\n 'aria-label': ariaLabel,\n tabIndex,\n offset,\n unfoldOn = 'hover',\n ...rest\n}: ChatButtonProps) {\n const label =\n ariaLabel ??\n (typeof children === 'string' && children.trim().length > 0\n ? children.trim()\n : FALLBACK_ARIA_LABEL);\n\n return (\n <button\n type={type}\n aria-label={label}\n tabIndex={tabIndex ?? 0}\n {...rest}\n className={twMerge(\n 'chat-border grid grid-cols-[24px_0fr] transition-[grid-template-columns] justify-center items-center overflow-hidden cursor-pointer transition-all rounded-pill px-8 md:px-16 outline-none group/Chatbutton focus-visible:ring-8 focus-visible:ring-lavender/20 pointer-events-auto h-48 min-h-48 md:min-w-80 md:h-80 active:scale-[0.98]',\n offset && 'md:translate-x-[40px] focus-visible:translate-x-0',\n unfoldOn === 'hover' &&\n 'group/hoverChatbutton hover:grid-cols-[24px_1fr] hover:translate-x-0',\n unfoldOn === 'active' &&\n 'group/activeChatbutton active:grid-cols-[24px_1fr] active:translate-x-0',\n 'focus-visible:grid-cols-[24px_1fr]',\n className,\n )}\n >\n <Icon\n name=\"Sparkles\"\n className={twMerge(\n 'chat-button-icon w-24 transition-all',\n offset &&\n 'relative md:start-[calc(-16px)] group-focus-visible/Chatbutton:start-0 group-hover/hoverChatbutton:start-0 group-active/activeChatbutton:start-0',\n )}\n />\n <div className=\"grid grid-cols-[0fr] overflow-hidden opacity-0 transition-opacity group-hover/hoverChatbutton:opacity-100 group-focus-visible/Chatbutton:opacity-100 group-active/activeChatbutton:opacity-100 duration-500\">\n <span\n aria-hidden=\"true\"\n className=\"chat-button-text items-center ps-20 flex gap-10 whitespace-nowrap font-semibold text-b3 text-black\"\n >\n {children}\n <Icon name=\"ArrowTailRight\" width=\"24px\" />\n </span>\n </div>\n </button>\n );\n}\n"],"mappings":";;;;AAIA,IAAM,IAAsB,sCACtB,IAAsB;AAO5B,SAAgB,EAAW,EACzB,cAAW,GACX,cACA,UAAO,UACP,cAAc,GACd,aACA,WACA,cAAW,SACX,GAAG,KACe;CAClB,IAAM,IACJ,MACC,OAAO,KAAa,YAAY,EAAS,MAAM,CAAC,SAAS,IACtD,EAAS,MAAM,GACf;AAEN,QACE,kBAAC,UAAD;EACQ;EACN,cAAY;EACZ,UAAU,KAAY;EACtB,GAAI;EACJ,WAAW,EACT,6UACA,KAAU,qDACV,MAAa,WACX,wEACF,MAAa,YACX,2EACF,sCACA,EACD;YAdH,CAgBE,kBAAC,GAAD;GACE,MAAK;GACL,WAAW,EACT,wCACA,KACE,mJACH;GACD,CAAA,EACF,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,QAAD;IACE,eAAY;IACZ,WAAU;cAFZ,CAIG,GACD,kBAAC,GAAD;KAAM,MAAK;KAAiB,OAAM;KAAS,CAAA,CACtC;;GACH,CAAA,CACC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, FunctionComponent } from 'react';
|
|
2
|
+
import { IconicNames } from '@clubmed/trident-icons';
|
|
3
|
+
export interface PageNavigationItem {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
href: string;
|
|
7
|
+
icon?: IconicNames;
|
|
8
|
+
}
|
|
9
|
+
export interface PageNavigationProps extends ComponentPropsWithoutRef<'nav'> {
|
|
10
|
+
items: PageNavigationItem[];
|
|
11
|
+
activeItem: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const PageNavigation: FunctionComponent<PageNavigationProps>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../chunks/clsx.js";
|
|
3
|
+
import { useCallback as t, useRef as n } from "react";
|
|
4
|
+
import { Icon as r } from "@clubmed/trident-icons";
|
|
5
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
|
+
//#region lib/ui/PageNavigation.tsx
|
|
7
|
+
var o = {
|
|
8
|
+
positionAnchor: "--page-nav-active",
|
|
9
|
+
top: "anchor(top)",
|
|
10
|
+
bottom: "anchor(bottom)",
|
|
11
|
+
left: "anchor(left)",
|
|
12
|
+
right: "anchor(right)",
|
|
13
|
+
position: "absolute"
|
|
14
|
+
}, s = { anchorName: "--page-nav-active" }, c = /* @__PURE__ */ i("span", {
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
className: "pointer-events-none absolute rounded-pill bg-black transition-all duration-300 [position-anchor:--page-nav-active]",
|
|
17
|
+
style: o
|
|
18
|
+
}), l = ({ items: o, activeItem: l, className: u, ...d }) => {
|
|
19
|
+
let f = n(null), p = t((e) => {
|
|
20
|
+
let t = Array.from(f.current?.querySelectorAll("a") ?? []), n = t.indexOf(document.activeElement);
|
|
21
|
+
if (n === -1) return;
|
|
22
|
+
let r = n;
|
|
23
|
+
if (e.key === "ArrowRight") r = (n + 1) % t.length;
|
|
24
|
+
else if (e.key === "ArrowLeft") r = (n - 1 + t.length) % t.length;
|
|
25
|
+
else if (e.key === "Home") r = 0;
|
|
26
|
+
else if (e.key === "End") r = t.length - 1;
|
|
27
|
+
else return;
|
|
28
|
+
e.preventDefault(), t[r].focus();
|
|
29
|
+
}, []);
|
|
30
|
+
return /* @__PURE__ */ i("nav", {
|
|
31
|
+
"aria-label": "Page navigation",
|
|
32
|
+
...d,
|
|
33
|
+
className: e("flex items-center", u),
|
|
34
|
+
children: /* @__PURE__ */ a("ul", {
|
|
35
|
+
ref: f,
|
|
36
|
+
onKeyDown: p,
|
|
37
|
+
className: "relative flex items-center gap-4 md:gap-16",
|
|
38
|
+
role: "list",
|
|
39
|
+
children: [c, o.map((t) => {
|
|
40
|
+
let n = t.id === l;
|
|
41
|
+
return /* @__PURE__ */ i("li", {
|
|
42
|
+
className: "relative",
|
|
43
|
+
children: /* @__PURE__ */ a("a", {
|
|
44
|
+
href: t.href,
|
|
45
|
+
"aria-current": n ? "page" : void 0,
|
|
46
|
+
style: n ? s : void 0,
|
|
47
|
+
className: e("relative z-10 grid items-center justify-center gap-2 rounded-pill", "font-sans text-b3 font-medium focus-visible:ring-8 focus-visible:ring-lavender/20 outline-none", n ? "[@supports(not(anchor-name:--x))]:bg-black" : "focus:bg-pearl", n ? "px-20 py-12" : "md:px-20 md:py-12", n ? "text-white" : "text-black"),
|
|
48
|
+
children: [t.icon && /* @__PURE__ */ i("div", {
|
|
49
|
+
className: e("row-start-1 row-end-1 col-start-1 col-end-1 flex items-center justify-center transition-opacity duration-300 md:hidden", "md:opacity-0 transition-opacity mx-auto", n && "opacity-0"),
|
|
50
|
+
"aria-hidden": "true",
|
|
51
|
+
children: /* @__PURE__ */ i(r, {
|
|
52
|
+
name: t.icon,
|
|
53
|
+
width: "30px"
|
|
54
|
+
})
|
|
55
|
+
}), /* @__PURE__ */ i("span", {
|
|
56
|
+
className: e("row-start-1 row-end-1 col-start-1 col-end-1 grid grid-cols-[0fr] md:grid-cols-[1fr] overflow-hidden transition-all opacity-0 duration-300 md:opacity-100 text-center", n && "grid-cols-[1fr] opacity-100"),
|
|
57
|
+
children: /* @__PURE__ */ i("span", {
|
|
58
|
+
className: "overflow-hidden mx-auto",
|
|
59
|
+
children: t.label
|
|
60
|
+
})
|
|
61
|
+
})]
|
|
62
|
+
})
|
|
63
|
+
}, t.id);
|
|
64
|
+
})]
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { l as PageNavigation };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=PageNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageNavigation.js","names":[],"sources":["../../lib/ui/PageNavigation.tsx"],"sourcesContent":["'use client';\n\nimport type {\n ComponentPropsWithoutRef,\n CSSProperties,\n FunctionComponent,\n KeyboardEvent,\n} from 'react';\nimport { useCallback, useRef } from 'react';\nimport clsx from 'clsx';\nimport { Icon, type IconicNames } from '@clubmed/trident-icons';\n\nexport interface PageNavigationItem {\n id: string;\n label: string;\n href: string;\n icon?: IconicNames;\n}\n\nexport interface PageNavigationProps extends ComponentPropsWithoutRef<'nav'> {\n items: PageNavigationItem[];\n activeItem: string;\n}\n\n// Static — hoisted outside component so it's not recreated on every render\nconst PILL_STYLE: CSSProperties = {\n positionAnchor: '--page-nav-active',\n top: 'anchor(top)',\n bottom: 'anchor(bottom)',\n left: 'anchor(left)',\n right: 'anchor(right)',\n position: 'absolute',\n};\n\nconst ACTIVE_ANCHOR_STYLE: CSSProperties = { anchorName: '--page-nav-active' };\n\nconst PILL = (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute rounded-pill bg-black transition-all duration-300 [position-anchor:--page-nav-active]\"\n style={PILL_STYLE}\n />\n);\n\nexport const PageNavigation: FunctionComponent<PageNavigationProps> = ({\n items,\n activeItem,\n className,\n ...attrs\n}) => {\n const listRef = useRef<HTMLUListElement>(null);\n\n const handleKeyDown = useCallback((e: KeyboardEvent<HTMLUListElement>) => {\n const links = Array.from(listRef.current?.querySelectorAll<HTMLAnchorElement>('a') ?? []);\n const focused = links.indexOf(document.activeElement as HTMLAnchorElement);\n if (focused === -1) return;\n\n let next = focused;\n if (e.key === 'ArrowRight') next = (focused + 1) % links.length;\n else if (e.key === 'ArrowLeft') next = (focused - 1 + links.length) % links.length;\n else if (e.key === 'Home') next = 0;\n else if (e.key === 'End') next = links.length - 1;\n else return;\n\n e.preventDefault();\n links[next].focus();\n }, []);\n\n return (\n <nav aria-label=\"Page navigation\" {...attrs} className={clsx('flex items-center', className)}>\n <ul\n ref={listRef}\n onKeyDown={handleKeyDown}\n className=\"relative flex items-center gap-4 md:gap-16\"\n role=\"list\"\n >\n {PILL}\n\n {items.map((item) => {\n const isActive = item.id === activeItem;\n\n return (\n <li key={item.id} className=\"relative\">\n <a\n href={item.href}\n aria-current={isActive ? 'page' : undefined}\n style={isActive ? ACTIVE_ANCHOR_STYLE : undefined}\n className={clsx(\n 'relative z-10 grid items-center justify-center gap-2 rounded-pill',\n 'font-sans text-b3 font-medium focus-visible:ring-8 focus-visible:ring-lavender/20 outline-none',\n isActive ? '[@supports(not(anchor-name:--x))]:bg-black' : 'focus:bg-pearl',\n isActive ? 'px-20 py-12' : 'md:px-20 md:py-12',\n isActive ? 'text-white' : 'text-black',\n )}\n >\n {item.icon && (\n <div\n className={clsx(\n 'row-start-1 row-end-1 col-start-1 col-end-1 flex items-center justify-center transition-opacity duration-300 md:hidden',\n 'md:opacity-0 transition-opacity mx-auto',\n isActive && 'opacity-0',\n )}\n aria-hidden=\"true\"\n >\n <Icon name={item.icon} width=\"30px\" />\n </div>\n )}\n\n <span\n className={clsx(\n 'row-start-1 row-end-1 col-start-1 col-end-1 grid grid-cols-[0fr] md:grid-cols-[1fr] overflow-hidden transition-all opacity-0 duration-300 md:opacity-100 text-center',\n isActive && 'grid-cols-[1fr] opacity-100',\n )}\n >\n <span className=\"overflow-hidden mx-auto\">{item.label}</span>\n </span>\n </a>\n </li>\n );\n })}\n </ul>\n </nav>\n );\n};\n"],"mappings":";;;;;;AAyBA,IAAM,IAA4B;CAChC,gBAAgB;CAChB,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;CACP,UAAU;CACX,EAEK,IAAqC,EAAE,YAAY,qBAAqB,EAExE,IACJ,kBAAC,QAAD;CACE,eAAY;CACZ,WAAU;CACV,OAAO;CACP,CAAA,EAGS,KAA0D,EACrE,UACA,eACA,cACA,GAAG,QACC;CACJ,IAAM,IAAU,EAAyB,KAAK,EAExC,IAAgB,GAAa,MAAuC;EACxE,IAAM,IAAQ,MAAM,KAAK,EAAQ,SAAS,iBAAoC,IAAI,IAAI,EAAE,CAAC,EACnF,IAAU,EAAM,QAAQ,SAAS,cAAmC;AAC1E,MAAI,MAAY,GAAI;EAEpB,IAAI,IAAO;AACX,MAAI,EAAE,QAAQ,aAAc,MAAQ,IAAU,KAAK,EAAM;WAChD,EAAE,QAAQ,YAAa,MAAQ,IAAU,IAAI,EAAM,UAAU,EAAM;WACnE,EAAE,QAAQ,OAAQ,KAAO;WACzB,EAAE,QAAQ,MAAO,KAAO,EAAM,SAAS;MAC3C;AAGL,EADA,EAAE,gBAAgB,EAClB,EAAM,GAAM,OAAO;IAClB,EAAE,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,cAAW;EAAkB,GAAI;EAAO,WAAW,EAAK,qBAAqB,EAAU;YAC1F,kBAAC,MAAD;GACE,KAAK;GACL,WAAW;GACX,WAAU;GACV,MAAK;aAJP,CAMG,GAEA,EAAM,KAAK,MAAS;IACnB,IAAM,IAAW,EAAK,OAAO;AAE7B,WACE,kBAAC,MAAD;KAAkB,WAAU;eAC1B,kBAAC,KAAD;MACE,MAAM,EAAK;MACX,gBAAc,IAAW,SAAS,KAAA;MAClC,OAAO,IAAW,IAAsB,KAAA;MACxC,WAAW,EACT,qEACA,kGACA,IAAW,+CAA+C,kBAC1D,IAAW,gBAAgB,qBAC3B,IAAW,eAAe,aAC3B;gBAVH,CAYG,EAAK,QACJ,kBAAC,OAAD;OACE,WAAW,EACT,0HACA,2CACA,KAAY,YACb;OACD,eAAY;iBAEZ,kBAAC,GAAD;QAAM,MAAM,EAAK;QAAM,OAAM;QAAS,CAAA;OAClC,CAAA,EAGR,kBAAC,QAAD;OACE,WAAW,EACT,wKACA,KAAY,8BACb;iBAED,kBAAC,QAAD;QAAM,WAAU;kBAA2B,EAAK;QAAa,CAAA;OACxD,CAAA,CAAA;;KAEN,EAnCI,EAAK,GAmCT;KAEP,CAAA;;EAEA,CAAA"}
|