infinity-ui-elements 1.4.1-beta.2 → 1.4.1-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -5,7 +5,7 @@ import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import { PulseLoader, ClipLoader } from 'react-spinners';
8
- import { ExternalLink } from 'lucide-react';
8
+ import { ExternalLink, Loader2, Search } from 'lucide-react';
9
9
 
10
10
  // Define patterns for custom classes that should be preserved
11
11
  // This approach is more scalable than hardcoding individual class names
@@ -990,6 +990,303 @@ const Divider = React.forwardRef(({ className, orientation = "horizontal", thick
990
990
  });
991
991
  Divider.displayName = "Divider";
992
992
 
993
+ const listItemVariants = cva("flex items-start gap-3 p-3 rounded-medium transition-colors cursor-pointer", {
994
+ variants: {
995
+ variant: {
996
+ default: `hover:bg-action-fill-neutral-faded
997
+ focus:bg-action-fill-neutral-faded
998
+ focus:ring-2
999
+ ring-action-outline-primary-faded-hover
1000
+ border border-transparent
1001
+ `,
1002
+ bordered: "border border-action-outline-primary-faded hover:bg-surface-fill-primary-subtle",
1003
+ primary: `hover:bg-action-fill-neutral-faded
1004
+ focus:bg-action-fill-neutral-faded
1005
+ focus:ring-2
1006
+ ring-action-outline-primary-faded-hover
1007
+ border border-transparent
1008
+ `,
1009
+ negative: `hover:bg-action-fill-negative-faded
1010
+ focus:bg-action-fill-negative-faded
1011
+ focus:ring-2 ring-action-outline-negative-faded-hover
1012
+ border border-transparent
1013
+ `,
1014
+ },
1015
+ isDisabled: {
1016
+ true: "cursor-not-allowed opacity-60",
1017
+ false: "",
1018
+ },
1019
+ isSelected: {
1020
+ true: "bg-action-fill-primary-faded border-action-outline-primary-faded",
1021
+ false: "",
1022
+ },
1023
+ },
1024
+ defaultVariants: {
1025
+ variant: "default",
1026
+ isDisabled: false,
1027
+ isSelected: false,
1028
+ },
1029
+ });
1030
+ const ChevronRightIcon = ({ className }) => (jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, children: jsx("path", { d: "M7.5 15L12.5 10L7.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
1031
+ const ListItem = React.forwardRef(({ className, type = "single", leadingIcon, title, description, trailingIcon, showChevron = true, variant = "default", isDisabled = false, isSelected = false, onSelectionChange, checkboxSize = "small", containerClassName, contentClassName, onClick, ...props }, ref) => {
1032
+ const [internalSelected, setInternalSelected] = React.useState(isSelected);
1033
+ // Sync internal state with prop
1034
+ React.useEffect(() => {
1035
+ setInternalSelected(isSelected);
1036
+ }, [isSelected]);
1037
+ const handleClick = (e) => {
1038
+ if (isDisabled)
1039
+ return;
1040
+ if (type === "multiple") {
1041
+ const newSelected = !internalSelected;
1042
+ setInternalSelected(newSelected);
1043
+ onSelectionChange?.(newSelected);
1044
+ }
1045
+ onClick?.(e);
1046
+ };
1047
+ const handleCheckboxChange = (e) => {
1048
+ e.stopPropagation();
1049
+ if (isDisabled)
1050
+ return;
1051
+ const newSelected = e.target.checked;
1052
+ setInternalSelected(newSelected);
1053
+ onSelectionChange?.(newSelected);
1054
+ };
1055
+ return (jsxs("div", { ref: ref, className: cn(listItemVariants({
1056
+ variant,
1057
+ isDisabled,
1058
+ isSelected: type === "multiple" ? internalSelected : false,
1059
+ }), containerClassName), onClick: handleClick, role: type === "multiple" ? "checkbox" : "button", "aria-checked": type === "multiple" ? internalSelected : undefined, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, ...props, children: [type === "multiple" && (jsx(Checkbox, { checked: internalSelected, onChange: handleCheckboxChange, isDisabled: isDisabled, size: checkboxSize, className: "shrink-0 mt-0.5" })), leadingIcon && (jsx("div", { className: cn(`shrink-0 flex items-center justify-center mt-0.5`, variant === "primary"
1060
+ ? "text-action-ink-primary-normal"
1061
+ : variant === "negative"
1062
+ ? "text-action-ink-negative-normal"
1063
+ : "text-action-ink-neutral-subtle", isDisabled && "text-surface-ink-neutral-disabled"), children: leadingIcon })), jsxs("div", { className: cn("flex-1 min-w-0 flex flex-col justify-center", contentClassName), children: [jsx("div", { className: cn("text-body-medium-regular truncate", variant === "primary"
1064
+ ? "text-action-ink-primary-normal"
1065
+ : variant === "negative"
1066
+ ? "text-action-ink-negative-normal"
1067
+ : "text-action-ink-neutral-normal", isDisabled && "text-surface-ink-neutral-disabled"), children: title }), description && (jsx("div", { className: cn("text-body-small-regular text-surface-ink-neutral-muted mt-0.5 line-clamp-2", isDisabled && "text-surface-ink-neutral-disabled"), children: description }))] }), (trailingIcon || showChevron) && (jsx("div", { className: "shrink-0 self-center text-action-ink-neutral-subtle", children: trailingIcon || jsx(ChevronRightIcon, {}) }))] }));
1068
+ });
1069
+ ListItem.displayName = "ListItem";
1070
+
1071
+ const linkVariants = cva("inline-flex items-center gap-1 whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none decoration-1 underline-offset-4", {
1072
+ variants: {
1073
+ type: {
1074
+ anchor: "hover:underline",
1075
+ action: "no-underline cursor-pointer",
1076
+ },
1077
+ color: {
1078
+ primary: "",
1079
+ positive: "",
1080
+ negative: "",
1081
+ notice: "",
1082
+ info: "",
1083
+ neutral: "",
1084
+ },
1085
+ size: {
1086
+ xsmall: "text-body-xsmall-medium gap-1",
1087
+ small: "text-body-small-medium gap-1",
1088
+ medium: "text-body-medium-medium gap-1.5",
1089
+ large: "text-body-large-medium gap-1.5",
1090
+ },
1091
+ isIconOnly: {
1092
+ true: "no-underline",
1093
+ false: "",
1094
+ },
1095
+ isDisabled: {
1096
+ true: "cursor-not-allowed opacity-50",
1097
+ false: "cursor-pointer",
1098
+ },
1099
+ },
1100
+ compoundVariants: [
1101
+ // Primary color variants
1102
+ {
1103
+ color: "primary",
1104
+ class: `text-action-ink-primary-normal
1105
+ hover:text-action-ink-primary-subtle
1106
+ hover:decoration-action-outline-primary-hover
1107
+ disabled:text-action-ink-primary-disabled
1108
+ focus:text-action-ink-primary-hover
1109
+ `,
1110
+ },
1111
+ // Positive color variants
1112
+ {
1113
+ color: "positive",
1114
+ class: `text-action-ink-positive-normal
1115
+ hover:text-action-ink-positive-subtle
1116
+ hover:decoration-action-outline-positive-hover
1117
+ hover:text-action-ink-positive-hover
1118
+ disabled:text-action-ink-positive-disabled
1119
+ focus:text-action-ink-positive-hover
1120
+ `,
1121
+ },
1122
+ // Negative color variants
1123
+ {
1124
+ color: "negative",
1125
+ class: `text-action-ink-negative-normal
1126
+ hover:text-action-ink-negative-subtle
1127
+ hover:decoration-action-outline-negative-hover
1128
+ hover:text-action-ink-negative-hover
1129
+ disabled:text-action-ink-negative-disabled
1130
+ focus:text-action-ink-negative-hover
1131
+ `,
1132
+ },
1133
+ // Notice color variants
1134
+ {
1135
+ color: "notice",
1136
+ class: `text-action-ink-notice-normal
1137
+ hover:text-action-ink-notice-subtle
1138
+ hover:decoration-action-outline-notice-hover
1139
+ hover:text-action-ink-notice-hover
1140
+ disabled:text-action-ink-notice-disabled
1141
+ focus:text-action-ink-notice-hover
1142
+ `,
1143
+ },
1144
+ // Info color variants
1145
+ {
1146
+ color: "info",
1147
+ class: `text-action-ink-info-normal
1148
+ hover:text-action-ink-info-subtle
1149
+ hover:decoration-action-outline-info-hover
1150
+ hover:text-action-ink-info-hover
1151
+ disabled:text-action-ink-info-disabled
1152
+ focus:text-action-ink-info-hover
1153
+ `,
1154
+ },
1155
+ // Neutral color variants
1156
+ {
1157
+ color: "neutral",
1158
+ class: `text-action-ink-neutral-normal
1159
+ hover:text-action-ink-neutral-subtle
1160
+ hover:decoration-action-outline-neutral-hover
1161
+ hover:text-action-ink-neutral-hover
1162
+ disabled:text-action-ink-neutral-disabled
1163
+ focus:text-action-ink-neutral-hover
1164
+ `,
1165
+ },
1166
+ ],
1167
+ defaultVariants: {
1168
+ type: "anchor",
1169
+ color: "primary",
1170
+ size: "medium",
1171
+ isIconOnly: false,
1172
+ isDisabled: false,
1173
+ },
1174
+ });
1175
+ const Link = React.forwardRef(({ className, type = "anchor", color = "primary", size = "medium", isIconOnly = false, isDisabled = false, asChild = false, showIcon = false, icon, leadingIcon, trailingIcon, children, onClick, ...props }, ref) => {
1176
+ const Comp = asChild ? Slot : "a";
1177
+ const handleClick = (e) => {
1178
+ if (isDisabled) {
1179
+ e.preventDefault();
1180
+ return;
1181
+ }
1182
+ onClick?.(e);
1183
+ };
1184
+ // Icon size based on link size
1185
+ const iconSize = {
1186
+ xsmall: 12,
1187
+ small: 14,
1188
+ medium: 16,
1189
+ large: 18,
1190
+ }[size];
1191
+ // Determine what to show as trailing icon
1192
+ // Priority: trailingIcon > (showIcon && icon) > (showIcon && default ExternalLink)
1193
+ const finalTrailingIcon = trailingIcon || (showIcon && (icon || jsx(ExternalLink, { size: iconSize })));
1194
+ const linkContent = (jsxs(Fragment, { children: [leadingIcon && !isIconOnly && (jsx("span", { className: "inline-flex items-center", children: leadingIcon })), !isIconOnly && children, isIconOnly && children, finalTrailingIcon && !isIconOnly && (jsx("span", { className: "inline-flex items-center", children: finalTrailingIcon })), isIconOnly &&
1195
+ (leadingIcon || finalTrailingIcon || (jsx(ExternalLink, { size: iconSize })))] }));
1196
+ return (jsx(Comp, { className: cn(linkVariants({
1197
+ type,
1198
+ color,
1199
+ size,
1200
+ isIconOnly,
1201
+ isDisabled,
1202
+ }), className), ref: ref, onClick: handleClick, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : undefined, ...props, children: linkContent }));
1203
+ });
1204
+ Link.displayName = "Link";
1205
+
1206
+ const DropdownMenu = React.forwardRef(({ items = [], sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, onClose, focusedIndex = -1, className, width = "auto", }, ref) => {
1207
+ const renderContent = () => {
1208
+ if (isLoading) {
1209
+ return (jsx("div", { className: "flex flex-col items-center justify-center py-12 px-6", children: jsx(Loader2, { className: "w-12 h-12 text-action-ink-primary-normal mb-4 animate-spin" }) }));
1210
+ }
1211
+ if (isEmpty || items.length === 0) {
1212
+ return (jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-6 text-center", children: [emptyIcon || (jsx(Search, { className: "w-12 h-12 text-surface-ink-neutral-muted mb-4" })), jsx(Text, { as: "h3", variant: "body", size: "small", weight: "semibold", className: "text-surface-ink-neutral-normal mb-2", children: emptyTitle }), jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", className: "text-surface-ink-neutral-muted mb-3", children: emptyDescription }), emptyLinkText && (jsx(Link, { type: "anchor", color: "primary", size: "small", onClick: onEmptyLinkClick, children: emptyLinkText }))] }));
1213
+ }
1214
+ return (jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsx("div", { className: "flex flex-col gap-1", children: items.map((item, index) => (jsx(ListItem, { title: item.title, description: item.description, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon, showChevron: showChevron, isDisabled: item.isDisabled, isSelected: index === focusedIndex, onClick: () => {
1215
+ item.onClick?.();
1216
+ onClose?.();
1217
+ }, containerClassName: cn(index === focusedIndex && "bg-action-fill-primary-faded") }, item.id))) })] }));
1218
+ };
1219
+ const widthClass = width === "full" ? "w-full" : width === "auto" ? "w-auto" : "";
1220
+ return (jsxs("div", { ref: ref, className: cn("bg-surface-fill-primary-normal rounded-large overflow-hidden", widthClass, className), style: {
1221
+ boxShadow: "0 1px 2px rgba(25, 25, 30, 0.1), 0 2px 6px rgba(25, 25, 30, 0.06)",
1222
+ ...(width !== "full" && width !== "auto" ? { width } : {}),
1223
+ }, children: [renderContent(), !disableFooter && (jsxs("div", { className: "flex flex-col", children: [jsx(Divider, { thickness: "thin", variant: "muted" }), jsxs("div", { className: "flex items-center gap-3 p-4", children: [jsx(Button, { variant: "secondary", color: "primary", size: "medium", isFullWidth: true, onClick: onSecondaryClick, children: secondaryButtonText }), jsx(Button, { variant: "primary", color: "primary", size: "medium", isFullWidth: true, onClick: onPrimaryClick, children: primaryButtonText })] })] }))] }));
1224
+ });
1225
+ DropdownMenu.displayName = "DropdownMenu";
1226
+
1227
+ const dropdownVariants = cva("bg-surface-fill-primary-normal border border-surface-outline-neutral-subtle rounded-large", {
1228
+ variants: {
1229
+ size: {
1230
+ small: "w-64",
1231
+ medium: "w-80",
1232
+ large: "w-96",
1233
+ },
1234
+ },
1235
+ defaultVariants: {
1236
+ size: "medium",
1237
+ },
1238
+ });
1239
+ const Dropdown = React.forwardRef(({ className, trigger, items = [], sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, size = "medium", open: controlledOpen, defaultOpen = false, onOpenChange, containerClassName, menuClassName, showChevron = false, emptyIcon, disableFooter = false, ...props }, ref) => {
1240
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
1241
+ const isOpen = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;
1242
+ const dropdownRef = React.useRef(null);
1243
+ const handleOpenChange = (newOpen) => {
1244
+ if (controlledOpen === undefined) {
1245
+ setUncontrolledOpen(newOpen);
1246
+ }
1247
+ onOpenChange?.(newOpen);
1248
+ };
1249
+ const toggleOpen = () => {
1250
+ handleOpenChange(!isOpen);
1251
+ };
1252
+ // Close dropdown when clicking outside
1253
+ React.useEffect(() => {
1254
+ const handleClickOutside = (event) => {
1255
+ if (dropdownRef.current &&
1256
+ !dropdownRef.current.contains(event.target)) {
1257
+ handleOpenChange(false);
1258
+ }
1259
+ };
1260
+ if (isOpen) {
1261
+ document.addEventListener("mousedown", handleClickOutside);
1262
+ return () => {
1263
+ document.removeEventListener("mousedown", handleClickOutside);
1264
+ };
1265
+ }
1266
+ }, [isOpen]);
1267
+ // Close on escape key
1268
+ React.useEffect(() => {
1269
+ const handleEscape = (event) => {
1270
+ if (event.key === "Escape") {
1271
+ handleOpenChange(false);
1272
+ }
1273
+ };
1274
+ if (isOpen) {
1275
+ document.addEventListener("keydown", handleEscape);
1276
+ return () => {
1277
+ document.removeEventListener("keydown", handleEscape);
1278
+ };
1279
+ }
1280
+ }, [isOpen]);
1281
+ const sizeMap = {
1282
+ small: "w-64",
1283
+ medium: "w-80",
1284
+ large: "w-96",
1285
+ };
1286
+ return (jsxs("div", { ref: dropdownRef, className: cn("relative inline-block", containerClassName), ...props, children: [trigger && (jsx("div", { onClick: toggleOpen, className: "cursor-pointer", children: trigger })), isOpen && (jsx(DropdownMenu, { ref: ref, items: items, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: isEmpty, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, onClose: () => handleOpenChange(false), className: cn("absolute z-50 mt-2", menuClassName, className), width: sizeMap[size] }))] }));
1287
+ });
1288
+ Dropdown.displayName = "Dropdown";
1289
+
993
1290
  const tooltipVariants = cva("fixed z-50 bg-popup-fill-intense text-action-ink-on-primary-normal rounded-medium border border-popup-outline-subtle flex flex-col p-4 rounded-xlarge min-w-[200px] max-w-[300px] transition-opacity duration-200", {
994
1291
  variants: {
995
1292
  isVisible: {
@@ -1239,218 +1536,10 @@ const FormHeader = React.forwardRef(({ label, size = "medium", isOptional = fals
1239
1536
  gap: "gap-2.5",
1240
1537
  },
1241
1538
  };
1242
- const config = sizeConfig[size];
1243
- return (jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-1", config.gap, className), children: [jsxs("div", { className: cn("flex items-center", config.gap), children: [jsxs("label", { htmlFor: htmlFor, className: cn("flex items-center", labelClassName), children: [jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", color: "subtle", children: label }), isRequired && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", className: "text-feedback-ink-negative-subtle ml-0.5", children: "*" })), isOptional && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", className: "text-surface-ink-neutral-muted ml-1", children: "(optional)" }))] }), infoDescription && (jsx(Tooltip, { description: infoDescription, heading: infoHeading, children: jsxs("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-surface-ink-neutral-muted cursor-help", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1" }), jsx("path", { d: "M7 6V10M7 4.5V4", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })] }) }))] }), linkText && (jsx("a", { href: linkHref, onClick: onLinkClick, className: cn("text-surface-ink-primary-normal hover:text-surface-ink-primary-hover transition-colors cursor-pointer font-display font-semibold leading-tight shrink-0", size === "small" && "text-xs", size === "medium" && "text-xs", size === "large" && "text-sm", linkClassName), children: linkText }))] }));
1244
- });
1245
- FormHeader.displayName = "FormHeader";
1246
-
1247
- const linkVariants = cva("inline-flex items-center gap-1 whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none underline decoration-1 underline-offset-4", {
1248
- variants: {
1249
- type: {
1250
- anchor: "",
1251
- action: "cursor-pointer",
1252
- },
1253
- color: {
1254
- primary: "",
1255
- positive: "",
1256
- negative: "",
1257
- notice: "",
1258
- info: "",
1259
- neutral: "",
1260
- },
1261
- size: {
1262
- xsmall: "text-body-xsmall-medium gap-1",
1263
- small: "text-body-small-medium gap-1",
1264
- medium: "text-body-medium-medium gap-1.5",
1265
- large: "text-body-large-medium gap-1.5",
1266
- },
1267
- isIconOnly: {
1268
- true: "no-underline",
1269
- false: "",
1270
- },
1271
- isDisabled: {
1272
- true: "cursor-not-allowed opacity-50",
1273
- false: "cursor-pointer",
1274
- },
1275
- },
1276
- compoundVariants: [
1277
- // Primary color variants
1278
- {
1279
- color: "primary",
1280
- class: `text-action-ink-primary-normal
1281
- hover:text-action-ink-primary-hover
1282
- disabled:text-action-ink-primary-disabled
1283
- active:text-action-ink-primary-activated
1284
- focus:text-action-ink-primary-hover
1285
- `,
1286
- },
1287
- // Positive color variants
1288
- {
1289
- color: "positive",
1290
- class: `text-action-ink-positive-normal
1291
- hover:text-action-ink-positive-hover
1292
- disabled:text-action-ink-positive-disabled
1293
- active:text-action-ink-positive-activated
1294
- focus:text-action-ink-positive-hover
1295
- `,
1296
- },
1297
- // Negative color variants
1298
- {
1299
- color: "negative",
1300
- class: `text-action-ink-negative-normal
1301
- hover:text-action-ink-negative-hover
1302
- disabled:text-action-ink-negative-disabled
1303
- active:text-action-ink-negative-activated
1304
- focus:text-action-ink-negative-hover
1305
- `,
1306
- },
1307
- // Notice color variants
1308
- {
1309
- color: "notice",
1310
- class: `text-action-ink-notice-normal
1311
- hover:text-action-ink-notice-hover
1312
- disabled:text-action-ink-notice-disabled
1313
- active:text-action-ink-notice-activated
1314
- focus:text-action-ink-notice-hover
1315
- `,
1316
- },
1317
- // Info color variants
1318
- {
1319
- color: "info",
1320
- class: `text-action-ink-info-normal
1321
- hover:text-action-ink-info-hover
1322
- disabled:text-action-ink-info-disabled
1323
- active:text-action-ink-info-activated
1324
- focus:text-action-ink-info-hover
1325
- `,
1326
- },
1327
- // Neutral color variants
1328
- {
1329
- color: "neutral",
1330
- class: `text-action-ink-neutral-normal
1331
- hover:text-action-ink-neutral-hover
1332
- disabled:text-action-ink-neutral-disabled
1333
- active:text-action-ink-neutral-activated
1334
- focus:text-action-ink-neutral-hover
1335
- `,
1336
- },
1337
- ],
1338
- defaultVariants: {
1339
- type: "anchor",
1340
- color: "primary",
1341
- size: "medium",
1342
- isIconOnly: false,
1343
- isDisabled: false,
1344
- },
1345
- });
1346
- const Link = React.forwardRef(({ className, type = "anchor", color = "primary", size = "medium", isIconOnly = false, isDisabled = false, asChild = false, showIcon = false, icon, leadingIcon, trailingIcon, children, onClick, ...props }, ref) => {
1347
- const Comp = asChild ? Slot : "a";
1348
- const handleClick = (e) => {
1349
- if (isDisabled) {
1350
- e.preventDefault();
1351
- return;
1352
- }
1353
- onClick?.(e);
1354
- };
1355
- // Icon size based on link size
1356
- const iconSize = {
1357
- xsmall: 12,
1358
- small: 14,
1359
- medium: 16,
1360
- large: 18,
1361
- }[size];
1362
- // Determine what to show as trailing icon
1363
- // Priority: trailingIcon > (showIcon && icon) > (showIcon && default ExternalLink)
1364
- const finalTrailingIcon = trailingIcon || (showIcon && (icon || jsx(ExternalLink, { size: iconSize })));
1365
- const linkContent = (jsxs(Fragment, { children: [leadingIcon && !isIconOnly && (jsx("span", { className: "inline-flex items-center", children: leadingIcon })), !isIconOnly && children, isIconOnly && children, finalTrailingIcon && !isIconOnly && (jsx("span", { className: "inline-flex items-center", children: finalTrailingIcon })), isIconOnly &&
1366
- (leadingIcon || finalTrailingIcon || (jsx(ExternalLink, { size: iconSize })))] }));
1367
- return (jsx(Comp, { className: cn(linkVariants({
1368
- type,
1369
- color,
1370
- size,
1371
- isIconOnly,
1372
- isDisabled,
1373
- }), className), ref: ref, onClick: handleClick, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : undefined, ...props, children: linkContent }));
1374
- });
1375
- Link.displayName = "Link";
1376
-
1377
- const listItemVariants = cva("flex items-start gap-3 p-3 rounded-medium transition-colors cursor-pointer", {
1378
- variants: {
1379
- variant: {
1380
- default: `hover:bg-action-fill-neutral-faded
1381
- focus:bg-action-fill-neutral-faded
1382
- focus:ring-2
1383
- ring-action-outline-primary-faded-hover
1384
- border border-transparent
1385
- `,
1386
- bordered: "border border-action-outline-primary-faded hover:bg-surface-fill-primary-subtle",
1387
- primary: `hover:bg-action-fill-neutral-faded
1388
- focus:bg-action-fill-neutral-faded
1389
- focus:ring-2
1390
- ring-action-outline-primary-faded-hover
1391
- border border-transparent
1392
- `,
1393
- negative: `hover:bg-action-fill-negative-faded
1394
- focus:bg-action-fill-negative-faded
1395
- focus:ring-2 ring-action-outline-negative-faded-hover
1396
- border border-transparent
1397
- `,
1398
- },
1399
- isDisabled: {
1400
- true: "cursor-not-allowed opacity-60",
1401
- false: "",
1402
- },
1403
- isSelected: {
1404
- true: "bg-action-fill-primary-faded border-action-outline-primary-faded",
1405
- false: "",
1406
- },
1407
- },
1408
- defaultVariants: {
1409
- variant: "default",
1410
- isDisabled: false,
1411
- isSelected: false,
1412
- },
1413
- });
1414
- const ChevronRightIcon = ({ className }) => (jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, children: jsx("path", { d: "M7.5 15L12.5 10L7.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
1415
- const ListItem = React.forwardRef(({ className, type = "single", leadingIcon, title, description, trailingIcon, showChevron = true, variant = "default", isDisabled = false, isSelected = false, onSelectionChange, checkboxSize = "small", containerClassName, contentClassName, onClick, ...props }, ref) => {
1416
- const [internalSelected, setInternalSelected] = React.useState(isSelected);
1417
- // Sync internal state with prop
1418
- React.useEffect(() => {
1419
- setInternalSelected(isSelected);
1420
- }, [isSelected]);
1421
- const handleClick = (e) => {
1422
- if (isDisabled)
1423
- return;
1424
- if (type === "multiple") {
1425
- const newSelected = !internalSelected;
1426
- setInternalSelected(newSelected);
1427
- onSelectionChange?.(newSelected);
1428
- }
1429
- onClick?.(e);
1430
- };
1431
- const handleCheckboxChange = (e) => {
1432
- e.stopPropagation();
1433
- if (isDisabled)
1434
- return;
1435
- const newSelected = e.target.checked;
1436
- setInternalSelected(newSelected);
1437
- onSelectionChange?.(newSelected);
1438
- };
1439
- return (jsxs("div", { ref: ref, className: cn(listItemVariants({
1440
- variant,
1441
- isDisabled,
1442
- isSelected: type === "multiple" ? internalSelected : false,
1443
- }), containerClassName), onClick: handleClick, role: type === "multiple" ? "checkbox" : "button", "aria-checked": type === "multiple" ? internalSelected : undefined, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, ...props, children: [type === "multiple" && (jsx(Checkbox, { checked: internalSelected, onChange: handleCheckboxChange, isDisabled: isDisabled, size: checkboxSize, className: "shrink-0 mt-0.5" })), leadingIcon && (jsx("div", { className: cn(`shrink-0 flex items-center justify-center mt-0.5`, variant === "primary"
1444
- ? "text-action-ink-primary-normal"
1445
- : variant === "negative"
1446
- ? "text-action-ink-negative-normal"
1447
- : "text-action-ink-neutral-subtle", isDisabled && "text-surface-ink-neutral-disabled"), children: leadingIcon })), jsxs("div", { className: cn("flex-1 min-w-0 flex flex-col justify-center", contentClassName), children: [jsx("div", { className: cn("text-body-medium-regular truncate", variant === "primary"
1448
- ? "text-action-ink-primary-normal"
1449
- : variant === "negative"
1450
- ? "text-action-ink-negative-normal"
1451
- : "text-action-ink-neutral-normal", isDisabled && "text-surface-ink-neutral-disabled"), children: title }), description && (jsx("div", { className: cn("text-body-small-regular text-surface-ink-neutral-muted mt-0.5 line-clamp-2", isDisabled && "text-surface-ink-neutral-disabled"), children: description }))] }), (trailingIcon || showChevron) && (jsx("div", { className: "shrink-0 self-center text-action-ink-neutral-subtle", children: trailingIcon || jsx(ChevronRightIcon, {}) }))] }));
1539
+ const config = sizeConfig[size];
1540
+ return (jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-1", config.gap, className), children: [jsxs("div", { className: cn("flex items-center", config.gap), children: [jsxs("label", { htmlFor: htmlFor, className: cn("flex items-center", labelClassName), children: [jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", color: "subtle", children: label }), isRequired && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", className: "text-feedback-ink-negative-subtle ml-0.5", children: "*" })), isOptional && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", className: "text-surface-ink-neutral-muted ml-1", children: "(optional)" }))] }), infoDescription && (jsx(Tooltip, { description: infoDescription, heading: infoHeading, children: jsxs("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-surface-ink-neutral-muted cursor-help", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1" }), jsx("path", { d: "M7 6V10M7 4.5V4", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })] }) }))] }), linkText && (jsx("a", { href: linkHref, onClick: onLinkClick, className: cn("text-surface-ink-primary-normal hover:text-surface-ink-primary-hover transition-colors cursor-pointer font-display font-semibold leading-tight shrink-0", size === "small" && "text-xs", size === "medium" && "text-xs", size === "large" && "text-sm", linkClassName), children: linkText }))] }));
1452
1541
  });
1453
- ListItem.displayName = "ListItem";
1542
+ FormHeader.displayName = "FormHeader";
1454
1543
 
1455
1544
  const radioVariants = cva("relative inline-flex items-center justify-center shrink-0 border transition-all cursor-pointer rounded-full", {
1456
1545
  variants: {
@@ -1617,6 +1706,214 @@ const Radio = React.forwardRef(({ label, errorText, size = "medium", validationS
1617
1706
  });
1618
1707
  Radio.displayName = "Radio";
1619
1708
 
1709
+ const textFieldVariants = cva("relative flex items-center gap-2 border rounded-medium transition-all font-display font-size-100 leading-100", {
1710
+ variants: {
1711
+ size: {
1712
+ small: "h-[28px] px-3 text-xs gap-2",
1713
+ medium: "h-[36px] px-4 text-sm gap-2",
1714
+ large: "h-[44px] px-5 text-base gap-3",
1715
+ },
1716
+ validationState: {
1717
+ none: `
1718
+ border-action-outline-neutral-faded
1719
+ hover:border-action-outline-primary-hover
1720
+ focus-within:border-action-outline-primary-hover
1721
+ focus-within:ring-2
1722
+ ring-action-outline-primary-faded-hover`,
1723
+ positive: `
1724
+ border-action-outline-positive-default
1725
+ focus-within:border-action-outline-positive-hover
1726
+ focus-within:ring-2
1727
+ ring-action-outline-positive-faded-hover`,
1728
+ negative: `border-action-outline-negative-default
1729
+ focus-within:border-action-outline-negative-hover
1730
+ focus-within:ring-2
1731
+ ring-action-outline-negative-faded-hover`,
1732
+ },
1733
+ isDisabled: {
1734
+ true: `
1735
+ border-[var(--border-width-thinner)]
1736
+ hover:border-action-outline-neutral-disabled
1737
+ border-action-outline-neutral-disabled
1738
+ bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
1739
+ false: "bg-surface-fill-neutral-intense",
1740
+ },
1741
+ },
1742
+ defaultVariants: {
1743
+ size: "medium",
1744
+ validationState: "none",
1745
+ isDisabled: false,
1746
+ },
1747
+ });
1748
+ const TextField = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isRequired = false, isOptional = false, prefix, suffix, showClearButton = false, infoDescription, infoHeading, linkText, linkHref, onLinkClick, onClear, containerClassName, labelClassName, inputClassName, className, value, onChange, ...props }, ref) => {
1749
+ const [internalValue, setInternalValue] = React.useState("");
1750
+ const inputValue = value !== undefined ? value : internalValue;
1751
+ const hasValue = inputValue && String(inputValue).length > 0;
1752
+ const handleChange = (e) => {
1753
+ if (onChange) {
1754
+ onChange(e);
1755
+ }
1756
+ else {
1757
+ setInternalValue(e.target.value);
1758
+ }
1759
+ };
1760
+ const handleClear = () => {
1761
+ if (onClear) {
1762
+ onClear();
1763
+ }
1764
+ else {
1765
+ setInternalValue("");
1766
+ }
1767
+ // Focus the input after clearing
1768
+ const input = document.getElementById(props.id || "");
1769
+ if (input) {
1770
+ input.focus();
1771
+ }
1772
+ };
1773
+ // Determine which helper text to show
1774
+ const displayHelperText = errorText || successText || helperText;
1775
+ const currentValidationState = errorText
1776
+ ? "negative"
1777
+ : successText
1778
+ ? "positive"
1779
+ : validationState;
1780
+ const sizeConfig = {
1781
+ small: {
1782
+ gap: "gap-2",
1783
+ },
1784
+ medium: {
1785
+ gap: "gap-2",
1786
+ },
1787
+ large: {
1788
+ gap: "gap-3",
1789
+ },
1790
+ };
1791
+ return (jsxs("div", { className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { className: cn(textFieldVariants({
1792
+ size,
1793
+ validationState: currentValidationState,
1794
+ isDisabled,
1795
+ }), className), children: [prefix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
1796
+ ? "text-surface-ink-neutral-disabled"
1797
+ : currentValidationState === "positive"
1798
+ ? "text-feedback-ink-positive-intense"
1799
+ : currentValidationState === "negative"
1800
+ ? "text-feedback-ink-negative-subtle"
1801
+ : "text-surface-ink-neutral-muted"), children: prefix })), jsx("input", { ref: ref, value: inputValue, onChange: handleChange, disabled: isDisabled, required: isRequired, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled font-display", inputClassName), ...props }), showClearButton && hasValue && !isDisabled && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
1802
+ ? "text-surface-ink-neutral-disabled"
1803
+ : currentValidationState === "positive"
1804
+ ? "text-feedback-ink-positive-intense"
1805
+ : currentValidationState === "negative"
1806
+ ? "text-feedback-ink-negative-subtle"
1807
+ : "text-surface-ink-neutral-muted"), children: suffix }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
1808
+ ? "default"
1809
+ : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
1810
+ });
1811
+ TextField.displayName = "TextField";
1812
+
1813
+ const defaultFilter = (item, query) => {
1814
+ const searchQuery = query.toLowerCase();
1815
+ return (item.title.toLowerCase().includes(searchQuery) ||
1816
+ (item.description?.toLowerCase().includes(searchQuery) ?? false));
1817
+ };
1818
+ const SearchableDropdown = React.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, dropdownWidth = "full", showChevron = false, emptyIcon, disableFooter = false, onSearchChange, onItemSelect, filterFunction = defaultFilter, searchValue: controlledSearchValue, defaultSearchValue = "", dropdownClassName, minSearchLength = 0, showOnFocus = true, containerClassName, ...textFieldProps }, ref) => {
1819
+ const [uncontrolledSearchValue, setUncontrolledSearchValue] = React.useState(defaultSearchValue);
1820
+ const [isOpen, setIsOpen] = React.useState(false);
1821
+ const [focusedIndex, setFocusedIndex] = React.useState(-1);
1822
+ const dropdownRef = React.useRef(null);
1823
+ const inputRef = React.useRef(null);
1824
+ React.useImperativeHandle(ref, () => inputRef.current);
1825
+ const searchValue = controlledSearchValue !== undefined
1826
+ ? controlledSearchValue
1827
+ : uncontrolledSearchValue;
1828
+ const handleSearchChange = (e) => {
1829
+ const newValue = e.target.value;
1830
+ if (controlledSearchValue === undefined) {
1831
+ setUncontrolledSearchValue(newValue);
1832
+ }
1833
+ onSearchChange?.(newValue);
1834
+ // Show dropdown if minimum search length is met
1835
+ if (newValue.length >= minSearchLength) {
1836
+ setIsOpen(true);
1837
+ }
1838
+ else {
1839
+ setIsOpen(false);
1840
+ }
1841
+ };
1842
+ const handleFocus = () => {
1843
+ if (showOnFocus && searchValue.length >= minSearchLength) {
1844
+ setIsOpen(true);
1845
+ }
1846
+ };
1847
+ const handleItemSelect = (item) => {
1848
+ onItemSelect?.(item);
1849
+ if (controlledSearchValue === undefined) {
1850
+ setUncontrolledSearchValue(item.value || item.title);
1851
+ }
1852
+ setIsOpen(false);
1853
+ inputRef.current?.focus();
1854
+ };
1855
+ // Filter items based on search
1856
+ const filteredItems = React.useMemo(() => {
1857
+ if (!searchValue)
1858
+ return items;
1859
+ return items.filter((item) => filterFunction(item, searchValue));
1860
+ }, [items, searchValue, filterFunction]);
1861
+ // Close dropdown when clicking outside
1862
+ React.useEffect(() => {
1863
+ const handleClickOutside = (event) => {
1864
+ if (dropdownRef.current &&
1865
+ !dropdownRef.current.contains(event.target)) {
1866
+ setIsOpen(false);
1867
+ }
1868
+ };
1869
+ if (isOpen) {
1870
+ document.addEventListener("mousedown", handleClickOutside);
1871
+ return () => {
1872
+ document.removeEventListener("mousedown", handleClickOutside);
1873
+ };
1874
+ }
1875
+ }, [isOpen]);
1876
+ // Handle keyboard navigation
1877
+ const handleKeyDown = (e) => {
1878
+ if (!isOpen) {
1879
+ if (e.key === "ArrowDown" || e.key === "Enter") {
1880
+ setIsOpen(true);
1881
+ e.preventDefault();
1882
+ }
1883
+ return;
1884
+ }
1885
+ switch (e.key) {
1886
+ case "ArrowDown":
1887
+ e.preventDefault();
1888
+ setFocusedIndex((prev) => prev < filteredItems.length - 1 ? prev + 1 : prev);
1889
+ break;
1890
+ case "ArrowUp":
1891
+ e.preventDefault();
1892
+ setFocusedIndex((prev) => (prev > 0 ? prev - 1 : -1));
1893
+ break;
1894
+ case "Enter":
1895
+ e.preventDefault();
1896
+ if (focusedIndex >= 0 && filteredItems[focusedIndex]) {
1897
+ handleItemSelect(filteredItems[focusedIndex]);
1898
+ }
1899
+ break;
1900
+ case "Escape":
1901
+ e.preventDefault();
1902
+ setIsOpen(false);
1903
+ setFocusedIndex(-1);
1904
+ break;
1905
+ }
1906
+ };
1907
+ // Update items with onClick handlers that call handleItemSelect
1908
+ const itemsWithHandlers = filteredItems.map((item) => ({
1909
+ ...item,
1910
+ onClick: () => handleItemSelect(item),
1911
+ }));
1912
+ const showDropdown = isOpen && searchValue.length >= minSearchLength;
1913
+ return (jsxs("div", { ref: dropdownRef, className: cn("relative", containerClassName), children: [jsx(TextField, { ref: inputRef, value: searchValue, onChange: handleSearchChange, onFocus: handleFocus, onKeyDown: handleKeyDown, containerClassName: "mb-0", ...textFieldProps }), showDropdown && (jsx(DropdownMenu, { items: itemsWithHandlers, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: filteredItems.length === 0, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, onClose: () => setIsOpen(false), focusedIndex: focusedIndex, className: cn("absolute z-50 mt-2", dropdownClassName), width: dropdownWidth === "full" ? "full" : "auto" }))] }));
1914
+ });
1915
+ SearchableDropdown.displayName = "SearchableDropdown";
1916
+
1620
1917
  const switchVariants = cva("relative inline-flex items-center shrink-0 cursor-pointer rounded-full transition-all duration-200", {
1621
1918
  variants: {
1622
1919
  size: {
@@ -1959,109 +2256,5 @@ const TextArea = React.forwardRef(({ label, helperText, errorText, successText,
1959
2256
  });
1960
2257
  TextArea.displayName = "TextArea";
1961
2258
 
1962
- const textFieldVariants = cva("relative flex items-center gap-2 border rounded-medium transition-all font-display font-size-100 leading-100", {
1963
- variants: {
1964
- size: {
1965
- small: "h-[28px] px-3 text-xs gap-2",
1966
- medium: "h-[36px] px-4 text-sm gap-2",
1967
- large: "h-[44px] px-5 text-base gap-3",
1968
- },
1969
- validationState: {
1970
- none: `
1971
- border-action-outline-neutral-faded
1972
- hover:border-action-outline-primary-hover
1973
- focus-within:border-action-outline-primary-hover
1974
- focus-within:ring-2
1975
- ring-action-outline-primary-faded-hover`,
1976
- positive: `
1977
- border-action-outline-positive-default
1978
- focus-within:border-action-outline-positive-hover
1979
- focus-within:ring-2
1980
- ring-action-outline-positive-faded-hover`,
1981
- negative: `border-action-outline-negative-default
1982
- focus-within:border-action-outline-negative-hover
1983
- focus-within:ring-2
1984
- ring-action-outline-negative-faded-hover`,
1985
- },
1986
- isDisabled: {
1987
- true: `
1988
- border-[var(--border-width-thinner)]
1989
- hover:border-action-outline-neutral-disabled
1990
- border-action-outline-neutral-disabled
1991
- bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
1992
- false: "bg-surface-fill-neutral-intense",
1993
- },
1994
- },
1995
- defaultVariants: {
1996
- size: "medium",
1997
- validationState: "none",
1998
- isDisabled: false,
1999
- },
2000
- });
2001
- const TextField = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isRequired = false, isOptional = false, prefix, suffix, showClearButton = false, infoDescription, infoHeading, linkText, linkHref, onLinkClick, onClear, containerClassName, labelClassName, inputClassName, className, value, onChange, ...props }, ref) => {
2002
- const [internalValue, setInternalValue] = React.useState("");
2003
- const inputValue = value !== undefined ? value : internalValue;
2004
- const hasValue = inputValue && String(inputValue).length > 0;
2005
- const handleChange = (e) => {
2006
- if (onChange) {
2007
- onChange(e);
2008
- }
2009
- else {
2010
- setInternalValue(e.target.value);
2011
- }
2012
- };
2013
- const handleClear = () => {
2014
- if (onClear) {
2015
- onClear();
2016
- }
2017
- else {
2018
- setInternalValue("");
2019
- }
2020
- // Focus the input after clearing
2021
- const input = document.getElementById(props.id || "");
2022
- if (input) {
2023
- input.focus();
2024
- }
2025
- };
2026
- // Determine which helper text to show
2027
- const displayHelperText = errorText || successText || helperText;
2028
- const currentValidationState = errorText
2029
- ? "negative"
2030
- : successText
2031
- ? "positive"
2032
- : validationState;
2033
- const sizeConfig = {
2034
- small: {
2035
- gap: "gap-2",
2036
- },
2037
- medium: {
2038
- gap: "gap-2",
2039
- },
2040
- large: {
2041
- gap: "gap-3",
2042
- },
2043
- };
2044
- return (jsxs("div", { className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { className: cn(textFieldVariants({
2045
- size,
2046
- validationState: currentValidationState,
2047
- isDisabled,
2048
- }), className), children: [prefix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
2049
- ? "text-surface-ink-neutral-disabled"
2050
- : currentValidationState === "positive"
2051
- ? "text-feedback-ink-positive-intense"
2052
- : currentValidationState === "negative"
2053
- ? "text-feedback-ink-negative-subtle"
2054
- : "text-surface-ink-neutral-muted"), children: prefix })), jsx("input", { ref: ref, value: inputValue, onChange: handleChange, disabled: isDisabled, required: isRequired, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled font-display", inputClassName), ...props }), showClearButton && hasValue && !isDisabled && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
2055
- ? "text-surface-ink-neutral-disabled"
2056
- : currentValidationState === "positive"
2057
- ? "text-feedback-ink-positive-intense"
2058
- : currentValidationState === "negative"
2059
- ? "text-feedback-ink-negative-subtle"
2060
- : "text-surface-ink-neutral-muted"), children: suffix }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
2061
- ? "default"
2062
- : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
2063
- });
2064
- TextField.displayName = "TextField";
2065
-
2066
- export { Badge, Button, Checkbox, Counter, Divider, FormFooter, FormHeader, Icon, Link, ListItem, Radio, Switch, TabItem, Tabs, Text, TextArea, TextField, Tooltip, badgeVariants, buttonVariants, checkboxVariants, cn, counterVariants, getAvailableIcons, hasIcon, iconRegistry, linkVariants, listItemVariants, radioVariants, switchVariants, textAreaVariants, textFieldVariants, tooltipVariants };
2259
+ export { Badge, Button, Checkbox, Counter, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, Link, ListItem, Radio, SearchableDropdown, Switch, TabItem, Tabs, Text, TextArea, TextField, Tooltip, badgeVariants, buttonVariants, checkboxVariants, cn, counterVariants, dropdownVariants, getAvailableIcons, hasIcon, iconRegistry, linkVariants, listItemVariants, radioVariants, switchVariants, textAreaVariants, textFieldVariants, tooltipVariants };
2067
2260
  //# sourceMappingURL=index.esm.js.map