@clubmed/trident-ui 2.0.0-beta.61 → 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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clubmed/trident-ui",
3
- "version": "2.0.0-beta.61",
3
+ "version": "2.0.0-beta.62",
4
4
  "type": "module",
5
5
  "description": "Shared ClubMed React UI components",
6
6
  "keywords": [
@@ -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"}