funda-ui 4.7.625 → 4.7.711

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 (90) 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 +2 -2
  8. package/EventCalendarTimeline/index.js +24 -6
  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/usePageVisibility.d.ts +5 -0
  28. package/Utils/usePageVisibility.js +166 -0
  29. package/Utils/useSSE.d.ts +50 -0
  30. package/Utils/useSSE.js +235 -0
  31. package/all.d.ts +1 -0
  32. package/all.js +1 -0
  33. package/lib/cjs/CascadingSelect/index.js +2 -2
  34. package/lib/cjs/CascadingSelectE2E/index.js +2 -2
  35. package/lib/cjs/Chatbox/index.js +3 -17
  36. package/lib/cjs/Checkbox/index.js +3 -3
  37. package/lib/cjs/ColorPicker/index.js +3 -18
  38. package/lib/cjs/Date/index.js +3 -18
  39. package/lib/cjs/EventCalendarTimeline/index.d.ts +2 -2
  40. package/lib/cjs/EventCalendarTimeline/index.js +24 -6
  41. package/lib/cjs/File/index.d.ts +9 -0
  42. package/lib/cjs/File/index.js +245 -93
  43. package/lib/cjs/Input/index.js +3 -18
  44. package/lib/cjs/LiveSearch/index.js +3 -18
  45. package/lib/cjs/NativeSelect/index.js +3 -3
  46. package/lib/cjs/NumberInput/index.js +3 -18
  47. package/lib/cjs/Popover/index.d.ts +4 -0
  48. package/lib/cjs/Popover/index.js +1808 -0
  49. package/lib/cjs/Radio/index.js +3 -3
  50. package/lib/cjs/RangeSlider/index.js +3 -18
  51. package/lib/cjs/SearchBar/index.js +3 -18
  52. package/lib/cjs/Select/index.js +3 -2
  53. package/lib/cjs/Switch/index.js +3 -3
  54. package/lib/cjs/TagInput/index.js +12 -23
  55. package/lib/cjs/Textarea/index.js +3 -17
  56. package/lib/cjs/Utils/usePageVisibility.d.ts +5 -0
  57. package/lib/cjs/Utils/usePageVisibility.js +166 -0
  58. package/lib/cjs/Utils/useSSE.d.ts +50 -0
  59. package/lib/cjs/Utils/useSSE.js +235 -0
  60. package/lib/cjs/index.d.ts +1 -0
  61. package/lib/cjs/index.js +1 -0
  62. package/lib/css/Popover/index.css +198 -0
  63. package/lib/css/TagInput/index.css +31 -31
  64. package/lib/esm/CascadingSelect/index.tsx +2 -2
  65. package/lib/esm/CascadingSelectE2E/index.tsx +2 -2
  66. package/lib/esm/Checkbox/index.tsx +3 -3
  67. package/lib/esm/ColorPicker/index.tsx +4 -15
  68. package/lib/esm/EventCalendarTimeline/index.tsx +30 -13
  69. package/lib/esm/File/index.tsx +148 -23
  70. package/lib/esm/Input/index.tsx +6 -17
  71. package/lib/esm/ModalDialog/index.tsx +0 -1
  72. package/lib/esm/NativeSelect/index.tsx +3 -3
  73. package/lib/esm/NumberInput/index.tsx +7 -15
  74. package/lib/esm/Popover/Popover.tsx +251 -0
  75. package/lib/esm/Popover/PopoverClose.tsx +51 -0
  76. package/lib/esm/Popover/PopoverContent.tsx +72 -0
  77. package/lib/esm/Popover/PopoverTrigger.tsx +62 -0
  78. package/lib/esm/Popover/index.scss +272 -0
  79. package/lib/esm/Popover/index.tsx +4 -0
  80. package/lib/esm/Radio/index.tsx +3 -3
  81. package/lib/esm/SearchBar/index.tsx +8 -12
  82. package/lib/esm/Select/index.tsx +2 -2
  83. package/lib/esm/Switch/index.tsx +3 -3
  84. package/lib/esm/TagInput/index.scss +24 -24
  85. package/lib/esm/TagInput/index.tsx +13 -20
  86. package/lib/esm/Textarea/index.tsx +6 -14
  87. package/lib/esm/Utils/hooks/usePageVisibility.tsx +84 -0
  88. package/lib/esm/Utils/hooks/useSSE.tsx +134 -0
  89. package/lib/esm/index.js +1 -0
  90. package/package.json +1 -1
