@stack-spot/citric-react 0.38.0 → 0.39.1

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 (191) hide show
  1. package/CHANGELOG.md +13 -13
  2. package/dist/citric.css +2844 -2844
  3. package/dist/components/Accordion.d.ts +1 -1
  4. package/dist/components/Accordion.js +1 -1
  5. package/dist/components/Alert.d.ts +1 -1
  6. package/dist/components/Alert.js +1 -1
  7. package/dist/components/AsyncContent.d.ts +1 -1
  8. package/dist/components/AsyncContent.js +1 -1
  9. package/dist/components/Avatar.d.ts +1 -1
  10. package/dist/components/Avatar.js +1 -1
  11. package/dist/components/AvatarGroup.d.ts +1 -1
  12. package/dist/components/AvatarGroup.js +1 -1
  13. package/dist/components/Badge.d.ts +1 -1
  14. package/dist/components/Badge.js +1 -1
  15. package/dist/components/Blockquote.d.ts +1 -1
  16. package/dist/components/Blockquote.js +1 -1
  17. package/dist/components/Breadcrumb.d.ts +1 -1
  18. package/dist/components/Breadcrumb.js +1 -1
  19. package/dist/components/Button.d.ts +1 -1
  20. package/dist/components/Button.js +1 -1
  21. package/dist/components/ButtonLink.d.ts +1 -1
  22. package/dist/components/ButtonLink.js +1 -1
  23. package/dist/components/Card.d.ts +1 -1
  24. package/dist/components/Card.js +1 -1
  25. package/dist/components/Checkbox.d.ts +1 -1
  26. package/dist/components/Checkbox.js +1 -1
  27. package/dist/components/CheckboxGroup.d.ts +1 -1
  28. package/dist/components/CheckboxGroup.d.ts.map +1 -1
  29. package/dist/components/CheckboxGroup.js +2 -2
  30. package/dist/components/CheckboxGroup.js.map +1 -1
  31. package/dist/components/Circle.d.ts +1 -1
  32. package/dist/components/Circle.js +1 -1
  33. package/dist/components/Divider.d.ts +1 -1
  34. package/dist/components/Divider.js +1 -1
  35. package/dist/components/ErrorBoundary.d.ts +1 -1
  36. package/dist/components/ErrorBoundary.js +1 -1
  37. package/dist/components/ErrorMessage.d.ts +1 -1
  38. package/dist/components/ErrorMessage.js +1 -1
  39. package/dist/components/FallbackBoundary.d.ts +1 -1
  40. package/dist/components/FallbackBoundary.js +1 -1
  41. package/dist/components/Favorite.d.ts +1 -1
  42. package/dist/components/Favorite.js +1 -1
  43. package/dist/components/FieldGroup.d.ts +1 -1
  44. package/dist/components/FieldGroup.js +1 -1
  45. package/dist/components/Form.d.ts +2 -2
  46. package/dist/components/Form.js +1 -1
  47. package/dist/components/FormGroup.d.ts +1 -1
  48. package/dist/components/FormGroup.js +1 -1
  49. package/dist/components/Icon.d.ts +1 -1
  50. package/dist/components/Icon.js +1 -1
  51. package/dist/components/IconBox.d.ts +3 -3
  52. package/dist/components/IconBox.js +1 -1
  53. package/dist/components/ImageBox.d.ts +3 -3
  54. package/dist/components/ImageBox.js +1 -1
  55. package/dist/components/ImageWithFallback.d.ts +1 -1
  56. package/dist/components/ImageWithFallback.js +1 -1
  57. package/dist/components/Input.d.ts +1 -1
  58. package/dist/components/Input.js +1 -1
  59. package/dist/components/Link.d.ts +1 -1
  60. package/dist/components/Link.js +1 -1
  61. package/dist/components/LoadingPanel.d.ts +1 -1
  62. package/dist/components/LoadingPanel.js +1 -1
  63. package/dist/components/MenuOverlay/Menu.d.ts +1 -1
  64. package/dist/components/MenuOverlay/Menu.js +1 -1
  65. package/dist/components/MenuOverlay/index.d.ts +1 -1
  66. package/dist/components/MenuOverlay/index.js +1 -1
  67. package/dist/components/Overlay/index.d.ts +4 -1
  68. package/dist/components/Overlay/index.d.ts.map +1 -1
  69. package/dist/components/Overlay/index.js +4 -1
  70. package/dist/components/Overlay/index.js.map +1 -1
  71. package/dist/components/Pagination.d.ts +1 -1
  72. package/dist/components/Pagination.js +1 -1
  73. package/dist/components/ProgressBar.d.ts +1 -1
  74. package/dist/components/ProgressBar.js +1 -1
  75. package/dist/components/ProgressCircular.d.ts +1 -1
  76. package/dist/components/ProgressCircular.js +1 -1
  77. package/dist/components/RadioGroup.d.ts +1 -1
  78. package/dist/components/RadioGroup.d.ts.map +1 -1
  79. package/dist/components/RadioGroup.js +2 -2
  80. package/dist/components/RadioGroup.js.map +1 -1
  81. package/dist/components/Rating.d.ts +1 -1
  82. package/dist/components/Rating.js +1 -1
  83. package/dist/components/Select/MultiSelect.d.ts +1 -1
  84. package/dist/components/Select/MultiSelect.js +1 -1
  85. package/dist/components/Select/RichSelect.d.ts +1 -1
  86. package/dist/components/Select/RichSelect.js +1 -1
  87. package/dist/components/Select/SimpleSelect.d.ts +1 -1
  88. package/dist/components/Select/SimpleSelect.js +1 -1
  89. package/dist/components/Select/index.d.ts +1 -1
  90. package/dist/components/Select/index.js +1 -1
  91. package/dist/components/SelectBox.d.ts +1 -1
  92. package/dist/components/SelectBox.js +1 -1
  93. package/dist/components/Skeleton.d.ts +1 -1
  94. package/dist/components/Skeleton.js +1 -1
  95. package/dist/components/Slider.d.ts +1 -1
  96. package/dist/components/Slider.js +1 -1
  97. package/dist/components/SmartTable.d.ts +1 -1
  98. package/dist/components/SmartTable.js +1 -1
  99. package/dist/components/Stepper.d.ts +1 -1
  100. package/dist/components/Stepper.js +1 -1
  101. package/dist/components/Table.d.ts +3 -3
  102. package/dist/components/Table.js +1 -1
  103. package/dist/components/Tabs/index.d.ts +1 -1
  104. package/dist/components/Tabs/index.js +1 -1
  105. package/dist/components/Textarea.d.ts +1 -1
  106. package/dist/components/Textarea.js +1 -1
  107. package/dist/components/Tooltip.d.ts +1 -1
  108. package/dist/components/Tooltip.js +1 -1
  109. package/dist/context/CitricProvider.d.ts +1 -1
  110. package/dist/context/CitricProvider.js +1 -1
  111. package/dist/overlay.js +1 -1
  112. package/dist/theme.css +415 -415
  113. package/package.json +1 -1
  114. package/scripts/build-css.ts +49 -49
  115. package/src/components/Accordion.tsx +130 -130
  116. package/src/components/Alert.tsx +24 -24
  117. package/src/components/AsyncContent.tsx +70 -70
  118. package/src/components/Avatar.tsx +45 -45
  119. package/src/components/AvatarGroup.tsx +49 -49
  120. package/src/components/Badge.tsx +47 -47
  121. package/src/components/Blockquote.tsx +18 -18
  122. package/src/components/Breadcrumb.tsx +33 -33
  123. package/src/components/Button.tsx +105 -105
  124. package/src/components/ButtonLink.tsx +45 -45
  125. package/src/components/Card.tsx +68 -68
  126. package/src/components/Checkbox.tsx +51 -51
  127. package/src/components/CheckboxGroup.tsx +153 -152
  128. package/src/components/Circle.tsx +43 -43
  129. package/src/components/CitricComponent.ts +47 -47
  130. package/src/components/Divider.tsx +24 -24
  131. package/src/components/ErrorBoundary.tsx +75 -75
  132. package/src/components/ErrorMessage.tsx +11 -11
  133. package/src/components/FallbackBoundary.tsx +40 -40
  134. package/src/components/Favorite.tsx +57 -57
  135. package/src/components/FieldGroup.tsx +46 -46
  136. package/src/components/Form.tsx +36 -36
  137. package/src/components/FormGroup.tsx +57 -57
  138. package/src/components/Icon.tsx +35 -35
  139. package/src/components/IconBox.tsx +134 -134
  140. package/src/components/ImageBox.tsx +125 -125
  141. package/src/components/ImageWithFallback.tsx +65 -65
  142. package/src/components/Input.tsx +49 -49
  143. package/src/components/Link.tsx +55 -55
  144. package/src/components/LoadingPanel.tsx +8 -8
  145. package/src/components/MenuOverlay/Menu.tsx +158 -158
  146. package/src/components/MenuOverlay/context.ts +20 -20
  147. package/src/components/MenuOverlay/index.tsx +55 -55
  148. package/src/components/MenuOverlay/keyboard.ts +60 -60
  149. package/src/components/MenuOverlay/types.ts +171 -171
  150. package/src/components/Overlay/context.ts +10 -10
  151. package/src/components/Overlay/index.tsx +167 -164
  152. package/src/components/Overlay/types.ts +70 -70
  153. package/src/components/Pagination.tsx +133 -133
  154. package/src/components/ProgressBar.tsx +45 -45
  155. package/src/components/ProgressCircular.tsx +45 -45
  156. package/src/components/RadioGroup.tsx +147 -146
  157. package/src/components/Rating.tsx +98 -98
  158. package/src/components/Select/MultiSelect.tsx +217 -217
  159. package/src/components/Select/RichSelect.tsx +128 -128
  160. package/src/components/Select/SimpleSelect.tsx +73 -73
  161. package/src/components/Select/hooks.ts +133 -133
  162. package/src/components/Select/index.tsx +35 -35
  163. package/src/components/Select/types.ts +134 -134
  164. package/src/components/SelectBox.tsx +167 -167
  165. package/src/components/Skeleton.tsx +53 -53
  166. package/src/components/Slider.tsx +89 -89
  167. package/src/components/SmartTable.tsx +227 -227
  168. package/src/components/Stepper.tsx +163 -163
  169. package/src/components/Table.tsx +234 -234
  170. package/src/components/Tabs/TabController.ts +54 -54
  171. package/src/components/Tabs/index.tsx +87 -87
  172. package/src/components/Tabs/types.ts +54 -54
  173. package/src/components/Tabs/utils.ts +6 -6
  174. package/src/components/Text.ts +111 -111
  175. package/src/components/Textarea.tsx +27 -27
  176. package/src/components/Tooltip.tsx +72 -72
  177. package/src/components/layout.tsx +101 -101
  178. package/src/context/CitricContext.tsx +4 -4
  179. package/src/context/CitricProvider.tsx +14 -14
  180. package/src/context/hooks.ts +6 -6
  181. package/src/index.ts +58 -58
  182. package/src/overlay.ts +341 -341
  183. package/src/types.ts +216 -216
  184. package/src/utils/ValueController.ts +28 -28
  185. package/src/utils/acessibility.ts +92 -92
  186. package/src/utils/checkbox.ts +121 -121
  187. package/src/utils/css.ts +119 -119
  188. package/src/utils/options.ts +9 -9
  189. package/src/utils/radio.ts +93 -93
  190. package/src/utils/react.ts +6 -6
  191. package/tsconfig.json +10 -10
