@clubmed/trident-ui 2.1.0-beta.1 → 2.1.0-beta.3

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.
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { r as e } from "./chunk.js";
2
+ import { n as e } from "./chunk.js";
3
3
  import { Button as t } from "../ui/buttons/Button.js";
4
4
  import { useDevice as n } from "../ui/contexts/devices/Device.js";
5
5
  import { a as r, i, r as a } from "./addLeadingZeros.js";
package/chunks/Tooltip.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { i as e, t } from "./chunk.js";
2
+ import { r as e, t } from "./chunk.js";
3
3
  import { t as n } from "./clsx.js";
4
4
  import * as r from "react";
5
5
  import { createElement as i, useLayoutEffect as a } from "react";
package/chunks/chunk.js CHANGED
@@ -1,23 +1,23 @@
1
1
  //#region \0rolldown/runtime.js
2
- var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (e && (t = e(e = 0)), t), s = (e, t) => () => (t || e((t = { exports: {} }).exports, t), t.exports), c = (e, n) => {
2
+ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || e((t = { exports: {} }).exports, t), t.exports), s = (e, n) => {
3
3
  let r = {};
4
4
  for (var i in e) t(r, i, {
5
5
  get: e[i],
6
6
  enumerable: !0
7
7
  });
8
8
  return n || t(r, Symbol.toStringTag, { value: "Module" }), r;
9
- }, l = (e, i, o, s) => {
9
+ }, c = (e, i, o, s) => {
10
10
  if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, {
11
11
  get: ((e) => i[e]).bind(null, d),
12
12
  enumerable: !(s = n(i, d)) || s.enumerable
13
13
  });
14
14
  return e;
15
- }, u = (n, r, a) => (a = n == null ? {} : e(i(n)), l(r || !n || !n.__esModule ? t(a, "default", {
15
+ }, l = (n, r, a) => (a = n == null ? {} : e(i(n)), c(r || !n || !n.__esModule ? t(a, "default", {
16
16
  value: n,
17
17
  enumerable: !0
18
- }) : a, n)), d = (e) => a.call(e, "module.exports") ? e["module.exports"] : l(t({}, "__esModule", { value: !0 }), e), f = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
18
+ }) : a, n)), u = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
19
19
  if (typeof require < "u") return require.apply(this, arguments);
20
20
  throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
21
21
  });
22
22
  //#endregion
