trotl-filter 1.0.43 → 1.0.44

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,327 @@ 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
+
8332
8654
  // import "src/style/DebounceSelect.css";
8333
8655
 
8334
8656
  const DebounceSelect = ({
@@ -11126,6 +11448,7 @@ exports.DateTimeInput = DateTimeInput;
11126
11448
  exports.DebounceSelect = DebounceSelect;
11127
11449
  exports.IconInput = IconInput;
11128
11450
  exports.LineDivider = LineDivider;
11451
+ exports.MultiSelect = MultiSelect;
11129
11452
  exports.MultiSelectDropdown = MultiSelectDropdown;
11130
11453
  exports.RangePicker = RangePicker;
11131
11454
  exports.SearchInput = SearchInput;