funda-ui 4.7.625 → 4.7.701

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 (84) hide show
  1. package/CascadingSelect/index.js +2 -2
  2. package/CascadingSelectE2E/index.js +2 -2
  3. package/Chatbox/index.js +3 -17
  4. package/Checkbox/index.js +3 -3
  5. package/ColorPicker/index.js +3 -18
  6. package/Date/index.js +3 -18
  7. package/EventCalendarTimeline/index.d.ts +1 -1
  8. package/EventCalendarTimeline/index.js +11 -1
  9. package/File/index.d.ts +9 -0
  10. package/File/index.js +245 -93
  11. package/Input/index.js +3 -18
  12. package/LiveSearch/index.js +3 -18
  13. package/NativeSelect/index.js +3 -3
  14. package/NumberInput/index.js +3 -18
  15. package/Popover/index.css +198 -0
  16. package/Popover/index.d.ts +4 -0
  17. package/Popover/index.js +1808 -0
  18. package/README.md +1 -0
  19. package/Radio/index.js +3 -3
  20. package/RangeSlider/index.js +3 -18
  21. package/SearchBar/index.js +3 -18
  22. package/Select/index.js +3 -2
  23. package/Switch/index.js +3 -3
  24. package/TagInput/index.css +31 -31
  25. package/TagInput/index.js +12 -23
  26. package/Textarea/index.js +3 -17
  27. package/Utils/useSSE.d.ts +9 -0
  28. package/Utils/useSSE.js +211 -0
  29. package/all.d.ts +1 -0
  30. package/all.js +1 -0
  31. package/lib/cjs/CascadingSelect/index.js +2 -2
  32. package/lib/cjs/CascadingSelectE2E/index.js +2 -2
  33. package/lib/cjs/Chatbox/index.js +3 -17
  34. package/lib/cjs/Checkbox/index.js +3 -3
  35. package/lib/cjs/ColorPicker/index.js +3 -18
  36. package/lib/cjs/Date/index.js +3 -18
  37. package/lib/cjs/EventCalendarTimeline/index.d.ts +1 -1
  38. package/lib/cjs/EventCalendarTimeline/index.js +11 -1
  39. package/lib/cjs/File/index.d.ts +9 -0
  40. package/lib/cjs/File/index.js +245 -93
  41. package/lib/cjs/Input/index.js +3 -18
  42. package/lib/cjs/LiveSearch/index.js +3 -18
  43. package/lib/cjs/NativeSelect/index.js +3 -3
  44. package/lib/cjs/NumberInput/index.js +3 -18
  45. package/lib/cjs/Popover/index.d.ts +4 -0
  46. package/lib/cjs/Popover/index.js +1808 -0
  47. package/lib/cjs/Radio/index.js +3 -3
  48. package/lib/cjs/RangeSlider/index.js +3 -18
  49. package/lib/cjs/SearchBar/index.js +3 -18
  50. package/lib/cjs/Select/index.js +3 -2
  51. package/lib/cjs/Switch/index.js +3 -3
  52. package/lib/cjs/TagInput/index.js +12 -23
  53. package/lib/cjs/Textarea/index.js +3 -17
  54. package/lib/cjs/Utils/useSSE.d.ts +9 -0
  55. package/lib/cjs/Utils/useSSE.js +211 -0
  56. package/lib/cjs/index.d.ts +1 -0
  57. package/lib/cjs/index.js +1 -0
  58. package/lib/css/Popover/index.css +198 -0
  59. package/lib/css/TagInput/index.css +31 -31
  60. package/lib/esm/CascadingSelect/index.tsx +2 -2
  61. package/lib/esm/CascadingSelectE2E/index.tsx +2 -2
  62. package/lib/esm/Checkbox/index.tsx +3 -3
  63. package/lib/esm/ColorPicker/index.tsx +4 -15
  64. package/lib/esm/EventCalendarTimeline/index.tsx +11 -2
  65. package/lib/esm/File/index.tsx +148 -23
  66. package/lib/esm/Input/index.tsx +6 -17
  67. package/lib/esm/NativeSelect/index.tsx +3 -3
  68. package/lib/esm/NumberInput/index.tsx +7 -15
  69. package/lib/esm/Popover/Popover.tsx +251 -0
  70. package/lib/esm/Popover/PopoverClose.tsx +51 -0
  71. package/lib/esm/Popover/PopoverContent.tsx +72 -0
  72. package/lib/esm/Popover/PopoverTrigger.tsx +62 -0
  73. package/lib/esm/Popover/index.scss +272 -0
  74. package/lib/esm/Popover/index.tsx +4 -0
  75. package/lib/esm/Radio/index.tsx +3 -3
  76. package/lib/esm/SearchBar/index.tsx +8 -12
  77. package/lib/esm/Select/index.tsx +2 -2
  78. package/lib/esm/Switch/index.tsx +3 -3
  79. package/lib/esm/TagInput/index.scss +24 -24
  80. package/lib/esm/TagInput/index.tsx +13 -20
  81. package/lib/esm/Textarea/index.tsx +6 -14
  82. package/lib/esm/Utils/hooks/useSSE.tsx +109 -0
  83. package/lib/esm/index.js +1 -0
  84. package/package.json +1 -1
