@clubmed/trident-ui 2.0.0-beta.41 → 2.0.0-beta.42

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 CountdownDemo(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { Countdown as e } from "../ui/Countdown.js";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ //#region lib/examples/countdown-demo.tsx
5
+ var r = {
6
+ days: "days",
7
+ hours: "hours",
8
+ minutes: "minutes",
9
+ seconds: "seconds"
10
+ }, i = /* @__PURE__ */ new Date();
11
+ i.setDate(i.getDate() + 1);
12
+ var a = /* @__PURE__ */ new Date();
13
+ a.setDate(a.getDate() + 7);
14
+ function o() {
15
+ return /* @__PURE__ */ n("div", {
16
+ className: "flex flex-col gap-8",
17
+ children: [/* @__PURE__ */ t(e, {
18
+ countdown: {
19
+ to: i.toISOString(),
20
+ labels: r
21
+ },
22
+ theme: "saffron"
23
+ }), /* @__PURE__ */ t("div", {
24
+ className: "bg-ultramarine p-6 rounded-16",
25
+ children: /* @__PURE__ */ t(e, {
26
+ countdown: {
27
+ to: a.toISOString(),
28
+ labels: r
29
+ },
30
+ theme: "white",
31
+ className: "text-white"
32
+ })
33
+ })]
34
+ });
35
+ }
36
+ //#endregion
37
+ export { o as default };
38
+
39
+ //# sourceMappingURL=countdown-demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"countdown-demo.js","names":[],"sources":["../../lib/examples/countdown-demo.tsx"],"sourcesContent":["'use client';\n\nimport { Countdown } from '@/ui/Countdown';\n\nconst labels = {\n days: 'days',\n hours: 'hours',\n minutes: 'minutes',\n seconds: 'seconds',\n};\n\nconst tomorrow = new Date();\ntomorrow.setDate(tomorrow.getDate() + 1);\n\nconst nextWeek = new Date();\nnextWeek.setDate(nextWeek.getDate() + 7);\n\nexport default function CountdownDemo() {\n return (\n <div className=\"flex flex-col gap-8\">\n <Countdown countdown={{ to: tomorrow.toISOString(), labels }} theme=\"saffron\" />\n <div className=\"bg-ultramarine p-6 rounded-16\">\n <Countdown\n countdown={{ to: nextWeek.toISOString(), labels }}\n theme=\"white\"\n className=\"text-white\"\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAIA,IAAM,IAAS;CACb,MAAM;CACN,OAAO;CACP,SAAS;CACT,SAAS;CACV,EAEK,oBAAW,IAAI,MAAM;AAC3B,EAAS,QAAQ,EAAS,SAAS,GAAG,EAAE;AAExC,IAAM,oBAAW,IAAI,MAAM;AAC3B,EAAS,QAAQ,EAAS,SAAS,GAAG,EAAE;AAExC,SAAwB,IAAgB;AACtC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GAAW,WAAW;IAAE,IAAI,EAAS,aAAa;IAAE;IAAQ;GAAE,OAAM;GAAY,CAAA,EAChF,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACE,WAAW;KAAE,IAAI,EAAS,aAAa;KAAE;KAAQ;IACjD,OAAM;IACN,WAAU;IACV,CAAA;GACE,CAAA,CAAA"}
@@ -0,0 +1 @@
1
+ export default function FloatingLabelTextFieldDemo(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { FloatingLabelTextField as e } from "../ui/forms/FloatingLabelTextField.js";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ //#region lib/examples/floating-label-text-field-demo.tsx
5
+ function r() {
6
+ return /* @__PURE__ */ n("div", {
7
+ className: "flex flex-col gap-16 w-full max-w-[496px]",
8
+ children: [
9
+ /* @__PURE__ */ t(e, { label: "Select" }),
10
+ /* @__PURE__ */ t(e, {
11
+ label: "Select",
12
+ value: "First value of the list",
13
+ hasDropdown: !0
14
+ }),
15
+ /* @__PURE__ */ t(e, {
16
+ label: "Select",
17
+ value: "First value of the list",
18
+ validationStatus: "error",
19
+ errorMessage: "Please select a value",
20
+ hasDropdown: !0
21
+ }),
22
+ /* @__PURE__ */ t(e, {
23
+ label: "Select",
24
+ disabled: !0
25
+ })
26
+ ]
27
+ });
28
+ }
29
+ //#endregion
30
+ export { r as default };
31
+
32
+ //# sourceMappingURL=floating-label-text-field-demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-label-text-field-demo.js","names":[],"sources":["../../lib/examples/floating-label-text-field-demo.tsx"],"sourcesContent":["'use client';\n\nimport { FloatingLabelTextField } from '@/ui/forms/FloatingLabelTextField';\n\nexport default function FloatingLabelTextFieldDemo() {\n return (\n <div className=\"flex flex-col gap-16 w-full max-w-[496px]\">\n <FloatingLabelTextField label=\"Select\" />\n\n <FloatingLabelTextField label=\"Select\" value=\"First value of the list\" hasDropdown />\n\n <FloatingLabelTextField\n label=\"Select\"\n value=\"First value of the list\"\n validationStatus=\"error\"\n errorMessage=\"Please select a value\"\n hasDropdown\n />\n\n <FloatingLabelTextField label=\"Select\" disabled />\n </div>\n );\n}\n"],"mappings":";;;;AAIA,SAAwB,IAA6B;AACnD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAwB,OAAM,UAAW,CAAA;GAEzC,kBAAC,GAAD;IAAwB,OAAM;IAAS,OAAM;IAA0B,aAAA;IAAc,CAAA;GAErF,kBAAC,GAAD;IACE,OAAM;IACN,OAAM;IACN,kBAAiB;IACjB,cAAa;IACb,aAAA;IACA,CAAA;GAEF,kBAAC,GAAD;IAAwB,OAAM;IAAS,UAAA;IAAW,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clubmed/trident-ui",
3
- "version": "2.0.0-beta.41",
3
+ "version": "2.0.0-beta.42",
4
4
  "type": "module",
5
5
  "description": "Shared ClubMed React UI components",
6
6
  "keywords": [
package/styles/theme.css CHANGED
@@ -1,7 +1,5 @@
1
1
  @theme {
2
2
  /* Colors */
3
-
4
- --color-*: initial;
5
3
  --color-current: currentColor;
6
4
  --color-transparent: transparent;
7
5
 
@@ -0,0 +1,16 @@
1
+ import { ComponentProps } from 'react';
2
+ import { Theme } from './types/Theme';
3
+ export interface CountdownLabels {
4
+ days: string;
5
+ hours: string;
6
+ minutes: string;
7
+ seconds: string;
8
+ }
9
+ export interface CountdownProps extends Omit<ComponentProps<'div'>, 'children'> {
10
+ countdown: {
11
+ labels: CountdownLabels;
12
+ to: string;
13
+ };
14
+ theme?: Theme;
15
+ }
16
+ export declare function Countdown({ className, countdown, theme, ...props }: CountdownProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { t as e } from "../chunks/clsx.js";
3
+ import { FlipCard as t } from "./FlipCard.js";
4
+ import { useEffect as n, useState as r } from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ //#region lib/ui/Countdown.tsx
7
+ var o = 1e3, s = o * 60, c = s * 60, l = c * 24, u = (e) => Math.max(Math.floor(e / l), 0), d = (e) => Math.max(Math.floor(e % l / c), 0), f = (e) => Math.max(Math.floor(e % c / s), 0), p = (e) => Math.max(Math.floor(e % s / o), 0);
8
+ function m({ className: n, countdown: r, theme: o = "white", ...s }) {
9
+ let { to: c, labels: l } = r, [u, d, f, p] = h(c), m = [
10
+ [u, l.days],
11
+ [d, l.hours],
12
+ [f, l.minutes],
13
+ [p, l.seconds]
14
+ ];
15
+ return /* @__PURE__ */ i("div", {
16
+ "data-name": "Countdown",
17
+ role: "timer",
18
+ ...s,
19
+ dir: "ltr",
20
+ className: e("flex gap-x-4", n),
21
+ children: m.map(([e, n], r) => {
22
+ let s = m.slice(0, r).every(([e]) => e === 0), c = e === 0 && s ? "black" : o;
23
+ return /* @__PURE__ */ a("div", {
24
+ className: "space-y-4",
25
+ children: [/* @__PURE__ */ i("div", {
26
+ className: "flex flex-row items-center gap-x-2 px-2",
27
+ children: e.toString().padStart(2, "0").split("").map((e, n) => /* @__PURE__ */ i(t, {
28
+ theme: c,
29
+ value: parseInt(e)
30
+ }, n))
31
+ }), /* @__PURE__ */ i("span", {
32
+ className: "text-b5 block max-w-58 truncate text-center",
33
+ children: n
34
+ })]
35
+ }, n);
36
+ })
37
+ });
38
+ }
39
+ function h(e) {
40
+ let t = new Date(e).getTime(), i = t - Date.now(), [a, o] = r(() => u(i)), [s, c] = r(() => d(i)), [l, m] = r(() => f(i)), [h, g] = r(() => p(i));
41
+ return n(() => {
42
+ let e = setInterval(() => {
43
+ let n = t - Date.now();
44
+ if (n < 0) {
45
+ clearInterval(e);
46
+ return;
47
+ }
48
+ o(u(n)), c(d(n)), m(f(n)), g(p(n));
49
+ }, 1e3);
50
+ return () => clearInterval(e);
51
+ }, [t]), [
52
+ a,
53
+ s,
54
+ l,
55
+ h
56
+ ];
57
+ }
58
+ //#endregion
59
+ export { m as Countdown };
60
+
61
+ //# sourceMappingURL=Countdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Countdown.js","names":[],"sources":["../../lib/ui/Countdown.tsx"],"sourcesContent":["'use client';\nimport type { ComponentProps } from 'react';\nimport { useEffect, useState } from 'react';\nimport clsx from 'clsx';\n\nimport { FlipCard } from './FlipCard';\nimport type { Theme } from './types/Theme';\n\nexport interface CountdownLabels {\n days: string;\n hours: string;\n minutes: string;\n seconds: string;\n}\n\nexport interface CountdownProps extends Omit<ComponentProps<'div'>, 'children'> {\n countdown: {\n labels: CountdownLabels;\n to: string;\n };\n theme?: Theme;\n}\n\nconst ONE_SEC = 1000;\nconst ONE_MIN = ONE_SEC * 60;\nconst ONE_HOUR = ONE_MIN * 60;\nconst ONE_DAY = ONE_HOUR * 24;\n\nconst getDay = (distance: number) => Math.max(Math.floor(distance / ONE_DAY), 0);\nconst getHour = (distance: number) => Math.max(Math.floor((distance % ONE_DAY) / ONE_HOUR), 0);\nconst getMinute = (distance: number) => Math.max(Math.floor((distance % ONE_HOUR) / ONE_MIN), 0);\nconst getSecond = (distance: number) => Math.max(Math.floor((distance % ONE_MIN) / ONE_SEC), 0);\n\nexport function Countdown({ className, countdown, theme = 'white', ...props }: CountdownProps) {\n const { to, labels } = countdown;\n const [days, hours, minutes, seconds] = useCountdown(to);\n\n const structure: [number, string][] = [\n [days, labels.days],\n [hours, labels.hours],\n [minutes, labels.minutes],\n [seconds, labels.seconds],\n ];\n\n return (\n <div\n data-name=\"Countdown\"\n role=\"timer\"\n {...props}\n dir=\"ltr\"\n className={clsx('flex gap-x-4', className)}\n >\n {structure.map(([division, label], index) => {\n const areAllPreviousZero = structure.slice(0, index).every(([d]) => d === 0);\n const divisionTheme = division === 0 && areAllPreviousZero ? 'black' : theme;\n\n return (\n <div className=\"space-y-4\" key={label}>\n <div className=\"flex flex-row items-center gap-x-2 px-2\">\n {division\n .toString()\n .padStart(2, '0')\n .split('')\n .map((digit, i) => (\n <FlipCard key={i} theme={divisionTheme} value={parseInt(digit)} />\n ))}\n </div>\n <span className=\"text-b5 block max-w-58 truncate text-center\">{label}</span>\n </div>\n );\n })}\n </div>\n );\n}\n\nfunction useCountdown(to: string): [number, number, number, number] {\n const toMs = new Date(to).getTime();\n const distance = toMs - Date.now();\n const [days, setDays] = useState(() => getDay(distance));\n const [hours, setHours] = useState(() => getHour(distance));\n const [minutes, setMinutes] = useState(() => getMinute(distance));\n const [seconds, setSeconds] = useState(() => getSecond(distance));\n\n useEffect(() => {\n const interval = setInterval(() => {\n const dist = toMs - Date.now();\n if (dist < 0) {\n clearInterval(interval);\n return;\n }\n setDays(getDay(dist));\n setHours(getHour(dist));\n setMinutes(getMinute(dist));\n setSeconds(getSecond(dist));\n }, 1000);\n\n return () => clearInterval(interval);\n }, [toMs]);\n\n return [days, hours, minutes, seconds];\n}\n"],"mappings":";;;;;;AAuBA,IAAM,IAAU,KACV,IAAU,IAAU,IACpB,IAAW,IAAU,IACrB,IAAU,IAAW,IAErB,KAAU,MAAqB,KAAK,IAAI,KAAK,MAAM,IAAW,EAAQ,EAAE,EAAE,EAC1E,KAAW,MAAqB,KAAK,IAAI,KAAK,MAAO,IAAW,IAAW,EAAS,EAAE,EAAE,EACxF,KAAa,MAAqB,KAAK,IAAI,KAAK,MAAO,IAAW,IAAY,EAAQ,EAAE,EAAE,EAC1F,KAAa,MAAqB,KAAK,IAAI,KAAK,MAAO,IAAW,IAAW,EAAQ,EAAE,EAAE;AAE/F,SAAgB,EAAU,EAAE,cAAW,cAAW,WAAQ,SAAS,GAAG,KAAyB;CAC7F,IAAM,EAAE,OAAI,cAAW,GACjB,CAAC,GAAM,GAAO,GAAS,KAAW,EAAa,EAAG,EAElD,IAAgC;EACpC,CAAC,GAAM,EAAO,KAAK;EACnB,CAAC,GAAO,EAAO,MAAM;EACrB,CAAC,GAAS,EAAO,QAAQ;EACzB,CAAC,GAAS,EAAO,QAAA;EAClB;AAED,QACE,kBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,GAAI;EACJ,KAAI;EACJ,WAAW,EAAK,gBAAgB,EAAU;YAEzC,EAAU,KAAK,CAAC,GAAU,IAAQ,MAAU;GAC3C,IAAM,IAAqB,EAAU,MAAM,GAAG,EAAM,CAAC,OAAO,CAAC,OAAO,MAAM,EAAE,EACtE,IAAgB,MAAa,KAAK,IAAqB,UAAU;AAEvE,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACZ,EACE,UAAU,CACV,SAAS,GAAG,IAAI,CAChB,MAAM,GAAG,CACT,KAAK,GAAO,MACX,kBAAC,GAAD;MAAkB,OAAO;MAAe,OAAO,SAAS,EAAA;MAAU,EAAnD,EAAmD,CAAA;KAElE,CAAA,EACN,kBAAC,QAAD;KAAM,WAAU;eAA+C;KAAa,CAAA,CAAA;MAV9C,EAW1B;;EAGN,CAAA;;AAIV,SAAS,EAAa,GAA8C;CAClE,IAAM,IAAO,IAAI,KAAK,EAAG,CAAC,SAAS,EAC7B,IAAW,IAAO,KAAK,KAAK,EAC5B,CAAC,GAAM,KAAW,QAAe,EAAO,EAAS,CAAC,EAClD,CAAC,GAAO,KAAY,QAAe,EAAQ,EAAS,CAAC,EACrD,CAAC,GAAS,KAAc,QAAe,EAAU,EAAS,CAAC,EAC3D,CAAC,GAAS,KAAc,QAAe,EAAU,EAAS,CAAC;AAkBjE,QAhBA,QAAgB;EACd,IAAM,IAAW,kBAAkB;GACjC,IAAM,IAAO,IAAO,KAAK,KAAK;AAC9B,OAAI,IAAO,GAAG;AACZ,kBAAc,EAAS;AACvB;;AAKF,GAHA,EAAQ,EAAO,EAAK,CAAC,EACrB,EAAS,EAAQ,EAAK,CAAC,EACvB,EAAW,EAAU,EAAK,CAAC,EAC3B,EAAW,EAAU,EAAK,CAAC;KAC1B,IAAK;AAER,eAAa,cAAc,EAAS;IACnC,CAAC,EAAK,CAAC,EAEH;EAAC;EAAM;EAAO;EAAS;EAAQ"}
@@ -0,0 +1,7 @@
1
+ import { ComponentProps } from 'react';
2
+ import { Theme } from './types/Theme';
3
+ export interface FlipCardProps extends Omit<ComponentProps<'div'>, 'children'> {
4
+ theme?: Theme;
5
+ value: number;
6
+ }
7
+ export declare function FlipCard({ className, theme, value, ...props }: FlipCardProps): import("react/jsx-runtime").JSX.Element;
package/ui/FlipCard.js ADDED
@@ -0,0 +1,59 @@
1
+ "use client";
2
+ import { t as e } from "../chunks/clsx.js";
3
+ import { getBgColor as t, getComplementaryTextColor as n, getThemeColor as r } from "./helpers/colors/colors.js";
4
+ import { useEffect as i, useRef as a, useState as o } from "react";
5
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
6
+ //#region lib/ui/FlipCard.tsx
7
+ var l = "flex w-full justify-center overflow-hidden", u = e(l, "relative h-full"), d = e(u, "rounded-16 rounded-b-4"), f = e(u, "rounded-16 rounded-t-4"), p = e(l, "absolute inset-x-0 h-16 w-full"), m = e(p, "rounded-16 rounded-b-4 top-0 origin-bottom [transform:rotateX(0deg)] [backface-visibility:hidden] [transform-style:preserve-3d]"), h = e(p, "rounded-16 rounded-t-4 top-16 origin-top [transform:rotateX(180deg)] [backface-visibility:hidden] [transform-style:preserve-3d]");
8
+ function g({ className: a, theme: l = "white", value: u, ...p }) {
9
+ let [g, v] = o(0), [y, b] = o(!1), x = _(g);
10
+ i(() => {
11
+ u !== x && (v(u), b((e) => !e));
12
+ }, [u, x]);
13
+ let S = r(l), C = t(S), w = n(S);
14
+ return /* @__PURE__ */ c("div", {
15
+ ...p,
16
+ role: "figure",
17
+ className: e("relative isolate grid h-32 w-22 grid-rows-2 [perspective:40px] [perspective-origin:50%_50%]", a),
18
+ children: [
19
+ /* @__PURE__ */ s("div", {
20
+ className: e(d, C),
21
+ children: /* @__PURE__ */ s("span", {
22
+ className: e("text-b4 translate-y-1/3", w),
23
+ children: g
24
+ })
25
+ }),
26
+ /* @__PURE__ */ s("div", {
27
+ className: e(f, C),
28
+ children: /* @__PURE__ */ s("span", {
29
+ className: e("text-b4 -translate-y-2/3", w),
30
+ children: x
31
+ })
32
+ }),
33
+ /* @__PURE__ */ s("div", {
34
+ className: e(y ? m : h, C, y ? "animate-tick" : "animate-tock"),
35
+ children: /* @__PURE__ */ s("span", {
36
+ className: e("text-b4", y ? "translate-y-1/3" : "-translate-y-2/3", w),
37
+ children: y ? x : g
38
+ })
39
+ }),
40
+ /* @__PURE__ */ s("div", {
41
+ className: e(y ? h : m, C, y ? "animate-tock" : "animate-tick"),
42
+ children: /* @__PURE__ */ s("span", {
43
+ className: e("text-b4", y ? "-translate-y-2/3" : "translate-y-1/3", w),
44
+ children: y ? g : x
45
+ })
46
+ })
47
+ ]
48
+ });
49
+ }
50
+ function _(e) {
51
+ let t = a(0);
52
+ return i(() => {
53
+ t.current = e;
54
+ }, [e]), t.current;
55
+ }
56
+ //#endregion
57
+ export { g as FlipCard };
58
+
59
+ //# sourceMappingURL=FlipCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlipCard.js","names":[],"sources":["../../lib/ui/FlipCard.tsx"],"sourcesContent":["'use client';\nimport type { ComponentProps } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\n\nimport { getBgColor, getComplementaryTextColor, getThemeColor } from './helpers/colors/colors';\nimport type { Theme } from './types/Theme';\n\nexport interface FlipCardProps extends Omit<ComponentProps<'div'>, 'children'> {\n theme?: Theme;\n value: number;\n}\n\nconst commonSection = 'flex w-full justify-center overflow-hidden';\nconst staticCard = clsx(commonSection, 'relative h-full');\nconst staticTop = clsx(staticCard, 'rounded-16 rounded-b-4');\nconst staticBottom = clsx(staticCard, 'rounded-16 rounded-t-4');\n\nconst animatedCard = clsx(commonSection, 'absolute inset-x-0 h-16 w-full');\nconst animatedTop = clsx(\n animatedCard,\n 'rounded-16 rounded-b-4 top-0 origin-bottom [transform:rotateX(0deg)] [backface-visibility:hidden] [transform-style:preserve-3d]',\n);\nconst animatedBottom = clsx(\n animatedCard,\n 'rounded-16 rounded-t-4 top-16 origin-top [transform:rotateX(180deg)] [backface-visibility:hidden] [transform-style:preserve-3d]',\n);\n\nexport function FlipCard({ className, theme = 'white', value, ...props }: FlipCardProps) {\n const [currentNumber, setCurrentNumber] = useState(0);\n const [tick, setTick] = useState(false);\n const previousNumber = usePrevious(currentNumber);\n\n useEffect(() => {\n if (value === previousNumber) return;\n setCurrentNumber(value);\n setTick((t) => !t);\n }, [value, previousNumber]);\n\n const themeColor = getThemeColor(theme);\n const thBackground = getBgColor(themeColor);\n const thText = getComplementaryTextColor(themeColor);\n\n return (\n <div\n {...props}\n role=\"figure\"\n className={clsx(\n 'relative isolate grid h-32 w-22 grid-rows-2 [perspective:40px] [perspective-origin:50%_50%]',\n className,\n )}\n >\n <div className={clsx(staticTop, thBackground)}>\n <span className={clsx('text-b4 translate-y-1/3', thText)}>{currentNumber}</span>\n </div>\n <div className={clsx(staticBottom, thBackground)}>\n <span className={clsx('text-b4 -translate-y-2/3', thText)}>{previousNumber}</span>\n </div>\n <div\n className={clsx(\n tick ? animatedTop : animatedBottom,\n thBackground,\n tick ? 'animate-tick' : 'animate-tock',\n )}\n >\n <span className={clsx('text-b4', tick ? 'translate-y-1/3' : '-translate-y-2/3', thText)}>\n {tick ? previousNumber : currentNumber}\n </span>\n </div>\n <div\n className={clsx(\n tick ? animatedBottom : animatedTop,\n thBackground,\n tick ? 'animate-tock' : 'animate-tick',\n )}\n >\n <span className={clsx('text-b4', tick ? '-translate-y-2/3' : 'translate-y-1/3', thText)}>\n {tick ? currentNumber : previousNumber}\n </span>\n </div>\n </div>\n );\n}\n\nfunction usePrevious(currentValue: number) {\n const ref = useRef(0);\n useEffect(() => {\n ref.current = currentValue;\n }, [currentValue]);\n return ref.current;\n}\n"],"mappings":";;;;;;AAaA,IAAM,IAAgB,8CAChB,IAAa,EAAK,GAAe,kBAAkB,EACnD,IAAY,EAAK,GAAY,yBAAyB,EACtD,IAAe,EAAK,GAAY,yBAAyB,EAEzD,IAAe,EAAK,GAAe,iCAAiC,EACpE,IAAc,EAClB,GACA,kIACD,EACK,IAAiB,EACrB,GACA,kIACD;AAED,SAAgB,EAAS,EAAE,cAAW,WAAQ,SAAS,UAAO,GAAG,KAAwB;CACvF,IAAM,CAAC,GAAe,KAAoB,EAAS,EAAE,EAC/C,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,IAAiB,EAAY,EAAc;AAEjD,SAAgB;AACV,QAAU,MACd,EAAiB,EAAM,EACvB,GAAS,MAAM,CAAC,EAAE;IACjB,CAAC,GAAO,EAAe,CAAC;CAE3B,IAAM,IAAa,EAAc,EAAM,EACjC,IAAe,EAAW,EAAW,EACrC,IAAS,EAA0B,EAAW;AAEpD,QACE,kBAAC,OAAD;EACE,GAAI;EACJ,MAAK;EACL,WAAW,EACT,+FACA,EACD;YANH;GAQE,kBAAC,OAAD;IAAK,WAAW,EAAK,GAAW,EAAa;cAC3C,kBAAC,QAAD;KAAM,WAAW,EAAK,2BAA2B,EAAO;eAAG;KAAqB,CAAA;IAC5E,CAAA;GACN,kBAAC,OAAD;IAAK,WAAW,EAAK,GAAc,EAAa;cAC9C,kBAAC,QAAD;KAAM,WAAW,EAAK,4BAA4B,EAAO;eAAG;KAAsB,CAAA;IAC9E,CAAA;GACN,kBAAC,OAAD;IACE,WAAW,EACT,IAAO,IAAc,GACrB,GACA,IAAO,iBAAiB,eACzB;cAED,kBAAC,QAAD;KAAM,WAAW,EAAK,WAAW,IAAO,oBAAoB,oBAAoB,EAAO;eACpF,IAAO,IAAiB;KACpB,CAAA;IACH,CAAA;GACN,kBAAC,OAAD;IACE,WAAW,EACT,IAAO,IAAiB,GACxB,GACA,IAAO,iBAAiB,eACzB;cAED,kBAAC,QAAD;KAAM,WAAW,EAAK,WAAW,IAAO,qBAAqB,mBAAmB,EAAO;eACpF,IAAO,IAAgB;KACnB,CAAA;IACH,CAAA;;;;AAKZ,SAAS,EAAY,GAAsB;CACzC,IAAM,IAAM,EAAO,EAAE;AAIrB,QAHA,QAAgB;AACd,IAAI,UAAU;IACb,CAAC,EAAa,CAAC,EACX,EAAI"}
@@ -0,0 +1,12 @@
1
+ import { UseValueProps } from '../hooks/useValue';
2
+ import { IconicNames, IconicTypes } from '@clubmed/trident-icons';
3
+ import { FormControlProps } from './FormControl';
4
+ export interface FloatingLabelTextFieldProps<Value = string> extends FormControlProps<Value> {
5
+ icon?: IconicNames;
6
+ iconType?: IconicTypes;
7
+ formatter?: UseValueProps<Value>['formatter'];
8
+ hasDropdown?: boolean;
9
+ clear?: string;
10
+ iconFirst?: boolean;
11
+ }
12
+ export declare const FloatingLabelTextField: <Value = string>(props: FloatingLabelTextFieldProps<Value>) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,132 @@
1
+ "use client";
2
+ import { t as e } from "../../chunks/clsx.js";
3
+ import { FormControlError as t } from "./FormControlError.js";
4
+ import { useInternalStatus as n } from "../hooks/useInternalStatus.js";
5
+ import { useValue as r } from "../hooks/useValue.js";
6
+ import { useId as i, useRef as a, useState as o } from "react";
7
+ import { Icon as s } from "@clubmed/trident-icons";
8
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
9
+ //#region lib/ui/forms/FloatingLabelTextField.tsx
10
+ var u = (u) => {
11
+ let d = i(), { id: f = d, name: p = f, label: m, labelClassName: h, value: g, validationStatus: _ = "default", errorMessage: v, disabled: y = !1, required: b = !1, hideRequiredStar: x, description: S, icon: C, iconType: w, iconFirst: T = !0, hasDropdown: E = !1, clear: D = "", className: O, dataTestId: k, dataName: A, "data-testid": j, onChange: M, formatter: N, ...P } = u, { value: F, setValue: I } = r({
12
+ initialValue: g,
13
+ onChange: M,
14
+ formatter: N
15
+ }), L = n({
16
+ isDisabled: y,
17
+ validationStatus: _
18
+ }), [R, z] = o(!1), B = a(null), V = R || F !== "" && F != null, H = L === "error" && v, U = !y && F !== "" && F != null && !!D, W = Number(!!C && T), G = Number(!!C && !T) + Number(U || E) + Number(L === "error" || L === "success");
19
+ return /* @__PURE__ */ l("div", {
20
+ className: e("flex flex-col gap-4", O),
21
+ "data-name": A ?? "FloatingLabelTextField",
22
+ "data-testid": j ?? k,
23
+ children: [
24
+ /* @__PURE__ */ l("div", {
25
+ className: "relative",
26
+ children: [
27
+ /* @__PURE__ */ c("input", {
28
+ ...P,
29
+ ref: B,
30
+ id: f,
31
+ name: p,
32
+ disabled: y,
33
+ required: b,
34
+ value: F,
35
+ onChange: (e) => I(e.target.value, e.nativeEvent),
36
+ onFocus: () => z(!0),
37
+ onBlur: () => z(!1),
38
+ style: {
39
+ "--nbIconsStart": W,
40
+ "--nbIconsEnd": G
41
+ },
42
+ className: e("text-b3 rounded-pill w-full border h-60 font-normal outline-none", "ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]", {
43
+ "pt-[26px] pb-[8px]": V && m,
44
+ "py-12": !(V && m),
45
+ "border-middleGrey focus:border-black active:border-black": L === "default",
46
+ "bg-white text-black": L !== "disabled",
47
+ "bg-pearl border-middleGrey": L === "disabled",
48
+ "border-red": L === "error",
49
+ "border-green": L === "success"
50
+ }),
51
+ "aria-label": m ? void 0 : p,
52
+ "aria-invalid": L === "error",
53
+ "aria-describedby": H ? `${f}-error` : void 0
54
+ }),
55
+ m && /* @__PURE__ */ l("label", {
56
+ htmlFor: f,
57
+ style: { left: `calc(20px + ${W} * 32px)` },
58
+ className: e("pointer-events-none absolute right-0 transition-all duration-150 select-none pe-[calc(20px+var(--nbIconsEnd)*32px)]", {
59
+ "top-[10px] text-b6 font-semibold": V,
60
+ "top-1/2 -translate-y-1/2 text-b3 font-normal": !V,
61
+ "text-red": L === "error" && V,
62
+ "text-middleGrey": L !== "error" && V,
63
+ "text-black": !V && L !== "disabled",
64
+ "text-grey": L === "disabled"
65
+ }, h),
66
+ children: [m, b && !x && /* @__PURE__ */ c("span", {
67
+ className: "text-red ms-4",
68
+ "aria-hidden": "true",
69
+ children: "*"
70
+ })]
71
+ }),
72
+ /* @__PURE__ */ l("div", {
73
+ className: e("pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12", {
74
+ "text-grey": L === "disabled",
75
+ "text-red": L === "error",
76
+ "text-green": L === "success"
77
+ }),
78
+ children: [C && T && /* @__PURE__ */ c(s, {
79
+ name: C,
80
+ width: "24px"
81
+ }), /* @__PURE__ */ l("span", {
82
+ className: "ms-auto flex gap-x-8",
83
+ children: [
84
+ L === "error" && /* @__PURE__ */ c(s, {
85
+ name: "CrossDefault",
86
+ width: "24px",
87
+ type: w
88
+ }),
89
+ L === "success" && /* @__PURE__ */ c(s, {
90
+ name: "CheckDefault",
91
+ width: "24px",
92
+ type: w
93
+ }),
94
+ (E || U) && (U ? /* @__PURE__ */ c("button", {
95
+ className: "pointer-events-auto",
96
+ onClick: (e) => I("", e.nativeEvent),
97
+ "aria-label": D,
98
+ type: "reset",
99
+ children: /* @__PURE__ */ c(s, {
100
+ name: "CrossDefault",
101
+ className: "text-black",
102
+ width: "24px"
103
+ })
104
+ }) : /* @__PURE__ */ c(s, {
105
+ name: "ArrowDefaultDown",
106
+ className: "text-black",
107
+ width: "24px"
108
+ })),
109
+ !T && C && /* @__PURE__ */ c(s, {
110
+ name: C,
111
+ width: "24px"
112
+ })
113
+ ]
114
+ })]
115
+ })
116
+ ]
117
+ }),
118
+ S && /* @__PURE__ */ c("span", {
119
+ className: "text-b4 text-darkGrey font-normal px-20",
120
+ children: S
121
+ }),
122
+ H && /* @__PURE__ */ c(t, {
123
+ id: `${f}-error`,
124
+ children: v
125
+ })
126
+ ]
127
+ });
128
+ };
129
+ //#endregion
130
+ export { u as FloatingLabelTextField };
131
+
132
+ //# sourceMappingURL=FloatingLabelTextField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FloatingLabelTextField.js","names":[],"sources":["../../../lib/ui/forms/FloatingLabelTextField.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState, useRef } from 'react';\nimport clsx from 'clsx';\nimport { useValue, type UseValueProps } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControlError } from './FormControlError';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport { type FormControlProps } from './FormControl';\n\nexport interface FloatingLabelTextFieldProps<Value = string> extends FormControlProps<Value> {\n icon?: IconicNames;\n iconType?: IconicTypes;\n formatter?: UseValueProps<Value>['formatter'];\n hasDropdown?: boolean;\n clear?: string;\n iconFirst?: boolean;\n}\n\nexport const FloatingLabelTextField = <Value = string,>(\n props: FloatingLabelTextFieldProps<Value>,\n) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n labelClassName,\n value: initialValue,\n validationStatus = 'default',\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n description,\n icon,\n iconType,\n iconFirst = true,\n hasDropdown = false,\n clear = '',\n className,\n dataTestId,\n dataName,\n 'data-testid': dataTestIdProp,\n onChange,\n formatter,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange, formatter });\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const [focused, setFocused] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const isFloating = focused || (value !== '' && value !== null && value !== undefined);\n const showError = internalStatus === 'error' && errorMessage;\n const shouldDisplayClearButton =\n !disabled && value !== '' && value !== null && value !== undefined && !!clear;\n\n const nbIconsStart = Number(!!icon && iconFirst);\n const nbIconsEnd =\n Number(!!icon && !iconFirst) +\n Number(shouldDisplayClearButton || hasDropdown) +\n Number(internalStatus === 'error' || internalStatus === 'success');\n\n return (\n <div\n className={clsx('flex flex-col gap-4', className)}\n data-name={dataName ?? 'FloatingLabelTextField'}\n data-testid={dataTestIdProp ?? dataTestId}\n >\n <div className=\"relative\">\n <input\n {...rest}\n ref={inputRef}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as string}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n style={\n {\n '--nbIconsStart': nbIconsStart,\n '--nbIconsEnd': nbIconsEnd,\n } as React.CSSProperties\n }\n className={clsx(\n 'text-b3 rounded-pill w-full border h-60 font-normal outline-none',\n 'ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'pt-[26px] pb-[8px]': isFloating && label,\n 'py-12': !(isFloating && label),\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={label ? undefined : name}\n aria-invalid={internalStatus === 'error'}\n aria-describedby={showError ? `${id}-error` : undefined}\n />\n\n {label && (\n <label\n htmlFor={id}\n style={\n {\n left: `calc(20px + ${nbIconsStart} * 32px)`,\n } as React.CSSProperties\n }\n className={clsx(\n 'pointer-events-none absolute right-0 transition-all duration-150 select-none pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'top-[10px] text-b6 font-semibold': isFloating,\n 'top-1/2 -translate-y-1/2 text-b3 font-normal': !isFloating,\n 'text-red': internalStatus === 'error' && isFloating,\n 'text-middleGrey': internalStatus !== 'error' && isFloating,\n 'text-black': !isFloating && internalStatus !== 'disabled',\n 'text-grey': internalStatus === 'disabled',\n },\n labelClassName,\n )}\n >\n {label}\n {required && !hideRequiredStar && (\n <span className=\"text-red ms-4\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && iconFirst && <Icon name={icon} width=\"24px\" />}\n\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n {(hasDropdown || shouldDisplayClearButton) &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" className=\"text-black\" width=\"24px\" />\n </button>\n ) : (\n <Icon name=\"ArrowDefaultDown\" className=\"text-black\" width=\"24px\" />\n ))}\n {!iconFirst && icon && <Icon name={icon} width=\"24px\" />}\n </span>\n </div>\n </div>\n\n {description && (\n <span className=\"text-b4 text-darkGrey font-normal px-20\">{description}</span>\n )}\n\n {showError && <FormControlError id={`${id}-error`}>{errorMessage}</FormControlError>}\n </div>\n );\n};\n"],"mappings":"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"}