@@ -1,164 +1,167 @@
1
- import { useEffect, useRef } from 'react'
2
- import { showOverlay } from '../../overlay'
3
- import { HTMLTag } from '../../types'
4
- import { focusFirstChild } from '../../utils/acessibility'
5
- import { OverlayProvider } from './context'
6
- import { OverlayController, OverlayProps } from './types'
7
-
8
- /**
9
- * An arbitrary time to wait for the next React render to be performed
10
- */
11
- const arbitraryRenderTime = 20
12
-
13
- /**
14
- * These todos are in order of priority.
15
- *
16
- * TODO: update position when the size changes. Currently, the top position seems out of place whenever the height changes. The same is
17
- * probably true for the left position if the width changes.
18
- * TODO: hoverDelayMS
19
- * TODO: reposition the overlay when it's under a scrollable element other then the body and this element is scrolled.
20
- * TODO: close the overlay when it's under a scrollable element other then the body and the element that triggered the tooltip becomes
21
- * hidden by the scroll.
22
- * TODO: use React Portal to implement overlays. The current implementation will lose every React context in the tree.
23
- */
24
-
25
- /**
26
- * Creates an overlay for the child component. The overlay can be any React element. The overlay can be triggered by "click" or "hover"
27
- * (default).
28
- *
29
- * @example
30
- *
31
- * ```
32
- * const overlay = <Card>Hey, this is my overlay!</Card>
33
- *
34
- * return (
35
- * <Overlay content={overlay} attributes={{ style: { margin: '20px' } }}>
36
- * <Button>Hover to see the overlay</Button>
37
- * </Overlay>
38
- * )
39
- * ```
40
- */
41
- export function Overlay<T extends keyof HTMLTag>({
42
- tag,
43
- children,
44
- content,
45
- position = 'top',
46
- triggerOn = 'hover',
47
- alignment = 'center',
48
- attributes,
49
- onRenderChild,
50
- autoFocusBehavior = 'keyboard',
51
- ...props
52
- }: OverlayProps<T>,
53
- ) {
54
- const controller = useRef<OverlayController>({ close: () => Promise.resolve() })
55
- const wrapper = useRef<HTMLDivElement | null>(null)
56
- // props that don't require removing and reattaching the event listeners
57
- const dynamic = useRef({ tag, content, position, alignment, attributes })
58
-
59
- useEffect(() => {
60
- dynamic.current = { tag, content, position, alignment, attributes }
61
- }, [tag, content, position, alignment, attributes])
62
-
63
- useEffect(() => {
64
- let visible = false
65
- let hideOnClickOutside: ((event: Event) => void) | undefined
66
- let hideOnEsc: ((event: Event) => void) | undefined
67
- let hideOverlay: (() => Promise<void>) | undefined
68
- let removeRefocusTargetListener: (() => void) | undefined
69
-
70
- function getTarget() {
71
- const target = wrapper.current?.firstChild
72
- return target instanceof HTMLElement ? target : undefined
73
- }
74
-
75
- if (onRenderChild) {
76
- const target = getTarget()
77
- if (target) onRenderChild(target)
78
- }
79
-
80
- async function show(event: Event) {
81
- if (visible) return
82
- visible = true
83
- const target = getTarget()
84
- if (!target) return
85
- const { overlay, hide: hideFn } = showOverlay({
86
- tag: dynamic.current.tag,
87
- content: ['string', 'number', 'boolean'].includes(typeof dynamic.current.content)
88
- ? dynamic.current.content
89
- : <OverlayProvider value={controller.current}>{dynamic.current.content}</OverlayProvider>,
90
- target,
91
- position: dynamic.current.position,
92
- alignment: dynamic.current.alignment,
93
- attributes: dynamic.current.attributes,
94
- })
95
- hideOverlay = hideFn
96
-
97
- function onHide(condition: (event: Event) => boolean) {
98
- return (event: Event) => {
99
- if (condition(event)) controller.current.close()
100
- }
101
- }
102
-
103
- if (event.type === 'click') {
104
- hideOnEsc = onHide(e => e instanceof KeyboardEvent && e.key === 'Escape')
105
- setTimeout(() => {
106
- hideOnClickOutside = onHide(e => e instanceof MouseEvent && e.button === 0 && !overlay.contains(e.target as HTMLElement))
107
- document.addEventListener('click', hideOnClickOutside)
108
- }, arbitraryRenderTime)
109
- document.addEventListener('keydown', hideOnEsc)
110
- }
111
-
112
- //focus target when the last overlay element loses focus
113
- function refocusTarget(e: KeyboardEvent) {
114
- if (e.key === 'Tab' && e.target instanceof HTMLElement) {
115
- const allItems = Array.from(e.target.closest('[data-citric="menu"]')?.querySelectorAll('a, button') ?? [])
116
- if (e.target === allItems[allItems.length - 1]) {
117
- getTarget()?.focus()
118
- e.preventDefault()
119
- }
120
- }
121
- }
122
- overlay.addEventListener('keydown', refocusTarget)
123
- removeRefocusTargetListener = () => overlay.removeEventListener('keydown', refocusTarget)
124
-
125
- // auto-focus
126
- const openedWithMouse = event instanceof MouseEvent && event.detail > 0
127
- if (autoFocusBehavior === 'always' || (autoFocusBehavior === 'keyboard' && !openedWithMouse)) {
128
- setTimeout(() => focusFirstChild(overlay), arbitraryRenderTime)
129
- }
130
- }
131
-
132
- controller.current.close = async () => {
133
- visible = false
134
- if (hideOnClickOutside) document.removeEventListener('click', hideOnClickOutside)
135
- if (hideOnEsc) document.removeEventListener('keydown', hideOnEsc)
136
- removeRefocusTargetListener?.()
137
- await hideOverlay?.()
138
- }
139
-
140
- if (triggerOn === 'hover') {
141
- getTarget()?.addEventListener('mouseenter', show)
142
- getTarget()?.addEventListener('mouseleave', controller.current.close)
143
- getTarget()?.addEventListener('focus', show)
144
- getTarget()?.addEventListener('blur', controller.current.close)
145
- return () => {
146
- getTarget()?.removeEventListener('mouseenter', show)
147
- getTarget()?.removeEventListener('mouseleave', controller.current.close)
148
- getTarget()?.removeEventListener('focus', show)
149
- getTarget()?.removeEventListener('blur', controller.current.close)
150
- }
151
- }
152
-
153
- if (triggerOn === 'click') {
154
- getTarget()?.addEventListener('click', show)
155
- return () => {
156
- controller.current.close()
157
- getTarget()?.removeEventListener('click', show)
158
- if (hideOnClickOutside) document.removeEventListener('click', hideOnClickOutside)
159
- }
160
- }
161
- }, [wrapper.current, triggerOn])
162
-
163
- return <div ref={wrapper} {...props}>{children}</div>
164
- }
1
+ import { useEffect, useRef } from 'react'
2
+ import { showOverlay } from '../../overlay'
3
+ import { HTMLTag } from '../../types'
4
+ import { focusFirstChild } from '../../utils/acessibility'
5
+ import { OverlayProvider } from './context'
6
+ import { OverlayController, OverlayProps } from './types'
7
+ export { useOverlayController } from './context'
8
+
9
+ /**
10
+ * An arbitrary time to wait for the next React render to be performed
11
+ */
12
+ const arbitraryRenderTime = 20
13
+
14
+ /**
15
+ * These todos are in order of priority.
16
+ *
17
+ * TODO: update position when the size changes. Currently, the top position seems out of place whenever the height changes. The same is
18
+ * probably true for the left position if the width changes.
19
+ * TODO: hoverDelayMS
20
+ * TODO: reposition the overlay when it's under a scrollable element other then the body and this element is scrolled.
21
+ * TODO: close the overlay when it's under a scrollable element other then the body and the element that triggered the tooltip becomes
22
+ * hidden by the scroll.
23
+ * TODO: use React Portal to implement overlays. The current implementation will lose every React context in the tree.
24
+ */
25
+
26
+ /**
27
+ * Creates an overlay for the child component. The overlay can be any React element. The overlay can be triggered by "click" or "hover"
28
+ * (default).
29
+ *
30
+ * The overlay can be hidden from within its content through the hook `useOverlayController()`.
31
+ *
32
+ * @example
33
+ *
34
+ * ```
35
+ * const overlay = <Card>Hey, this is my overlay!</Card>
36
+ *
37
+ * return (
38
+ * <Overlay content={overlay} attributes={{ style: { margin: '20px' } }}>
39
+ * <Button>Hover to see the overlay</Button>
40
+ * </Overlay>
41
+ * )
42
+ * ```
43
+ */
44
+ export function Overlay<T extends keyof HTMLTag>({
45
+ tag,
46
+ children,
47
+ content,
48
+ position = 'top',
49
+ triggerOn = 'hover',
50
+ alignment = 'center',
51
+ attributes,
52
+ onRenderChild,
53
+ autoFocusBehavior = 'keyboard',
54
+ ...props
55
+ }: OverlayProps<T>,
56
+ ) {
57
+ const controller = useRef<OverlayController>({ close: () => Promise.resolve() })
58
+ const wrapper = useRef<HTMLDivElement | null>(null)
59
+ // props that don't require removing and reattaching the event listeners
60
+ const dynamic = useRef({ tag, content, position, alignment, attributes })
61
+
62
+ useEffect(() => {
63
+ dynamic.current = { tag, content, position, alignment, attributes }
64
+ }, [tag, content, position, alignment, attributes])
65
+
66
+ useEffect(() => {
67
+ let visible = false
68
+ let hideOnClickOutside: ((event: Event) => void) | undefined
69
+ let hideOnEsc: ((event: Event) => void) | undefined
70
+ let hideOverlay: (() => Promise<void>) | undefined
71
+ let removeRefocusTargetListener: (() => void) | undefined
72
+
73
+ function getTarget() {
74
+ const target = wrapper.current?.firstChild
75
+ return target instanceof HTMLElement ? target : undefined
76
+ }
77
+
78
+ if (onRenderChild) {
79
+ const target = getTarget()
80
+ if (target) onRenderChild(target)
81
+ }
82
+
83
+ async function show(event: Event) {
84
+ if (visible) return
85
+ visible = true
86
+ const target = getTarget()
87
+ if (!target) return
88
+ const { overlay, hide: hideFn } = showOverlay({
89
+ tag: dynamic.current.tag,
90
+ content: ['string', 'number', 'boolean'].includes(typeof dynamic.current.content)
91
+ ? dynamic.current.content
92
+ : <OverlayProvider value={controller.current}>{dynamic.current.content}</OverlayProvider>,
93
+ target,
94
+ position: dynamic.current.position,
95
+ alignment: dynamic.current.alignment,
96
+ attributes: dynamic.current.attributes,
97
+ })
98
+ hideOverlay = hideFn
99
+
100
+ function onHide(condition: (event: Event) => boolean) {
101
+ return (event: Event) => {
102
+ if (condition(event)) controller.current.close()
103
+ }
104
+ }
105
+
106
+ if (event.type === 'click') {
107
+ hideOnEsc = onHide(e => e instanceof KeyboardEvent && e.key === 'Escape')
108
+ setTimeout(() => {
109
+ hideOnClickOutside = onHide(e => e instanceof MouseEvent && e.button === 0 && !overlay.contains(e.target as HTMLElement))
110
+ document.addEventListener('click', hideOnClickOutside)
111
+ }, arbitraryRenderTime)
112
+ document.addEventListener('keydown', hideOnEsc)
113
+ }
114
+
115
+ //focus target when the last overlay element loses focus
116
+ function refocusTarget(e: KeyboardEvent) {
117
+ if (e.key === 'Tab' && e.target instanceof HTMLElement) {
118
+ const allItems = Array.from(e.target.closest('[data-citric="menu"]')?.querySelectorAll('a, button') ?? [])
119
+ if (e.target === allItems[allItems.length - 1]) {
120
+ getTarget()?.focus()
121
+ e.preventDefault()
122
+ }
123
+ }
124
+ }
125
+ overlay.addEventListener('keydown', refocusTarget)
126
+ removeRefocusTargetListener = () => overlay.removeEventListener('keydown', refocusTarget)
127
+
128
+ // auto-focus
129
+ const openedWithMouse = event instanceof MouseEvent && event.detail > 0
130
+ if (autoFocusBehavior === 'always' || (autoFocusBehavior === 'keyboard' && !openedWithMouse)) {
131
+ setTimeout(() => focusFirstChild(overlay), arbitraryRenderTime)
132
+ }
133
+ }
134
+
135
+ controller.current.close = async () => {
136
+ visible = false
137
+ if (hideOnClickOutside) document.removeEventListener('click', hideOnClickOutside)
138
+ if (hideOnEsc) document.removeEventListener('keydown', hideOnEsc)
139
+ removeRefocusTargetListener?.()
140
+ await hideOverlay?.()
141
+ }
142
+
143
+ if (triggerOn === 'hover') {
144
+ getTarget()?.addEventListener('mouseenter', show)
145
+ getTarget()?.addEventListener('mouseleave', controller.current.close)
146
+ getTarget()?.addEventListener('focus', show)
147
+ getTarget()?.addEventListener('blur', controller.current.close)
148
+ return () => {
149
+ getTarget()?.removeEventListener('mouseenter', show)
150
+ getTarget()?.removeEventListener('mouseleave', controller.current.close)
151
+ getTarget()?.removeEventListener('focus', show)
152
+ getTarget()?.removeEventListener('blur', controller.current.close)
153
+ }
154
+ }
155
+
156
+ if (triggerOn === 'click') {
157
+ getTarget()?.addEventListener('click', show)
158
+ return () => {
159
+ controller.current.close()
160
+ getTarget()?.removeEventListener('click', show)
161
+ if (hideOnClickOutside) document.removeEventListener('click', hideOnClickOutside)
162
+ }
163
+ }
164
+ }, [wrapper.current, triggerOn])
165
+
166
+ return <div ref={wrapper} {...props}>{children}</div>
167
+ }
@@ -1,70 +1,70 @@
1
- import { OverlayOptions } from '../../overlay'
2
- import { HTMLTag } from '../../types'
3
-
4
- export type TriggerOn = 'hover' | 'click'
5
-
6
- export interface BaseOverlayProps<T extends keyof HTMLTag> extends Omit<OverlayOptions<T>, 'target'> {
7
- /**
8
- * When should the overlay element be created? When the child is clicked or when the child is hovered?
9
- *
10
- * Accessibility:
11
- * Click = focus + press enter to open; focus + enter to close OR esc.
12
- * Hover = focus to open; blur to close.
13
- *
14
- * @default 'hover'
15
- */
16
- triggerOn?: TriggerOn,
17
- /**
18
- * TODO: not implemented yet.
19
- *
20
- * Only valid if `triggerOn` is "hover".
21
- *
22
- * If the overlay is hidden right after the mouse leaves the element, then it becomes impossible to interact with anything inside the
23
- * tooltip. This sets a delay for the overlay to disappear, giving it time for the user to hover the overlay or gocus one of its children,
24
- * which will prevent it from closing.
25
- *
26
- * When `hoverDelayMS` is greater then zero, the hover effect is also applied to the overlay itself instead of just the child element.
27
- *
28
- * When set to "auto", a hover delay of 1 second will be used if the overlay contains any focusable element.
29
- *
30
- * @default 'auto'
31
- */
32
- hoverDelayMS?: number | 'auto',
33
- /**
34
- * TODO: not implemented yet.
35
- *
36
- * - Never: the focus won't changes when the overlay opens.
37
- * - All: the focus always changes when the overlay opens (given there's a focusable element in the overlay).
38
- * - Keyboard (default): the focus only changes when the overlay is opened via the keyboard.
39
- *
40
- * The first focusable element in the overlay will be focused as soon as it's rendered. When it's closed, the child element
41
- * (`children`) regains focus.
42
- *
43
- * The focus control will be such that, after the last element in the overlay is focused, the next focus will move to the child element
44
- * (`children`).
45
- *
46
- * If the overlay has no focusable element, this properties makes no difference.
47
- *
48
- * Attention: focusable elements inside the overlay can be ignored by setting `auto-focus` to false.
49
- *
50
- * @default 'keyboard'
51
- */
52
- autoFocusBehavior?: 'never' | 'always' | 'keyboard',
53
- /**
54
- * The element to receive the overlay.
55
- */
56
- children: React.ReactElement,
57
- /**
58
- * Function to run when the child is rendered. It receives the child element as a parameter.
59
- *
60
- * This is useful for easily adding attributes to the element (mainly accessibility ones).
61
- * @param element the child element, the one that receives the overlay.
62
- */
63
- onRenderChild?: (element: HTMLElement) => void,
64
- }
65
-
66
- export type OverlayProps<T extends keyof HTMLTag> = Omit<React.JSX.IntrinsicElements['div'], 'content'> & BaseOverlayProps<T>
67
-
68
- export interface OverlayController {
69
- close: () => Promise<void>,
70
- }
1
+ import { OverlayOptions } from '../../overlay'
2
+ import { HTMLTag } from '../../types'
3
+
4
+ export type TriggerOn = 'hover' | 'click'
5
+
6
+ export interface BaseOverlayProps<T extends keyof HTMLTag> extends Omit<OverlayOptions<T>, 'target'> {
7
+ /**
8
+ * When should the overlay element be created? When the child is clicked or when the child is hovered?
9
+ *
10
+ * Accessibility:
11
+ * Click = focus + press enter to open; focus + enter to close OR esc.
12
+ * Hover = focus to open; blur to close.
13
+ *
14
+ * @default 'hover'
15
+ */
16
+ triggerOn?: TriggerOn,
17
+ /**
18
+ * TODO: not implemented yet.
19
+ *
20
+ * Only valid if `triggerOn` is "hover".
21
+ *
22
+ * If the overlay is hidden right after the mouse leaves the element, then it becomes impossible to interact with anything inside the
23
+ * tooltip. This sets a delay for the overlay to disappear, giving it time for the user to hover the overlay or gocus one of its children,
24
+ * which will prevent it from closing.
25
+ *
26
+ * When `hoverDelayMS` is greater then zero, the hover effect is also applied to the overlay itself instead of just the child element.
27
+ *
28
+ * When set to "auto", a hover delay of 1 second will be used if the overlay contains any focusable element.
29
+ *
30
+ * @default 'auto'
31
+ */
32
+ hoverDelayMS?: number | 'auto',
33
+ /**
34
+ * TODO: not implemented yet.
35
+ *
36
+ * - Never: the focus won't changes when the overlay opens.
37
+ * - All: the focus always changes when the overlay opens (given there's a focusable element in the overlay).
38
+ * - Keyboard (default): the focus only changes when the overlay is opened via the keyboard.
39
+ *
40
+ * The first focusable element in the overlay will be focused as soon as it's rendered. When it's closed, the child element
41
+ * (`children`) regains focus.
42
+ *
43
+ * The focus control will be such that, after the last element in the overlay is focused, the next focus will move to the child element
44
+ * (`children`).
45
+ *
46
+ * If the overlay has no focusable element, this properties makes no difference.
47
+ *
48
+ * Attention: focusable elements inside the overlay can be ignored by setting `auto-focus` to false.
49
+ *
50
+ * @default 'keyboard'
51
+ */
52
+ autoFocusBehavior?: 'never' | 'always' | 'keyboard',
53
+ /**
54
+ * The element to receive the overlay.
55
+ */
56
+ children: React.ReactElement,
57
+ /**
58
+ * Function to run when the child is rendered. It receives the child element as a parameter.
59
+ *
60
+ * This is useful for easily adding attributes to the element (mainly accessibility ones).
61
+ * @param element the child element, the one that receives the overlay.
62
+ */
63
+ onRenderChild?: (element: HTMLElement) => void,
64
+ }
65
+
66
+ export type OverlayProps<T extends keyof HTMLTag> = Omit<React.JSX.IntrinsicElements['div'], 'content'> & BaseOverlayProps<T>
67
+
68
+ export interface OverlayController {
69
+ close: () => Promise<void>,
70
+ }