uiplex 1.0.0 → 1.0.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.
package/dist/index.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var React = require('react');
5
+ var reactDom = require('react-dom');
5
6
 
6
7
  const Button = ({ children, variant = "primary", size = "md", colorScheme = "", disabled = false, loading = false, leftIcon, rightIcon, onClick, className = "", style, ...props }) => {
7
8
  const buttonClasses = [
@@ -388,6 +389,225 @@ const Textarea = ({ size = "md", variant = "outline", isInvalid, isDisabled, isR
388
389
  return (jsxRuntime.jsx("textarea", { id: textareaId, className: textareaClasses, disabled: disabled, readOnly: isReadOnly, "aria-invalid": invalid, "aria-describedby": invalid && formControl.id ? `${formControl.id}-error` : undefined, style: style, ...props }));
389
390
  };
390
391
 
392
+ const Select = ({ size = "md", variant = "outline", isInvalid, isDisabled, isReadOnly, options = [], placeholder = "Select...", value: controlledValue, defaultValue, onChange, mode = "single", searchable = false, allowClear = false, width, className = "", style, id, }) => {
393
+ const formControl = useFormControlContext();
394
+ const invalid = isInvalid ?? formControl.isInvalid ?? false;
395
+ const disabled = isDisabled ?? formControl.isDisabled ?? false;
396
+ const selectId = id || formControl.id;
397
+ const [isOpen, setIsOpen] = React.useState(false);
398
+ const [searchTerm, setSearchTerm] = React.useState("");
399
+ const [internalValue, setInternalValue] = React.useState(defaultValue || (mode === "multiple" ? [] : ""));
400
+ const [dropdownPosition, setDropdownPosition] = React.useState(null);
401
+ const isControlled = controlledValue !== undefined;
402
+ const value = isControlled ? controlledValue : internalValue;
403
+ const selectRef = React.useRef(null);
404
+ const dropdownRef = React.useRef(null);
405
+ const inputRef = React.useRef(null);
406
+ const triggerRef = React.useRef(null);
407
+ const clickFromTriggerRef = React.useRef(false);
408
+ // Close dropdown on outside click
409
+ React.useEffect(() => {
410
+ if (!isOpen)
411
+ return;
412
+ const handleClickOutside = (event) => {
413
+ const target = event.target;
414
+ // If click originated from trigger, ignore it
415
+ if (clickFromTriggerRef.current) {
416
+ return;
417
+ }
418
+ // Check if refs are available
419
+ if (!selectRef.current || !dropdownRef.current) {
420
+ return;
421
+ }
422
+ // Check if click is inside select trigger or dropdown
423
+ const clickedInsideSelect = selectRef.current.contains(target);
424
+ const clickedInsideDropdown = dropdownRef.current.contains(target);
425
+ // Close if clicked outside both
426
+ if (!clickedInsideSelect && !clickedInsideDropdown) {
427
+ setIsOpen(false);
428
+ setSearchTerm("");
429
+ setDropdownPosition(null);
430
+ }
431
+ };
432
+ // Use mousedown in capture phase for more reliable detection
433
+ // This prevents the double-click issue
434
+ document.addEventListener("mousedown", handleClickOutside, true);
435
+ document.addEventListener("touchstart", handleClickOutside, true);
436
+ return () => {
437
+ document.removeEventListener("mousedown", handleClickOutside, true);
438
+ document.removeEventListener("touchstart", handleClickOutside, true);
439
+ };
440
+ }, [isOpen]);
441
+ // Calculate and update dropdown position
442
+ const updateDropdownPosition = React.useCallback(() => {
443
+ if (!triggerRef.current)
444
+ return;
445
+ const rect = triggerRef.current.getBoundingClientRect();
446
+ setDropdownPosition({
447
+ top: rect.bottom + 4,
448
+ left: rect.left,
449
+ width: rect.width,
450
+ });
451
+ }, []);
452
+ // Calculate dropdown position when it opens
453
+ React.useEffect(() => {
454
+ if (isOpen) {
455
+ updateDropdownPosition();
456
+ }
457
+ else {
458
+ setDropdownPosition(null);
459
+ }
460
+ }, [isOpen, updateDropdownPosition]);
461
+ // Update position on scroll/resize
462
+ React.useEffect(() => {
463
+ if (!isOpen)
464
+ return;
465
+ // Update position immediately
466
+ updateDropdownPosition();
467
+ // Listen to scroll events on all scrollable containers
468
+ const handleScroll = () => {
469
+ updateDropdownPosition();
470
+ };
471
+ const handleResize = () => {
472
+ updateDropdownPosition();
473
+ };
474
+ // Add listeners to window and all scrollable parents
475
+ window.addEventListener("scroll", handleScroll, true);
476
+ window.addEventListener("resize", handleResize);
477
+ // Also listen to scroll on the document
478
+ document.addEventListener("scroll", handleScroll, true);
479
+ return () => {
480
+ window.removeEventListener("scroll", handleScroll, true);
481
+ window.removeEventListener("resize", handleResize);
482
+ document.removeEventListener("scroll", handleScroll, true);
483
+ };
484
+ }, [isOpen, updateDropdownPosition]);
485
+ // Focus search input when dropdown opens
486
+ React.useEffect(() => {
487
+ if (isOpen && searchable && inputRef.current) {
488
+ inputRef.current.focus();
489
+ }
490
+ }, [isOpen, searchable]);
491
+ // Filter options based on search term
492
+ const filteredOptions = searchable
493
+ ? options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()))
494
+ : options;
495
+ // Get selected option(s)
496
+ const getSelectedOptions = React.useCallback(() => {
497
+ if (mode === "multiple") {
498
+ const values = Array.isArray(value) ? value : [];
499
+ return options.filter((opt) => values.includes(opt.value));
500
+ }
501
+ else {
502
+ return options.find((opt) => opt.value === value);
503
+ }
504
+ }, [value, options, mode]);
505
+ const selectedOptions = getSelectedOptions();
506
+ const displayValue = mode === "multiple"
507
+ ? Array.isArray(selectedOptions) && selectedOptions.length > 0
508
+ ? `${selectedOptions.length} selected`
509
+ : placeholder
510
+ : selectedOptions && !Array.isArray(selectedOptions)
511
+ ? selectedOptions.label
512
+ : placeholder;
513
+ const handleToggle = (e) => {
514
+ if (disabled || isReadOnly)
515
+ return;
516
+ e.stopPropagation();
517
+ // Set flag to prevent outside click handler from firing
518
+ clickFromTriggerRef.current = true;
519
+ setIsOpen((prev) => {
520
+ const newIsOpen = !prev;
521
+ if (newIsOpen) {
522
+ setSearchTerm("");
523
+ }
524
+ // Reset flag after state update
525
+ setTimeout(() => {
526
+ clickFromTriggerRef.current = false;
527
+ }, 100);
528
+ return newIsOpen;
529
+ });
530
+ };
531
+ const handleSelect = (optionValue) => {
532
+ if (mode === "multiple") {
533
+ const currentValues = Array.isArray(value) ? value : [];
534
+ const newValues = currentValues.includes(optionValue)
535
+ ? currentValues.filter((v) => v !== optionValue)
536
+ : [...currentValues, optionValue];
537
+ if (!isControlled) {
538
+ setInternalValue(newValues);
539
+ }
540
+ onChange?.(newValues);
541
+ }
542
+ else {
543
+ if (!isControlled) {
544
+ setInternalValue(optionValue);
545
+ }
546
+ onChange?.(optionValue);
547
+ setIsOpen(false);
548
+ }
549
+ };
550
+ const handleClear = (e) => {
551
+ e.stopPropagation();
552
+ const newValue = mode === "multiple" ? [] : "";
553
+ if (!isControlled) {
554
+ setInternalValue(newValue);
555
+ }
556
+ onChange?.(newValue);
557
+ };
558
+ const isSelected = (optionValue) => {
559
+ if (mode === "multiple") {
560
+ return Array.isArray(value) && value.includes(optionValue);
561
+ }
562
+ return value === optionValue;
563
+ };
564
+ const hasValue = mode === "multiple"
565
+ ? Array.isArray(value) && value.length > 0
566
+ : value !== "" && value !== undefined && value !== null;
567
+ const selectClasses = [
568
+ "ui-select",
569
+ `ui-select--${size}`,
570
+ `ui-select--${variant}`,
571
+ invalid && "ui-select--invalid",
572
+ disabled && "ui-select--disabled",
573
+ isReadOnly && "ui-select--readonly",
574
+ isOpen && "ui-select--open",
575
+ className,
576
+ ]
577
+ .filter(Boolean)
578
+ .join(" ");
579
+ const wrapperStyle = {
580
+ ...style,
581
+ ...(width && {
582
+ width: typeof width === "number" ? `${width}px` : width,
583
+ }),
584
+ };
585
+ return (jsxRuntime.jsxs("div", { ref: selectRef, className: "ui-select-wrapper", style: wrapperStyle, children: [jsxRuntime.jsxs("div", { ref: triggerRef, id: selectId, className: selectClasses, onClick: handleToggle, "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-invalid": invalid, "aria-describedby": invalid && formControl.id ? `${formControl.id}-error` : undefined, role: "combobox", tabIndex: disabled || isReadOnly ? -1 : 0, children: [jsxRuntime.jsx("div", { className: "ui-select__value", children: mode === "multiple" && hasValue && Array.isArray(selectedOptions) && selectedOptions.length > 0 ? (jsxRuntime.jsxs("div", { className: "ui-select__tags", children: [selectedOptions.slice(0, 2).map((option) => (jsxRuntime.jsxs("span", { className: "ui-select__tag", children: [option.label, jsxRuntime.jsx("button", { type: "button", className: "ui-select__tag-close", onClick: (e) => {
586
+ e.stopPropagation();
587
+ handleSelect(option.value);
588
+ }, "aria-label": `Remove ${option.label}`, children: "\u00D7" })] }, option.value))), selectedOptions.length > 2 && (jsxRuntime.jsxs("span", { className: "ui-select__tag-more", children: ["+", selectedOptions.length - 2] }))] })) : (jsxRuntime.jsx("span", { className: `ui-select__text ${!hasValue ? "ui-select__text--placeholder" : ""}`, children: displayValue })) }), jsxRuntime.jsxs("div", { className: "ui-select__actions", children: [allowClear && hasValue && !disabled && !isReadOnly && (jsxRuntime.jsx("button", { type: "button", className: "ui-select__clear", onClick: handleClear, "aria-label": "Clear selection", children: "\u00D7" })), jsxRuntime.jsx("span", { className: "ui-select__arrow", "aria-hidden": "true", children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), isOpen &&
589
+ dropdownPosition &&
590
+ typeof window !== "undefined" &&
591
+ reactDom.createPortal(jsxRuntime.jsxs("div", { ref: dropdownRef, className: "ui-select-dropdown", role: "listbox", style: {
592
+ position: "fixed",
593
+ top: `${dropdownPosition.top}px`,
594
+ left: `${dropdownPosition.left}px`,
595
+ width: `${dropdownPosition.width}px`,
596
+ }, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), children: [searchable && (jsxRuntime.jsx("div", { className: "ui-select-dropdown__search", children: jsxRuntime.jsx("input", { ref: inputRef, type: "text", className: "ui-select-dropdown__search-input", placeholder: "Search...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), onClick: (e) => e.stopPropagation(), onKeyDown: (e) => {
597
+ if (e.key === "Escape") {
598
+ setIsOpen(false);
599
+ }
600
+ } }) })), jsxRuntime.jsx("div", { className: "ui-select-dropdown__options", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "ui-select-dropdown__empty", children: "No options found" })) : (filteredOptions.map((option) => {
601
+ const selected = isSelected(option.value);
602
+ return (jsxRuntime.jsxs("div", { className: `ui-select-dropdown__option ${selected ? "ui-select-dropdown__option--selected" : ""} ${option.disabled ? "ui-select-dropdown__option--disabled" : ""}`, onClick: (e) => {
603
+ e.stopPropagation();
604
+ if (!option.disabled) {
605
+ handleSelect(option.value);
606
+ }
607
+ }, role: "option", "aria-selected": selected, children: [mode === "multiple" && (jsxRuntime.jsx("span", { className: "ui-select-dropdown__checkbox", children: selected ? "✓" : "" })), jsxRuntime.jsx("span", { className: "ui-select-dropdown__option-label", children: option.label })] }, option.value));
608
+ })) })] }), document.body)] }));
609
+ };
610
+
391
611
  const normalizeValue = (value) => {
392
612
  if (value === undefined)
393
613
  return undefined;
@@ -519,7 +739,7 @@ const useOutsideClick = ({ handler, refs, enabled = true, }) => {
519
739
  }, [handler, refs, enabled]);
520
740
  };
521
741
 
522
- const Tooltip = ({ children, label, placement = "top", isOpen: controlledIsOpen, defaultIsOpen = false, closeOnClick = false, className = "", style, }) => {
742
+ const Tooltip = ({ children, label, placement = "top", isOpen: controlledIsOpen, defaultIsOpen = false, closeOnClick = false, width, className = "", style, }) => {
523
743
  const [internalIsOpen, setInternalIsOpen] = React.useState(defaultIsOpen);
524
744
  const tooltipRef = React.useRef(null);
525
745
  const triggerRef = React.useRef(null);
@@ -555,7 +775,11 @@ const Tooltip = ({ children, label, placement = "top", isOpen: controlledIsOpen,
555
775
  onMouseLeave: handleMouseLeave,
556
776
  onClick: handleClick,
557
777
  });
558
- return (jsxRuntime.jsxs("div", { className: `ui-tooltip-wrapper ${className}`, style: style, children: [clonedChild, isOpen && (jsxRuntime.jsx("div", { ref: tooltipRef, className: `ui-tooltip ui-tooltip--${placement}`, role: "tooltip", children: label }))] }));
778
+ return (jsxRuntime.jsxs("div", { className: `ui-tooltip-wrapper ${className}`, style: style, children: [clonedChild, isOpen && (jsxRuntime.jsx("div", { ref: tooltipRef, className: `ui-tooltip ui-tooltip--${placement} ${width ? "ui-tooltip--wrappable" : ""}`, role: "tooltip", style: width
779
+ ? {
780
+ width: typeof width === "number" ? `${width}px` : width,
781
+ }
782
+ : undefined, children: label }))] }));
559
783
  };
560
784
 
561
785
  const PopoverContent = ({ children, className = "", }) => {
@@ -870,7 +1094,7 @@ const useTheme = () => {
870
1094
  }
871
1095
  return context;
872
1096
  };
873
- const ThemeProvider = ({ children, defaultTheme = "system", storageKey = "uilab-theme" }) => {
1097
+ const ThemeProvider = ({ children, defaultTheme = "system", storageKey = "uiplex-theme" }) => {
874
1098
  const [theme, setTheme] = React.useState(defaultTheme);
875
1099
  const [resolvedTheme, setResolvedTheme] = React.useState("light");
876
1100
  // Get system preference
@@ -1082,6 +1306,7 @@ exports.PopoverFooter = PopoverFooter;
1082
1306
  exports.PopoverHeader = PopoverHeader;
1083
1307
  exports.Radio = Radio;
1084
1308
  exports.RadioGroup = RadioGroup;
1309
+ exports.Select = Select;
1085
1310
  exports.Text = Text;
1086
1311
  exports.Textarea = Textarea;
1087
1312
  exports.ThemeProvider = ThemeProvider;
package/dist/index.css CHANGED
@@ -1220,6 +1220,403 @@
1220
1220
  }
1221
1221
 
1222
1222
 
1223
+ .ui-select-wrapper {
1224
+ position: relative;
1225
+ display: inline-block;
1226
+ width: 100%;
1227
+ z-index: 1;
1228
+ }
1229
+
1230
+ .ui-select {
1231
+ width: 100%;
1232
+ font-family: inherit;
1233
+ font-size: 1rem;
1234
+ line-height: 1.5;
1235
+ color: var(--text-primary, #111827);
1236
+ background-color: var(--bg-primary, #ffffff);
1237
+ border: 1px solid var(--border-primary, #d1d5db);
1238
+ border-radius: 0.375rem;
1239
+ transition: all 0.2s ease-in-out;
1240
+ outline: none;
1241
+ box-sizing: border-box;
1242
+ cursor: pointer;
1243
+ display: flex;
1244
+ align-items: center;
1245
+ justify-content: space-between;
1246
+ min-height: 2.5rem;
1247
+ padding: 0 0.75rem 0 1rem;
1248
+ position: relative;
1249
+ }
1250
+
1251
+ .ui-select:focus,
1252
+ .ui-select--open {
1253
+ border-color: var(--accent-primary, #bb00ed);
1254
+ box-shadow: 0 0 0 3px rgba(187, 0, 237, 0.1);
1255
+ }
1256
+
1257
+ .ui-select:disabled,
1258
+ .ui-select--disabled {
1259
+ opacity: 0.6;
1260
+ cursor: not-allowed;
1261
+ background-color: var(--bg-secondary, #f3f4f6);
1262
+ }
1263
+
1264
+ .ui-select--readonly {
1265
+ cursor: default;
1266
+ background-color: var(--bg-secondary, #f3f4f6);
1267
+ }
1268
+
1269
+ .ui-select--invalid {
1270
+ border-color: var(--danger, #dc2626);
1271
+ }
1272
+
1273
+ .ui-select--invalid:focus,
1274
+ .ui-select--invalid.ui-select--open {
1275
+ border-color: var(--danger, #dc2626);
1276
+ box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.1);
1277
+ }
1278
+
1279
+ .ui-select__value {
1280
+ flex: 1;
1281
+ display: flex;
1282
+ align-items: center;
1283
+ min-width: 0;
1284
+ overflow: hidden;
1285
+ }
1286
+
1287
+ .ui-select__text {
1288
+ display: block;
1289
+ overflow: hidden;
1290
+ text-overflow: ellipsis;
1291
+ white-space: nowrap;
1292
+ }
1293
+
1294
+ .ui-select__text--placeholder {
1295
+ color: var(--text-secondary, #9ca3af);
1296
+ }
1297
+
1298
+ .ui-select__tags {
1299
+ display: flex;
1300
+ flex-wrap: wrap;
1301
+ gap: 0.25rem;
1302
+ align-items: center;
1303
+ flex: 1;
1304
+ min-width: 0;
1305
+ }
1306
+
1307
+ .ui-select__tag {
1308
+ display: inline-flex;
1309
+ align-items: center;
1310
+ gap: 0.25rem;
1311
+ padding: 0.125rem 0.5rem;
1312
+ background-color: var(--bg-secondary, #f3f4f6);
1313
+ border: 1px solid var(--border-primary, #d1d5db);
1314
+ border-radius: 0.25rem;
1315
+ font-size: 0.875rem;
1316
+ max-width: 100%;
1317
+ }
1318
+
1319
+ .ui-select__tag-close {
1320
+ display: inline-flex;
1321
+ align-items: center;
1322
+ justify-content: center;
1323
+ width: 14px;
1324
+ height: 14px;
1325
+ border: none;
1326
+ background: none;
1327
+ cursor: pointer;
1328
+ color: var(--text-secondary, #6b7280);
1329
+ padding: 0;
1330
+ line-height: 1;
1331
+ font-size: 1rem;
1332
+ transition: color 0.2s;
1333
+ }
1334
+
1335
+ .ui-select__tag-close:hover {
1336
+ color: var(--text-primary, #111827);
1337
+ }
1338
+
1339
+ .ui-select__tag-more {
1340
+ display: inline-flex;
1341
+ align-items: center;
1342
+ padding: 0.125rem 0.5rem;
1343
+ background-color: var(--bg-secondary, #f3f4f6);
1344
+ border: 1px solid var(--border-primary, #d1d5db);
1345
+ border-radius: 0.25rem;
1346
+ font-size: 0.875rem;
1347
+ color: var(--text-secondary, #6b7280);
1348
+ }
1349
+
1350
+ .ui-select__actions {
1351
+ display: flex;
1352
+ align-items: center;
1353
+ gap: 0.5rem;
1354
+ flex-shrink: 0;
1355
+ margin-left: 0.5rem;
1356
+ position: absolute;
1357
+ right: 0.75rem;
1358
+ top: 50%;
1359
+ transform: translateY(-50%);
1360
+ }
1361
+
1362
+ .ui-select__clear {
1363
+ display: flex;
1364
+ align-items: center;
1365
+ justify-content: center;
1366
+ width: 16px;
1367
+ height: 16px;
1368
+ border: none;
1369
+ background: none;
1370
+ cursor: pointer;
1371
+ color: var(--text-secondary, #6b7280);
1372
+ padding: 0;
1373
+ font-size: 1.25rem;
1374
+ line-height: 1;
1375
+ transition: color 0.2s;
1376
+ border-radius: 50%;
1377
+ }
1378
+
1379
+ .ui-select__clear:hover {
1380
+ color: var(--text-primary, #111827);
1381
+ background-color: var(--bg-secondary, #f3f4f6);
1382
+ }
1383
+
1384
+ .ui-select__arrow {
1385
+ display: flex;
1386
+ align-items: center;
1387
+ justify-content: center;
1388
+ color: var(--text-secondary, #6b7280);
1389
+ transition: transform 0.2s;
1390
+ flex-shrink: 0;
1391
+ }
1392
+
1393
+ .ui-select--open .ui-select__arrow {
1394
+ transform: translateY(-50%) rotate(180deg);
1395
+ }
1396
+
1397
+ /* Sizes */
1398
+ .ui-select--sm {
1399
+ min-height: 2rem;
1400
+ padding: 0 0.75rem 0 0.75rem;
1401
+ font-size: 0.875rem;
1402
+ }
1403
+
1404
+ .ui-select--sm .ui-select__actions {
1405
+ right: 0.5rem;
1406
+ }
1407
+
1408
+ .ui-select--md {
1409
+ min-height: 2.5rem;
1410
+ padding: 0 0.75rem 0 1rem;
1411
+ font-size: 1rem;
1412
+ }
1413
+
1414
+ .ui-select--lg {
1415
+ min-height: 3rem;
1416
+ padding: 0 0.75rem 0 1.25rem;
1417
+ font-size: 1.125rem;
1418
+ }
1419
+
1420
+ .ui-select--lg .ui-select__actions {
1421
+ right: 1rem;
1422
+ }
1423
+
1424
+ /* Variants */
1425
+ .ui-select--outline {
1426
+ background-color: var(--bg-primary, #ffffff);
1427
+ border: 1px solid var(--border-primary, #d1d5db);
1428
+ }
1429
+
1430
+ .ui-select--filled {
1431
+ background-color: var(--bg-secondary, #f3f4f6);
1432
+ border: 1px solid transparent;
1433
+ }
1434
+
1435
+ .ui-select--filled:focus,
1436
+ .ui-select--filled.ui-select--open {
1437
+ background-color: var(--bg-primary, #ffffff);
1438
+ border-color: var(--accent-primary, #bb00ed);
1439
+ }
1440
+
1441
+ .ui-select--unstyled {
1442
+ background-color: transparent;
1443
+ border: none;
1444
+ border-radius: 0;
1445
+ padding-left: 0;
1446
+ padding-right: 1.5rem;
1447
+ }
1448
+
1449
+ .ui-select--unstyled:focus,
1450
+ .ui-select--unstyled.ui-select--open {
1451
+ box-shadow: none;
1452
+ border-bottom: 2px solid var(--accent-primary, #bb00ed);
1453
+ }
1454
+
1455
+ /* Dropdown */
1456
+ .ui-select-dropdown {
1457
+ position: fixed;
1458
+ z-index: 9999;
1459
+ background-color: var(--bg-primary, #ffffff);
1460
+ border: 1px solid var(--border-primary, #d1d5db);
1461
+ border-radius: 0.375rem;
1462
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
1463
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
1464
+ max-height: 300px;
1465
+ overflow: hidden;
1466
+ display: flex;
1467
+ flex-direction: column;
1468
+ animation: select-dropdown-fade-in 0.15s ease-out;
1469
+ visibility: visible;
1470
+ opacity: 1;
1471
+ }
1472
+
1473
+ @keyframes select-dropdown-fade-in {
1474
+ from {
1475
+ opacity: 0;
1476
+ transform: translateY(-4px);
1477
+ }
1478
+ to {
1479
+ opacity: 1;
1480
+ transform: translateY(0);
1481
+ }
1482
+ }
1483
+
1484
+ .ui-select-dropdown__search {
1485
+ padding: 0.5rem;
1486
+ border-bottom: 1px solid var(--border-primary, #e5e7eb);
1487
+ }
1488
+
1489
+ .ui-select-dropdown__search-input {
1490
+ width: 100%;
1491
+ padding: 0.5rem 0.75rem;
1492
+ font-size: 0.875rem;
1493
+ border: 1px solid var(--border-primary, #d1d5db);
1494
+ border-radius: 0.25rem;
1495
+ outline: none;
1496
+ transition: border-color 0.2s;
1497
+ }
1498
+
1499
+ .ui-select-dropdown__search-input:focus {
1500
+ border-color: var(--accent-primary, #bb00ed);
1501
+ }
1502
+
1503
+ .ui-select-dropdown__options {
1504
+ overflow-y: auto;
1505
+ max-height: 250px;
1506
+ padding: 0.25rem;
1507
+ }
1508
+
1509
+ .ui-select-dropdown__option {
1510
+ display: flex;
1511
+ align-items: center;
1512
+ gap: 0.5rem;
1513
+ padding: 0.5rem 0.75rem;
1514
+ cursor: pointer;
1515
+ border-radius: 0.25rem;
1516
+ transition: background-color 0.15s;
1517
+ font-size: 0.875rem;
1518
+ color: var(--text-primary, #111827);
1519
+ }
1520
+
1521
+ .ui-select-dropdown__option:hover:not(.ui-select-dropdown__option--disabled) {
1522
+ background-color: var(--bg-secondary, #f9fafb);
1523
+ }
1524
+
1525
+ .ui-select-dropdown__option--selected {
1526
+ background-color: rgba(187, 0, 237, 0.1);
1527
+ color: var(--accent-primary, #bb00ed);
1528
+ font-weight: 500;
1529
+ }
1530
+
1531
+ .ui-select-dropdown__option--selected:hover {
1532
+ background-color: rgba(187, 0, 237, 0.15);
1533
+ }
1534
+
1535
+ .ui-select-dropdown__option--disabled {
1536
+ opacity: 0.5;
1537
+ cursor: not-allowed;
1538
+ }
1539
+
1540
+ .ui-select-dropdown__checkbox {
1541
+ display: inline-flex;
1542
+ align-items: center;
1543
+ justify-content: center;
1544
+ width: 16px;
1545
+ height: 16px;
1546
+ border: 1px solid var(--border-primary, #d1d5db);
1547
+ border-radius: 0.25rem;
1548
+ background-color: var(--bg-primary, #ffffff);
1549
+ flex-shrink: 0;
1550
+ font-size: 0.75rem;
1551
+ color: var(--accent-primary, #bb00ed);
1552
+ }
1553
+
1554
+ .ui-select-dropdown__option--selected .ui-select-dropdown__checkbox {
1555
+ background-color: var(--accent-primary, #bb00ed);
1556
+ border-color: var(--accent-primary, #bb00ed);
1557
+ color: white;
1558
+ }
1559
+
1560
+ .ui-select-dropdown__option-label {
1561
+ flex: 1;
1562
+ overflow: hidden;
1563
+ text-overflow: ellipsis;
1564
+ white-space: nowrap;
1565
+ }
1566
+
1567
+ .ui-select-dropdown__empty {
1568
+ padding: 1rem;
1569
+ text-align: center;
1570
+ color: var(--text-secondary, #6b7280);
1571
+ font-size: 0.875rem;
1572
+ }
1573
+
1574
+ /* Dark mode support */
1575
+ .dark .ui-select {
1576
+ background-color: var(--bg-primary, #1f2937);
1577
+ border-color: var(--border-primary, #374151);
1578
+ color: var(--text-primary, #f9fafb);
1579
+ }
1580
+
1581
+ .dark .ui-select:focus,
1582
+ .dark .ui-select--open {
1583
+ border-color: var(--accent-primary, #bb00ed);
1584
+ }
1585
+
1586
+ .dark .ui-select--filled {
1587
+ background-color: var(--bg-secondary, #111827);
1588
+ }
1589
+
1590
+ .dark .ui-select--filled:focus,
1591
+ .dark .ui-select--filled.ui-select--open {
1592
+ background-color: var(--bg-primary, #1f2937);
1593
+ }
1594
+
1595
+ .dark .ui-select-dropdown {
1596
+ background-color: var(--bg-primary, #1f2937);
1597
+ border-color: var(--border-primary, #374151);
1598
+ }
1599
+
1600
+ .dark .ui-select-dropdown__option:hover:not(.ui-select-dropdown__option--disabled) {
1601
+ background-color: var(--bg-secondary, #111827);
1602
+ }
1603
+
1604
+ .dark .ui-select-dropdown__option--selected {
1605
+ background-color: rgba(187, 0, 237, 0.2);
1606
+ }
1607
+
1608
+ .dark .ui-select__tag {
1609
+ background-color: var(--bg-secondary, #111827);
1610
+ border-color: var(--border-primary, #374151);
1611
+ color: var(--text-primary, #f9fafb);
1612
+ }
1613
+
1614
+ .dark .ui-select-dropdown__checkbox {
1615
+ background-color: var(--bg-primary, #1f2937);
1616
+ border-color: var(--border-primary, #374151);
1617
+ }
1618
+
1619
+
1223
1620
  .ui-link {
1224
1621
  color: var(--accent-primary, #bb00ed);
1225
1622
  text-decoration: none;
@@ -1502,6 +1899,12 @@
1502
1899
  animation: tooltip-fade-in 0.15s ease-out;
1503
1900
  }
1504
1901
 
1902
+ .ui-tooltip--wrappable {
1903
+ white-space: normal;
1904
+ word-wrap: break-word;
1905
+ overflow-wrap: break-word;
1906
+ }
1907
+
1505
1908
  .ui-tooltip--top {
1506
1909
  bottom: 100%;
1507
1910
  left: 50%;
@@ -2290,7 +2693,7 @@
2290
2693
  }
2291
2694
 
2292
2695
 
2293
- /* Uilab Theme Variables */
2696
+ /* Uiplex Theme Variables */
2294
2697
 
2295
2698
  :root {
2296
2699
  /* Light theme variables */