@fanvue/ui 1.18.0 → 1.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/cjs/components/Accordion/AccordionContent.cjs +11 -3
  2. package/dist/cjs/components/Accordion/AccordionContent.cjs.map +1 -1
  3. package/dist/cjs/components/Accordion/AccordionItem.cjs +1 -5
  4. package/dist/cjs/components/Accordion/AccordionItem.cjs.map +1 -1
  5. package/dist/cjs/components/Autocomplete/useAutocomplete.cjs.map +1 -1
  6. package/dist/cjs/components/Avatar/Avatar.cjs +1 -1
  7. package/dist/cjs/components/Avatar/Avatar.cjs.map +1 -1
  8. package/dist/cjs/components/BottomNavigation/BottomNavigation.cjs +5 -17
  9. package/dist/cjs/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  10. package/dist/cjs/components/BottomNavigation/BottomNavigationAction.cjs +6 -22
  11. package/dist/cjs/components/BottomNavigation/BottomNavigationAction.cjs.map +1 -1
  12. package/dist/cjs/components/Icons/LockerOffIcon.cjs +1 -1
  13. package/dist/cjs/components/Icons/LockerOffIcon.cjs.map +1 -1
  14. package/dist/cjs/components/Icons/LockerOnIcon.cjs +1 -1
  15. package/dist/cjs/components/Icons/LockerOnIcon.cjs.map +1 -1
  16. package/dist/cjs/components/Icons/PinIcon.cjs +1 -1
  17. package/dist/cjs/components/Icons/PinIcon.cjs.map +1 -1
  18. package/dist/cjs/components/Pagination/Pagination.cjs +1 -1
  19. package/dist/cjs/components/Pagination/Pagination.cjs.map +1 -1
  20. package/dist/cjs/components/PasswordField/PasswordField.cjs +1 -1
  21. package/dist/cjs/components/PasswordField/PasswordField.cjs.map +1 -1
  22. package/dist/cjs/components/Tabs/TabsTrigger.cjs +10 -1
  23. package/dist/cjs/components/Tabs/TabsTrigger.cjs.map +1 -1
  24. package/dist/cjs/components/TextArea/TextArea.cjs +1 -1
  25. package/dist/cjs/components/TextArea/TextArea.cjs.map +1 -1
  26. package/dist/cjs/components/TextField/TextField.cjs +5 -1
  27. package/dist/cjs/components/TextField/TextField.cjs.map +1 -1
  28. package/dist/components/Accordion/AccordionContent.mjs +11 -3
  29. package/dist/components/Accordion/AccordionContent.mjs.map +1 -1
  30. package/dist/components/Accordion/AccordionItem.mjs +1 -5
  31. package/dist/components/Accordion/AccordionItem.mjs.map +1 -1
  32. package/dist/components/Autocomplete/useAutocomplete.mjs.map +1 -1
  33. package/dist/components/Avatar/Avatar.mjs +1 -1
  34. package/dist/components/Avatar/Avatar.mjs.map +1 -1
  35. package/dist/components/BottomNavigation/BottomNavigation.mjs +5 -17
  36. package/dist/components/BottomNavigation/BottomNavigation.mjs.map +1 -1
  37. package/dist/components/BottomNavigation/BottomNavigationAction.mjs +6 -22
  38. package/dist/components/BottomNavigation/BottomNavigationAction.mjs.map +1 -1
  39. package/dist/components/Icons/LockerOffIcon.mjs +1 -1
  40. package/dist/components/Icons/LockerOffIcon.mjs.map +1 -1
  41. package/dist/components/Icons/LockerOnIcon.mjs +1 -1
  42. package/dist/components/Icons/LockerOnIcon.mjs.map +1 -1
  43. package/dist/components/Icons/PinIcon.mjs +1 -1
  44. package/dist/components/Icons/PinIcon.mjs.map +1 -1
  45. package/dist/components/Pagination/Pagination.mjs +1 -1
  46. package/dist/components/Pagination/Pagination.mjs.map +1 -1
  47. package/dist/components/PasswordField/PasswordField.mjs +1 -1
  48. package/dist/components/PasswordField/PasswordField.mjs.map +1 -1
  49. package/dist/components/Tabs/TabsTrigger.mjs +10 -1
  50. package/dist/components/Tabs/TabsTrigger.mjs.map +1 -1
  51. package/dist/components/TextArea/TextArea.mjs +1 -1
  52. package/dist/components/TextArea/TextArea.mjs.map +1 -1
  53. package/dist/components/TextField/TextField.mjs +5 -1
  54. package/dist/components/TextField/TextField.mjs.map +1 -1
  55. package/dist/index.d.ts +2 -6
  56. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.mjs","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ChevronLeftIcon } from \"../Icons/ChevronLeftIcon\";\nimport { ChevronRightIcon } from \"../Icons/ChevronRightIcon\";\n\n/** Pagination display style — numbered buttons or minimal dots. */\nexport type PaginationVariant = \"default\" | \"dots\";\n\nexport interface PaginationProps extends Omit<React.HTMLAttributes<HTMLElement>, \"onChange\"> {\n /** Display style — numbered page buttons or minimal dots. @default \"default\" */\n variant?: PaginationVariant;\n /** Total number of pages. */\n totalPages: number;\n /** Current active page (1-indexed). */\n currentPage: number;\n /** Callback fired when the active page changes. Receives the new 1-indexed page number. */\n onPageChange?: (page: number) => void;\n /** Accessible label for the `<nav>` landmark. @default \"Pagination\" */\n ariaLabel?: string;\n /** Accessible label for the previous-page button. @default \"Previous page\" */\n previousLabel?: string;\n /** Accessible label for the next-page button. @default \"Next page\" */\n nextLabel?: string;\n /** Function that returns an accessible label for each page button. @default (page) => \\`Page ${page}\\` */\n getPageLabel?: (page: number) => string;\n}\n\ntype PageItem = number | \"ellipsis-start\" | \"ellipsis-end\";\n\nfunction getVisiblePages(currentPage: number, totalPages: number): PageItem[] {\n if (totalPages <= 7) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n\n const pages: PageItem[] = [1];\n\n if (currentPage <= 4) {\n pages.push(2, 3, 4, 5, \"ellipsis-end\");\n } else if (currentPage >= totalPages - 3) {\n pages.push(\"ellipsis-start\", totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1);\n } else {\n pages.push(\"ellipsis-start\", currentPage - 1, currentPage, currentPage + 1, \"ellipsis-end\");\n }\n\n pages.push(totalPages);\n return pages;\n}\n\n/**\n * Page navigation control with previous/next buttons and numbered page\n * indicators. Supports a numbered-buttons layout (`\"default\"`) and a compact\n * dots layout (`\"dots\"`).\n *\n * @example\n * ```tsx\n * <Pagination totalPages={10} currentPage={page} onPageChange={setPage} />\n * ```\n */\nexport const Pagination = React.forwardRef<HTMLElement, PaginationProps>(\n (\n {\n variant = \"default\",\n totalPages,\n currentPage,\n onPageChange,\n ariaLabel = \"Pagination\",\n previousLabel = \"Previous page\",\n nextLabel = \"Next page\",\n getPageLabel = (page: number) => `Page ${page}`,\n className,\n ...props\n },\n ref,\n ) => {\n const isFirstPage = currentPage <= 1;\n const isLastPage = currentPage >= totalPages;\n\n const handlePrevious = () => {\n if (!isFirstPage) onPageChange?.(currentPage - 1);\n };\n\n const handleNext = () => {\n if (!isLastPage) onPageChange?.(currentPage + 1);\n };\n\n return (\n <nav\n ref={ref}\n aria-label={ariaLabel}\n className={cn(\n \"inline-flex items-center\",\n variant === \"default\" && \"gap-3\",\n variant === \"dots\" && \"gap-4\",\n className,\n )}\n {...props}\n >\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ChevronLeftIcon />}\n aria-label={previousLabel}\n disabled={isFirstPage}\n onClick={handlePrevious}\n />\n\n {variant === \"default\" && (\n <div className=\"flex items-center gap-3\">\n {getVisiblePages(currentPage, totalPages).map((page) =>\n typeof page === \"string\" ? (\n <span\n key={page}\n className=\"flex size-4 items-center justify-center text-foreground-secondary text-xs\"\n aria-hidden=\"true\"\n >\n &hellip;\n </span>\n ) : (\n <button\n key={page}\n type=\"button\"\n aria-label={getPageLabel(page)}\n aria-current={page === currentPage ? \"page\" : undefined}\n onClick={() => onPageChange?.(page)}\n className={cn(\n \"flex size-4 cursor-pointer items-center justify-center rounded-full text-xs focus-visible:shadow-focus-ring focus-visible:outline-none motion-safe:transition-colors motion-safe:duration-150\",\n page === currentPage\n ? \"bg-neutral-400 text-foreground-inverse\"\n : \"bg-neutral-100 text-foreground-default hover:bg-neutral-200 active:bg-neutral-200\",\n )}\n >\n {page}\n </button>\n ),\n )}\n </div>\n )}\n\n {variant === \"dots\" && (\n <div className=\"flex items-center\">\n {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (\n <button\n key={page}\n type=\"button\"\n aria-label={getPageLabel(page)}\n aria-current={page === currentPage ? \"page\" : undefined}\n onClick={() => onPageChange?.(page)}\n className=\"flex size-6 cursor-pointer items-center justify-center rounded-full focus-visible:shadow-focus-ring focus-visible:outline-none\"\n >\n <span\n className={cn(\n \"block rounded-full motion-safe:transition-all motion-safe:duration-150\",\n page === currentPage\n ? \"size-2 bg-neutral-400\"\n : \"size-1.5 bg-neutral-200 hover:bg-neutral-250 active:bg-neutral-250\",\n )}\n />\n </button>\n ))}\n </div>\n )}\n\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ChevronRightIcon />}\n aria-label={nextLabel}\n disabled={isLastPage}\n onClick={handleNext}\n />\n </nav>\n );\n },\n);\n\nPagination.displayName = \"Pagination\";\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Pagination.mjs","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ChevronLeftIcon } from \"../Icons/ChevronLeftIcon\";\nimport { ChevronRightIcon } from \"../Icons/ChevronRightIcon\";\n\n/** Pagination display style — numbered buttons or minimal dots. */\nexport type PaginationVariant = \"default\" | \"dots\";\n\nexport interface PaginationProps extends Omit<React.HTMLAttributes<HTMLElement>, \"onChange\"> {\n /** Display style — numbered page buttons or minimal dots. @default \"default\" */\n variant?: PaginationVariant;\n /** Total number of pages. */\n totalPages: number;\n /** Current active page (1-indexed). */\n currentPage: number;\n /** Callback fired when the active page changes. Receives the new 1-indexed page number. */\n onPageChange?: (page: number) => void;\n /** Accessible label for the `<nav>` landmark. @default \"Pagination\" */\n ariaLabel?: string;\n /** Accessible label for the previous-page button. @default \"Previous page\" */\n previousLabel?: string;\n /** Accessible label for the next-page button. @default \"Next page\" */\n nextLabel?: string;\n /** Function that returns an accessible label for each page button. @default (page) => \\`Page ${page}\\` */\n getPageLabel?: (page: number) => string;\n}\n\ntype PageItem = number | \"ellipsis-start\" | \"ellipsis-end\";\n\nfunction getVisiblePages(currentPage: number, totalPages: number): PageItem[] {\n if (totalPages <= 7) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n\n const pages: PageItem[] = [1];\n\n if (currentPage <= 4) {\n pages.push(2, 3, 4, 5, \"ellipsis-end\");\n } else if (currentPage >= totalPages - 3) {\n pages.push(\"ellipsis-start\", totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1);\n } else {\n pages.push(\"ellipsis-start\", currentPage - 1, currentPage, currentPage + 1, \"ellipsis-end\");\n }\n\n pages.push(totalPages);\n return pages;\n}\n\n/**\n * Page navigation control with previous/next buttons and numbered page\n * indicators. Supports a numbered-buttons layout (`\"default\"`) and a compact\n * dots layout (`\"dots\"`).\n *\n * @example\n * ```tsx\n * <Pagination totalPages={10} currentPage={page} onPageChange={setPage} />\n * ```\n */\nexport const Pagination = React.forwardRef<HTMLElement, PaginationProps>(\n (\n {\n variant = \"default\",\n totalPages,\n currentPage,\n onPageChange,\n ariaLabel = \"Pagination\",\n previousLabel = \"Previous page\",\n nextLabel = \"Next page\",\n getPageLabel = (page: number) => `Page ${page}`,\n className,\n ...props\n },\n ref,\n ) => {\n const isFirstPage = currentPage <= 1;\n const isLastPage = currentPage >= totalPages;\n\n const handlePrevious = () => {\n if (!isFirstPage) onPageChange?.(currentPage - 1);\n };\n\n const handleNext = () => {\n if (!isLastPage) onPageChange?.(currentPage + 1);\n };\n\n return (\n <nav\n ref={ref}\n aria-label={ariaLabel}\n className={cn(\n \"inline-flex items-center pb-4\",\n variant === \"default\" && \"gap-3\",\n variant === \"dots\" && \"gap-4\",\n className,\n )}\n {...props}\n >\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ChevronLeftIcon />}\n aria-label={previousLabel}\n disabled={isFirstPage}\n onClick={handlePrevious}\n />\n\n {variant === \"default\" && (\n <div className=\"flex items-center gap-3\">\n {getVisiblePages(currentPage, totalPages).map((page) =>\n typeof page === \"string\" ? (\n <span\n key={page}\n className=\"flex size-4 items-center justify-center text-foreground-secondary text-xs\"\n aria-hidden=\"true\"\n >\n &hellip;\n </span>\n ) : (\n <button\n key={page}\n type=\"button\"\n aria-label={getPageLabel(page)}\n aria-current={page === currentPage ? \"page\" : undefined}\n onClick={() => onPageChange?.(page)}\n className={cn(\n \"flex size-4 cursor-pointer items-center justify-center rounded-full text-xs focus-visible:shadow-focus-ring focus-visible:outline-none motion-safe:transition-colors motion-safe:duration-150\",\n page === currentPage\n ? \"bg-neutral-400 text-foreground-inverse\"\n : \"bg-neutral-100 text-foreground-default hover:bg-neutral-200 active:bg-neutral-200\",\n )}\n >\n {page}\n </button>\n ),\n )}\n </div>\n )}\n\n {variant === \"dots\" && (\n <div className=\"flex items-center\">\n {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (\n <button\n key={page}\n type=\"button\"\n aria-label={getPageLabel(page)}\n aria-current={page === currentPage ? \"page\" : undefined}\n onClick={() => onPageChange?.(page)}\n className=\"flex size-6 cursor-pointer items-center justify-center rounded-full focus-visible:shadow-focus-ring focus-visible:outline-none\"\n >\n <span\n className={cn(\n \"block rounded-full motion-safe:transition-all motion-safe:duration-150\",\n page === currentPage\n ? \"size-2 bg-neutral-400\"\n : \"size-1.5 bg-neutral-200 hover:bg-neutral-250 active:bg-neutral-250\",\n )}\n />\n </button>\n ))}\n </div>\n )}\n\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ChevronRightIcon />}\n aria-label={nextLabel}\n disabled={isLastPage}\n onClick={handleNext}\n />\n </nav>\n );\n },\n);\n\nPagination.displayName = \"Pagination\";\n"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ const PasswordField = React.forwardRef(
18
18
  disabled,
19
19
  "aria-label": showPassword ? "Hide password" : "Show password",
20
20
  tabIndex: -1,
21
- className: "flex size-5 shrink-0 items-center justify-center text-foreground-secondary transition-colors hover:text-foreground-default focus:outline-none disabled:cursor-not-allowed",
21
+ className: "flex size-5 shrink-0 cursor-default items-center justify-center text-foreground-secondary transition-colors hover:text-foreground-default focus:outline-none disabled:cursor-not-allowed",
22
22
  children: showPassword ? /* @__PURE__ */ jsx(EyeSlashIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
23
23
  }
24
24
  );
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordField.mjs","sources":["../../../src/components/PasswordField/PasswordField.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { EyeIcon } from \"../Icons/EyeIcon\";\nimport { EyeSlashIcon } from \"../Icons/EyeSlashIcon\";\nimport { TextField, type TextFieldProps } from \"../TextField/TextField\";\n\nexport type PasswordFieldSize = \"48\" | \"40\" | \"32\";\n\nexport interface PasswordFieldProps extends Omit<TextFieldProps, \"type\" | \"rightIcon\"> {\n /** Size variant of the password field */\n size?: PasswordFieldSize;\n}\n\nexport const PasswordField = React.forwardRef<HTMLInputElement, PasswordFieldProps>(\n ({ disabled, ...props }, ref) => {\n const [showPassword, setShowPassword] = React.useState(false);\n\n const togglePasswordVisibility = () => {\n setShowPassword((prev) => !prev);\n };\n\n const rightIcon = (\n <button\n type=\"button\"\n onClick={togglePasswordVisibility}\n disabled={disabled}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n tabIndex={-1}\n className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary transition-colors hover:text-foreground-default focus:outline-none disabled:cursor-not-allowed\"\n >\n {showPassword ? <EyeSlashIcon /> : <EyeIcon />}\n </button>\n );\n\n return (\n <TextField\n ref={ref}\n type={showPassword ? \"text\" : \"password\"}\n disabled={disabled}\n rightIcon={rightIcon}\n aria-label={!props.label ? \"Password field\" : undefined}\n {...props}\n />\n );\n },\n);\n\nPasswordField.displayName = \"PasswordField\";\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,gBAAgB,MAAM;AAAA,EACjC,CAAC,EAAE,UAAU,GAAG,MAAA,GAAS,QAAQ;AAC/B,UAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,KAAK;AAE5D,UAAM,2BAA2B,MAAM;AACrC,sBAAgB,CAAC,SAAS,CAAC,IAAI;AAAA,IACjC;AAEA,UAAM,YACJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,cAAY,eAAe,kBAAkB;AAAA,QAC7C,UAAU;AAAA,QACV,WAAU;AAAA,QAET,UAAA,eAAe,oBAAC,cAAA,CAAA,CAAa,wBAAM,SAAA,CAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAIhD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAM,eAAe,SAAS;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,cAAY,CAAC,MAAM,QAAQ,mBAAmB;AAAA,QAC7C,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,cAAc,cAAc;"}
1
+ {"version":3,"file":"PasswordField.mjs","sources":["../../../src/components/PasswordField/PasswordField.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { EyeIcon } from \"../Icons/EyeIcon\";\nimport { EyeSlashIcon } from \"../Icons/EyeSlashIcon\";\nimport { TextField, type TextFieldProps } from \"../TextField/TextField\";\n\nexport type PasswordFieldSize = \"48\" | \"40\" | \"32\";\n\nexport interface PasswordFieldProps extends Omit<TextFieldProps, \"type\" | \"rightIcon\"> {\n /** Size variant of the password field */\n size?: PasswordFieldSize;\n}\n\nexport const PasswordField = React.forwardRef<HTMLInputElement, PasswordFieldProps>(\n ({ disabled, ...props }, ref) => {\n const [showPassword, setShowPassword] = React.useState(false);\n\n const togglePasswordVisibility = () => {\n setShowPassword((prev) => !prev);\n };\n\n const rightIcon = (\n <button\n type=\"button\"\n onClick={togglePasswordVisibility}\n disabled={disabled}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n tabIndex={-1}\n className=\"flex size-5 shrink-0 cursor-default items-center justify-center text-foreground-secondary transition-colors hover:text-foreground-default focus:outline-none disabled:cursor-not-allowed\"\n >\n {showPassword ? <EyeSlashIcon /> : <EyeIcon />}\n </button>\n );\n\n return (\n <TextField\n ref={ref}\n type={showPassword ? \"text\" : \"password\"}\n disabled={disabled}\n rightIcon={rightIcon}\n aria-label={!props.label ? \"Password field\" : undefined}\n {...props}\n />\n );\n },\n);\n\nPasswordField.displayName = \"PasswordField\";\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,gBAAgB,MAAM;AAAA,EACjC,CAAC,EAAE,UAAU,GAAG,MAAA,GAAS,QAAQ;AAC/B,UAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,KAAK;AAE5D,UAAM,2BAA2B,MAAM;AACrC,sBAAgB,CAAC,SAAS,CAAC,IAAI;AAAA,IACjC;AAEA,UAAM,YACJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,cAAY,eAAe,kBAAkB;AAAA,QAC7C,UAAU;AAAA,QACV,WAAU;AAAA,QAET,UAAA,eAAe,oBAAC,cAAA,CAAA,CAAa,wBAAM,SAAA,CAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAIhD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAM,eAAe,SAAS;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,cAAY,CAAC,MAAM,QAAQ,mBAAmB;AAAA,QAC7C,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,cAAc,cAAc;"}
@@ -3,10 +3,19 @@ import { jsx } from "react/jsx-runtime";
3
3
  import * as TabsPrimitive from "@radix-ui/react-tabs";
4
4
  import * as React from "react";
5
5
  import { cn } from "../../utils/cn.mjs";
6
- const TabsTrigger = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
6
+ const TabsTrigger = React.forwardRef(({ className, children, onMouseDown, ...props }, ref) => /* @__PURE__ */ jsx(
7
7
  TabsPrimitive.Trigger,
8
8
  {
9
9
  ref,
10
+ onMouseDown: (e) => {
11
+ if (e.button !== 0) {
12
+ onMouseDown?.(e);
13
+ return;
14
+ }
15
+ e.preventDefault();
16
+ if (!props.disabled) e.currentTarget.focus();
17
+ onMouseDown?.(e);
18
+ },
10
19
  className: cn(
11
20
  "inline-flex min-w-0 items-center justify-center",
12
21
  "rounded-xs",
@@ -1 +1 @@
1
- {"version":3,"file":"TabsTrigger.mjs","sources":["../../../src/components/Tabs/TabsTrigger.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsTrigger} button component. */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/** An interactive tab button that activates its associated {@link TabsContent} panel when clicked. */\nexport const TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex min-w-0 items-center justify-center\",\n \"rounded-xs\",\n \"typography-semibold-body-lg cursor-pointer text-foreground-default\",\n \"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out\",\n \"data-[orientation=horizontal]:px-4 data-[orientation=horizontal]:py-3\",\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:px-4 data-[orientation=vertical]:py-3\",\n \"data-[state=active]:hover:text-neutral-350\",\n \"data-[state=inactive]:hover:text-neutral-300\",\n \"data-[state=active]:active:text-neutral-350\",\n \"data-[state=inactive]:active:text-neutral-300\",\n \"data-disabled:pointer-events-none\",\n \"data-disabled:data-[state=active]:text-neutral-250\",\n \"data-disabled:data-[state=inactive]:text-neutral-300\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-page\",\n className,\n )}\n {...props}\n >\n <span className=\"min-w-0 truncate\">{children}</span>\n </TabsPrimitive.Trigger>\n));\n\nTabsTrigger.displayName = \"TabsTrigger\";\n"],"names":[],"mappings":";;;;;AAQO,MAAM,cAAc,MAAM,WAG/B,CAAC,EAAE,WAAW,UAAU,GAAG,SAAS,QACpC;AAAA,EAAC,cAAc;AAAA,EAAd;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,IAEJ,UAAA,oBAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,EAAA;AAC/C,CACD;AAED,YAAY,cAAc;"}
1
+ {"version":3,"file":"TabsTrigger.mjs","sources":["../../../src/components/Tabs/TabsTrigger.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsTrigger} button component. */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/** An interactive tab button that activates its associated {@link TabsContent} panel when clicked. */\nexport const TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, onMouseDown, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n onMouseDown={(e) => {\n // Only intercept primary (left) button clicks. Right-click and other\n // buttons should fall through untouched so context menus are unaffected.\n if (e.button !== 0) {\n onMouseDown?.(e);\n return;\n }\n // Prevent :focus-visible from appearing on mouse clicks. Native focus is\n // suppressed via preventDefault; we re-apply focus programmatically so\n // the element remains focusable for keyboard users, but the browser won't\n // mark the focus origin as \"pointer\", so Escape won't trigger the ring.\n e.preventDefault();\n if (!props.disabled) e.currentTarget.focus();\n onMouseDown?.(e);\n }}\n className={cn(\n \"inline-flex min-w-0 items-center justify-center\",\n \"rounded-xs\",\n \"typography-semibold-body-lg cursor-pointer text-foreground-default\",\n \"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out\",\n \"data-[orientation=horizontal]:px-4 data-[orientation=horizontal]:py-3\",\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:px-4 data-[orientation=vertical]:py-3\",\n \"data-[state=active]:hover:text-neutral-350\",\n \"data-[state=inactive]:hover:text-neutral-300\",\n \"data-[state=active]:active:text-neutral-350\",\n \"data-[state=inactive]:active:text-neutral-300\",\n \"data-disabled:pointer-events-none\",\n \"data-disabled:data-[state=active]:text-neutral-250\",\n \"data-disabled:data-[state=inactive]:text-neutral-300\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-page\",\n className,\n )}\n {...props}\n >\n <span className=\"min-w-0 truncate\">{children}</span>\n </TabsPrimitive.Trigger>\n));\n\nTabsTrigger.displayName = \"TabsTrigger\";\n"],"names":[],"mappings":";;;;;AAQO,MAAM,cAAc,MAAM,WAG/B,CAAC,EAAE,WAAW,UAAU,aAAa,GAAG,SAAS,QACjD;AAAA,EAAC,cAAc;AAAA,EAAd;AAAA,IACC;AAAA,IACA,aAAa,CAAC,MAAM;AAGlB,UAAI,EAAE,WAAW,GAAG;AAClB,sBAAc,CAAC;AACf;AAAA,MACF;AAKA,QAAE,eAAA;AACF,UAAI,CAAC,MAAM,SAAU,GAAE,cAAc,MAAA;AACrC,oBAAc,CAAC;AAAA,IACjB;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,IAEJ,UAAA,oBAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,EAAA;AAC/C,CACD;AAED,YAAY,cAAc;"}
@@ -32,7 +32,7 @@ const CLEAR_BUTTON_RIGHT = {
32
32
  };
33
33
  function getContainerClassName(size, error, disabled) {
34
34
  return cn(
35
- "relative overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors",
35
+ "relative rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors",
36
36
  error ? "border-error-default" : "border-transparent",
37
37
  !disabled && !error && "hover:border-neutral-400",
38
38
  CONTAINER_MIN_HEIGHT[size],
@@ -1 +1 @@
1
- {"version":3,"file":"TextArea.mjs","sources":["../../../src/components/TextArea/TextArea.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CheckOutlineIcon } from \"../Icons/CheckOutlineIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Text area height in pixels. */\nexport type TextAreaSize = \"48\" | \"40\" | \"32\";\n\nexport interface TextAreaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, \"size\"> {\n /** Label text displayed above the textarea. Also used as the accessible name. */\n label?: string;\n /** Helper text displayed below the textarea. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Minimum height of the text area in pixels. @default \"48\" */\n size?: TextAreaSize;\n /** Whether the text area is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the textarea. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Whether the text area is validated. @default false */\n validated?: boolean;\n /** Whether the text area stretches to fill its container width. @default false */\n fullWidth?: boolean;\n /** Whether to show a clear button when text is present. @default false */\n showClearButton?: boolean;\n /** Callback fired when the clear button is clicked. Note: `onChange` is also called with an empty value when clearing. */\n onClear?: () => void;\n /** Minimum number of rows (lines) for the textarea. */\n minRows?: number;\n /** Maximum number of rows (lines) for the textarea. */\n maxRows?: number;\n /** Whether the textarea can be resized by the user. @default true */\n resizable?: boolean;\n}\n\nconst CONTAINER_MIN_HEIGHT: Record<TextAreaSize, string> = {\n \"48\": \"min-h-12\",\n \"40\": \"min-h-10\",\n \"32\": \"min-h-8\",\n};\n\nconst TEXTAREA_SIZE_CLASSES: Record<TextAreaSize, string> = {\n \"48\": \"py-3 typography-regular-body-lg\",\n \"40\": \"py-2 typography-regular-body-lg\",\n \"32\": \"py-2 typography-regular-body-md\",\n};\n\nconst PADDING_HORIZONTAL: Record<TextAreaSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst PADDING_RIGHT_WITH_CLEAR: Record<TextAreaSize, string> = {\n \"48\": \"pr-11\",\n \"40\": \"pr-11\",\n \"32\": \"pr-10\",\n};\n\nconst CLEAR_BUTTON_RIGHT: Record<TextAreaSize, string> = {\n \"48\": \"right-4 top-3\",\n \"40\": \"right-4 top-2\",\n \"32\": \"right-3 top-2\",\n};\n\nfunction getContainerClassName(size: TextAreaSize, error: boolean, disabled?: boolean) {\n return cn(\n \"relative overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n CONTAINER_MIN_HEIGHT[size],\n disabled && \"opacity-50\",\n );\n}\n\nfunction getTextareaClassName(\n size: TextAreaSize,\n hasClearButton: boolean,\n hasMinRows: boolean,\n resizable: boolean,\n) {\n return cn(\n \"w-full rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n resizable ? \"resize-y\" : \"resize-none\",\n !hasMinRows && \"min-h-[80px]\",\n TEXTAREA_SIZE_CLASSES[size],\n PADDING_HORIZONTAL[size],\n hasClearButton ? PADDING_RIGHT_WITH_CLEAR[size] : \"\",\n );\n}\n\nfunction TextAreaHelperText({\n id,\n error,\n children,\n}: {\n id: string;\n error: boolean;\n children: React.ReactNode;\n}) {\n return (\n <p\n id={id}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"TextArea: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\nfunction calculateMaxHeight(size: TextAreaSize, maxRows?: number): string | undefined {\n if (!maxRows) return undefined;\n\n // Line height is 24px for body-1 (sizes 48 and 40) and 20px for body-2 (size 32)\n const lineHeight = size === \"32\" ? 20 : 24;\n // py-2 = 8px, py-3 = 12px\n const verticalPadding = size === \"32\" ? 8 : size === \"40\" ? 8 : 12;\n\n return `${lineHeight * maxRows + verticalPadding * 2}px`;\n}\n\nfunction useTextAreaValue(\n value: React.TextareaHTMLAttributes<HTMLTextAreaElement>[\"value\"],\n defaultValue: React.TextareaHTMLAttributes<HTMLTextAreaElement>[\"defaultValue\"],\n showClearButton: boolean,\n onChange?: React.ChangeEventHandler<HTMLTextAreaElement>,\n onClear?: () => void,\n textareaRef?: React.RefObject<HTMLTextAreaElement | null>,\n) {\n const [internalValue, setInternalValue] = React.useState(defaultValue ?? \"\");\n const resolvedValue = value !== undefined ? value : internalValue;\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInternalValue(e.target.value);\n onChange?.(e);\n };\n\n const handleClear = () => {\n setInternalValue(\"\");\n\n if (onChange && textareaRef?.current) {\n const syntheticEvent = {\n target: { ...textareaRef.current, value: \"\" },\n currentTarget: { ...textareaRef.current, value: \"\" },\n } as React.ChangeEvent<HTMLTextAreaElement>;\n onChange(syntheticEvent);\n }\n\n onClear?.();\n };\n\n return {\n resolvedValue,\n displayValue: showClearButton ? resolvedValue : value,\n resolvedDefaultValue: showClearButton ? undefined : defaultValue,\n handleChange,\n handleClear,\n };\n}\n\n/**\n * A multi-line text input with optional label, helper/error text, and clear button.\n *\n * Provide at least one of `label`, `aria-label`, or `aria-labelledby` for\n * accessibility — a console warning is emitted in development if none are set.\n *\n * @example\n * ```tsx\n * <TextArea\n * label=\"Description\"\n * placeholder=\"Enter your description...\"\n * showClearButton\n * error={!!descError}\n * errorMessage={descError}\n * />\n * ```\n */\nexport const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n validated = false,\n className,\n id,\n disabled,\n fullWidth = false,\n showClearButton = false,\n onClear,\n value,\n defaultValue,\n onChange,\n minRows,\n maxRows,\n resizable = false,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n const maxHeight = calculateMaxHeight(size, maxRows);\n\n const internalRef = React.useRef<HTMLTextAreaElement>(null);\n\n const { resolvedValue, displayValue, resolvedDefaultValue, handleChange, handleClear } =\n useTextAreaValue(value, defaultValue, showClearButton, onChange, onClear, internalRef);\n\n const mergedRef = (node: HTMLTextAreaElement | null) => {\n internalRef.current = node;\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLTextAreaElement | null>).current = node;\n }\n };\n\n const showClear = showClearButton && resolvedValue !== \"\" && !disabled;\n const showValidated = validated && !showClear;\n const ariaDescribedBy = bottomText ? helperTextId : undefined;\n const textareaStyle = maxHeight ? { maxHeight } : undefined;\n\n warnMissingAccessibleName(label, props[\"aria-label\"], props[\"aria-labelledby\"]);\n\n return (\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <div className={getContainerClassName(size, error, disabled)}>\n <textarea\n ref={mergedRef}\n id={inputId}\n disabled={disabled}\n aria-describedby={ariaDescribedBy}\n aria-invalid={error || undefined}\n className={getTextareaClassName(size, showClear, !!minRows, resizable)}\n value={displayValue}\n defaultValue={resolvedDefaultValue}\n onChange={handleChange}\n rows={minRows}\n style={textareaStyle}\n {...props}\n />\n\n {showClear && (\n <IconButton\n variant=\"tertiary\"\n size=\"24\"\n icon={<CloseIcon />}\n aria-label=\"Clear text\"\n onClick={handleClear}\n className={cn(\n \"absolute flex size-5 items-center justify-center self-end\",\n CLEAR_BUTTON_RIGHT[size],\n )}\n />\n )}\n {showValidated && (\n <div\n className={cn(\n \"pointer-events-none absolute flex size-5 items-center justify-center\",\n CLEAR_BUTTON_RIGHT[size],\n )}\n >\n <CheckOutlineIcon className=\"text-success-default\" />\n </div>\n )}\n </div>\n\n {bottomText && (\n <TextAreaHelperText id={helperTextId} error={error}>\n {bottomText}\n </TextAreaHelperText>\n )}\n </div>\n );\n },\n);\n\nTextArea.displayName = \"TextArea\";\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TextArea.mjs","sources":["../../../src/components/TextArea/TextArea.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CheckOutlineIcon } from \"../Icons/CheckOutlineIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Text area height in pixels. */\nexport type TextAreaSize = \"48\" | \"40\" | \"32\";\n\nexport interface TextAreaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, \"size\"> {\n /** Label text displayed above the textarea. Also used as the accessible name. */\n label?: string;\n /** Helper text displayed below the textarea. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Minimum height of the text area in pixels. @default \"48\" */\n size?: TextAreaSize;\n /** Whether the text area is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the textarea. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Whether the text area is validated. @default false */\n validated?: boolean;\n /** Whether the text area stretches to fill its container width. @default false */\n fullWidth?: boolean;\n /** Whether to show a clear button when text is present. @default false */\n showClearButton?: boolean;\n /** Callback fired when the clear button is clicked. Note: `onChange` is also called with an empty value when clearing. */\n onClear?: () => void;\n /** Minimum number of rows (lines) for the textarea. */\n minRows?: number;\n /** Maximum number of rows (lines) for the textarea. */\n maxRows?: number;\n /** Whether the textarea can be resized by the user. @default true */\n resizable?: boolean;\n}\n\nconst CONTAINER_MIN_HEIGHT: Record<TextAreaSize, string> = {\n \"48\": \"min-h-12\",\n \"40\": \"min-h-10\",\n \"32\": \"min-h-8\",\n};\n\nconst TEXTAREA_SIZE_CLASSES: Record<TextAreaSize, string> = {\n \"48\": \"py-3 typography-regular-body-lg\",\n \"40\": \"py-2 typography-regular-body-lg\",\n \"32\": \"py-2 typography-regular-body-md\",\n};\n\nconst PADDING_HORIZONTAL: Record<TextAreaSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst PADDING_RIGHT_WITH_CLEAR: Record<TextAreaSize, string> = {\n \"48\": \"pr-11\",\n \"40\": \"pr-11\",\n \"32\": \"pr-10\",\n};\n\nconst CLEAR_BUTTON_RIGHT: Record<TextAreaSize, string> = {\n \"48\": \"right-4 top-3\",\n \"40\": \"right-4 top-2\",\n \"32\": \"right-3 top-2\",\n};\n\nfunction getContainerClassName(size: TextAreaSize, error: boolean, disabled?: boolean) {\n return cn(\n \"relative rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n CONTAINER_MIN_HEIGHT[size],\n disabled && \"opacity-50\",\n );\n}\n\nfunction getTextareaClassName(\n size: TextAreaSize,\n hasClearButton: boolean,\n hasMinRows: boolean,\n resizable: boolean,\n) {\n return cn(\n \"w-full rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n resizable ? \"resize-y\" : \"resize-none\",\n !hasMinRows && \"min-h-[80px]\",\n TEXTAREA_SIZE_CLASSES[size],\n PADDING_HORIZONTAL[size],\n hasClearButton ? PADDING_RIGHT_WITH_CLEAR[size] : \"\",\n );\n}\n\nfunction TextAreaHelperText({\n id,\n error,\n children,\n}: {\n id: string;\n error: boolean;\n children: React.ReactNode;\n}) {\n return (\n <p\n id={id}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"TextArea: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\nfunction calculateMaxHeight(size: TextAreaSize, maxRows?: number): string | undefined {\n if (!maxRows) return undefined;\n\n // Line height is 24px for body-1 (sizes 48 and 40) and 20px for body-2 (size 32)\n const lineHeight = size === \"32\" ? 20 : 24;\n // py-2 = 8px, py-3 = 12px\n const verticalPadding = size === \"32\" ? 8 : size === \"40\" ? 8 : 12;\n\n return `${lineHeight * maxRows + verticalPadding * 2}px`;\n}\n\nfunction useTextAreaValue(\n value: React.TextareaHTMLAttributes<HTMLTextAreaElement>[\"value\"],\n defaultValue: React.TextareaHTMLAttributes<HTMLTextAreaElement>[\"defaultValue\"],\n showClearButton: boolean,\n onChange?: React.ChangeEventHandler<HTMLTextAreaElement>,\n onClear?: () => void,\n textareaRef?: React.RefObject<HTMLTextAreaElement | null>,\n) {\n const [internalValue, setInternalValue] = React.useState(defaultValue ?? \"\");\n const resolvedValue = value !== undefined ? value : internalValue;\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInternalValue(e.target.value);\n onChange?.(e);\n };\n\n const handleClear = () => {\n setInternalValue(\"\");\n\n if (onChange && textareaRef?.current) {\n const syntheticEvent = {\n target: { ...textareaRef.current, value: \"\" },\n currentTarget: { ...textareaRef.current, value: \"\" },\n } as React.ChangeEvent<HTMLTextAreaElement>;\n onChange(syntheticEvent);\n }\n\n onClear?.();\n };\n\n return {\n resolvedValue,\n displayValue: showClearButton ? resolvedValue : value,\n resolvedDefaultValue: showClearButton ? undefined : defaultValue,\n handleChange,\n handleClear,\n };\n}\n\n/**\n * A multi-line text input with optional label, helper/error text, and clear button.\n *\n * Provide at least one of `label`, `aria-label`, or `aria-labelledby` for\n * accessibility — a console warning is emitted in development if none are set.\n *\n * @example\n * ```tsx\n * <TextArea\n * label=\"Description\"\n * placeholder=\"Enter your description...\"\n * showClearButton\n * error={!!descError}\n * errorMessage={descError}\n * />\n * ```\n */\nexport const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n validated = false,\n className,\n id,\n disabled,\n fullWidth = false,\n showClearButton = false,\n onClear,\n value,\n defaultValue,\n onChange,\n minRows,\n maxRows,\n resizable = false,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n const maxHeight = calculateMaxHeight(size, maxRows);\n\n const internalRef = React.useRef<HTMLTextAreaElement>(null);\n\n const { resolvedValue, displayValue, resolvedDefaultValue, handleChange, handleClear } =\n useTextAreaValue(value, defaultValue, showClearButton, onChange, onClear, internalRef);\n\n const mergedRef = (node: HTMLTextAreaElement | null) => {\n internalRef.current = node;\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLTextAreaElement | null>).current = node;\n }\n };\n\n const showClear = showClearButton && resolvedValue !== \"\" && !disabled;\n const showValidated = validated && !showClear;\n const ariaDescribedBy = bottomText ? helperTextId : undefined;\n const textareaStyle = maxHeight ? { maxHeight } : undefined;\n\n warnMissingAccessibleName(label, props[\"aria-label\"], props[\"aria-labelledby\"]);\n\n return (\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <div className={getContainerClassName(size, error, disabled)}>\n <textarea\n ref={mergedRef}\n id={inputId}\n disabled={disabled}\n aria-describedby={ariaDescribedBy}\n aria-invalid={error || undefined}\n className={getTextareaClassName(size, showClear, !!minRows, resizable)}\n value={displayValue}\n defaultValue={resolvedDefaultValue}\n onChange={handleChange}\n rows={minRows}\n style={textareaStyle}\n {...props}\n />\n\n {showClear && (\n <IconButton\n variant=\"tertiary\"\n size=\"24\"\n icon={<CloseIcon />}\n aria-label=\"Clear text\"\n onClick={handleClear}\n className={cn(\n \"absolute flex size-5 items-center justify-center self-end\",\n CLEAR_BUTTON_RIGHT[size],\n )}\n />\n )}\n {showValidated && (\n <div\n className={cn(\n \"pointer-events-none absolute flex size-5 items-center justify-center\",\n CLEAR_BUTTON_RIGHT[size],\n )}\n >\n <CheckOutlineIcon className=\"text-success-default\" />\n </div>\n )}\n </div>\n\n {bottomText && (\n <TextAreaHelperText id={helperTextId} error={error}>\n {bottomText}\n </TextAreaHelperText>\n )}\n </div>\n );\n },\n);\n\nTextArea.displayName = \"TextArea\";\n"],"names":[],"mappings":"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"}
@@ -25,7 +25,7 @@ const ICON_SPACING = {
25
25
  };
26
26
  function getContainerClassName(size, error, disabled) {
27
27
  return cn(
28
- "flex items-center overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors",
28
+ "flex items-center rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors",
29
29
  error ? "border-error-default" : "border-transparent",
30
30
  !disabled && !error && "hover:border-neutral-400",
31
31
  CONTAINER_HEIGHT[size],
@@ -37,6 +37,10 @@ function getContainerClassName(size, error, disabled) {
37
37
  function getInputClassName(size) {
38
38
  return cn(
39
39
  "h-full min-w-0 flex-1 rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed",
40
+ // Override browser autofill background so it fills the full container consistently
41
+ "[&:-webkit-autofill]:[box-shadow:inset_0_0_0_1000px_var(--color-neutral-100)] [&:-webkit-autofill]:[-webkit-text-fill-color:var(--color-foreground-default)]",
42
+ "[&:-webkit-autofill:hover]:[box-shadow:inset_0_0_0_1000px_var(--color-neutral-100)]",
43
+ "[&:-webkit-autofill:focus]:[box-shadow:inset_0_0_0_1000px_var(--color-neutral-100)]",
40
44
  INPUT_SIZE_CLASSES[size]
41
45
  );
42
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextField.mjs","sources":["../../../src/components/TextField/TextField.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CheckOutlineIcon } from \"@/index\";\nimport { cn } from \"../../utils/cn\";\n\n/** Text field height in pixels. */\nexport type TextFieldSize = \"48\" | \"40\" | \"32\";\n\nexport interface TextFieldProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"size\" | \"prefix\"> {\n /** Label text displayed above the input. Also used as the accessible name. */\n label?: string;\n /** Helper text displayed below the input. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Height of the text field in pixels. @default \"48\" */\n size?: TextFieldSize;\n /** Whether the text field is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the input. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Whether the text field is validated. @default false */\n validated?: boolean;\n /** Icon element displayed at the left side of the input. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed at the right side of the input. */\n rightIcon?: React.ReactNode;\n /** Whether the text field stretches to fill its container width. @default false */\n fullWidth?: boolean;\n}\n\nconst CONTAINER_HEIGHT: Record<TextFieldSize, string> = {\n \"48\": \"h-12\",\n \"40\": \"h-10\",\n \"32\": \"h-8\",\n};\n\nconst INPUT_SIZE_CLASSES: Record<TextFieldSize, string> = {\n \"48\": \"py-3 typography-regular-body-lg\",\n \"40\": \"py-2 typography-regular-body-lg\",\n \"32\": \"py-2 typography-regular-body-md\",\n};\n\nconst PADDING_HORIZONTAL: Record<TextFieldSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst ICON_SPACING: Record<TextFieldSize, string> = {\n \"48\": \"gap-3\",\n \"40\": \"gap-3\",\n \"32\": \"gap-2\",\n};\n\nfunction getContainerClassName(size: TextFieldSize, error: boolean, disabled?: boolean) {\n return cn(\n \"flex items-center overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n CONTAINER_HEIGHT[size],\n PADDING_HORIZONTAL[size],\n ICON_SPACING[size],\n disabled && \"opacity-50\",\n );\n}\n\nfunction getInputClassName(size: TextFieldSize) {\n return cn(\n \"h-full min-w-0 flex-1 rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n INPUT_SIZE_CLASSES[size],\n );\n}\n\nfunction TextFieldIcon({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n {children}\n </div>\n );\n}\n\nfunction TextFieldHelperText({\n id,\n error,\n children,\n}: {\n id: string;\n error: boolean;\n children: React.ReactNode;\n}) {\n return (\n <p\n id={id}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"TextField: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n/**\n * A text input field with optional label, helper/error text, and icon slots.\n *\n * Provide at least one of `label`, `aria-label`, or `aria-labelledby` for\n * accessibility — a console warning is emitted in development if none are set.\n *\n * @example\n * ```tsx\n * <TextField\n * label=\"Email\"\n * placeholder=\"you@example.com\"\n * error={!!emailError}\n * errorMessage={emailError}\n * />\n * ```\n */\nexport const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n validated = false,\n leftIcon,\n rightIcon,\n className,\n id,\n disabled,\n fullWidth = false,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n warnMissingAccessibleName(label, props[\"aria-label\"], props[\"aria-labelledby\"]);\n\n return (\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <div className={getContainerClassName(size, error, disabled)}>\n {leftIcon && <TextFieldIcon>{leftIcon}</TextFieldIcon>}\n\n <input\n ref={ref}\n id={inputId}\n disabled={disabled}\n aria-describedby={bottomText ? helperTextId : undefined}\n aria-invalid={error || undefined}\n className={cn(\n getInputClassName(size),\n // Hide native clear button for input[type=\"search\"] in WebKit browsers (Safari/Chrome)\n \"[&[type='search']::-webkit-search-cancel-button]:hidden [&[type='search']::-webkit-search-cancel-button]:appearance-none\",\n )}\n {...props}\n />\n\n {rightIcon && <TextFieldIcon>{rightIcon}</TextFieldIcon>}\n {validated && (\n <TextFieldIcon>\n <CheckOutlineIcon className=\"text-success-default\" />\n </TextFieldIcon>\n )}\n </div>\n\n {bottomText && (\n <TextFieldHelperText id={helperTextId} error={error}>\n {bottomText}\n </TextFieldHelperText>\n )}\n </div>\n );\n },\n);\n\nTextField.displayName = \"TextField\";\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TextField.mjs","sources":["../../../src/components/TextField/TextField.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CheckOutlineIcon } from \"@/index\";\nimport { cn } from \"../../utils/cn\";\n\n/** Text field height in pixels. */\nexport type TextFieldSize = \"48\" | \"40\" | \"32\";\n\nexport interface TextFieldProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"size\" | \"prefix\"> {\n /** Label text displayed above the input. Also used as the accessible name. */\n label?: string;\n /** Helper text displayed below the input. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Height of the text field in pixels. @default \"48\" */\n size?: TextFieldSize;\n /** Whether the text field is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the input. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Whether the text field is validated. @default false */\n validated?: boolean;\n /** Icon element displayed at the left side of the input. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed at the right side of the input. */\n rightIcon?: React.ReactNode;\n /** Whether the text field stretches to fill its container width. @default false */\n fullWidth?: boolean;\n}\n\nconst CONTAINER_HEIGHT: Record<TextFieldSize, string> = {\n \"48\": \"h-12\",\n \"40\": \"h-10\",\n \"32\": \"h-8\",\n};\n\nconst INPUT_SIZE_CLASSES: Record<TextFieldSize, string> = {\n \"48\": \"py-3 typography-regular-body-lg\",\n \"40\": \"py-2 typography-regular-body-lg\",\n \"32\": \"py-2 typography-regular-body-md\",\n};\n\nconst PADDING_HORIZONTAL: Record<TextFieldSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst ICON_SPACING: Record<TextFieldSize, string> = {\n \"48\": \"gap-3\",\n \"40\": \"gap-3\",\n \"32\": \"gap-2\",\n};\n\nfunction getContainerClassName(size: TextFieldSize, error: boolean, disabled?: boolean) {\n return cn(\n \"flex items-center rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n CONTAINER_HEIGHT[size],\n PADDING_HORIZONTAL[size],\n ICON_SPACING[size],\n disabled && \"opacity-50\",\n );\n}\n\nfunction getInputClassName(size: TextFieldSize) {\n return cn(\n \"h-full min-w-0 flex-1 rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n // Override browser autofill background so it fills the full container consistently\n \"[&:-webkit-autofill]:[box-shadow:inset_0_0_0_1000px_var(--color-neutral-100)] [&:-webkit-autofill]:[-webkit-text-fill-color:var(--color-foreground-default)]\",\n \"[&:-webkit-autofill:hover]:[box-shadow:inset_0_0_0_1000px_var(--color-neutral-100)]\",\n \"[&:-webkit-autofill:focus]:[box-shadow:inset_0_0_0_1000px_var(--color-neutral-100)]\",\n INPUT_SIZE_CLASSES[size],\n );\n}\n\nfunction TextFieldIcon({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n {children}\n </div>\n );\n}\n\nfunction TextFieldHelperText({\n id,\n error,\n children,\n}: {\n id: string;\n error: boolean;\n children: React.ReactNode;\n}) {\n return (\n <p\n id={id}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"TextField: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n/**\n * A text input field with optional label, helper/error text, and icon slots.\n *\n * Provide at least one of `label`, `aria-label`, or `aria-labelledby` for\n * accessibility — a console warning is emitted in development if none are set.\n *\n * @example\n * ```tsx\n * <TextField\n * label=\"Email\"\n * placeholder=\"you@example.com\"\n * error={!!emailError}\n * errorMessage={emailError}\n * />\n * ```\n */\nexport const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n validated = false,\n leftIcon,\n rightIcon,\n className,\n id,\n disabled,\n fullWidth = false,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n warnMissingAccessibleName(label, props[\"aria-label\"], props[\"aria-labelledby\"]);\n\n return (\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <div className={getContainerClassName(size, error, disabled)}>\n {leftIcon && <TextFieldIcon>{leftIcon}</TextFieldIcon>}\n\n <input\n ref={ref}\n id={inputId}\n disabled={disabled}\n aria-describedby={bottomText ? helperTextId : undefined}\n aria-invalid={error || undefined}\n className={cn(\n getInputClassName(size),\n // Hide native clear button for input[type=\"search\"] in WebKit browsers (Safari/Chrome)\n \"[&[type='search']::-webkit-search-cancel-button]:hidden [&[type='search']::-webkit-search-cancel-button]:appearance-none\",\n )}\n {...props}\n />\n\n {rightIcon && <TextFieldIcon>{rightIcon}</TextFieldIcon>}\n {validated && (\n <TextFieldIcon>\n <CheckOutlineIcon className=\"text-success-default\" />\n </TextFieldIcon>\n )}\n </div>\n\n {bottomText && (\n <TextFieldHelperText id={helperTextId} error={error}>\n {bottomText}\n </TextFieldHelperText>\n )}\n </div>\n );\n },\n);\n\nTextField.displayName = \"TextField\";\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -388,9 +388,9 @@ export declare const BottomNavigationAction: React_2.ForwardRefExoticComponent<B
388
388
  export declare interface BottomNavigationActionProps extends Omit<React_2.ButtonHTMLAttributes<HTMLButtonElement>, "value"> {
389
389
  /** Unique value that identifies this action. */
390
390
  value: string;
391
- /** Icon element displayed above the label. */
391
+ /** Icon element displayed in the action. */
392
392
  icon: React_2.ReactElement;
393
- /** Text label displayed below the icon. */
393
+ /** Accessible label applied as `aria-label`. */
394
394
  label?: string;
395
395
  /** Optional badge element (e.g. {@link Count}) rendered at the top-end corner of the icon. */
396
396
  badge?: React_2.ReactNode;
@@ -403,10 +403,6 @@ export declare interface BottomNavigationProps extends React_2.HTMLAttributes<HT
403
403
  value?: string;
404
404
  /** Called when the selected action changes. */
405
405
  onValueChange?: (value: string) => void;
406
- /** When `true`, labels are only shown on the active action. @default false */
407
- showLabelsOnlyWhenActive?: boolean;
408
- /** When `true`, all labels are hidden. @default false */
409
- hideLabels?: boolean;
410
406
  /** When `true`, the navigation bar is hidden on viewports wider than `md` (768 px). @default false */
411
407
  hideOnDesktop?: boolean;
412
408
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanvue/ui",
3
- "version": "1.18.0",
3
+ "version": "1.18.2",
4
4
  "description": "React component library built with Tailwind CSS for Fanvue ecosystem",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",