funda-ui 4.7.133 → 4.7.152

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CascadingSelect/index.css +15 -4
  2. package/CascadingSelect/index.d.ts +2 -0
  3. package/CascadingSelect/index.js +294 -22
  4. package/CascadingSelectE2E/index.css +15 -4
  5. package/CascadingSelectE2E/index.d.ts +2 -0
  6. package/CascadingSelectE2E/index.js +300 -28
  7. package/Chatbox/index.d.ts +7 -0
  8. package/Chatbox/index.js +247 -163
  9. package/Checkbox/index.js +4 -2
  10. package/LiveSearch/index.js +2 -1
  11. package/Refresher/index.js +3 -3
  12. package/Select/index.css +33 -0
  13. package/Select/index.d.ts +1 -0
  14. package/Select/index.js +350 -39
  15. package/SplitterPanel/index.js +3 -3
  16. package/Switch/index.js +4 -2
  17. package/Utils/format-string.d.ts +2 -1
  18. package/Utils/format-string.js +22 -12
  19. package/Utils/time.d.ts +3 -3
  20. package/Utils/useIsMobile.js +3 -3
  21. package/lib/cjs/CascadingSelect/index.d.ts +2 -0
  22. package/lib/cjs/CascadingSelect/index.js +294 -22
  23. package/lib/cjs/CascadingSelectE2E/index.d.ts +2 -0
  24. package/lib/cjs/CascadingSelectE2E/index.js +300 -28
  25. package/lib/cjs/Chatbox/index.d.ts +7 -0
  26. package/lib/cjs/Chatbox/index.js +247 -163
  27. package/lib/cjs/Checkbox/index.js +4 -2
  28. package/lib/cjs/LiveSearch/index.js +2 -1
  29. package/lib/cjs/Refresher/index.js +3 -3
  30. package/lib/cjs/Select/index.d.ts +1 -0
  31. package/lib/cjs/Select/index.js +350 -39
  32. package/lib/cjs/SplitterPanel/index.js +3 -3
  33. package/lib/cjs/Switch/index.js +4 -2
  34. package/lib/cjs/Utils/format-string.d.ts +2 -1
  35. package/lib/cjs/Utils/format-string.js +22 -12
  36. package/lib/cjs/Utils/time.d.ts +3 -3
  37. package/lib/cjs/Utils/useIsMobile.js +3 -3
  38. package/lib/css/CascadingSelect/index.css +15 -4
  39. package/lib/css/CascadingSelectE2E/index.css +15 -4
  40. package/lib/css/Select/index.css +33 -0
  41. package/lib/esm/CascadingSelect/index.scss +22 -7
  42. package/lib/esm/CascadingSelect/index.tsx +49 -1
  43. package/lib/esm/CascadingSelectE2E/Group.tsx +1 -0
  44. package/lib/esm/CascadingSelectE2E/index.scss +23 -6
  45. package/lib/esm/CascadingSelectE2E/index.tsx +53 -1
  46. package/lib/esm/Chatbox/index.tsx +96 -11
  47. package/lib/esm/Checkbox/index.tsx +5 -3
  48. package/lib/esm/LiveSearch/index.tsx +2 -1
  49. package/lib/esm/Select/index.scss +43 -2
  50. package/lib/esm/Select/index.tsx +81 -24
  51. package/lib/esm/Select/utils/func.ts +0 -10
  52. package/lib/esm/Switch/index.tsx +4 -2
  53. package/lib/esm/Textarea/index.tsx +0 -1
  54. package/lib/esm/Utils/hooks/useIsMobile.tsx +9 -12
  55. package/lib/esm/Utils/libs/format-string.ts +22 -12
  56. package/lib/esm/Utils/libs/time.ts +6 -6
  57. package/package.json +1 -1
@@ -459,10 +459,10 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
459
459
  // Set the mounted state to true after the component has mounted
460
460
  setIsMounted(true);