@@ -209,12 +209,6 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
209
209
  function handleChange(event: ChangeEvent<HTMLInputElement>) {
210
210
 
211
211
  const val = event.target.value;
212
-
213
- //----
214
- //remove focus style
215
- if (val === '') {
216
- rootRef.current?.classList.remove('focus');
217
- }
218
212
 
219
213
  //
220
214
  let _alreadyInItems = alreadyInItems;
@@ -239,7 +233,8 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
239
233
 
240
234
 
241
235
  function handleFocus(event: FocusEvent<HTMLInputElement>) {
242
- rootRef.current?.classList.add('focus');
236
+ // tag style
237
+ rootRef.current?.classList.add('focus-floating');
243
238
 
244
239
  //
245
240
  onFocus?.(event);
@@ -250,14 +245,9 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
250
245
  const el = event.target;
251
246
  const val = event.target.value;
252
247
 
248
+ setUserInput('');
249
+ setAlreadyInItems(false);
253
250
 
254
- //----
255
- //remove focus style
256
- if (val === '') {
257
- rootRef.current?.classList.remove('focus');
258
- }
259
-
260
- //
261
251
  onBlur?.(event);
262
252
  }
263
253
 
@@ -277,16 +267,19 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
277
267
  <>
278
268
 
279
269
  <div className={combinedCls(
280
- 'tag-input__wrapper',
281
- clsWrite(wrapperClassName, 'mb-3 position-relative')
270
+ 'taginput__wrapper',
271
+ clsWrite(wrapperClassName, 'mb-3 position-relative'),
272
+ {
273
+ 'focus-floating': userInput !== ''
274
+ }
282
275
  )} ref={rootRef}>
283
276
 
284
277
  {label ? <>{typeof label === 'string' ? <label htmlFor={`label-${idRes}`} className="form-label" dangerouslySetInnerHTML={{__html: `${label}`}}></label> : <label htmlFor={`label-${idRes}`} className="form-label">{label}</label>}</> : null}
285
278
 
286
279
 
287
- <div className="tag-input__control-wrapper">
280
+ <div className="taginput__control-wrapper">
288
281
  <div>
289
- <ul className="tag-input__list">
282
+ <ul className="taginput__list">
290
283
 
291
284
  {/* ITEMS LIST */}
292
285
  {typeof renderSelectedValue === 'function' ? <>
@@ -308,7 +301,7 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
308
301
 
309
302
 
310
303
  <div className={combinedCls(
311
- 'tag-input__control',
304
+ 'taginput__control',
312
305
  {
313
306
  'disabled': disabled
314
307
  }
@@ -321,7 +314,7 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
321
314
 
322
315
  // Don't use "name", it's just a container to display the label
323
316
  data-name={name?.match(/(\[.*?\])/gi) ? `${name.split('[')[0]}-label[]` : `${name}-label`}
324
- data-tag-input
317
+ data-taginput
325
318
  autoComplete={typeof autoComplete === 'undefined' ? 'off' : autoComplete}
326
319
  autoCapitalize={typeof autoCapitalize === 'undefined' ? 'off' : autoCapitalize}
327
320
  spellCheck={typeof spellCheck === 'undefined' ? false : spellCheck}
@@ -335,7 +335,6 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
335
335
 
336
336
  function handleFocus(event: FocusEvent<HTMLTextAreaElement>): void {
337
337
  const el = event.target;
338
- rootRef.current?.classList.add('focus');
339
338
 
340
339
  //
341
340
  onFocus?.(event, valRef.current as HTMLTextAreaElement);
@@ -346,12 +345,6 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
346
345
 
347
346
  setChangedVal(curVal);
348
347
 
349
- //----
350
- //remove focus style
351
- if (curVal === '') {
352
- rootRef.current?.classList.remove('focus');
353
- }
354
-
355
348
  //
356
349
  onChange?.(event, valRef.current as HTMLTextAreaElement, curVal);
357
350
 
@@ -368,12 +361,6 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
368
361
  const val = el.value;
369
362
 
370
363
 
371
- //----
372
- //remove focus style
373
- if (val === '') {
374
- rootRef.current?.classList.remove('focus');
375
- }
376
-
377
364
  //
378
365
  onBlur?.(event, valRef.current as HTMLTextAreaElement);
379
366
 
@@ -516,7 +503,12 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
516
503
  return (
517
504
  <>
518
505
 
519
- <div className={clsWrite(wrapperClassName, 'mb-3 position-relative')} ref={rootRef}>
506
+ <div className={combinedCls(
507
+ clsWrite(wrapperClassName, 'mb-3 position-relative'),
508
+ {
509
+ 'focus-floating': changedVal !== ''
510
+ }
511
+ )} ref={rootRef}>
520
512
  {label ? <>{typeof label === 'string' ? <label htmlFor={idRes} className="form-label" dangerouslySetInnerHTML={{__html: `${label}`}}></label> : <label htmlFor={idRes} className="form-label">{label}</label>}</> : null}
521
513
 
522
514
 
@@ -0,0 +1,109 @@
1
+ /**
2
+ * SSE
3
+ *
4
+ * @usage:
5
+ *
6
+ * const App = () => {
7
+ * const { connected, messages, disconnect, reconnect } = useSSE('http://localhost:3000/sse');
8
+ *
9
+ * return (
10
+ * <div>
11
+ * <p>Status: {connected ? '✅ Connected' : '❌ Disconnected'}</p>
12
+ * <button onClick={disconnect}>Disconnect</button>
13
+ * <button onClick={reconnect}>Reconnect</button>
14
+ * {messages.map((m, i) => <div key={i}>{m}</div>)}
15
+ * </div>
16
+ * );
17
+ * };
18
+ */
19
+ import { useEffect, useRef, useState, useCallback } from 'react';
20
+
21
+ const useSSE = (url: string | null | undefined, retryDelay: number = 3000) => {
22
+ const [connected, setConnected] = useState<boolean>(false);
23
+ const [messages, setMessages] = useState<string[]>([]);
24
+ const sourceRef = useRef<EventSource | null>(null);
25
+ const reconnectTimerRef = useRef<NodeJS.Timeout | null>(null);
26
+ const manuallyClosedRef = useRef<boolean>(false);
27
+
28
+ const internalCleanup = useCallback(() => {
29
+ if (reconnectTimerRef.current) {
30
+ clearTimeout(reconnectTimerRef.current);
31
+ reconnectTimerRef.current = null;
32
+ }
33
+
34
+ if (sourceRef.current) {
35
+ try {
36
+ sourceRef.current.close();
37
+ } catch (_) {
38
+ // Ignore errors during cleanup
39
+ }
40
+ sourceRef.current = null;
41
+ }
42
+
43
+ setConnected(false);
44
+ }, []);
45
+
46
+ const connect = useCallback(() => {
47
+ if (!url || manuallyClosedRef.current) return;
48
+
49
+ // Prevent duplicate connections
50
+ if (sourceRef.current) return;
51
+
52
+ const source = new EventSource(url);
53
+ sourceRef.current = source;
54
+
55
+ source.onopen = () => {
56
+ setConnected(true);
57
+ };
58
+
59
+ source.onmessage = (event: MessageEvent) => {
60
+ setMessages([event.data]);
61
+ };
62
+
63
+ source.onerror = (err: Event) => {
64
+ internalCleanup();
65
+
66
+ if (!manuallyClosedRef.current) {
67
+ reconnectTimerRef.current = setTimeout(() => {
68
+ connect();
69
+ }, retryDelay);
70
+ }
71
+ };
72
+ }, [internalCleanup, retryDelay, url]);
73
+
74
+ const disconnect = useCallback(() => {
75
+ manuallyClosedRef.current = true;
76
+ internalCleanup();
77
+ }, [internalCleanup]);
78
+
79
+ const reconnect = useCallback(() => {
80
+ manuallyClosedRef.current = false;
81
+ internalCleanup();
82
+ connect();
83
+ }, [connect, internalCleanup]);
84
+
85
+ const resetMessages = useCallback(() => setMessages([]), []);
86
+
87
+ useEffect(() => {
88
+ if (!url) return;
89
+
90
+ manuallyClosedRef.current = false;
91
+ connect();
92
+
93
+ return () => {
94
+ // Cleanup on unmount (does not mark manual close)
95
+ internalCleanup();
96
+ };
97
+ }, [url, connect, internalCleanup]);
98
+
99
+ return {
100
+ connected,
101
+ messages,
102
+ disconnect,
103
+ reconnect,
104
+ resetMessages
105
+ } as const;
106
+ };
107
+
108
+ export default useSSE;
109
+ export { useSSE };
package/lib/esm/index.js CHANGED
@@ -25,6 +25,7 @@ export { default as MultipleSelect } from './MultipleSelect';
25
25
  export { default as NativeSelect } from './NativeSelect';
26
26
  export { default as NumberInput } from './NumberInput';
27
27
  export { default as Pagination } from './Pagination';
28
+ export { default as Popover } from './Popover';
28
29
  export { default as Radio } from './Radio';
29
30
  export { default as RangeSlider } from './RangeSlider';
30
31
  export { default as Refresher } from './Refresher';
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"UIUX Lab","email":"uiuxlab@gmail.com","name":"funda-ui","version":"4.7.625","description":"React components using pure Bootstrap 5+ which does not contain any external style and script libraries.","repository":{"type":"git","url":"git+https://github.com/xizon/funda-ui.git"},"scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":["bootstrap","react-bootstrap","react-components","components","components-react","react-bootstrap-components","react","funda-ui","fundaui","uikit","ui-kit","ui-components"],"bugs":{"url":"https://github.com/xizon/funda-ui/issues"},"homepage":"https://github.com/xizon/funda-ui#readme","main":"all.js","license":"MIT","dependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"types":"all.d.ts","publishConfig":{"directory":"lib"},"directories":{"lib":"lib"}}
1
+ {"author":"UIUX Lab","email":"uiuxlab@gmail.com","name":"funda-ui","version":"4.7.701","description":"React components using pure Bootstrap 5+ which does not contain any external style and script libraries.","repository":{"type":"git","url":"git+https://github.com/xizon/funda-ui.git"},"scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":["bootstrap","react-bootstrap","react-components","components","components-react","react-bootstrap-components","react","funda-ui","fundaui","uikit","ui-kit","ui-components"],"bugs":{"url":"https://github.com/xizon/funda-ui/issues"},"homepage":"https://github.com/xizon/funda-ui#readme","main":"all.js","license":"MIT","dependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"types":"all.d.ts","publishConfig":{"directory":"lib"},"directories":{"lib":"lib"}}