@@ -0,0 +1,251 @@
1
+ import React, { useState, useRef, useEffect, useImperativeHandle, forwardRef, useMemo, createContext, useContext } from 'react';
2
+
3
+ import useComId from 'funda-utils/dist/cjs/useComId';
4
+ import useClickOutside from 'funda-utils/dist/cjs/useClickOutside';
5
+ import {
6
+ getAbsolutePositionOfStage
7
+ } from 'funda-utils/dist/cjs/getElementProperty';
8
+ import { getElCSS } from 'funda-utils/dist/cjs/inputsCalculation';
9
+
10
+ // Context for Popover state management
11
+ export interface PopoverContextValue {
12
+ isOpen: boolean;
13
+ setIsOpen: (open: boolean) => void;
14
+ triggerRef: React.RefObject<HTMLElement>;
15
+ contentRef: React.RefObject<HTMLDivElement>;
16
+ id: string;
17
+ direction?: string;
18
+ offset?: number;
19
+ exceededSidePosOffset?: number;
20
+ size?: string;
21
+ popupArrowColor?: number[];
22
+ popupContentStyle?: React.CSSProperties;
23
+ wrapperClassName?: string;
24
+ position: { x: string; y: string };
25
+ setPosition: (pos: { x: string; y: string }) => void;
26
+ popupArrowStyle?: React.CSSProperties;
27
+ }
28
+
29
+ export const PopoverContext = createContext<PopoverContextValue | null>(null);
30
+
31
+ export const usePopoverContext = () => {
32
+ const context = useContext(PopoverContext);
33
+ if (!context) {
34
+ throw new Error('Popover components must be used within a Popover');
35
+ }
36
+ return context;
37
+ };
38
+
39
+ // Main Popover component (container)
40
+ export type PopoverProps = {
41
+ /** The direction of the tip. Defaults to `top`. Possible values are: `top`, `top-right`, `top-left`, `bottom`, `bottom-right`, `bottom-left` */
42
+ direction?: string;
43
+ /** Position offset */
44
+ offset?: number;
45
+ /** Offset px that exceeds the far right or left side of the screen */
46
+ exceededSidePosOffset?: number;
47
+ /** The size of the content area. Defaults to `auto`. Possible values are: `auto`, `large`, `medium`, `small` */
48
+ size?: string;
49
+ /** Custom color for the popup arrow */
50
+ popupArrowColor?: number[];
51
+ /** Custom style for the popup content */
52
+ popupContentStyle?: React.CSSProperties;
53
+ /** The class name of the control wrapper. */
54
+ wrapperClassName?: string;
55
+ /** -- */
56
+ id?: string;
57
+ /** Controls whether the Popover is open (controlled mode) */
58
+ open?: boolean;
59
+ /** Callback fired when the open state changes (controlled mode) */
60
+ onOpenChange?: (open: boolean) => void;
61
+ children: React.ReactNode;
62
+ };
63
+
64
+ const Popover = forwardRef<any, PopoverProps>((props, ref) => {
65
+ const {
66
+ direction,
67
+ offset,
68
+ exceededSidePosOffset,
69
+ size,
70
+ popupArrowColor,
71
+ popupContentStyle,
72
+ wrapperClassName,
73
+ id,
74
+ open,
75
+ onOpenChange,
76
+ children
77
+ } = props;
78
+
79
+ const POS_OFFSET = Number(offset) || 4;
80
+ const EXCEEDED_SIDE_POS_OFFSET = Number(exceededSidePosOffset) || 15;
81
+ const uniqueID = useComId();
82
+ const idRes = id || uniqueID;
83
+ const triggerRef = useRef<HTMLElement>(null);
84
+ const contentRef = useRef<HTMLDivElement>(null);
85
+ const [uncontrolledOpen, setUncontrolledOpen] = useState<boolean>(false);
86
+ const isControlled = typeof open === 'boolean';
87
+ const isOpen = isControlled ? !!open : uncontrolledOpen;
88
+ const [position, setPosition] = useState<{ x: string; y: string }>({
89
+ x: '0',
90
+ y: '0'
91
+ });
92
+
93
+ const setIsOpen = (nextOpen: boolean) => {
94
+ if (!isControlled) {
95
+ setUncontrolledOpen(nextOpen);
96
+ }
97
+ if (typeof onOpenChange === 'function') {
98
+ onOpenChange(nextOpen);
99
+ }
100
+ };
101
+
102
+ const popupArrowStyle = useMemo(() => {
103
+ if (
104
+ typeof popupArrowColor !== 'undefined' &&
105
+ Array.isArray(popupArrowColor) &&
106
+ popupArrowColor.length === 4
107
+ ) {
108
+ return {
109
+ '--cus-popover-arrow-bg-top': `url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%28${popupArrowColor[0]},%20${popupArrowColor[1]},%20${popupArrowColor[2]},%20${popupArrowColor[3]}%29%22%20transform%3D%22rotate%280%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat`,
110
+ '--cus-popover-arrow-bg-bottom': `url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%28${popupArrowColor[0]},%20${popupArrowColor[1]},%20${popupArrowColor[2]},%20${popupArrowColor[3]}%29%22%20transform%3D%22rotate%28180%2018%206%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat`,
111
+ '--cus-popover-arrow-bg-left': `url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2212px%22%20height%3D%2236px%22%3E%3Cpath%20fill%3D%22rgba%28${popupArrowColor[0]},%20${popupArrowColor[1]},%20${popupArrowColor[2]},%20${popupArrowColor[3]}%29%22%20transform%3D%22rotate%28-90%2018%2018%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat`,
112
+ '--cus-popover-arrow-bg-right': `url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2212px%22%20height%3D%2236px%22%3E%3Cpath%20fill%3D%22rgba%28${popupArrowColor[0]},%20${popupArrowColor[1]},%20${popupArrowColor[2]},%20${popupArrowColor[3]}%29%22%20transform%3D%22rotate%2890%206%206%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat`,
113
+ } as React.CSSProperties;
114
+ }
115
+ return undefined;
116
+ }, [popupArrowColor]);
117
+
118
+ // Calculate position based on trigger element
119
+ const calculatePosition = () => {
120
+ const triggerEl = triggerRef.current;
121
+ if (!triggerEl) return;
122
+
123
+ const { x, y, width, height } = getAbsolutePositionOfStage(triggerEl);
124
+ const pos = direction || 'top';
125
+
126
+ if (pos.indexOf('top') >= 0) {
127
+ setPosition({
128
+ x: x + (width / 2) + 'px',
129
+ y: y - height - POS_OFFSET + 'px'
130
+ });
131
+ } else if (pos.indexOf('bottom') >= 0) {
132
+ setPosition({
133
+ x: x + (width / 2) + 'px',
134
+ y: y + height + POS_OFFSET + 'px'
135
+ });
136
+ }
137
+ };
138
+
139
+ // Expose show/hide methods to parent via ref
140
+ useImperativeHandle(ref, () => ({
141
+ show: () => {
142
+ calculatePosition();
143
+ setIsOpen(true);
144
+ },
145
+ hide: () => {
146
+ setIsOpen(false);
147
+ }
148
+ }), [direction, POS_OFFSET]);
149
+
150
+ // Click outside to close
151
+ useClickOutside({
152
+ enabled: isOpen && triggerRef.current !== null,
153
+ isOutside: (event: any) => {
154
+ // Prevent closing when clicking inside the popover wrapper
155
+ if (contentRef.current && contentRef.current.contains(event.target)) {
156
+ return false;
157
+ }
158
+ return (
159
+ triggerRef.current !== event.target &&
160
+ !triggerRef.current?.contains(event.target as HTMLElement)
161
+ );
162
+ },
163
+ handle: () => {
164
+ setIsOpen(false);
165
+ }
166
+ }, [isOpen]);
167
+
168
+ const exceededOffsetInit = () => {
169
+ // Determine whether it exceeds the far right or left side of the screen
170
+ //------------------
171
+ const _modalRef: any = contentRef.current;
172
+ if (_modalRef === null) return;
173
+
174
+
175
+ const _modalContent = _modalRef.querySelector('.cus-popover__content');
176
+ if (!_modalContent) return;
177
+
178
+ const _modalBox = _modalContent.getBoundingClientRect();
179
+ if (typeof _modalContent.dataset.offset === 'undefined' && _modalBox.left > 0) {
180
+
181
+ // Adjust the coordinates due to height
182
+ //------------------
183
+ const triggerEl: any = document.querySelector(`[data-overlay-id="${_modalRef.id}"]`);
184
+ if (triggerEl !== null) {
185
+ let pos = triggerEl.dataset.microtipPosition;
186
+ if (typeof pos === 'undefined') pos = 'top';
187
+
188
+ const _offsetY = _modalBox.height - getElCSS(_modalContent, 'font-size', true) - getElCSS(_modalContent, 'padding-top', true) - getElCSS(_modalContent, 'padding-bottom', true);
189
+
190
+ if (pos.indexOf('top') >= 0) {
191
+ _modalRef.style.transform = `translateY(-${_offsetY}px)`;
192
+ }
193
+ }
194
+
195
+ // 10 pixels is used to account for some bias in mobile devices
196
+ if ((_modalBox.right + 10) > window.innerWidth) {
197
+ const _modalOffsetPosition = _modalBox.right - window.innerWidth + EXCEEDED_SIDE_POS_OFFSET;
198
+ _modalContent.dataset.offset = _modalOffsetPosition;
199
+ _modalContent.style.marginLeft = `-${_modalOffsetPosition}px`;
200
+ }
201
+
202
+ if ((_modalBox.left - 10) < 0) {
203
+ const _modalOffsetPosition = Math.abs(_modalBox.left) + EXCEEDED_SIDE_POS_OFFSET;
204
+ _modalContent.dataset.offset = _modalOffsetPosition;
205
+ _modalContent.style.marginLeft = `${_modalOffsetPosition}px`;
206
+ }
207
+ }
208
+ };
209
+
210
+ // Update position when opening
211
+ useEffect(() => {
212
+ if (isOpen) {
213
+ calculatePosition();
214
+ }
215
+ }, [isOpen, direction, POS_OFFSET]);
216
+
217
+ // Prevent element data from being unable to be obtained when ref is null
218
+ useEffect(() => {
219
+ exceededOffsetInit();
220
+ });
221
+
222
+
223
+
224
+ const contextValue: PopoverContextValue = {
225
+ isOpen,
226
+ setIsOpen,
227
+ triggerRef,
228
+ contentRef,
229
+ id: idRes,
230
+ direction,
231
+ offset,
232
+ exceededSidePosOffset,
233
+ size,
234
+ popupArrowColor,
235
+ popupContentStyle,
236
+ wrapperClassName,
237
+ position,
238
+ setPosition,
239
+ popupArrowStyle
240
+ };
241
+
242
+ return (
243
+ <PopoverContext.Provider value={contextValue}>
244
+ {children}
245
+ </PopoverContext.Provider>
246
+ );
247
+ });
248
+
249
+ Popover.displayName = 'Popover';
250
+
251
+ export default Popover;
@@ -0,0 +1,51 @@
1
+ import React, { forwardRef } from 'react';
2
+ import { combinedCls } from 'funda-utils/dist/cjs/cls';
3
+
4
+
5
+ import { usePopoverContext } from './Popover';
6
+
7
+ export type PopoverCloseProps = {
8
+ asChild?: boolean;
9
+ className?: string;
10
+ children?: React.ReactNode;
11
+ } & React.HTMLAttributes<HTMLElement>;
12
+
13
+ const PopoverClose = forwardRef<HTMLElement, PopoverCloseProps>((props, ref) => {
14
+ const { asChild, className, children, onClick, ...rest } = props;
15
+ const { setIsOpen } = usePopoverContext();
16
+
17
+ const handleClick = (event: React.MouseEvent<HTMLElement>) => {
18
+ if (typeof onClick === 'function') {
19
+ onClick(event);
20
+ }
21
+
22
+ if (!event.defaultPrevented) {
23
+ setIsOpen(false);
24
+ }
25
+ };
26
+
27
+ const closeProps: any = {
28
+ ref,
29
+ className: combinedCls('cus-popover__close', className),
30
+ onClick: handleClick,
31
+ ...rest
32
+ };
33
+
34
+ if (asChild && React.isValidElement(children)) {
35
+ return React.cloneElement(children as React.ReactElement<any>, {
36
+ ...closeProps,
37
+ ...(children.props || {})
38
+ });
39
+ }
40
+
41
+ return (
42
+ <button type="button" {...closeProps}>
43
+ {children || 'Close'}
44
+ </button>
45
+ );
46
+ });
47
+
48
+ PopoverClose.displayName = 'PopoverClose';
49
+
50
+ export default PopoverClose;
51
+
@@ -0,0 +1,72 @@
1
+ import React, { forwardRef } from 'react';
2
+ import RootPortal from 'funda-root-portal';
3
+ import { combinedCls } from 'funda-utils/dist/cjs/cls';
4
+
5
+
6
+ import { usePopoverContext } from './Popover';
7
+
8
+ // PopoverContent component
9
+ export type PopoverContentProps = {
10
+ children: React.ReactNode;
11
+ className?: string;
12
+ };
13
+
14
+ const PopoverContent = forwardRef<HTMLDivElement, PopoverContentProps>((props, ref) => {
15
+ const { children, className } = props;
16
+ const {
17
+ isOpen,
18
+ contentRef,
19
+ id,
20
+ direction,
21
+ size,
22
+ popupArrowStyle,
23
+ popupContentStyle,
24
+ wrapperClassName,
25
+ position
26
+ } = usePopoverContext();
27
+
28
+ const wrapperRef = (node: HTMLDivElement | null) => {
29
+ if (node) {
30
+ (contentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
31
+ }
32
+ if (typeof ref === 'function') {
33
+ ref(node);
34
+ } else if (ref && node) {
35
+ (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
36
+ }
37
+ };
38
+
39
+ return (
40
+ <RootPortal show={isOpen} containerClassName="Popover">
41
+ <div
42
+ ref={wrapperRef}
43
+ id={`cus-popover__wrapper-${id}`}
44
+ className={combinedCls(
45
+ 'cus-popover__wrapper',
46
+ wrapperClassName,
47
+ 'active'
48
+ )}
49
+ role="popover"
50
+ data-microtip-position={direction || 'top'}
51
+ data-microtip-size={size || 'auto'}
52
+ style={{
53
+ left: position.x,
54
+ top: position.y,
55
+ display: 'none',
56
+ ...popupArrowStyle
57
+ }}
58
+ >
59
+ <div
60
+ className={combinedCls('cus-popover__content', className)}
61
+ style={popupContentStyle}
62
+ >
63
+ {children}
64
+ </div>
65
+ </div>
66
+ </RootPortal>
67
+ );
68
+ });
69
+
70
+ PopoverContent.displayName = 'PopoverContent';
71
+
72
+ export default PopoverContent;
@@ -0,0 +1,62 @@
1
+ import React, { forwardRef } from 'react';
2
+ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
3
+
4
+
5
+ import { usePopoverContext } from './Popover';
6
+
7
+ // PopoverTrigger component
8
+ export type PopoverTriggerProps = {
9
+ asChild?: boolean;
10
+ className?: string;
11
+ children: React.ReactNode;
12
+ };
13
+
14
+ const PopoverTrigger = forwardRef<HTMLElement, PopoverTriggerProps>((props, ref) => {
15
+ const { asChild, className, children } = props;
16
+ const { triggerRef, setIsOpen, isOpen, id, direction, size } = usePopoverContext();
17
+
18
+ const handleClick = (e: React.MouseEvent) => {
19
+ e.preventDefault();
20
+ setIsOpen(!isOpen);
21
+ };
22
+
23
+ const setRefs = (node: HTMLElement | null) => {
24
+ if (node) {
25
+ (triggerRef as React.MutableRefObject<HTMLElement | null>).current = node;
26
+ }
27
+ if (typeof ref === 'function') {
28
+ ref(node);
29
+ } else if (ref && node) {
30
+ (ref as React.MutableRefObject<HTMLElement | null>).current = node;
31
+ }
32
+ };
33
+
34
+ const triggerProps: any = {
35
+ ref: setRefs,
36
+ 'data-overlay-id': `cus-popover__wrapper-${id}`,
37
+ className: combinedCls(
38
+ 'cus-popover__trigger',
39
+ clsWrite(className, 'd-inline-block')
40
+ ),
41
+ 'data-microtip-position': direction || 'top',
42
+ 'data-microtip-size': size || 'auto',
43
+ onClick: handleClick
44
+ };
45
+
46
+ if (asChild && React.isValidElement(children)) {
47
+ return React.cloneElement(children as React.ReactElement<any>, {
48
+ ...triggerProps,
49
+ ...(children.props || {})
50
+ });
51
+ }
52
+
53
+ return (
54
+ <div {...triggerProps}>
55
+ {children}
56
+ </div>
57
+ );
58
+ });
59
+
60
+ PopoverTrigger.displayName = 'PopoverTrigger';
61
+
62
+ export default PopoverTrigger;