461
461
  var handleResize = function handleResize() {
462
- if (window) {
462
+ if (typeof window !== 'undefined') {
463
463
  var detectDeviceType = function detectDeviceType() {
464
464
  // 1. First check if window and navigator are available (SSR compatibility)
465
- if (typeof window === 'undefined' || !navigator) {
465
+ if (typeof window === 'undefined' || typeof navigator === 'undefined') {
466
466
  return 'desktop'; // Default to desktop
467
467
  }
468
468
 
@@ -470,7 +470,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
470
470
  var ua = navigator.userAgent.toLowerCase();
471
471
 
472
472
  // 3. Get platform info
473
- var platform = navigator.platform.toLowerCase();
473
+ var platform = navigator.platform ? navigator.platform.toLowerCase() : '';
474
474
 
475
475
  // 4. Check screen characteristics using window.matchMedia
476
476
  var isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
@@ -533,7 +533,7 @@ var Switch = /*#__PURE__*/(0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(func
533
533
  var uniqueID = funda_utils_dist_cjs_useComId__WEBPACK_IMPORTED_MODULE_1___default()();
534
534
  var idRes = id || uniqueID;
535
535
  var rootRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
536
- var _useState = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)( false || false),
536
+ var _useState = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false),
537
537
  _useState2 = _slicedToArray(_useState, 2),
538
538
  val = _useState2[0],
539
539
  setVal = _useState2[1]; // Avoid the error "react checkbox changing an uncontrolled input to be controlled"
@@ -569,7 +569,9 @@ var Switch = /*#__PURE__*/(0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(func
569
569
  onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
570
570
  }
571
571
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(function () {
572
- setVal(checked);
572
+ if (typeof checked === 'boolean') {
573
+ setVal(checked);
574
+ }
573
575
  }, [checked]);
574
576
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
575
577
  className: (0,funda_utils_dist_cjs_cls__WEBPACK_IMPORTED_MODULE_2__.clsWrite)(wrapperClassName, 'mb-3 position-relative'),
@@ -32,13 +32,14 @@ declare function trimAll(input: string): string;
32
32
  */
33
33
  declare function multiSpacesToSingle(input: string): string;
34
34
  /**
35
- * Convert HTML text to plain text
35
+ * Convert HTML text to plain text (Remove html tag content)
36
36
  * @param {string} input - The input string to process
37
37
  * @returns {string} The processed string
38
38
  */
39
39
  declare function htmlToPlain(input: string): string;
40
40
  /**
41
41
  * Strip HTML tags and their content
42
+ * !!!Important: It will remove nested tags
42
43
  * @param {string} input - The input string to process
43
44
  * @returns {string} The processed string
44
45
  */
@@ -67,7 +67,7 @@ __webpack_require__.r(__webpack_exports__);
67
67
  * @returns {string} The processed string
68
68
  */
69
69
  function rmSpec(input) {
70
- return input.replace(/[^a-zA-Z0-9 \u4E00-\u9FFF]/g, "");
70
+ return input === null || input === void 0 ? void 0 : input.replace(/[^a-zA-Z0-9 \u4E00-\u9FFF]/g, "");
71
71
  }
72
72
 
73
73
  /**
@@ -76,7 +76,7 @@ function rmSpec(input) {
76
76
  * @returns {string} The processed string
77
77
  */
78
78
  function onlyNumAndLetter(input) {
79
- return input.replace(/[^a-zA-Z0-9 ]/g, "");
79
+ return input === null || input === void 0 ? void 0 : input.replace(/[^a-zA-Z0-9 ]/g, "");
80
80
  }
81
81
 
82
82
  /**
@@ -85,7 +85,7 @@ function onlyNumAndLetter(input) {
85
85
  * @returns {string} The processed string
86
86
  */
87
87
  function rmAllSpace(input) {
88
- return input.replace(/\s/g, "");
88
+ return input === null || input === void 0 ? void 0 : input.replace(/\s/g, "");
89
89
  }
90
90
 
91
91
  /**
@@ -94,7 +94,7 @@ function rmAllSpace(input) {
94
94
  * @returns {string} The processed string
95
95
  */
96
96
  function trimAll(input) {
97
- return input.replace(/(^\s+)|(\s+$)/g, "");
97
+ return input === null || input === void 0 ? void 0 : input.replace(/(^\s+)|(\s+$)/g, "");
98
98
  }
99
99
 
100
100
  /**
@@ -103,25 +103,35 @@ function trimAll(input) {
103
103
  * @returns {string} The processed string
104
104
  */
105
105
  function multiSpacesToSingle(input) {
106
- return input.replace(/\s+(\W)/g, ' ');
106
+ return input === null || input === void 0 ? void 0 : input.replace(/\s+(\W)/g, ' ');
107
107
  }
108
108
 
109
109
  /**
110
- * Convert HTML text to plain text
110
+ * Convert HTML text to plain text (Remove html tag content)
111
111
  * @param {string} input - The input string to process
112
112
  * @returns {string} The processed string
113
113
  */
114
+ /*
115
+ Examples:
116
+ console.log(htmlToPlain("<p>Hello <b>World</b></p>")); // Hello World
117
+ */
114
118
  function htmlToPlain(input) {
115
- return input.replace(/(<([^>]+)>)/ig, '');
119
+ return input === null || input === void 0 ? void 0 : input.replace(/(<([^>]+)>)/ig, '');
116
120
  }
117
121
 
118
122
  /**
119
- * Strip HTML tags and their content
123
+ * Strip HTML tags and their content
124
+ * !!!Important: It will remove nested tags
120
125
  * @param {string} input - The input string to process
121
126
  * @returns {string} The processed string
122
127
  */
128
+ /*
129
+ Examples:
130
+ console.log(stripTagsAndContent("<p>Hello <b>World</b></p>")); // World
131
+ console.log(stripTagsAndContent("Hello <b>World</b>")); // Hello
132
+ */
123
133
  function stripTagsAndContent(input) {
124
- return input.replace(/<\/?[^>]+(>|$)(.*?)<\/?[^>]+(>|$)/ig, '');
134
+ return input === null || input === void 0 ? void 0 : input.replace(/<\/?[^>]+(>|$)(.*?)<\/?[^>]+(>|$)/ig, '');
125
135
  }
126
136
 
127
137
  /**
@@ -130,7 +140,7 @@ function stripTagsAndContent(input) {
130
140
  * @returns {string} The processed URL
131
141
  */
132
142
  function removeFirstLastSlash(input) {
133
- return input.replace(/^\/|\/$/g, '');
143
+ return input === null || input === void 0 ? void 0 : input.replace(/^\/|\/$/g, '');
134
144
  }
135
145
 
136
146
  /**
@@ -139,7 +149,7 @@ function removeFirstLastSlash(input) {
139
149
  * @returns {string} The processed URL
140
150
  */
141
151
  function removeTrailingSlash(input) {
142
- return input.replace(/\/+$/, '');
152
+ return input === null || input === void 0 ? void 0 : input.replace(/\/+$/, '');
143
153
  }
144
154
 
145
155
  /**
@@ -148,7 +158,7 @@ function removeTrailingSlash(input) {
148
158
  * @returns {string} The processed URL
149
159
  */
150
160
  function removeFirstSlash(input) {
151
- return input.replace(/\//, '');
161
+ return input === null || input === void 0 ? void 0 : input.replace(/\//, '');
152
162
  }
153
163
 
154
164
  /******/ return __webpack_exports__;
@@ -17,18 +17,18 @@ declare function getTimeslots(startTime: string, endTime: string, timeInterval:
17
17
  * @param {Date} endDate - ebd date
18
18
  * @returns Number
19
19
  */
20
- declare function getMinutesBetweenDates(startDate: any, endDate: any): number;
20
+ declare function getMinutesBetweenDates(startDate: Date, endDate: Date): number;
21
21
  /**
22
22
  * Get minutes between two time
23
23
  * @param {String} startTime - start time
24
24
  * @param {String} endTime - ebd time
25
25
  * @returns Number
26
26
  */
27
- declare function getMinutesBetweenTime(startTime: any, endTime: any): string;
27
+ declare function getMinutesBetweenTime(startTime: string, endTime: string): string;
28
28
  /**
29
29
  * Convert HH:MM:SS into minute
30
30
  * @param {String} timeStr - time string
31
31
  * @returns Number
32
32
  */
33
- declare function convertTimeToMin(timeStr: any): number;
33
+ declare function convertTimeToMin(timeStr: string): number;
34
34
  export { getTimeslots, getMinutesBetweenDates, getMinutesBetweenTime, convertTimeToMin };
@@ -140,10 +140,10 @@ var useIsMobile = function useIsMobile() {
140
140
  // Set the mounted state to true after the component has mounted
141
141
  setIsMounted(true);
142
142
  var handleResize = function handleResize() {
143
- if (window) {
143
+ if (typeof window !== 'undefined') {
144
144
  var detectDeviceType = function detectDeviceType() {
145
145
  // 1. First check if window and navigator are available (SSR compatibility)
146
- if (typeof window === 'undefined' || !navigator) {
146
+ if (typeof window === 'undefined' || typeof navigator === 'undefined') {
147
147
  return 'desktop'; // Default to desktop
148
148
  }
149
149
 
@@ -151,7 +151,7 @@ var useIsMobile = function useIsMobile() {
151
151
  var ua = navigator.userAgent.toLowerCase();
152
152
 
153
153
  // 3. Get platform info
154
- var platform = navigator.platform.toLowerCase();
154
+ var platform = navigator.platform ? navigator.platform.toLowerCase() : '';
155
155
 
156
156
  // 4. Check screen characteristics using window.matchMedia
157
157
  var isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
@@ -89,10 +89,11 @@
89
89
  --cas-select-items-li-border-color: #eee;
90
90
  --cas-select-loader-color: #000000;
91
91
  --cas-select-clean-btn-color: #b5b5b5;
92
+ --cas-select-searchbox-border-color: #ddd;
92
93
  box-shadow: var(--cas-select-items-box-shadow);
93
94
  position: absolute;
94
95
  left: auto;
95
- max-height: 350px;
96
+ max-height: 300px;
96
97
  border: 1px solid var(--cas-select-items-border-color);
97
98
  background: var(--cas-select-items-bg);
98
99
  padding: 10px;
@@ -106,6 +107,7 @@
106
107
  display: none;
107
108
  z-index: 1055; /* --bs-modal-zindex */
108
109
  /* each item */
110
+ /* Searchbox */
109
111
  /* Options */
110
112
  }
111
113
  .cas-select__items-wrapper.active {
@@ -124,19 +126,22 @@
124
126
  top: 0;
125
127
  margin-left: 5px;
126
128
  z-index: 1;
127
- z-index: 1;
128
129
  width: 12px;
129
130
  height: 12px;
130
131
  text-align: center;
131
- transform-origin: bottom;
132
+ transform-origin: center;
133
+ transform: translate(2px, 5px) rotate(0);
132
134
  animation: 1s linear infinite cas-select__spinner;
133
135
  }
136
+ .cas-select__items-wrapper .cas-select__items-loader svg {
137
+ vertical-align: top;
138
+ }
134
139
  .cas-select__items-wrapper .cas-select__items-loader svg path {
135
140
  fill: var(--cas-select-loader-color);
136
141
  }
137
142
  @keyframes cas-select__spinner {
138
143
  to {
139
- transform: rotate(-360deg);
144
+ transform: translate(2px, 5px) rotate(-360deg);
140
145
  }
141
146
  }
142
147
  .cas-select__items-wrapper .cas-select__close svg {
@@ -167,6 +172,12 @@
167
172
  margin-right: 0;
168
173
  border-right: none;
169
174
  }
175
+ .cas-select__items-wrapper .cas-select__items-col-searchbox input {
176
+ border: 1px solid var(--cas-select-searchbox-border-color);
177
+ border-radius: 0.35rem;
178
+ background: transparent;
179
+ font-size: 0.75rem;
180
+ }
170
181
  .cas-select__items-wrapper .cas-select__opt {
171
182
  padding: var(--cas-select-opt-padding-y) var(--cas-select-opt-padding-x);
172
183
  font-size: var(--cas-select-opt-font-size);
@@ -89,10 +89,11 @@
89
89
  --cas-select-e2e-items-li-border-color: #eee;
90
90
  --cas-select-e2e-loader-color: #000000;
91
91
  --cas-select-e2e-clean-btn-color: #b5b5b5;
92
+ --cas-select-e2e-searchbox-border-color: #ddd;
92
93
  box-shadow: var(--cas-select-e2e-items-box-shadow);
93
94
  position: absolute;
94
95
  left: auto;
95
- max-height: 350px;
96
+ max-height: 300px;
96
97
  border: 1px solid var(--cas-select-e2e-items-border-color);
97
98
  background: var(--cas-select-e2e-items-bg);
98
99
  padding: 10px;
@@ -106,6 +107,7 @@
106
107
  display: none;
107
108
  z-index: 1055; /* --bs-modal-zindex */
108
109
  /* each item */
110
+ /* Searchbox */
109
111
  /* Options */
110
112
  }
111
113
  .cas-select-e2e__items-wrapper.active {
@@ -124,19 +126,22 @@
124
126
  top: 0;
125
127
  margin-left: 5px;
126
128
  z-index: 1;
127
- z-index: 1;
128
129
  width: 12px;
129
130
  height: 12px;
130
131
  text-align: center;
131
- transform-origin: bottom;
132
+ transform-origin: center;
133
+ transform: translate(2px, 5px) rotate(0);
132
134
  animation: 1s linear infinite cas-select-e2e__spinner;
133
135
  }
136
+ .cas-select-e2e__items-wrapper .cas-select-e2e__items-loader svg {
137
+ vertical-align: top;
138
+ }
134
139
  .cas-select-e2e__items-wrapper .cas-select-e2e__items-loader svg path {
135
140
  fill: var(--cas-select-e2e-loader-color);
136
141
  }
137
142
  @keyframes cas-select-e2e__spinner {
138
143
  to {
139
- transform: rotate(-360deg);
144
+ transform: translate(2px, 5px) rotate(-360deg);
140
145
  }
141
146
  }
142
147
  .cas-select-e2e__items-wrapper .cas-select-e2e__close svg {
@@ -167,6 +172,12 @@
167
172
  margin-right: 0;
168
173
  border-right: none;
169
174
  }
175
+ .cas-select-e2e__items-wrapper .cas-select-e2e__items-col-searchbox input {
176
+ border: 1px solid var(--cas-select-e2e-searchbox-border-color);
177
+ border-radius: 0.35rem;
178
+ background: transparent;
179
+ font-size: 0.75rem;
180
+ }
170
181
  .cas-select-e2e__items-wrapper .cas-select-e2e__opt {
171
182
  padding: var(--cas-select-e2e-opt-padding-y) var(--cas-select-e2e-opt-padding-x);
172
183
  font-size: var(--cas-select-e2e-opt-font-size);
@@ -56,6 +56,8 @@
56
56
  .custom-select__wrapper .custom-select-multi__control-blinking-cursor {
57
57
  display: inline-block;
58
58
  color: var(--cus-sel-placeholder-color);
59
+ width: 100%;
60
+ /* Text preview */
59
61
  }
60
62
  .custom-select__wrapper .custom-select-multi__control-blinking-cursor.animated {
61
63
  animation: 1s mf-sel-blink step-end infinite;
@@ -63,6 +65,13 @@
63
65
  .custom-select__wrapper .custom-select-multi__control-blinking-cursor.control-placeholder {
64
66
  color: var(--cus-sel-input-placeholder-color);
65
67
  }
68
+ .custom-select__wrapper .custom-select-multi__control-blinking-cursor > span {
69
+ display: inline-block;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ overflow: hidden;
73
+ max-width: 100%;
74
+ }
66
75
  .custom-select__wrapper .custom-select-multi__control-blinking-following-cursor {
67
76
  position: absolute;
68
77
  top: 0.375rem;
@@ -269,9 +278,12 @@
269
278
  --cus-sel-listgroup-content-scrollbar-w: 10px;
270
279
  --cus-sel-listgroup-grouptitle-color: #a2a2a2;
271
280
  --cus-sel-listgroup-groupborder-color: #d8d8d8;
281
+ --cus-sel-loader-color: #000000;
272
282
  display: none;
273
283
  min-width: var(--cus-sel-listgroup-popwin-min-width);
274
284
  z-index: 1055; /* --bs-modal-zindex */
285
+ /*------ Loader ------*/
286
+ /*------ Options ------*/
275
287
  /*------ Multiple selection ------*/
276
288
  /*------ Group ------*/
277
289
  /*------ Extended buttons of Multiple selection ------*/
@@ -280,6 +292,27 @@
280
292
  .custom-select__options-wrapper.active {
281
293
  display: block !important;
282
294
  }
295
+ .custom-select__options-wrapper .cus-select-loader {
296
+ pointer-events: none;
297
+ z-index: 1;
298
+ width: 12px;
299
+ height: 12px;
300
+ text-align: center;
301
+ transform-origin: center;
302
+ transform: translate(-5px, 0) rotate(0);
303
+ animation: 1s linear infinite cus-select__spinner;
304
+ }
305
+ .custom-select__options-wrapper .cus-select-loader svg {
306
+ vertical-align: top;
307
+ }
308
+ .custom-select__options-wrapper .cus-select-loader svg path {
309
+ fill: var(--cus-sel-loader-color);
310
+ }
311
+ @keyframes cus-select__spinner {
312
+ to {
313
+ transform: translate(-5px, 0) rotate(-360deg);
314
+ }
315
+ }
283
316
  .custom-select__options-wrapper .custom-select__options-contentlist {
284
317
  overflow: hidden;
285
318
  overflow-y: auto;
@@ -125,11 +125,13 @@
125
125
  --cas-select-loader-color: #000000;
126
126
  --cas-select-clean-btn-color: #b5b5b5;
127
127
 
128
+ --cas-select-searchbox-border-color: #ddd;
129
+
128
130
 
129
131
  box-shadow: var(--cas-select-items-box-shadow);
130
132
  position: absolute;
131
133
  left: auto;
132
- max-height: 350px;
134
+ max-height: 300px;
133
135
  border: 1px solid var(--cas-select-items-border-color);
134
136
  background: var(--cas-select-items-bg);
135
137
  padding: 10px;
@@ -165,21 +167,25 @@
165
167
  top: 0;
166
168
  margin-left: 5px;
167
169
  z-index: 1;
168
- z-index: 1;
169
170
  width: 12px;
170
171
  height: 12px;
171
172
  text-align: center;
172
- transform-origin: bottom;
173
+ transform-origin: center;
174
+ transform: translate(2px, 5px) rotate(0);
173
175
  animation: 1s linear infinite cas-select__spinner;
174
176
 
175
- svg path {
176
- fill: var(--cas-select-loader-color);
177
+ svg {
178
+ vertical-align: top;
179
+
180
+ path {
181
+ fill: var(--cas-select-loader-color);
182
+ }
177
183
  }
178
184
  }
179
185
 
180
186
  @keyframes cas-select__spinner {
181
187
  to {
182
- transform: rotate(-360deg);
188
+ transform: translate(2px, 5px) rotate(-360deg);
183
189
  }
184
190
  }
185
191
 
@@ -224,7 +230,16 @@
224
230
  }
225
231
 
226
232
 
227
-
233
+ /* Searchbox */
234
+ .cas-select__items-col-searchbox {
235
+ input {
236
+ border: 1px solid var(--cas-select-searchbox-border-color);
237
+ border-radius: 0.35rem;
238
+ background: transparent;
239
+ font-size: 0.75rem;
240
+ }
241
+ }
242
+
228
243
  /* Options */
229
244
  .cas-select__opt {
230
245
  padding: var(--cas-select-opt-padding-y) var(--cas-select-opt-padding-x);
@@ -15,6 +15,9 @@ import {
15
15
  import {
16
16
  getAbsolutePositionOfStage
17
17
  } from 'funda-utils/dist/cjs/getElementProperty';
18
+ import {
19
+ htmlToPlain
20
+ } from 'funda-utils/dist/cjs/format-string';
18
21
  import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
19
22
 
20
23
 
@@ -29,6 +32,8 @@ export type CascadingSelectProps = {
29
32
  wrapperClassName?: string;
30
33
  controlClassName?: string;
31
34
  controlExClassName?: string;
35
+ searchable?: boolean;
36
+ searchPlaceholder?: string;
32
37
  perColumnHeadersShow?: boolean;
33
38
  exceededSidePosOffset?: number;
34
39
  value?: string;
@@ -89,6 +94,8 @@ const CascadingSelect = (props: CascadingSelectProps) => {
89
94
  wrapperClassName,
90
95
  controlClassName,
91
96
  controlExClassName,
97
+ searchable = false,
98
+ searchPlaceholder = '',
92
99
  perColumnHeadersShow = true,
93
100
  exceededSidePosOffset,
94
101
  disabled,
@@ -135,6 +142,8 @@ const CascadingSelect = (props: CascadingSelectProps) => {
135
142
  const valRef = useRef<any>(null);
136
143
  const listRef = useRef<any>(null);
137
144
 
145
+ // searchable
146
+ const [columnSearchKeywords, setColumnSearchKeywords] = useState<string[]>([]);
138
147
 
139
148
  // exposes the following methods
140
149
  useImperativeHandle(
@@ -1079,6 +1088,16 @@ const CascadingSelect = (props: CascadingSelectProps) => {
1079
1088
 
1080
1089
  }, [value]);
1081
1090
 
1091
+ // Automatically complete and truncate column Search Keywords each time the number of columns changes
1092
+ useEffect(() => {
1093
+ if (listData.current.length !== columnSearchKeywords.length) {
1094
+ setColumnSearchKeywords(
1095
+ Array(listData.current.length).fill('').map((v, i) => columnSearchKeywords[i] || '')
1096
+ );
1097
+ }
1098
+ }, [listData.current.length]);
1099
+
1100
+
1082
1101
  return (
1083
1102
  <>
1084
1103
 
@@ -1115,13 +1134,42 @@ const CascadingSelect = (props: CascadingSelectProps) => {
1115
1134
  {listData.current.map((item: any, level: number) => {
1116
1135
 
1117
1136
  if (item.length > 0) {
1137
+
1138
+ // filter data
1139
+ let filteredItem = item;
1140
+ if (searchable && columnSearchKeywords[level]) {
1141
+ const keyword = columnSearchKeywords[level].toLowerCase();
1142
+ filteredItem = item.filter((opt: any) =>
1143
+ (htmlToPlain(opt.name) || '').toLowerCase().includes(keyword)
1144
+ );
1145
+ }
1146
+
1147
+
1118
1148
  return (
1119
1149
  <li key={level} data-col={level} className="cas-select__items-col">
1150
+
1151
+ {/* SEARCH BOX */}
1152
+ {searchable && (
1153
+ <div className="cas-select__items-col-searchbox">
1154
+ <input
1155
+ type="text"
1156
+ placeholder={searchPlaceholder}
1157
+ value={columnSearchKeywords[level] || ''}
1158
+ onChange={e => {
1159
+ const newKeywords = [...columnSearchKeywords];
1160
+ newKeywords[level] = e.target.value;
1161
+ setColumnSearchKeywords(newKeywords);
1162
+ }}
1163
+ />
1164
+ </div>
1165
+ )}
1166
+ {/* /SEARCH BOX */}
1167
+
1120
1168
  <Group
1121
1169
  perColumnHeadersShow={perColumnHeadersShow}
1122
1170
  level={level}
1123
1171
  columnTitle={columnTitleData}
1124
- data={item}
1172
+ data={filteredItem} // filter result
1125
1173
  cleanNodeBtnClassName={cleanNodeBtnClassName}
1126
1174
  cleanNodeBtnContent={cleanNodeBtnContent}
1127
1175
  selectEv={(e, value, index, ) => handleClickItem(e, value, index, level, listData.current)}
@@ -2,6 +2,7 @@ import React from 'react';
2
2
 
3
3
  import { combinedCls } from 'funda-utils/dist/cjs/cls';
4
4
 
5
+
5
6
  export type GroupFnType = (arg1: any, arg2: any, arg3: number) => void;
6
7
 
7
8
  export type GroupProps = {
@@ -127,11 +127,12 @@
127
127
  --cas-select-e2e-loader-color: #000000;
128
128
  --cas-select-e2e-clean-btn-color: #b5b5b5;
129
129
 
130
+ --cas-select-e2e-searchbox-border-color: #ddd;
130
131
 
131
132
  box-shadow: var(--cas-select-e2e-items-box-shadow);
132
133
  position: absolute;
133
134
  left: auto;
134
- max-height: 350px;
135
+ max-height: 300px;
135
136
  border: 1px solid var(--cas-select-e2e-items-border-color);
136
137
  background: var(--cas-select-e2e-items-bg);
137
138
  padding: 10px;
@@ -160,6 +161,7 @@
160
161
  padding: 0;
161
162
  }
162
163
 
164
+
163
165
  .cas-select-e2e__items-loader {
164
166
  position: absolute;
165
167
  pointer-events: none;
@@ -167,21 +169,25 @@
167
169
  top: 0;
168
170
  margin-left: 5px;
169
171
  z-index: 1;
170
- z-index: 1;
171
172
  width: 12px;
172
173
  height: 12px;
173
174
  text-align: center;
174
- transform-origin: bottom;
175
+ transform-origin: center;
176
+ transform: translate(2px, 5px) rotate(0);
175
177
  animation: 1s linear infinite cas-select-e2e__spinner;
176
178
 
177
- svg path {
178
- fill: var(--cas-select-e2e-loader-color);
179
+ svg {
180
+ vertical-align: top;
181
+
182
+ path {
183
+ fill: var(--cas-select-e2e-loader-color);
184
+ }
179
185
  }
180
186
  }
181
187
 
182
188
  @keyframes cas-select-e2e__spinner {
183
189
  to {
184
- transform: rotate(-360deg);
190
+ transform: translate(2px, 5px) rotate(-360deg);
185
191
  }
186
192
  }
187
193
 
@@ -227,6 +233,17 @@
227
233
 
228
234
 
229
235
 
236
+ /* Searchbox */
237
+ .cas-select-e2e__items-col-searchbox {
238
+ input {
239
+ border: 1px solid var(--cas-select-e2e-searchbox-border-color);
240
+ border-radius: 0.35rem;
241
+ background: transparent;
242
+ font-size: 0.75rem;
243
+ }
244
+ }
245
+
246
+
230
247
  /* Options */
231
248
  .cas-select-e2e__opt {
232
249
  padding: var(--cas-select-e2e-opt-padding-y) var(--cas-select-e2e-opt-padding-x);