23
- export { d as a, f as i, o as n, u as o, c as r, s as t };
23
+ export { l as i, s as n, u as r, o as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clubmed/trident-ui",
3
- "version": "2.1.0-beta.1",
3
+ "version": "2.1.0-beta.3",
4
4
  "type": "module",
5
5
  "description": "Shared ClubMed React UI components",
6
6
  "keywords": [
@@ -86,7 +86,6 @@
86
86
  "date-fns": ">=2.30.0",
87
87
  "embla-carousel-react": "^8.6.0",
88
88
  "embla-carousel-wheel-gestures": "^8.1.0",
89
- "leva": "^0.10.1",
90
89
  "react-day-picker": ">=8.10.0",
91
90
  "react-hot-toast": ">=2.4.1",
92
91
  "react-transition-state": ">=2.3.2",
package/ui/ChatBody.d.ts CHANGED
@@ -6,7 +6,7 @@ import { HTMLAttributes, ReactNode } from 'react';
6
6
  export interface ChatMessage {
7
7
  id: string;
8
8
  sender: ChatMessageSender;
9
- content: string;
9
+ content: ReactNode;
10
10
  }
11
11
  export interface ChatBodyProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
12
12
  greeting?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBody.js","names":[],"sources":["../../lib/ui/ChatBody.tsx"],"sourcesContent":["import { ChatMessage, type ChatMessageSender } from './ChatMessage';\nimport { ChatTypingIndicator } from './ChatTypingIndicator';\nimport type { ChatWindowCsatPromptLabels } from './ChatWindowCsatPrompt';\nimport { ChatWindowCsatPrompt } from './ChatWindowCsatPrompt';\nimport {\n ChatWindowCsatThankYou,\n type ChatWindowCsatThankYouLabels,\n} from './ChatWindowCsatThankYou';\nimport { ChatWindowQuote, type ChatWindowQuoteItem } from './ChatWindowQuote';\nimport {\n forwardRef,\n type HTMLAttributes,\n type ReactNode,\n type Ref,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { twMerge } from './helpers/twMerge';\n\nexport interface ChatMessage {\n id: string;\n sender: ChatMessageSender;\n content: string;\n}\n\nexport interface ChatBodyProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n greeting?: string;\n messages: ChatMessage[];\n isTyping?: boolean;\n onFeedbackRate?: (rating: number) => void;\n csatLabels?: ChatWindowCsatPromptLabels;\n csatRenderRatingLabel?: (rating: number) => ReactNode;\n csatThankYouLabels?: ChatWindowCsatThankYouLabels;\n onQuoteCtaClick?: (quote: ChatWindowQuoteItem) => void;\n}\n\nexport interface ChatHandle {\n askForFeedback: () => void;\n showQuotes: (quotes: ChatWindowQuoteItem[]) => void;\n}\n\nfunction useChat(\n { messages, isTyping, csatRenderRatingLabel, onFeedbackRate, csatLabels }: ChatBodyProps,\n ref: Ref<ChatHandle>,\n) {\n const logRef = useRef<HTMLDivElement>(null);\n const [showCsat, setShowCsat] = useState(false);\n const [csatRatingMessage, setCsatRatingMessage] = useState<string | null>(null);\n const [quoteGroups, setQuoteGroups] = useState<ChatWindowQuoteItem[][]>([]);\n\n useImperativeHandle(ref, () => ({\n askForFeedback() {\n setShowCsat(true);\n },\n showQuotes(quotes: ChatWindowQuoteItem[]) {\n setQuoteGroups((prev) => [...prev, quotes]);\n },\n }));\n\n useEffect(() => {\n const el = logRef.current;\n if (el) el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });\n }, [messages, isTyping, showCsat, csatRatingMessage, quoteGroups]);\n\n function handleRate(rating: number) {\n const label = csatRenderRatingLabel ? String(csatRenderRatingLabel(rating)) : String(rating);\n setCsatRatingMessage(label);\n onFeedbackRate?.(rating);\n }\n\n const csatReady = showCsat && csatLabels && csatRenderRatingLabel;\n\n return { logRef, csatRatingMessage, quoteGroups, handleRate, csatReady };\n}\n\nexport const ChatBody = forwardRef<ChatHandle, ChatBodyProps>(function Chat(props, ref) {\n const { logRef, csatRatingMessage, quoteGroups, handleRate, csatReady } = useChat(props, ref);\n\n const {\n greeting,\n messages,\n isTyping = false,\n csatLabels,\n csatRenderRatingLabel,\n csatThankYouLabels,\n onQuoteCtaClick,\n className,\n ...extraProps\n } = props;\n\n return (\n <div\n {...extraProps}\n ref={logRef}\n role=\"log\"\n aria-label=\"Chat messages\"\n aria-live=\"polite\"\n className={twMerge(\n 'chat-message-log flex flex-col flex-1 gap-20 overflow-y-auto py-20',\n className,\n )}\n >\n {greeting ? (\n <div className=\"px-20\">\n <p className=\"text-b3 text-black\">{greeting}</p>\n </div>\n ) : null}\n\n {messages.map((msg) => (\n <ChatMessage key={msg.id} sender={msg.sender}>\n {msg.content}\n </ChatMessage>\n ))}\n\n {isTyping && (\n <div className=\"px-12\">\n <ChatTypingIndicator />\n </div>\n )}\n\n {csatReady && (\n <ChatWindowCsatPrompt\n onRate={handleRate}\n labels={csatLabels!}\n renderRatingLabel={csatRenderRatingLabel!}\n />\n )}\n\n {csatRatingMessage && <ChatMessage sender=\"user\">{csatRatingMessage}</ChatMessage>}\n\n {csatRatingMessage && csatThankYouLabels && (\n <ChatWindowCsatThankYou labels={csatThankYouLabels} />\n )}\n\n {quoteGroups.map((quotes, idx) => (\n <ChatWindowQuote key={idx} quotes={quotes} onCtaClick={onQuoteCtaClick} />\n ))}\n </div>\n );\n});\n"],"mappings":";;;;;;;;;AA2CA,SAAS,EACP,EAAE,aAAU,aAAU,0BAAuB,mBAAgB,iBAC7D,GACA;CACA,IAAM,IAAS,EAAuB,KAAK,EACrC,CAAC,GAAU,KAAe,EAAS,GAAM,EACzC,CAAC,GAAmB,KAAwB,EAAwB,KAAK,EACzE,CAAC,GAAa,KAAkB,EAAkC,EAAE,CAAC;AAW3E,CATA,EAAoB,UAAY;EAC9B,iBAAiB;AACf,KAAY,GAAK;;EAEnB,WAAW,GAA+B;AACxC,MAAgB,MAAS,CAAC,GAAG,GAAM,EAAO,CAAC;;EAE9C,EAAE,EAEH,QAAgB;EACd,IAAM,IAAK,EAAO;AAClB,EAAI,KAAI,EAAG,SAAS;GAAE,KAAK,EAAG;GAAc,UAAU;GAAU,CAAC;IAChE;EAAC;EAAU;EAAU;EAAU;EAAmB;EAAY,CAAC;CAElE,SAAS,EAAW,GAAgB;AAGlC,EADA,EADsC,OAAxB,IAA+B,EAAsB,EAAO,GAAW,EAAO,CACjE,EAC3B,IAAiB,EAAO;;AAK1B,QAAO;EAAE;EAAQ;EAAmB;EAAa;EAAY,WAF3C,KAAY,KAAc;EAE4B;;AAG1E,IAAa,IAAW,EAAsC,SAAc,GAAO,GAAK;CACtF,IAAM,EAAE,WAAQ,sBAAmB,gBAAa,eAAY,iBAAc,EAAQ,GAAO,EAAI,EAEvF,EACJ,aACA,aACA,cAAW,IACX,eACA,0BACA,uBACA,oBACA,cACA,GAAG,MACD;AAEJ,QACE,kBAAC,OAAD;EACE,GAAI;EACJ,KAAK;EACL,MAAK;EACL,cAAW;EACX,aAAU;EACV,WAAW,EACT,sEACA,EACD;YATH;GAWG,IACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAAa,CAAA;IAC5C,CAAA,GACJ;GAEH,EAAS,KAAK,MACb,kBAAC,GAAD;IAA0B,QAAQ,EAAI;cACnC,EAAI;IACO,EAFI,EAAI,GAER,CACd;GAED,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAuB,CAAA;IACnB,CAAA;GAGP,KACC,kBAAC,GAAD;IACE,QAAQ;IACR,QAAQ;IACR,mBAAmB;IACnB,CAAA;GAGH,KAAqB,kBAAC,GAAD;IAAa,QAAO;cAAQ;IAAgC,CAAA;GAEjF,KAAqB,KACpB,kBAAC,GAAD,EAAwB,QAAQ,GAAsB,CAAA;GAGvD,EAAY,KAAK,GAAQ,MACxB,kBAAC,GAAD;IAAmC;IAAQ,YAAY;IAAmB,EAApD,EAAoD,CAC1E;GACE;;EAER"}
1
+ {"version":3,"file":"ChatBody.js","names":[],"sources":["../../lib/ui/ChatBody.tsx"],"sourcesContent":["import { ChatMessage, type ChatMessageSender } from './ChatMessage';\nimport { ChatTypingIndicator } from './ChatTypingIndicator';\nimport type { ChatWindowCsatPromptLabels } from './ChatWindowCsatPrompt';\nimport { ChatWindowCsatPrompt } from './ChatWindowCsatPrompt';\nimport {\n ChatWindowCsatThankYou,\n type ChatWindowCsatThankYouLabels,\n} from './ChatWindowCsatThankYou';\nimport { ChatWindowQuote, type ChatWindowQuoteItem } from './ChatWindowQuote';\nimport {\n forwardRef,\n type HTMLAttributes,\n type ReactNode,\n type Ref,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { twMerge } from './helpers/twMerge';\n\nexport interface ChatMessage {\n id: string;\n sender: ChatMessageSender;\n content: ReactNode;\n}\n\nexport interface ChatBodyProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n greeting?: string;\n messages: ChatMessage[];\n isTyping?: boolean;\n onFeedbackRate?: (rating: number) => void;\n csatLabels?: ChatWindowCsatPromptLabels;\n csatRenderRatingLabel?: (rating: number) => ReactNode;\n csatThankYouLabels?: ChatWindowCsatThankYouLabels;\n onQuoteCtaClick?: (quote: ChatWindowQuoteItem) => void;\n}\n\nexport interface ChatHandle {\n askForFeedback: () => void;\n showQuotes: (quotes: ChatWindowQuoteItem[]) => void;\n}\n\nfunction useChat(\n { messages, isTyping, csatRenderRatingLabel, onFeedbackRate, csatLabels }: ChatBodyProps,\n ref: Ref<ChatHandle>,\n) {\n const logRef = useRef<HTMLDivElement>(null);\n const [showCsat, setShowCsat] = useState(false);\n const [csatRatingMessage, setCsatRatingMessage] = useState<string | null>(null);\n const [quoteGroups, setQuoteGroups] = useState<ChatWindowQuoteItem[][]>([]);\n\n useImperativeHandle(ref, () => ({\n askForFeedback() {\n setShowCsat(true);\n },\n showQuotes(quotes: ChatWindowQuoteItem[]) {\n setQuoteGroups((prev) => [...prev, quotes]);\n },\n }));\n\n useEffect(() => {\n const el = logRef.current;\n if (el) el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });\n }, [messages, isTyping, showCsat, csatRatingMessage, quoteGroups]);\n\n function handleRate(rating: number) {\n const label = csatRenderRatingLabel ? String(csatRenderRatingLabel(rating)) : String(rating);\n setCsatRatingMessage(label);\n onFeedbackRate?.(rating);\n }\n\n const csatReady = showCsat && csatLabels && csatRenderRatingLabel;\n\n return { logRef, csatRatingMessage, quoteGroups, handleRate, csatReady };\n}\n\nexport const ChatBody = forwardRef<ChatHandle, ChatBodyProps>(function Chat(props, ref) {\n const { logRef, csatRatingMessage, quoteGroups, handleRate, csatReady } = useChat(props, ref);\n\n const {\n greeting,\n messages,\n isTyping = false,\n csatLabels,\n csatRenderRatingLabel,\n csatThankYouLabels,\n onQuoteCtaClick,\n className,\n ...extraProps\n } = props;\n\n return (\n <div\n {...extraProps}\n ref={logRef}\n role=\"log\"\n aria-label=\"Chat messages\"\n aria-live=\"polite\"\n className={twMerge(\n 'chat-message-log flex flex-col flex-1 gap-20 overflow-y-auto py-20',\n className,\n )}\n >\n {greeting ? (\n <div className=\"px-20\">\n <p className=\"text-b3 text-black\">{greeting}</p>\n </div>\n ) : null}\n\n {messages.map((msg) => (\n <ChatMessage key={msg.id} sender={msg.sender}>\n {msg.content}\n </ChatMessage>\n ))}\n\n {isTyping && (\n <div className=\"px-12\">\n <ChatTypingIndicator />\n </div>\n )}\n\n {csatReady && (\n <ChatWindowCsatPrompt\n onRate={handleRate}\n labels={csatLabels!}\n renderRatingLabel={csatRenderRatingLabel!}\n />\n )}\n\n {csatRatingMessage && <ChatMessage sender=\"user\">{csatRatingMessage}</ChatMessage>}\n\n {csatRatingMessage && csatThankYouLabels && (\n <ChatWindowCsatThankYou labels={csatThankYouLabels} />\n )}\n\n {quoteGroups.map((quotes, idx) => (\n <ChatWindowQuote key={idx} quotes={quotes} onCtaClick={onQuoteCtaClick} />\n ))}\n </div>\n );\n});\n"],"mappings":";;;;;;;;;AA2CA,SAAS,EACP,EAAE,aAAU,aAAU,0BAAuB,mBAAgB,iBAC7D,GACA;CACA,IAAM,IAAS,EAAuB,KAAK,EACrC,CAAC,GAAU,KAAe,EAAS,GAAM,EACzC,CAAC,GAAmB,KAAwB,EAAwB,KAAK,EACzE,CAAC,GAAa,KAAkB,EAAkC,EAAE,CAAC;AAW3E,CATA,EAAoB,UAAY;EAC9B,iBAAiB;AACf,KAAY,GAAK;;EAEnB,WAAW,GAA+B;AACxC,MAAgB,MAAS,CAAC,GAAG,GAAM,EAAO,CAAC;;EAE9C,EAAE,EAEH,QAAgB;EACd,IAAM,IAAK,EAAO;AAClB,EAAI,KAAI,EAAG,SAAS;GAAE,KAAK,EAAG;GAAc,UAAU;GAAU,CAAC;IAChE;EAAC;EAAU;EAAU;EAAU;EAAmB;EAAY,CAAC;CAElE,SAAS,EAAW,GAAgB;AAGlC,EADA,EADsC,OAAxB,IAA+B,EAAsB,EAAO,GAAW,EAAO,CACjE,EAC3B,IAAiB,EAAO;;AAK1B,QAAO;EAAE;EAAQ;EAAmB;EAAa;EAAY,WAF3C,KAAY,KAAc;EAE4B;;AAG1E,IAAa,IAAW,EAAsC,SAAc,GAAO,GAAK;CACtF,IAAM,EAAE,WAAQ,sBAAmB,gBAAa,eAAY,iBAAc,EAAQ,GAAO,EAAI,EAEvF,EACJ,aACA,aACA,cAAW,IACX,eACA,0BACA,uBACA,oBACA,cACA,GAAG,MACD;AAEJ,QACE,kBAAC,OAAD;EACE,GAAI;EACJ,KAAK;EACL,MAAK;EACL,cAAW;EACX,aAAU;EACV,WAAW,EACT,sEACA,EACD;YATH;GAWG,IACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAAa,CAAA;IAC5C,CAAA,GACJ;GAEH,EAAS,KAAK,MACb,kBAAC,GAAD;IAA0B,QAAQ,EAAI;cACnC,EAAI;IACO,EAFI,EAAI,GAER,CACd;GAED,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAuB,CAAA;IACnB,CAAA;GAGP,KACC,kBAAC,GAAD;IACE,QAAQ;IACR,QAAQ;IACR,mBAAmB;IACnB,CAAA;GAGH,KAAqB,kBAAC,GAAD;IAAa,QAAO;cAAQ;IAAgC,CAAA;GAEjF,KAAqB,KACpB,kBAAC,GAAD,EAAwB,QAAQ,GAAsB,CAAA;GAGvD,EAAY,KAAK,GAAQ,MACxB,kBAAC,GAAD;IAAmC;IAAQ,YAAY;IAAmB,EAApD,EAAoD,CAC1E;GACE;;EAER"}
@@ -10,7 +10,7 @@ export type { ChatWindowCsatPromptLabels, ChatWindowCsatThankYouLabels, ChatWind
10
10
  export interface ChatWindowMessage {
11
11
  id: string;
12
12
  sender: ChatMessageSender;
13
- content: string;
13
+ content: ReactNode;
14
14
  }
15
15
  interface ChatWindowInputProps {
16
16
  inputValue: ChatInputProps['value'];
@@ -1 +1 @@
1
- {"version":3,"file":"ChatWindow.js","names":[],"sources":["../../lib/ui/ChatWindow.tsx"],"sourcesContent":["'use client';\n\nimport { Icon } from '@clubmed/trident-icons';\nimport { forwardRef, type ReactNode } from 'react';\nimport { twMerge } from './helpers/twMerge';\nimport type { ChatMessageSender } from './ChatMessage';\nimport type { ChatWindowCsatPromptLabels } from './ChatWindowCsatPrompt';\nimport type { ChatWindowCsatThankYouLabels } from './ChatWindowCsatThankYou';\nimport type { ChatWindowQuoteItem } from './ChatWindowQuote';\nimport { ChatHeader, type ChatHeaderProps } from './ChatHeader';\nimport { ChatBody, type ChatBodyProps } from './ChatBody';\nimport { ChatInput, type ChatInputProps } from '@/ui/ChatInput';\n\nexport type { ChatWindowCsatPromptLabels, ChatWindowCsatThankYouLabels, ChatWindowQuoteItem };\n\nexport interface ChatWindowMessage {\n id: string;\n sender: ChatMessageSender;\n content: string;\n}\n\ninterface ChatWindowInputProps {\n inputValue: ChatInputProps['value'];\n inputPlaceholder?: ChatInputProps['placeholder'];\n onInputChange: ChatInputProps['onValueChange'];\n onSubmit: ChatInputProps['onSubmit'];\n onAudioClick?: ChatInputProps['onAudioClick'];\n}\n\ninterface ChatWindowBaseProps extends ChatHeaderProps {\n onClose?: () => void;\n}\n\n// Either compose the panel from `ChatHeader`/`ChatBody`/`ChatInput` children,\n// or fall back to the opaque props-only form — in which case the message-log\n// and input props become required.\nexport type ChatWindowProps = ChatWindowBaseProps &\n (\n | ({ children: ReactNode } & Partial<ChatBodyProps> & Partial<ChatWindowInputProps>)\n | (ChatBodyProps & ChatWindowInputProps & { children?: undefined })\n );\n\nexport interface ChatWindowHandle {\n askForFeedback: () => void;\n showQuotes: (quotes: ChatWindowQuoteItem[]) => void;\n}\n\nexport const ChatWindow = forwardRef<ChatWindowHandle, ChatWindowProps>(function ChatWindow(\n {\n title,\n onClose,\n logo,\n className,\n children,\n inputValue,\n inputPlaceholder,\n onInputChange,\n onSubmit,\n onAudioClick,\n greeting,\n messages,\n isTyping,\n onFeedbackRate,\n csatLabels,\n csatRenderRatingLabel,\n csatThankYouLabels,\n onQuoteCtaClick,\n ...props\n },\n ref,\n) {\n return (\n <div {...props} className={twMerge('flex flex-col gap-20 items-center', className)}>\n <div className=\"chat-border bg-white flex flex-col h-full w-full rounded-32 overflow-hidden\">\n {children ?? (\n <>\n <ChatHeader title={title} logo={logo} />\n <ChatBody\n greeting={greeting}\n messages={messages!}\n isTyping={isTyping}\n onFeedbackRate={onFeedbackRate}\n csatLabels={csatLabels}\n csatRenderRatingLabel={csatRenderRatingLabel}\n csatThankYouLabels={csatThankYouLabels}\n onQuoteCtaClick={onQuoteCtaClick}\n ref={ref}\n />\n <div className=\"shrink-0 px-8 pb-8 pt-12\">\n <ChatInput\n value={inputValue!}\n placeholder={inputPlaceholder}\n onValueChange={onInputChange!}\n onSubmit={onSubmit!}\n onAudioClick={onAudioClick}\n />\n </div>\n </>\n )}\n </div>\n\n {onClose && (\n <button\n type=\"button\"\n aria-label=\"Close chat\"\n onClick={onClose}\n className=\"flex items-center justify-center size-48 rounded-full bg-black border border-black text-white shrink-0 hover:opacity-80 transition-opacity outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n >\n <Icon name=\"CrossDefault\" width=\"24px\" />\n </button>\n )}\n </div>\n );\n});\n"],"mappings":";;;;;;;;;AA+CA,IAAa,IAAa,EAA8C,SACtE,EACE,UACA,YACA,SACA,cACA,aACA,eACA,qBACA,kBACA,aACA,iBACA,aACA,aACA,aACA,mBACA,eACA,0BACA,uBACA,oBACA,GAAG,KAEL,GACA;AACA,QACE,kBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,EAAQ,qCAAqC,EAAU;YAAlF,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,KACC,kBAAA,GAAA,EAAA,UAAA;IACE,kBAAC,GAAD;KAAmB;KAAa;KAAQ,CAAA;IACxC,kBAAC,GAAD;KACY;KACA;KACA;KACM;KACJ;KACW;KACH;KACH;KACZ;KACL,CAAA;IACF,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MACE,OAAO;MACP,aAAa;MACb,eAAe;MACL;MACI;MACd,CAAA;KACE,CAAA;IACL,EAAA,CAAA;GAED,CAAA,EAEL,KACC,kBAAC,UAAD;GACE,MAAK;GACL,cAAW;GACX,SAAS;GACT,WAAU;aAEV,kBAAC,GAAD;IAAM,MAAK;IAAe,OAAM;IAAS,CAAA;GAClC,CAAA,CAAA;;EAIf"}
1
+ {"version":3,"file":"ChatWindow.js","names":[],"sources":["../../lib/ui/ChatWindow.tsx"],"sourcesContent":["'use client';\n\nimport { Icon } from '@clubmed/trident-icons';\nimport { forwardRef, type ReactNode } from 'react';\nimport { twMerge } from './helpers/twMerge';\nimport type { ChatMessageSender } from './ChatMessage';\nimport type { ChatWindowCsatPromptLabels } from './ChatWindowCsatPrompt';\nimport type { ChatWindowCsatThankYouLabels } from './ChatWindowCsatThankYou';\nimport type { ChatWindowQuoteItem } from './ChatWindowQuote';\nimport { ChatHeader, type ChatHeaderProps } from './ChatHeader';\nimport { ChatBody, type ChatBodyProps } from './ChatBody';\nimport { ChatInput, type ChatInputProps } from '@/ui/ChatInput';\n\nexport type { ChatWindowCsatPromptLabels, ChatWindowCsatThankYouLabels, ChatWindowQuoteItem };\n\nexport interface ChatWindowMessage {\n id: string;\n sender: ChatMessageSender;\n content: ReactNode;\n}\n\ninterface ChatWindowInputProps {\n inputValue: ChatInputProps['value'];\n inputPlaceholder?: ChatInputProps['placeholder'];\n onInputChange: ChatInputProps['onValueChange'];\n onSubmit: ChatInputProps['onSubmit'];\n onAudioClick?: ChatInputProps['onAudioClick'];\n}\n\ninterface ChatWindowBaseProps extends ChatHeaderProps {\n onClose?: () => void;\n}\n\n// Either compose the panel from `ChatHeader`/`ChatBody`/`ChatInput` children,\n// or fall back to the opaque props-only form — in which case the message-log\n// and input props become required.\nexport type ChatWindowProps = ChatWindowBaseProps &\n (\n | ({ children: ReactNode } & Partial<ChatBodyProps> & Partial<ChatWindowInputProps>)\n | (ChatBodyProps & ChatWindowInputProps & { children?: undefined })\n );\n\nexport interface ChatWindowHandle {\n askForFeedback: () => void;\n showQuotes: (quotes: ChatWindowQuoteItem[]) => void;\n}\n\nexport const ChatWindow = forwardRef<ChatWindowHandle, ChatWindowProps>(function ChatWindow(\n {\n title,\n onClose,\n logo,\n className,\n children,\n inputValue,\n inputPlaceholder,\n onInputChange,\n onSubmit,\n onAudioClick,\n greeting,\n messages,\n isTyping,\n onFeedbackRate,\n csatLabels,\n csatRenderRatingLabel,\n csatThankYouLabels,\n onQuoteCtaClick,\n ...props\n },\n ref,\n) {\n return (\n <div {...props} className={twMerge('flex flex-col gap-20 items-center', className)}>\n <div className=\"chat-border bg-white flex flex-col h-full w-full rounded-32 overflow-hidden\">\n {children ?? (\n <>\n <ChatHeader title={title} logo={logo} />\n <ChatBody\n greeting={greeting}\n messages={messages!}\n isTyping={isTyping}\n onFeedbackRate={onFeedbackRate}\n csatLabels={csatLabels}\n csatRenderRatingLabel={csatRenderRatingLabel}\n csatThankYouLabels={csatThankYouLabels}\n onQuoteCtaClick={onQuoteCtaClick}\n ref={ref}\n />\n <div className=\"shrink-0 px-8 pb-8 pt-12\">\n <ChatInput\n value={inputValue!}\n placeholder={inputPlaceholder}\n onValueChange={onInputChange!}\n onSubmit={onSubmit!}\n onAudioClick={onAudioClick}\n />\n </div>\n </>\n )}\n </div>\n\n {onClose && (\n <button\n type=\"button\"\n aria-label=\"Close chat\"\n onClick={onClose}\n className=\"flex items-center justify-center size-48 rounded-full bg-black border border-black text-white shrink-0 hover:opacity-80 transition-opacity outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n >\n <Icon name=\"CrossDefault\" width=\"24px\" />\n </button>\n )}\n </div>\n );\n});\n"],"mappings":";;;;;;;;;AA+CA,IAAa,IAAa,EAA8C,SACtE,EACE,UACA,YACA,SACA,cACA,aACA,eACA,qBACA,kBACA,aACA,iBACA,aACA,aACA,aACA,mBACA,eACA,0BACA,uBACA,oBACA,GAAG,KAEL,GACA;AACA,QACE,kBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,EAAQ,qCAAqC,EAAU;YAAlF,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,KACC,kBAAA,GAAA,EAAA,UAAA;IACE,kBAAC,GAAD;KAAmB;KAAa;KAAQ,CAAA;IACxC,kBAAC,GAAD;KACY;KACA;KACA;KACM;KACJ;KACW;KACH;KACH;KACZ;KACL,CAAA;IACF,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MACE,OAAO;MACP,aAAa;MACb,eAAe;MACL;MACI;MACd,CAAA;KACE,CAAA;IACL,EAAA,CAAA;GAED,CAAA,EAEL,KACC,kBAAC,UAAD;GACE,MAAK;GACL,cAAW;GACX,SAAS;GACT,WAAU;aAEV,kBAAC,GAAD;IAAM,MAAK;IAAe,OAAM;IAAS,CAAA;GAClC,CAAA,CAAA;;EAIf"}
@@ -1,4 +1,4 @@
1
- import { o as e, t } from "../../chunks/chunk.js";
1
+ import { i as e, t } from "../../chunks/chunk.js";
2
2
  import { createContext as n, useContext as r } from "react";
3
3
  import { jsx as i } from "react/jsx-runtime";
4
4
  //#region ../../node_modules/.pnpm/lodash@4.17.23/node_modules/lodash/isArray.js
package/ui/tabs/Tabs.js CHANGED
@@ -101,9 +101,9 @@ var _ = ({ className: e, compacted: t = !1, selected: r, children: i }) => /* @_
101
101
  icon: "ArrowDefaultLeft",
102
102
  size: "small",
103
103
  className: l("pointer-events-auto transition-opacity duration-200 focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2", v ? "opacity-100" : "pointer-events-none opacity-0"),
104
- onMouseDown: () => D(-1),
105
- onMouseUp: E,
106
- onMouseLeave: E,
104
+ onPointerDown: () => D(-1),
105
+ onPointerUp: E,
106
+ onPointerLeave: E,
107
107
  onKeyDown: k,
108
108
  onKeyUp: O,
109
109
  inert: !v,
@@ -138,9 +138,9 @@ var _ = ({ className: e, compacted: t = !1, selected: r, children: i }) => /* @_
138
138
  icon: "ArrowDefaultRight",
139
139
  size: "small",
140
140
  className: l("pointer-events-auto transition-opacity duration-200 focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2", b ? "opacity-100" : "pointer-events-none opacity-0"),
141
- onMouseDown: () => D(1),
142
- onMouseUp: E,
143
- onMouseLeave: E,
141
+ onPointerDown: () => D(1),
142
+ onPointerUp: E,
143
+ onPointerLeave: E,
144
144
  onKeyDown: A,
145
145
  onKeyUp: O,
146
146
  inert: !b,
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.js","names":[],"sources":["../../../lib/ui/tabs/Tabs.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ComponentProps,\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type FunctionComponent,\n type PropsWithChildren,\n type RefObject,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useRef,\n useState,\n useMemo,\n} from 'react';\n\nimport { TabsProvider } from '../contexts/TabControl';\nimport {\n useActiveTab,\n useActiveTabControl,\n useRegisterTabControl,\n useTabDispatch,\n useTabsUid,\n} from '../hooks/tabControl';\nimport { useKeyboardControls } from '../hooks/useKeyboardControls';\nimport { Select } from '../forms/Select';\nimport { cn } from '../helpers/cn';\nimport { ArrowButton } from '../buttons/ArrowButton';\n\ntype ProviderProps = ComponentProps<typeof TabsProvider>;\n\ninterface Props extends ProviderProps {\n className?: string;\n /**\n * Shrink the spacing between tabs and panels\n */\n compacted?: boolean;\n}\n\nexport const Tabs: FunctionComponent<PropsWithChildren<Props>> = ({\n className,\n compacted = false,\n selected,\n children,\n}) => {\n return (\n <div\n className={cn(\n 'flex flex-col',\n {\n 'sm:gap-y-20': !compacted,\n },\n className,\n )}\n data-name=\"Tabs\"\n >\n <TabsProvider selected={selected}>{children}</TabsProvider>\n </div>\n );\n};\n\ninterface TabsBodyProps {\n className?: string;\n}\n\nexport const TabsBody: FunctionComponent<PropsWithChildren<TabsBodyProps>> = ({\n className,\n children,\n}) => {\n return (\n <div data-name=\"TabsBody\" className={cn('grid grid-rows-1 overflow-hidden', className)}>\n {children}\n </div>\n );\n};\n\ninterface TabPanelProps {\n className?: string;\n /**\n * Tab panel index<br/>\n * _Can be **0** or **1** indexed_\n */\n value: number;\n /**\n * on panel select handler\n */\n onSelect?: (context: { value: TabPanelProps['value'] }) => void;\n}\n\nexport const TabPanel: FunctionComponent<PropsWithChildren<TabPanelProps>> = ({\n value,\n className,\n onSelect,\n children,\n ...attrs\n}) => {\n const uid = useTabsUid();\n const mounted = useRef(false);\n const tabSelected = useActiveTab();\n const isActive = tabSelected === value;\n\n useEffect(() => {\n if (!mounted.current) {\n mounted.current = true;\n return;\n }\n\n if (isActive) {\n onSelect?.({ value });\n }\n }, [isActive, value, onSelect]);\n\n return (\n <div\n {...attrs}\n aria-hidden={!isActive}\n className={cn(\n 'relative col-start-1 row-start-1 transition-opacity duration-500',\n {\n 'pointer-events-none z-0 h-0 opacity-0': !isActive,\n 'pointer-events-auto z-1 h-auto opacity-100': isActive,\n },\n className,\n )}\n inert={isActive ? undefined : true}\n tabIndex={isActive ? 0 : -1}\n id={`TabPanel_${value}_${uid}`}\n data-name={`TabPanel_${value}`}\n role=\"tabpanel\"\n aria-labelledby={`Tab_${value}_${uid}`}\n >\n {children}\n </div>\n );\n};\n\ninterface TabListProps {\n className?: string;\n /**\n * Remove filler placeholders\n */\n constrained?: boolean;\n}\n\nexport const TabList: FunctionComponent<PropsWithChildren<TabListProps>> = ({\n className,\n constrained = false,\n children,\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n const spacerRef = useRef<HTMLDivElement>(null);\n const [, currentControl] = useActiveTabControl();\n const uid = useTabsUid();\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(false);\n\n const anchorName = `--tab-pill-${uid}` as CSSProperties['anchorName'];\n\n const pillStyle = useMemo<CSSProperties>(\n () => ({\n positionAnchor: anchorName,\n top: 'anchor(top)',\n bottom: 'anchor(bottom)',\n left: 'anchor(left)',\n right: 'anchor(right)',\n position: 'absolute',\n }),\n [anchorName],\n );\n\n const updateScrollState = useCallback(() => {\n const el = ref.current;\n if (!el) return;\n setCanScrollLeft(el.scrollLeft > 0);\n setCanScrollRight(Math.ceil(el.scrollLeft) < el.scrollWidth - el.clientWidth);\n }, []);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n updateScrollState();\n\n const observer = new ResizeObserver(updateScrollState);\n observer.observe(el);\n el.addEventListener('scroll', updateScrollState, { passive: true });\n\n return () => {\n observer.disconnect();\n el.removeEventListener('scroll', updateScrollState);\n };\n }, [updateScrollState]);\n\n useEffect(() => {\n if (!currentControl?.current || !ref.current) {\n return;\n }\n\n const spacerWidth = spacerRef.current!.offsetWidth ?? 0;\n const currentRect = currentControl.current.getBoundingClientRect();\n const containerRect = ref.current!.getBoundingClientRect();\n\n ref.current.scrollBy({\n left: currentRect.left - containerRect.left - spacerWidth,\n behavior: 'smooth',\n });\n }, [currentControl]);\n\n const scrollRafRef = useRef<number | null>(null);\n\n const stopScroll = useCallback(() => {\n if (scrollRafRef.current !== null) {\n cancelAnimationFrame(scrollRafRef.current);\n scrollRafRef.current = null;\n }\n }, []);\n\n const startScroll = useCallback((direction: -1 | 1) => {\n if (scrollRafRef.current !== null) return;\n const step = () => {\n ref.current?.scrollBy({ left: direction * 6 });\n scrollRafRef.current = requestAnimationFrame(step);\n };\n scrollRafRef.current = requestAnimationFrame(step);\n }, []);\n\n const handleScrollKeyUp = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') stopScroll();\n },\n [stopScroll],\n );\n\n const handleScrollLeftKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n startScroll(-1);\n }\n },\n [startScroll],\n );\n\n const handleScrollRightKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n startScroll(1);\n }\n },\n [startScroll],\n );\n\n useEffect(() => stopScroll, [stopScroll]);\n\n const isScrollable = canScrollLeft || canScrollRight;\n\n return (\n <div className=\"relative\" data-name=\"TabsHeader\">\n {isScrollable && (\n <div className=\"pointer-events-none absolute inset-y-0 left-0 z-10 flex items-center\">\n <ArrowButton\n icon=\"ArrowDefaultLeft\"\n size=\"small\"\n className={cn(\n 'pointer-events-auto transition-opacity duration-200 focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n canScrollLeft ? 'opacity-100' : 'pointer-events-none opacity-0',\n )}\n onMouseDown={() => startScroll(-1)}\n onMouseUp={stopScroll}\n onMouseLeave={stopScroll}\n onKeyDown={handleScrollLeftKeyDown}\n onKeyUp={handleScrollKeyUp}\n inert={!canScrollLeft}\n tabIndex={canScrollLeft ? 0 : -1}\n >\n Scroll tabs left\n </ArrowButton>\n </div>\n )}\n <div\n className={cn(\n 'scrollbar-hidden relative isolate flex max-w-full overflow-x-auto py-20',\n className,\n )}\n ref={ref}\n >\n <div role=\"tablist\" className=\"relative flex flex-row\">\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute rounded-pill bg-black transition-all duration-300\"\n style={pillStyle}\n />\n <div\n ref={spacerRef}\n className={cn('shrink-0', {\n 'w-16 lg:w-[max(calc((100vw-1212px)/2),116px)] xl:w-[max(calc((100vw-1212px)/2),156px)]':\n !constrained,\n })}\n />\n {children}\n <div\n className={cn('shrink-0', {\n 'w-16 lg:w-[max(calc((100vw-1212px)/2),116px)] xl:w-[max(calc((100vw-1212px)/2),156px)]':\n !constrained,\n })}\n />\n </div>\n </div>\n {isScrollable && (\n <div className=\"pointer-events-none absolute inset-y-0 right-0 z-10 flex items-center\">\n <ArrowButton\n icon=\"ArrowDefaultRight\"\n size=\"small\"\n className={cn(\n 'pointer-events-auto transition-opacity duration-200 focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n canScrollRight ? 'opacity-100' : 'pointer-events-none opacity-0',\n )}\n onMouseDown={() => startScroll(1)}\n onMouseUp={stopScroll}\n onMouseLeave={stopScroll}\n onKeyDown={handleScrollRightKeyDown}\n onKeyUp={handleScrollKeyUp}\n inert={!canScrollRight}\n tabIndex={canScrollRight ? 0 : -1}\n >\n Scroll tabs right\n </ArrowButton>\n </div>\n )}\n </div>\n );\n};\n\nexport interface TabSelectProps {\n items: { label: string; value: number }[];\n className?: string;\n 'aria-label'?: string;\n}\n\nexport const TabSelect: FunctionComponent<TabSelectProps> = ({\n items,\n className,\n 'aria-label': ariaLabel = 'Select tab',\n}) => {\n const activeTab = useActiveTab();\n const dispatch = useTabDispatch();\n\n const handleChange = (_event: Event, value: string) => {\n dispatch({ type: 'update', payload: Number(value) });\n };\n\n const selectValue = activeTab === -1 ? undefined : activeTab;\n\n return (\n <Select\n value={selectValue?.toString()}\n onChange={handleChange}\n name={ariaLabel}\n className={cn(className)}\n >\n {items.map((item) => (\n <option key={item.value} value={item.value}>\n {item.label}\n </option>\n ))}\n </Select>\n );\n};\n\ninterface TabProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onSelect'> {\n /**\n * Notification content\n */\n notification?: ReactNode;\n /**\n * Tab Heading text\n */\n label?: string;\n /**\n * Tab heading index<br/>\n * _Can be **0** or **1** indexed_\n */\n value: number;\n /**\n * on tab select handler\n */\n onSelect?: (context: { value: TabProps['value']; label: TabProps['label'] }) => void;\n /**\n * Heading type\n * _default: **h2**_\n */\n as?: 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5';\n}\n\nexport const Tab: FunctionComponent<PropsWithChildren<TabProps>> = ({\n as: TagName = 'h2',\n label,\n children,\n value,\n onSelect,\n className,\n notification,\n ...attr\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n const activeTab = useActiveTab();\n const uid = useTabsUid();\n const dispatch = useRegisterTabControl({ value, ref: ref as RefObject<HTMLDivElement> });\n const previousActiveTab = useRef(activeTab);\n\n const isActive = useRef(activeTab === value);\n isActive.current = activeTab === value;\n\n const anchorName = `--tab-pill-${uid}` as CSSProperties['anchorName'];\n\n useEffect(() => {\n if (previousActiveTab.current !== activeTab && value === activeTab) {\n ref.current?.focus();\n onSelect?.({ value, label });\n }\n if (previousActiveTab.current !== activeTab) {\n previousActiveTab.current = activeTab;\n }\n }, [label, value, onSelect, activeTab]);\n\n const start = useCallback(() => {\n dispatch({ type: 'start' });\n }, [dispatch]);\n\n const end = useCallback(() => {\n dispatch({ type: 'end' });\n }, [dispatch]);\n\n const up = useCallback(() => {\n dispatch({ type: 'previous' });\n }, [dispatch]);\n\n const down = useCallback(() => {\n dispatch({ type: 'next' });\n }, [dispatch]);\n\n const left = useCallback(() => {\n const isRTL = document.documentElement.dir === 'rtl';\n\n dispatch({ type: isRTL ? 'next' : 'previous' });\n }, [dispatch]);\n\n const right = useCallback(() => {\n const isRTL = document.documentElement.dir === 'rtl';\n\n dispatch({ type: isRTL ? 'previous' : 'next' });\n }, [dispatch]);\n\n const keyboardHandler = useKeyboardControls({\n start,\n end,\n up,\n down,\n left,\n right,\n });\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n const isSpace = e.key === ' ' || e.key === 'Spacebar' || e.code === 'Space';\n const isEnter = e.key === 'Enter' || e.code === 'Enter';\n\n if (isActive.current && (isSpace || isEnter)) {\n e.preventDefault();\n return;\n }\n\n keyboardHandler(e);\n },\n [keyboardHandler],\n );\n\n const handleClick = () => {\n if (isActive.current) {\n return;\n }\n\n dispatch({ type: 'update', payload: value });\n };\n\n return (\n <div\n {...attr}\n id={attr.id || `Tab_${value}_${uid}`}\n data-name=\"Tab\"\n ref={ref}\n role=\"tab\"\n aria-selected={isActive.current}\n aria-controls={`TabPanel_${value}_${uid}`}\n tabIndex={isActive.current ? 0 : -1}\n className={cn(\n 'group/tab text-b3 inline-block cursor-pointer overflow-hidden bg-transparent align-middle font-semibold whitespace-nowrap outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 rounded-pill',\n {\n 'text-white': isActive.current,\n 'text-black': !isActive.current,\n 'transition-transform active:scale-[1.03]': isActive.current,\n '[@supports(not(anchor-name:--x))]:bg-black': isActive.current,\n },\n )}\n onKeyDown={handleKeyDown}\n onClick={handleClick}\n >\n <TagName\n className={cn(\n 'relative inline-block px-20 py-12',\n !isActive.current &&\n 'before:rounded-pill before:transition-colors/opacity before:absolute before:inset-0 before:-z-1 before:duration-300 group-focus-within/tab:before:bg-(--color-pearl) group-hover/tab:before:bg-(--color-pearl) group/tab-focus:before:bg-(--color-pearl)',\n className,\n )}\n style={isActive.current ? { anchorName } : undefined}\n {...(!isActive.current ? { role: 'presentation' } : {})}\n >\n <span className=\"flex items-center gap-8\">\n {children ?? label}\n {notification && (\n <div\n className={cn(\n 'size-18 flex items-center justify-center text-b5 rounded-full bg-saffron text-black transition-colors duration-300',\n {\n 'group-focus-within/tab:bg-darkGrey group-hover/tab:bg-darkGrey group-focus-within/tab:text-pearl group-hover/tab:text-pearl':\n !isActive.current,\n },\n )}\n >\n {notification}\n </div>\n )}\n </span>\n </TagName>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tabs.js","names":[],"sources":["../../../lib/ui/tabs/Tabs.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ComponentProps,\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type FunctionComponent,\n type PropsWithChildren,\n type RefObject,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useRef,\n useState,\n useMemo,\n} from 'react';\n\nimport { TabsProvider } from '../contexts/TabControl';\nimport {\n useActiveTab,\n useActiveTabControl,\n useRegisterTabControl,\n useTabDispatch,\n useTabsUid,\n} from '../hooks/tabControl';\nimport { useKeyboardControls } from '../hooks/useKeyboardControls';\nimport { Select } from '../forms/Select';\nimport { cn } from '../helpers/cn';\nimport { ArrowButton } from '../buttons/ArrowButton';\n\ntype ProviderProps = ComponentProps<typeof TabsProvider>;\n\ninterface Props extends ProviderProps {\n className?: string;\n /**\n * Shrink the spacing between tabs and panels\n */\n compacted?: boolean;\n}\n\nexport const Tabs: FunctionComponent<PropsWithChildren<Props>> = ({\n className,\n compacted = false,\n selected,\n children,\n}) => {\n return (\n <div\n className={cn(\n 'flex flex-col',\n {\n 'sm:gap-y-20': !compacted,\n },\n className,\n )}\n data-name=\"Tabs\"\n >\n <TabsProvider selected={selected}>{children}</TabsProvider>\n </div>\n );\n};\n\ninterface TabsBodyProps {\n className?: string;\n}\n\nexport const TabsBody: FunctionComponent<PropsWithChildren<TabsBodyProps>> = ({\n className,\n children,\n}) => {\n return (\n <div data-name=\"TabsBody\" className={cn('grid grid-rows-1 overflow-hidden', className)}>\n {children}\n </div>\n );\n};\n\ninterface TabPanelProps {\n className?: string;\n /**\n * Tab panel index<br/>\n * _Can be **0** or **1** indexed_\n */\n value: number;\n /**\n * on panel select handler\n */\n onSelect?: (context: { value: TabPanelProps['value'] }) => void;\n}\n\nexport const TabPanel: FunctionComponent<PropsWithChildren<TabPanelProps>> = ({\n value,\n className,\n onSelect,\n children,\n ...attrs\n}) => {\n const uid = useTabsUid();\n const mounted = useRef(false);\n const tabSelected = useActiveTab();\n const isActive = tabSelected === value;\n\n useEffect(() => {\n if (!mounted.current) {\n mounted.current = true;\n return;\n }\n\n if (isActive) {\n onSelect?.({ value });\n }\n }, [isActive, value, onSelect]);\n\n return (\n <div\n {...attrs}\n aria-hidden={!isActive}\n className={cn(\n 'relative col-start-1 row-start-1 transition-opacity duration-500',\n {\n 'pointer-events-none z-0 h-0 opacity-0': !isActive,\n 'pointer-events-auto z-1 h-auto opacity-100': isActive,\n },\n className,\n )}\n inert={isActive ? undefined : true}\n tabIndex={isActive ? 0 : -1}\n id={`TabPanel_${value}_${uid}`}\n data-name={`TabPanel_${value}`}\n role=\"tabpanel\"\n aria-labelledby={`Tab_${value}_${uid}`}\n >\n {children}\n </div>\n );\n};\n\ninterface TabListProps {\n className?: string;\n /**\n * Remove filler placeholders\n */\n constrained?: boolean;\n}\n\nexport const TabList: FunctionComponent<PropsWithChildren<TabListProps>> = ({\n className,\n constrained = false,\n children,\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n const spacerRef = useRef<HTMLDivElement>(null);\n const [, currentControl] = useActiveTabControl();\n const uid = useTabsUid();\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(false);\n\n const anchorName = `--tab-pill-${uid}` as CSSProperties['anchorName'];\n\n const pillStyle = useMemo<CSSProperties>(\n () => ({\n positionAnchor: anchorName,\n top: 'anchor(top)',\n bottom: 'anchor(bottom)',\n left: 'anchor(left)',\n right: 'anchor(right)',\n position: 'absolute',\n }),\n [anchorName],\n );\n\n const updateScrollState = useCallback(() => {\n const el = ref.current;\n if (!el) return;\n setCanScrollLeft(el.scrollLeft > 0);\n setCanScrollRight(Math.ceil(el.scrollLeft) < el.scrollWidth - el.clientWidth);\n }, []);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n updateScrollState();\n\n const observer = new ResizeObserver(updateScrollState);\n observer.observe(el);\n el.addEventListener('scroll', updateScrollState, { passive: true });\n\n return () => {\n observer.disconnect();\n el.removeEventListener('scroll', updateScrollState);\n };\n }, [updateScrollState]);\n\n useEffect(() => {\n if (!currentControl?.current || !ref.current) {\n return;\n }\n\n const spacerWidth = spacerRef.current!.offsetWidth ?? 0;\n const currentRect = currentControl.current.getBoundingClientRect();\n const containerRect = ref.current!.getBoundingClientRect();\n\n ref.current.scrollBy({\n left: currentRect.left - containerRect.left - spacerWidth,\n behavior: 'smooth',\n });\n }, [currentControl]);\n\n const scrollRafRef = useRef<number | null>(null);\n\n const stopScroll = useCallback(() => {\n if (scrollRafRef.current !== null) {\n cancelAnimationFrame(scrollRafRef.current);\n scrollRafRef.current = null;\n }\n }, []);\n\n const startScroll = useCallback((direction: -1 | 1) => {\n if (scrollRafRef.current !== null) return;\n const step = () => {\n ref.current?.scrollBy({ left: direction * 6 });\n scrollRafRef.current = requestAnimationFrame(step);\n };\n scrollRafRef.current = requestAnimationFrame(step);\n }, []);\n\n const handleScrollKeyUp = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') stopScroll();\n },\n [stopScroll],\n );\n\n const handleScrollLeftKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n startScroll(-1);\n }\n },\n [startScroll],\n );\n\n const handleScrollRightKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n startScroll(1);\n }\n },\n [startScroll],\n );\n\n useEffect(() => stopScroll, [stopScroll]);\n\n const isScrollable = canScrollLeft || canScrollRight;\n\n return (\n <div className=\"relative\" data-name=\"TabsHeader\">\n {isScrollable && (\n <div className=\"pointer-events-none absolute inset-y-0 left-0 z-10 flex items-center\">\n <ArrowButton\n icon=\"ArrowDefaultLeft\"\n size=\"small\"\n className={cn(\n 'pointer-events-auto transition-opacity duration-200 focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n canScrollLeft ? 'opacity-100' : 'pointer-events-none opacity-0',\n )}\n onPointerDown={() => startScroll(-1)}\n onPointerUp={stopScroll}\n onPointerLeave={stopScroll}\n onKeyDown={handleScrollLeftKeyDown}\n onKeyUp={handleScrollKeyUp}\n inert={!canScrollLeft}\n tabIndex={canScrollLeft ? 0 : -1}\n >\n Scroll tabs left\n </ArrowButton>\n </div>\n )}\n <div\n className={cn(\n 'scrollbar-hidden relative isolate flex max-w-full overflow-x-auto py-20',\n className,\n )}\n ref={ref}\n >\n <div role=\"tablist\" className=\"relative flex flex-row\">\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute rounded-pill bg-black transition-all duration-300\"\n style={pillStyle}\n />\n <div\n ref={spacerRef}\n className={cn('shrink-0', {\n 'w-16 lg:w-[max(calc((100vw-1212px)/2),116px)] xl:w-[max(calc((100vw-1212px)/2),156px)]':\n !constrained,\n })}\n />\n {children}\n <div\n className={cn('shrink-0', {\n 'w-16 lg:w-[max(calc((100vw-1212px)/2),116px)] xl:w-[max(calc((100vw-1212px)/2),156px)]':\n !constrained,\n })}\n />\n </div>\n </div>\n {isScrollable && (\n <div className=\"pointer-events-none absolute inset-y-0 right-0 z-10 flex items-center\">\n <ArrowButton\n icon=\"ArrowDefaultRight\"\n size=\"small\"\n className={cn(\n 'pointer-events-auto transition-opacity duration-200 focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n canScrollRight ? 'opacity-100' : 'pointer-events-none opacity-0',\n )}\n onPointerDown={() => startScroll(1)}\n onPointerUp={stopScroll}\n onPointerLeave={stopScroll}\n onKeyDown={handleScrollRightKeyDown}\n onKeyUp={handleScrollKeyUp}\n inert={!canScrollRight}\n tabIndex={canScrollRight ? 0 : -1}\n >\n Scroll tabs right\n </ArrowButton>\n </div>\n )}\n </div>\n );\n};\n\nexport interface TabSelectProps {\n items: { label: string; value: number }[];\n className?: string;\n 'aria-label'?: string;\n}\n\nexport const TabSelect: FunctionComponent<TabSelectProps> = ({\n items,\n className,\n 'aria-label': ariaLabel = 'Select tab',\n}) => {\n const activeTab = useActiveTab();\n const dispatch = useTabDispatch();\n\n const handleChange = (_event: Event, value: string) => {\n dispatch({ type: 'update', payload: Number(value) });\n };\n\n const selectValue = activeTab === -1 ? undefined : activeTab;\n\n return (\n <Select\n value={selectValue?.toString()}\n onChange={handleChange}\n name={ariaLabel}\n className={cn(className)}\n >\n {items.map((item) => (\n <option key={item.value} value={item.value}>\n {item.label}\n </option>\n ))}\n </Select>\n );\n};\n\ninterface TabProps extends Omit<ComponentPropsWithoutRef<'div'>, 'onSelect'> {\n /**\n * Notification content\n */\n notification?: ReactNode;\n /**\n * Tab Heading text\n */\n label?: string;\n /**\n * Tab heading index<br/>\n * _Can be **0** or **1** indexed_\n */\n value: number;\n /**\n * on tab select handler\n */\n onSelect?: (context: { value: TabProps['value']; label: TabProps['label'] }) => void;\n /**\n * Heading type\n * _default: **h2**_\n */\n as?: 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5';\n}\n\nexport const Tab: FunctionComponent<PropsWithChildren<TabProps>> = ({\n as: TagName = 'h2',\n label,\n children,\n value,\n onSelect,\n className,\n notification,\n ...attr\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n const activeTab = useActiveTab();\n const uid = useTabsUid();\n const dispatch = useRegisterTabControl({ value, ref: ref as RefObject<HTMLDivElement> });\n const previousActiveTab = useRef(activeTab);\n\n const isActive = useRef(activeTab === value);\n isActive.current = activeTab === value;\n\n const anchorName = `--tab-pill-${uid}` as CSSProperties['anchorName'];\n\n useEffect(() => {\n if (previousActiveTab.current !== activeTab && value === activeTab) {\n ref.current?.focus();\n onSelect?.({ value, label });\n }\n if (previousActiveTab.current !== activeTab) {\n previousActiveTab.current = activeTab;\n }\n }, [label, value, onSelect, activeTab]);\n\n const start = useCallback(() => {\n dispatch({ type: 'start' });\n }, [dispatch]);\n\n const end = useCallback(() => {\n dispatch({ type: 'end' });\n }, [dispatch]);\n\n const up = useCallback(() => {\n dispatch({ type: 'previous' });\n }, [dispatch]);\n\n const down = useCallback(() => {\n dispatch({ type: 'next' });\n }, [dispatch]);\n\n const left = useCallback(() => {\n const isRTL = document.documentElement.dir === 'rtl';\n\n dispatch({ type: isRTL ? 'next' : 'previous' });\n }, [dispatch]);\n\n const right = useCallback(() => {\n const isRTL = document.documentElement.dir === 'rtl';\n\n dispatch({ type: isRTL ? 'previous' : 'next' });\n }, [dispatch]);\n\n const keyboardHandler = useKeyboardControls({\n start,\n end,\n up,\n down,\n left,\n right,\n });\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n const isSpace = e.key === ' ' || e.key === 'Spacebar' || e.code === 'Space';\n const isEnter = e.key === 'Enter' || e.code === 'Enter';\n\n if (isActive.current && (isSpace || isEnter)) {\n e.preventDefault();\n return;\n }\n\n keyboardHandler(e);\n },\n [keyboardHandler],\n );\n\n const handleClick = () => {\n if (isActive.current) {\n return;\n }\n\n dispatch({ type: 'update', payload: value });\n };\n\n return (\n <div\n {...attr}\n id={attr.id || `Tab_${value}_${uid}`}\n data-name=\"Tab\"\n ref={ref}\n role=\"tab\"\n aria-selected={isActive.current}\n aria-controls={`TabPanel_${value}_${uid}`}\n tabIndex={isActive.current ? 0 : -1}\n className={cn(\n 'group/tab text-b3 inline-block cursor-pointer overflow-hidden bg-transparent align-middle font-semibold whitespace-nowrap outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 rounded-pill',\n {\n 'text-white': isActive.current,\n 'text-black': !isActive.current,\n 'transition-transform active:scale-[1.03]': isActive.current,\n '[@supports(not(anchor-name:--x))]:bg-black': isActive.current,\n },\n )}\n onKeyDown={handleKeyDown}\n onClick={handleClick}\n >\n <TagName\n className={cn(\n 'relative inline-block px-20 py-12',\n !isActive.current &&\n 'before:rounded-pill before:transition-colors/opacity before:absolute before:inset-0 before:-z-1 before:duration-300 group-focus-within/tab:before:bg-(--color-pearl) group-hover/tab:before:bg-(--color-pearl) group/tab-focus:before:bg-(--color-pearl)',\n className,\n )}\n style={isActive.current ? { anchorName } : undefined}\n {...(!isActive.current ? { role: 'presentation' } : {})}\n >\n <span className=\"flex items-center gap-8\">\n {children ?? label}\n {notification && (\n <div\n className={cn(\n 'size-18 flex items-center justify-center text-b5 rounded-full bg-saffron text-black transition-colors duration-300',\n {\n 'group-focus-within/tab:bg-darkGrey group-hover/tab:bg-darkGrey group-focus-within/tab:text-pearl group-hover/tab:text-pearl':\n !isActive.current,\n },\n )}\n >\n {notification}\n </div>\n )}\n </span>\n </TagName>\n </div>\n );\n};\n"],"mappings":"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"}