trotl-filter 1.0.43 → 1.0.45

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.js CHANGED
@@ -7224,12 +7224,12 @@ const MultiSelectDropdown = ({
7224
7224
  maxHeight: 34,
7225
7225
  minHeight: 34,
7226
7226
  height: "auto",
7227
- backgroundColor: theme === "dark" ? "#1e1e1e" : "#fff",
7227
+ background: disabled ? '#f5f5f5' : theme === "dark" ? "#1e1e1e" : "#fff",
7228
7228
  borderColor: theme === "dark" ? "#555" : "#ccc",
7229
7229
  color: theme === "dark" ? "#eee" : "#333",
7230
7230
  boxShadow: "none",
7231
7231
  borderRadius: 2,
7232
- cursor: "pointer",
7232
+ cursor: disabled ? 'not-allowed' : "pointer",
7233
7233
  paddingRight: showSpinner ? 36 : base.paddingRight
7234
7234
  }),
7235
7235
  menu: base => ({
@@ -7293,7 +7293,8 @@ const MultiSelectDropdown = ({
7293
7293
  position: 'relative',
7294
7294
  ...style,
7295
7295
  ...(disabled ? {
7296
- opacity: 0.6
7296
+ opacity: 0.6,
7297
+ background: '#f5f5f5'
7297
7298
  } : {})
7298
7299
  },
7299
7300
  ref: containerRef,
@@ -8329,6 +8330,485 @@ function requirePropTypes () {
8329
8330
  var propTypesExports = /*@__PURE__*/ requirePropTypes();
8330
8331
  var PropTypes = /*@__PURE__*/getDefaultExportFromCjs(propTypesExports);
8331
8332
 
8333
+ function MultiSelect({
8334
+ isMulti = false,
8335
+ options = [],
8336
+ selected = [],
8337
+ onChange,
8338
+ placeholder = 'Select...',
8339
+ allowClear = false,
8340
+ disabled = false,
8341
+ addItem,
8342
+ pushUrlParamObj = false,
8343
+ loading = false,
8344
+ controlStyle = {},
8345
+ className = ''
8346
+ }) {
8347
+ const containerRef = React.useRef(null);
8348
+ const [open, setOpen] = React.useState(false);
8349
+ const [inputValue, setInputValue] = React.useState('');
8350
+ const [maxVisible, setMaxVisible] = React.useState(3);
8351
+ const [isFocused, setIsFocused] = React.useState(false);
8352
+ React.useEffect(() => {
8353
+ if (!containerRef.current) return;
8354
+ const calc = () => {
8355
+ const w = containerRef.current.offsetWidth || 200;
8356
+ const avg = 90;
8357
+ setMaxVisible(Math.max(1, Math.floor((w - 40) / avg)));
8358
+ };
8359
+ calc();
8360
+ window.addEventListener('resize', calc);
8361
+ return () => window.removeEventListener('resize', calc);
8362
+ }, []);
8363
+
8364
+ // URL sync helpers
8365
+ const setUrlParam = value => {
8366
+ if (!pushUrlParamObj) return;
8367
+ const url = new URL(window.location);
8368
+ if (!value || Array.isArray(value) && value.length === 0) url.searchParams.delete(pushUrlParamObj);else url.searchParams.set(pushUrlParamObj, Array.isArray(value) ? value.join(',') : value);
8369
+ window.history.replaceState({}, '', url);
8370
+ };
8371
+ React.useEffect(() => {
8372
+ if (!pushUrlParamObj || !options || options.length === 0) return;
8373
+ const read = () => {
8374
+ const params = new URLSearchParams(window.location.search);
8375
+ const val = params.get(pushUrlParamObj);
8376
+ if (!val) return;
8377
+ if (isMulti) {
8378
+ const arr = val.split(',').filter(Boolean);
8379
+ if (JSON.stringify(arr) !== JSON.stringify(selected)) onChange?.(arr);
8380
+ } else {
8381
+ if (!selected || selected[0] !== val) onChange?.([val]);
8382
+ }
8383
+ };
8384
+ read();
8385
+ window.addEventListener('popstate', read);
8386
+ return () => window.removeEventListener('popstate', read);
8387
+ }, [pushUrlParamObj, options, isMulti, selected, onChange]);
8388
+ const selectedOptions = React.useMemo(() => {
8389
+ if (isMulti) return options.filter(o => (selected || []).includes(o.value));
8390
+ return options.find(o => o.value === (selected && selected[0])) || null;
8391
+ }, [options, selected, isMulti]);
8392
+ const inputExists = React.useMemo(() => {
8393
+ return options.some(opt => String(opt.label).toLowerCase() === inputValue.trim().toLowerCase());
8394
+ }, [inputValue, options]);
8395
+ const menuOptions = React.useMemo(() => {
8396
+ if (inputValue && !inputExists && typeof addItem === 'function') {
8397
+ return [...options, {
8398
+ label: `+ Add "${inputValue.trim()}"`,
8399
+ value: '__add_new__',
8400
+ __isAddNew: true
8401
+ }];
8402
+ }
8403
+ return options;
8404
+ }, [options, inputValue, inputExists, addItem]);
8405
+
8406
+ // Labels for items hidden behind the "overflow" indicator
8407
+ const hiddenLabels = React.useMemo(() => {
8408
+ if (!isMulti) return "";
8409
+ const arr = (selectedOptions || []).slice(maxVisible).map(s => s.label);
8410
+ return arr.join(', ');
8411
+ }, [isMulti, selectedOptions, maxVisible]);
8412
+ const toggleValue = val => {
8413
+ if (disabled) return;
8414
+ if (isMulti) {
8415
+ const prev = Array.isArray(selected) ? [...selected] : [];
8416
+ const idx = prev.findIndex(x => String(x) === String(val));
8417
+ if (idx === -1) prev.push(val);else prev.splice(idx, 1);
8418
+ onChange?.(prev);
8419
+ if (pushUrlParamObj) setUrlParam(prev);
8420
+ } else {
8421
+ const out = [val];
8422
+ onChange?.(out);
8423
+ if (pushUrlParamObj) setUrlParam(val);
8424
+ setOpen(false);
8425
+ }
8426
+ };
8427
+ const handleAddNew = () => {
8428
+ if (disabled) return;
8429
+ const label = inputValue.trim();
8430
+ if (!label) return;
8431
+ const exists = options.some(opt => String(opt.value).toLowerCase() === label.toLowerCase() || String(opt.label).toLowerCase() === label.toLowerCase());
8432
+ if (exists) {
8433
+ setInputValue('');
8434
+ return;
8435
+ }
8436
+ const newOpt = {
8437
+ label,
8438
+ value: label
8439
+ };
8440
+ if (typeof addItem === 'function') addItem(newOpt);
8441
+ if (isMulti) {
8442
+ const next = [...(selected || []), newOpt.value];
8443
+ onChange?.(next);
8444
+ if (pushUrlParamObj) setUrlParam(next);
8445
+ } else {
8446
+ onChange?.([newOpt.value]);
8447
+ if (pushUrlParamObj) setUrlParam(newOpt.value);
8448
+ setOpen(false);
8449
+ }
8450
+ setInputValue('');
8451
+ };
8452
+ const clearSelection = () => {
8453
+ if (disabled) return;
8454
+ onChange?.([]);
8455
+ if (pushUrlParamObj) setUrlParam([]);
8456
+ };
8457
+ React.useEffect(() => {
8458
+ const onDocClick = e => {
8459
+ if (!containerRef.current) return;
8460
+ if (!containerRef.current.contains(e.target)) setOpen(false);
8461
+ };
8462
+ document.addEventListener('mousedown', onDocClick);
8463
+ return () => document.removeEventListener('mousedown', onDocClick);
8464
+ }, []);
8465
+ return /*#__PURE__*/React.createElement("div", {
8466
+ ref: containerRef,
8467
+ className: className,
8468
+ style: {
8469
+ position: 'relative',
8470
+ width: '100%',
8471
+ ...controlStyle,
8472
+ ...(disabled ? {
8473
+ background: '#f5f5f5',
8474
+ opacity: 0.9
8475
+ } : {})
8476
+ }
8477
+ }, /*#__PURE__*/React.createElement("div", {
8478
+ role: "button",
8479
+ tabIndex: 0,
8480
+ onClick: () => !disabled && setOpen(s => !s),
8481
+ onKeyDown: e => {
8482
+ if (e.key === 'Enter' && !disabled) setOpen(s => !s);
8483
+ },
8484
+ onFocus: () => setIsFocused(true),
8485
+ onBlur: () => setIsFocused(false),
8486
+ style: {
8487
+ minHeight: 36,
8488
+ display: 'flex',
8489
+ alignItems: 'center',
8490
+ gap: 8,
8491
+ padding: '6px 8px',
8492
+ border: disabled ? '1px solid #eee' : isFocused && (isMulti ? (selected || []).length > 0 : selected && selected[0] != null) ? '1px solid transparent' : '1px solid #ccc',
8493
+ borderRadius: 2,
8494
+ cursor: disabled ? 'not-allowed' : 'pointer',
8495
+ background: disabled ? '#f5f5f5' : '#fff',
8496
+ outline: 'none',
8497
+ ...controlStyle
8498
+ }
8499
+ }, /*#__PURE__*/React.createElement("div", {
8500
+ style: {
8501
+ display: 'flex',
8502
+ gap: 6,
8503
+ alignItems: 'center',
8504
+ flexWrap: 'nowrap',
8505
+ flex: 1,
8506
+ overflow: 'hidden',
8507
+ minWidth: 0
8508
+ }
8509
+ }, isMulti ? (selectedOptions || []).slice(0, maxVisible).map(s => /*#__PURE__*/React.createElement("div", {
8510
+ key: s.value,
8511
+ onClick: e => e.stopPropagation(),
8512
+ style: {
8513
+ display: 'inline-flex',
8514
+ alignItems: 'center',
8515
+ gap: 6,
8516
+ padding: '4px 8px',
8517
+ background: '#e6f4ff',
8518
+ borderRadius: 2,
8519
+ fontSize: 13,
8520
+ whiteSpace: 'nowrap',
8521
+ overflow: 'hidden',
8522
+ textOverflow: 'ellipsis',
8523
+ maxWidth: 200,
8524
+ minWidth: 0
8525
+ }
8526
+ }, /*#__PURE__*/React.createElement("span", {
8527
+ style: {
8528
+ overflow: 'hidden',
8529
+ textOverflow: 'ellipsis',
8530
+ whiteSpace: 'nowrap',
8531
+ display: 'inline-block'
8532
+ }
8533
+ }, s.label), /*#__PURE__*/React.createElement("button", {
8534
+ "aria-label": `Remove ${s.label}`,
8535
+ onClick: e => {
8536
+ e.stopPropagation();
8537
+ if (!disabled) toggleValue(s.value);
8538
+ },
8539
+ style: {
8540
+ border: 'none',
8541
+ background: 'transparent',
8542
+ cursor: disabled ? 'not-allowed' : 'pointer',
8543
+ padding: 0,
8544
+ margin: 0,
8545
+ fontSize: 12
8546
+ }
8547
+ }, "\u2716"))) : /*#__PURE__*/React.createElement("div", {
8548
+ style: {
8549
+ fontSize: 14,
8550
+ color: selectedOptions ? '#000' : '#666',
8551
+ overflow: 'hidden',
8552
+ textOverflow: 'ellipsis',
8553
+ whiteSpace: 'nowrap'
8554
+ }
8555
+ }, selectedOptions ? selectedOptions.label : placeholder), isMulti && (selectedOptions || []).length > maxVisible && /*#__PURE__*/React.createElement("div", {
8556
+ title: hiddenLabels,
8557
+ style: {
8558
+ fontSize: 13,
8559
+ color: '#666',
8560
+ cursor: 'default',
8561
+ flex: '0 0 auto',
8562
+ paddingLeft: 4
8563
+ }
8564
+ }, "\u2026")), /*#__PURE__*/React.createElement("div", {
8565
+ style: {
8566
+ display: 'flex',
8567
+ alignItems: 'center',
8568
+ gap: 8
8569
+ }
8570
+ }, allowClear && selected && selected.length > 0 && /*#__PURE__*/React.createElement("span", {
8571
+ onClick: e => {
8572
+ e.stopPropagation();
8573
+ clearSelection();
8574
+ },
8575
+ disabled: disabled,
8576
+ style: {
8577
+ cursor: disabled ? 'not-allowed' : 'pointer'
8578
+ }
8579
+ }, "\u2716"), loading && !disabled && /*#__PURE__*/React.createElement("div", {
8580
+ style: {
8581
+ width: 16,
8582
+ height: 16,
8583
+ borderRadius: 2,
8584
+ border: '2px solid #ccc',
8585
+ borderTopColor: '#444',
8586
+ animation: 'spin 0.9s linear infinite'
8587
+ }
8588
+ }))), open && /*#__PURE__*/React.createElement("div", {
8589
+ style: {
8590
+ position: 'absolute',
8591
+ zIndex: 50,
8592
+ marginTop: 6,
8593
+ width: '100%',
8594
+ background: '#fff',
8595
+ border: '1px solid #ddd',
8596
+ borderRadius: 2,
8597
+ boxShadow: '0 4px 12px rgba(0,0,0,0.08)',
8598
+ maxHeight: 260,
8599
+ overflow: 'auto'
8600
+ }
8601
+ }, /*#__PURE__*/React.createElement("div", {
8602
+ style: {
8603
+ padding: 8,
8604
+ borderBottom: '1px solid #f1f1f1'
8605
+ }
8606
+ }, /*#__PURE__*/React.createElement("input", {
8607
+ autoFocus: true,
8608
+ value: inputValue,
8609
+ onChange: e => setInputValue(e.target.value),
8610
+ onKeyDown: e => {
8611
+ if (e.key === 'Enter' && inputValue && typeof addItem === 'function') {
8612
+ handleAddNew();
8613
+ }
8614
+ },
8615
+ placeholder: "Type to search...",
8616
+ disabled: disabled,
8617
+ style: {
8618
+ padding: '6px 8px',
8619
+ borderRadius: 2,
8620
+ border: '1px solid #ffffff'
8621
+ }
8622
+ })), /*#__PURE__*/React.createElement("div", null, menuOptions.filter(opt => String(opt.label).toLowerCase().includes(inputValue.trim().toLowerCase())).map(opt => /*#__PURE__*/React.createElement("div", {
8623
+ key: opt.value,
8624
+ onClick: e => {
8625
+ e.stopPropagation();
8626
+ if (opt.__isAddNew) {
8627
+ handleAddNew();
8628
+ } else {
8629
+ toggleValue(opt.value);
8630
+ }
8631
+ },
8632
+ style: {
8633
+ padding: '8px 12px',
8634
+ cursor: disabled ? 'not-allowed' : 'pointer',
8635
+ background: (isMulti ? (selected || []).includes(opt.value) : selected && selected[0] === opt.value) ? '#eef6ff' : '#fff'
8636
+ }
8637
+ }, opt.label)))), /*#__PURE__*/React.createElement("style", null, `@keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }`));
8638
+ }
8639
+ MultiSelect.propTypes = {
8640
+ isMulti: PropTypes.bool,
8641
+ options: PropTypes.array,
8642
+ selected: PropTypes.array,
8643
+ onChange: PropTypes.func,
8644
+ placeholder: PropTypes.string,
8645
+ allowClear: PropTypes.bool,
8646
+ disabled: PropTypes.bool,
8647
+ addItem: PropTypes.func,
8648
+ pushUrlParamObj: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
8649
+ loading: PropTypes.bool,
8650
+ controlStyle: PropTypes.object,
8651
+ className: PropTypes.string
8652
+ };
8653
+
8654
+ // Simple, dependency-free ColorPicker
8655
+ // Props: value (hex), onChange(hex), disabled, label, presetColors, allowCustom, size
8656
+ function ColorPicker({
8657
+ value = '#1677ff',
8658
+ onChange,
8659
+ disabled = false,
8660
+ label = null,
8661
+ presetColors = ['#1677ff', '#ff4d4f', '#52c41a', '#faad14', '#722ed1', '#13c2c2', '#f5222d'],
8662
+ allowCustom = true,
8663
+ showHexInput = true,
8664
+ size = 'medium',
8665
+ // small | medium | large
8666
+ className = '',
8667
+ style = {}
8668
+ }) {
8669
+ const [open, setOpen] = React.useState(false);
8670
+ const [internal, setInternal] = React.useState(value || '');
8671
+ const ref = React.useRef(null);
8672
+ React.useEffect(() => setInternal(value || ''), [value]);
8673
+ React.useEffect(() => {
8674
+ const onDoc = e => {
8675
+ if (!ref.current) return;
8676
+ if (!ref.current.contains(e.target)) setOpen(false);
8677
+ };
8678
+ window.addEventListener('mousedown', onDoc);
8679
+ return () => window.removeEventListener('mousedown', onDoc);
8680
+ }, []);
8681
+ const apply = hex => {
8682
+ setInternal(hex);
8683
+ onChange?.(hex);
8684
+ };
8685
+ const btnSize = size === 'small' ? 20 : size === 'large' ? 36 : 28;
8686
+ return /*#__PURE__*/React.createElement("div", {
8687
+ ref: ref,
8688
+ className: `color-picker ${className}`,
8689
+ style: {
8690
+ display: 'inline-block',
8691
+ ...style
8692
+ }
8693
+ }, label && /*#__PURE__*/React.createElement("div", {
8694
+ style: {
8695
+ marginBottom: 6,
8696
+ fontSize: 13
8697
+ }
8698
+ }, label), /*#__PURE__*/React.createElement("button", {
8699
+ type: "button",
8700
+ onClick: () => !disabled && setOpen(s => !s),
8701
+ disabled: disabled,
8702
+ "aria-label": label || 'Choose color',
8703
+ style: {
8704
+ display: 'inline-flex',
8705
+ alignItems: 'center',
8706
+ gap: 8,
8707
+ padding: '6px 8px',
8708
+ borderRadius: 6,
8709
+ border: '1px solid #d9d9d9',
8710
+ background: '#fff',
8711
+ cursor: disabled ? 'not-allowed' : 'pointer'
8712
+ }
8713
+ }, /*#__PURE__*/React.createElement("span", {
8714
+ style: {
8715
+ width: btnSize,
8716
+ height: btnSize,
8717
+ borderRadius: 4,
8718
+ background: internal || '#fff',
8719
+ border: '1px solid #ccc'
8720
+ }
8721
+ }), /*#__PURE__*/React.createElement("span", {
8722
+ style: {
8723
+ fontSize: 13,
8724
+ color: disabled ? '#9ca3af' : '#000'
8725
+ }
8726
+ }, internal || '—')), open && /*#__PURE__*/React.createElement("div", {
8727
+ style: {
8728
+ position: 'absolute',
8729
+ zIndex: 60,
8730
+ marginTop: 8,
8731
+ background: '#fff',
8732
+ border: '1px solid #e8e8e8',
8733
+ boxShadow: '0 6px 18px rgba(0,0,0,0.08)',
8734
+ borderRadius: 6,
8735
+ padding: 12,
8736
+ minWidth: 220
8737
+ }
8738
+ }, /*#__PURE__*/React.createElement("div", {
8739
+ style: {
8740
+ display: 'flex',
8741
+ gap: 8,
8742
+ flexWrap: 'wrap'
8743
+ }
8744
+ }, presetColors.map(c => /*#__PURE__*/React.createElement("button", {
8745
+ key: c,
8746
+ onClick: () => apply(c),
8747
+ "aria-label": c,
8748
+ style: {
8749
+ width: 28,
8750
+ height: 28,
8751
+ borderRadius: 4,
8752
+ background: c,
8753
+ border: c.toLowerCase() === (internal || '').toLowerCase() ? '2px solid #00000033' : '1px solid #eee',
8754
+ cursor: 'pointer'
8755
+ }
8756
+ })), allowCustom && /*#__PURE__*/React.createElement("input", {
8757
+ type: "color",
8758
+ value: internal || '#000000',
8759
+ onChange: e => apply(e.target.value),
8760
+ style: {
8761
+ width: 36,
8762
+ height: 36,
8763
+ padding: 0,
8764
+ border: 'none',
8765
+ background: 'transparent',
8766
+ cursor: 'pointer'
8767
+ },
8768
+ title: "Custom color"
8769
+ })), showHexInput && /*#__PURE__*/React.createElement("div", {
8770
+ style: {
8771
+ marginTop: 8,
8772
+ display: 'flex',
8773
+ gap: 8,
8774
+ alignItems: 'center'
8775
+ }
8776
+ }, /*#__PURE__*/React.createElement("input", {
8777
+ value: internal || '',
8778
+ onChange: e => setInternal(e.target.value),
8779
+ onBlur: e => {
8780
+ const v = e.target.value.trim();
8781
+ if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(v)) apply(v);else setInternal(value || '');
8782
+ },
8783
+ placeholder: "#rrggbb",
8784
+ disabled: disabled,
8785
+ style: {
8786
+ padding: '6px 8px',
8787
+ borderRadius: 4,
8788
+ border: '1px solid #e5e7eb',
8789
+ width: 120
8790
+ }
8791
+ }), /*#__PURE__*/React.createElement("button", {
8792
+ onClick: () => {
8793
+ if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(internal)) apply(internal);
8794
+ },
8795
+ disabled: disabled,
8796
+ className: "basic-btn"
8797
+ }, "Apply"))));
8798
+ }
8799
+ ColorPicker.propTypes = {
8800
+ value: PropTypes.string,
8801
+ onChange: PropTypes.func,
8802
+ disabled: PropTypes.bool,
8803
+ label: PropTypes.string,
8804
+ presetColors: PropTypes.array,
8805
+ allowCustom: PropTypes.bool,
8806
+ showHexInput: PropTypes.bool,
8807
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
8808
+ className: PropTypes.string,
8809
+ style: PropTypes.object
8810
+ };
8811
+
8332
8812
  // import "src/style/DebounceSelect.css";
8333
8813
 
8334
8814
  const DebounceSelect = ({
@@ -11122,10 +11602,12 @@ Upload.propTypes = {
11122
11602
 
11123
11603
  exports.Button = Button;
11124
11604
  exports.CalendarRangePicker = CalendarRangePicker;
11605
+ exports.ColorPicker = ColorPicker;
11125
11606
  exports.DateTimeInput = DateTimeInput;
11126
11607
  exports.DebounceSelect = DebounceSelect;
11127
11608
  exports.IconInput = IconInput;
11128
11609
  exports.LineDivider = LineDivider;
11610
+ exports.MultiSelect = MultiSelect;
11129
11611
  exports.MultiSelectDropdown = MultiSelectDropdown;
11130
11612
  exports.RangePicker = RangePicker;
11131
11613
  exports.SearchInput = SearchInput;