@musecat/uikit 0.1.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 (180) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +51 -0
  3. package/index.ts +78 -0
  4. package/package.json +103 -0
  5. package/packages/Components/Box/Box.tsx +173 -0
  6. package/packages/Components/Box/Box.types.ts +48 -0
  7. package/packages/Components/Button/Button.tsx +275 -0
  8. package/packages/Components/Button/Button.types.ts +44 -0
  9. package/packages/Components/Card/Card.default.tsx +180 -0
  10. package/packages/Components/Card/Card.foldable.tsx +383 -0
  11. package/packages/Components/Card/Card.module.scss +23 -0
  12. package/packages/Components/Card/Card.tsx +8 -0
  13. package/packages/Components/Card/Card.types.ts +91 -0
  14. package/packages/Components/Card/Card.utils.ts +66 -0
  15. package/packages/Components/Checkbox/Checkbox.module.scss +11 -0
  16. package/packages/Components/Checkbox/Checkbox.tsx +104 -0
  17. package/packages/Components/Checkbox/Checkbox.types.ts +24 -0
  18. package/packages/Components/CodeBox/CodeBox.copy.tsx +43 -0
  19. package/packages/Components/CodeBox/CodeBox.module.scss +72 -0
  20. package/packages/Components/CodeBox/CodeBox.tsx +91 -0
  21. package/packages/Components/CodeBox/CodeBox.types.ts +17 -0
  22. package/packages/Components/ContextMenu/ContextMenu.module.scss +8 -0
  23. package/packages/Components/ContextMenu/ContextMenu.options.tsx +126 -0
  24. package/packages/Components/ContextMenu/ContextMenu.tsx +381 -0
  25. package/packages/Components/ContextMenu/ContextMenu.types.ts +46 -0
  26. package/packages/Components/ContributionGraph/ContributionGraph.module.scss +42 -0
  27. package/packages/Components/ContributionGraph/ContributionGraph.tsx +454 -0
  28. package/packages/Components/ContributionGraph/ContributionGraph.types.ts +27 -0
  29. package/packages/Components/DatePicker/DatePicker.calendar.tsx +161 -0
  30. package/packages/Components/DatePicker/DatePicker.core.tsx +582 -0
  31. package/packages/Components/DatePicker/DatePicker.module.scss +26 -0
  32. package/packages/Components/DatePicker/DatePicker.tsx +786 -0
  33. package/packages/Components/DatePicker/DatePicker.types.ts +36 -0
  34. package/packages/Components/DatePicker/DatePicker.utils.ts +80 -0
  35. package/packages/Components/DatePicker/hooks/useCalendar.ts +61 -0
  36. package/packages/Components/DatePicker/hooks/useSelection.ts +208 -0
  37. package/packages/Components/Divider/Divider.tsx +46 -0
  38. package/packages/Components/Divider/Divider.types.ts +12 -0
  39. package/packages/Components/Header/Header.module.scss +74 -0
  40. package/packages/Components/Header/Header.tsx +47 -0
  41. package/packages/Components/Header/Header.types.ts +8 -0
  42. package/packages/Components/Icon/Icon.group.tsx +122 -0
  43. package/packages/Components/Icon/Icon.group.types.ts +20 -0
  44. package/packages/Components/Icon/Icon.tsx +341 -0
  45. package/packages/Components/Icon/Icon.types.ts +59 -0
  46. package/packages/Components/Icon/SVG/data.tsx +232 -0
  47. package/packages/Components/Input/Input.module.scss +5 -0
  48. package/packages/Components/Input/Input.tsx +87 -0
  49. package/packages/Components/Input/Input.types.ts +14 -0
  50. package/packages/Components/Label/Label.module.scss +19 -0
  51. package/packages/Components/Label/Label.tsx +115 -0
  52. package/packages/Components/Label/Label.types.ts +28 -0
  53. package/packages/Components/Layout/Layout.docs.module.scss +42 -0
  54. package/packages/Components/Layout/Layout.docs.tsx +150 -0
  55. package/packages/Components/Layout/Layout.docs.types.ts +18 -0
  56. package/packages/Components/Layout/Layout.module.scss +91 -0
  57. package/packages/Components/Layout/Layout.tsx +306 -0
  58. package/packages/Components/Layout/Layout.types.ts +71 -0
  59. package/packages/Components/Maps/OSM/MapOSM.module.scss +11 -0
  60. package/packages/Components/Maps/OSM/MapOSM.shared.ts +121 -0
  61. package/packages/Components/Maps/OSM/MapOSM.tsx +279 -0
  62. package/packages/Components/Maps/OSM/MapOSM.types.ts +18 -0
  63. package/packages/Components/Nav/Nav.module.scss +137 -0
  64. package/packages/Components/Nav/Nav.tsx +304 -0
  65. package/packages/Components/Nav/Nav.types.ts +32 -0
  66. package/packages/Components/Nav/hooks/useNavDrag.ts +374 -0
  67. package/packages/Components/Nav/hooks/useNavIndicator.ts +137 -0
  68. package/packages/Components/Pagination/Pagination.tsx +254 -0
  69. package/packages/Components/Pagination/Pagination.types.ts +18 -0
  70. package/packages/Components/Pill/Pill.tsx +127 -0
  71. package/packages/Components/Pill/Pill.types.ts +33 -0
  72. package/packages/Components/Profile/Profile.shared.ts +74 -0
  73. package/packages/Components/Profile/Profile.tsx +382 -0
  74. package/packages/Components/Profile/Profile.types.ts +55 -0
  75. package/packages/Components/Progress/Progress.module.scss +15 -0
  76. package/packages/Components/Progress/Progress.tsx +88 -0
  77. package/packages/Components/Progress/Progress.types.ts +22 -0
  78. package/packages/Components/Radio/Radio.module.scss +11 -0
  79. package/packages/Components/Radio/Radio.tsx +121 -0
  80. package/packages/Components/Radio/Radio.types.ts +20 -0
  81. package/packages/Components/Select/Select.keyboard.tsx +76 -0
  82. package/packages/Components/Select/Select.trigger.tsx +88 -0
  83. package/packages/Components/Select/Select.tsx +11 -0
  84. package/packages/Components/Select/Select.types.ts +38 -0
  85. package/packages/Components/Select/Select.utils.ts +84 -0
  86. package/packages/Components/Select/hooks/useSelectNavigation.ts +461 -0
  87. package/packages/Components/Select/hooks/useSelectSelection.ts +142 -0
  88. package/packages/Components/Select/hooks/useSelectState.ts +314 -0
  89. package/packages/Components/Select/select.control.tsx +228 -0
  90. package/packages/Components/Select/select.inner.tsx +312 -0
  91. package/packages/Components/Skeleton/Skeleton.tsx +30 -0
  92. package/packages/Components/Skeleton/Skeleton.types.ts +12 -0
  93. package/packages/Components/Spinner/Spinner.module.scss +78 -0
  94. package/packages/Components/Spinner/Spinner.tsx +125 -0
  95. package/packages/Components/Spinner/Spinner.types.ts +19 -0
  96. package/packages/Components/Text/Text.module.scss +7 -0
  97. package/packages/Components/Text/Text.tsx +49 -0
  98. package/packages/Components/Text/Text.types.ts +33 -0
  99. package/packages/Components/TimePicker/TimePicker.core.tsx +448 -0
  100. package/packages/Components/TimePicker/TimePicker.module.scss +30 -0
  101. package/packages/Components/TimePicker/TimePicker.tsx +511 -0
  102. package/packages/Components/TimePicker/TimePicker.types.ts +22 -0
  103. package/packages/Components/Timeline/Timeline.tsx +111 -0
  104. package/packages/Components/Timeline/Timeline.types.ts +23 -0
  105. package/packages/Components/Title/Title.tsx +305 -0
  106. package/packages/Components/Title/Title.types.ts +64 -0
  107. package/packages/Components/Toggle/Toggle.module.scss +32 -0
  108. package/packages/Components/Toggle/Toggle.tsx +272 -0
  109. package/packages/Components/Toggle/Toggle.types.ts +17 -0
  110. package/packages/Components/Tooltip/Tooltip.module.scss +44 -0
  111. package/packages/Components/Tooltip/Tooltip.tsx +340 -0
  112. package/packages/Components/Tooltip/Tooltip.types.ts +38 -0
  113. package/packages/Frameworks/Dialog/Dialog.background.tsx +88 -0
  114. package/packages/Frameworks/Dialog/Dialog.boot.tsx +32 -0
  115. package/packages/Frameworks/Dialog/Dialog.store.ts +199 -0
  116. package/packages/Frameworks/Dialog/Dialog.tsx +185 -0
  117. package/packages/Frameworks/Dialog/Dialog.types.ts +264 -0
  118. package/packages/Frameworks/Dialog/Dialog.utils.ts +22 -0
  119. package/packages/Frameworks/Dialog/contents/Dialog.footer.tsx +79 -0
  120. package/packages/Frameworks/Dialog/contents/Dialog.funnel.tsx +260 -0
  121. package/packages/Frameworks/Dialog/contents/Dialog.header.tsx +137 -0
  122. package/packages/Frameworks/Dialog/hooks/useDialogPosition.ts +298 -0
  123. package/packages/Frameworks/Dialog/hooks/useSheetDrag.ts +325 -0
  124. package/packages/Frameworks/Dialog/hooks/useSheetGeometry.ts +201 -0
  125. package/packages/Frameworks/Dialog/hooks/useSheetProgressive.ts +98 -0
  126. package/packages/Frameworks/Dialog/renderers/renderModal.tsx +228 -0
  127. package/packages/Frameworks/Dialog/renderers/renderPopover.tsx +220 -0
  128. package/packages/Frameworks/Dialog/renderers/renderSheet.tsx +571 -0
  129. package/packages/Frameworks/EdgeEffect/EdgeEffect.tsx +52 -0
  130. package/packages/Frameworks/EdgeEffect/EdgeEffect.types.ts +5 -0
  131. package/packages/Frameworks/Motion/Motion.presets.ts +49 -0
  132. package/packages/Frameworks/Pressable/Pressable.module.scss +19 -0
  133. package/packages/Frameworks/Pressable/Pressable.tsx +651 -0
  134. package/packages/Frameworks/Pressable/Pressable.types.ts +73 -0
  135. package/packages/Frameworks/Squircle/Squircle.tsx +263 -0
  136. package/packages/Frameworks/Squircle/Squircle.types.ts +15 -0
  137. package/packages/Frameworks/Theme/Radius.types.ts +55 -0
  138. package/packages/Frameworks/Theme/Theme.types.ts +325 -0
  139. package/packages/Frameworks/Toaster/Toaster.boot.tsx +47 -0
  140. package/packages/Frameworks/Toaster/Toaster.module.scss +168 -0
  141. package/packages/Frameworks/Toaster/Toaster.types.ts +13 -0
  142. package/packages/Frameworks/View/DNDView/DNDView.module.scss +8 -0
  143. package/packages/Frameworks/View/DNDView/DNDView.tsx +470 -0
  144. package/packages/Frameworks/View/DNDView/DNDView.types.ts +61 -0
  145. package/packages/Frameworks/View/HScrollView/HScrollView.module.scss +59 -0
  146. package/packages/Frameworks/View/HScrollView/HScrollView.tsx +386 -0
  147. package/packages/Frameworks/View/HScrollView/HScrollView.types.ts +46 -0
  148. package/packages/Frameworks/View/ImageView/Dialog/ImageDialog.counter.tsx +27 -0
  149. package/packages/Frameworks/View/ImageView/Dialog/ImageDialog.footer.tsx +76 -0
  150. package/packages/Frameworks/View/ImageView/Dialog/ImageDialog.header.tsx +49 -0
  151. package/packages/Frameworks/View/ImageView/Dialog/ImageDialog.list.tsx +74 -0
  152. package/packages/Frameworks/View/ImageView/Dialog/ImageDialog.slide.tsx +71 -0
  153. package/packages/Frameworks/View/ImageView/Dialog/ImageDialog.tsx +175 -0
  154. package/packages/Frameworks/View/ImageView/Image.controls.tsx +39 -0
  155. package/packages/Frameworks/View/ImageView/Image.hooks.ts +82 -0
  156. package/packages/Frameworks/View/ImageView/Image.module.scss +7 -0
  157. package/packages/Frameworks/View/ImageView/Image.tsx +375 -0
  158. package/packages/Frameworks/View/ImageView/Image.types.ts +71 -0
  159. package/packages/Frameworks/View/ImageView/Image.utils.ts +79 -0
  160. package/packages/Frameworks/View/View.module.scss +34 -0
  161. package/packages/Frameworks/View/View.tsx +200 -0
  162. package/packages/Frameworks/View/View.types.ts +36 -0
  163. package/packages/Frameworks/_shared/Padding.types.ts +52 -0
  164. package/packages/Frameworks/_shared/StopParentInteraction.tsx +45 -0
  165. package/packages/Frameworks/_shared/Wind.types.ts +17 -0
  166. package/packages/Frameworks/_shared/bodyScrollLock.ts +127 -0
  167. package/packages/Frameworks/_shared/layer.constants.ts +8 -0
  168. package/packages/Frameworks/_shared/normalize.ts +39 -0
  169. package/packages/Frameworks/_shared/sizing.ts +55 -0
  170. package/packages/Frameworks/_shared/useControllableState.ts +29 -0
  171. package/packages/Styles/_animation.scss +42 -0
  172. package/packages/Styles/_color.scss +131 -0
  173. package/packages/Styles/_font.scss +30 -0
  174. package/packages/Styles/_icon.scss +782 -0
  175. package/packages/Styles/_importer.scss +9 -0
  176. package/packages/Styles/_system.scss +69 -0
  177. package/packages/Styles/_textstyle.scss +111 -0
  178. package/packages/Styles/_theme.scss +452 -0
  179. package/packages/Styles/_viewport-global.scss +99 -0
  180. package/packages/Styles/_viewport.scss +108 -0
@@ -0,0 +1,651 @@
1
+ "use client";
2
+ import clsx from "clsx";
3
+ import { motion } from "motion/react";
4
+ import Link from "next/link";
5
+ import {
6
+ type CSSProperties,
7
+ createContext,
8
+ forwardRef,
9
+ type KeyboardEvent,
10
+ type MutableRefObject,
11
+ type Ref,
12
+ useContext,
13
+ useEffect,
14
+ useId,
15
+ useRef,
16
+ useState,
17
+ } from "react";
18
+ import { resolvePadding } from "@/packages/Frameworks/_shared/Padding.types";
19
+ import { Size } from "@/packages/Frameworks/_shared/sizing";
20
+ import Dialog from "@/packages/Frameworks/Dialog/Dialog";
21
+ import styles from "@/packages/Frameworks/Pressable/Pressable.module.scss";
22
+ import type { PressableProps } from "@/packages/Frameworks/Pressable/Pressable.types";
23
+ import Squircle from "@/packages/Frameworks/Squircle/Squircle";
24
+ import { Radius } from "@/packages/Frameworks/Theme/Radius.types";
25
+ import {
26
+ BackgroundBlur,
27
+ Border,
28
+ resolveThemeClasses,
29
+ resolveThemeHasBorder,
30
+ Shadow,
31
+ } from "@/packages/Frameworks/Theme/Theme.types";
32
+ import View from "@/packages/Frameworks/View/View";
33
+
34
+ export const ButtonNestingContext = createContext(false);
35
+ export const PopoverContext = createContext<{
36
+ close: () => void;
37
+ } | null>(null);
38
+ const isButtonType = (type?: string) =>
39
+ type === "button" || type === "submit" || type === "reset";
40
+ const hasExternalScheme = (href: string) =>
41
+ /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href);
42
+ const MotionLink = motion.create(Link);
43
+
44
+ const setRefValue = (
45
+ ref: Ref<HTMLElement> | undefined,
46
+ value: HTMLElement | null,
47
+ ) => {
48
+ if (typeof ref === "function") {
49
+ ref(value);
50
+ return;
51
+ }
52
+
53
+ if (ref) {
54
+ (ref as MutableRefObject<HTMLElement | null>).current = value;
55
+ }
56
+ };
57
+ const getFormProps = (form: PressableProps["form"]) => {
58
+ if (!form || form === true) return undefined;
59
+ return form;
60
+ };
61
+ const Pressable = forwardRef<HTMLElement, PressableProps>((props, ref) => {
62
+ const {
63
+ href,
64
+ onClick,
65
+ target,
66
+ rel,
67
+ download,
68
+ children,
69
+ className,
70
+ themePreset,
71
+ background,
72
+ color,
73
+ themeInteractive,
74
+ selected,
75
+ border,
76
+ radius,
77
+ backgroundBlur,
78
+ shadow,
79
+ width,
80
+ height,
81
+ margin,
82
+ gap,
83
+ alignItems,
84
+ justifyContent,
85
+ alignSelf,
86
+ column,
87
+ row,
88
+ fullWidth,
89
+ opacity,
90
+ padding,
91
+ paddingHorizontal,
92
+ paddingVertical,
93
+ style,
94
+ title,
95
+ "aria-label": ariaLabel,
96
+ "aria-labelledby": ariaLabelledBy,
97
+ "aria-describedby": ariaDescribedBy,
98
+ "aria-controls": ariaControls,
99
+ "aria-expanded": ariaExpanded,
100
+ "aria-haspopup": ariaHasPopup,
101
+ type,
102
+ disabled,
103
+ onChange,
104
+ checked,
105
+ value,
106
+ name,
107
+ form,
108
+ readOnly,
109
+ onMouseEnter,
110
+ onMouseLeave,
111
+ onMouseDown,
112
+ onMouseUp,
113
+ onPointerDown,
114
+ onPointerUp,
115
+ onPointerCancel,
116
+ onPointerLeave,
117
+ onTouchStart,
118
+ onTouchEnd,
119
+ onTouchCancel,
120
+ onContextMenu,
121
+ onKeyDown,
122
+ onKeyUp,
123
+ tabIndex,
124
+ motion: motionProps,
125
+ popover,
126
+ "data-color-mode": dataColorMode,
127
+ noSquircle,
128
+ ...restProps
129
+ } = props;
130
+ const insideButton = useContext(ButtonNestingContext);
131
+ const isControlType = type === "checkbox" || type === "radio";
132
+ const shouldRenderButton = !!(popover || onClick || isButtonType(type));
133
+ const isInteractive = Boolean(href || shouldRenderButton || isControlType);
134
+ const resolvedFormProps = getFormProps(form);
135
+ const resolvedTitle = title ?? ariaLabel;
136
+ const resolvedAriaDescribedBy = ariaDescribedBy;
137
+ const resolvedAriaLabel = ariaLabel;
138
+ const nativeTitle = resolvedTitle;
139
+ const popoverRootRef = useRef<HTMLDivElement>(null);
140
+ const popoverAnchorRef = useRef<HTMLDivElement>(null);
141
+ const popoverOwnerId = useId();
142
+ const [internalPopoverOpen, setInternalPopoverOpen] = useState(
143
+ popover?.defaultOpen ?? false,
144
+ );
145
+ const isPopoverControlled = popover?.open !== undefined;
146
+ const popoverOpen = isPopoverControlled
147
+ ? !!popover?.open
148
+ : internalPopoverOpen;
149
+
150
+ const themeClasses = resolveThemeClasses({
151
+ themePreset,
152
+ background,
153
+ color,
154
+ shadow,
155
+ themeInteractive,
156
+ selected: selected || popoverOpen,
157
+ disabled,
158
+ readOnly,
159
+ isInteractive,
160
+ });
161
+
162
+ const hasRadius = Boolean(radius && radius !== "None");
163
+ const hasBorder = resolveThemeHasBorder({ border, themePreset });
164
+ const _hasShadow = Boolean(shadow && shadow !== "None");
165
+ const isSquircle = hasRadius && !hasBorder && !noSquircle;
166
+ const commonClassName = clsx(
167
+ styles.Pressable,
168
+ ...themeClasses,
169
+ Border(border),
170
+ Shadow(shadow),
171
+ BackgroundBlur(backgroundBlur),
172
+ className,
173
+ );
174
+ const layoutStyle: CSSProperties = {
175
+ display: "flex",
176
+ width: fullWidth ? "100%" : Size(width),
177
+ height: Size(height),
178
+ margin: Size(margin),
179
+ gap: Size(gap),
180
+ alignItems,
181
+ justifyContent,
182
+ alignSelf,
183
+ flexDirection: column ? "column" : row ? "row" : undefined,
184
+ opacity,
185
+ padding: resolvePadding(padding, paddingHorizontal, paddingVertical),
186
+ };
187
+
188
+ const defaultGap = 24;
189
+ const resolvedGap = Size(gap ?? defaultGap);
190
+
191
+ const commonStyle = {
192
+ borderRadius: Radius(radius),
193
+ ...layoutStyle,
194
+ gap: resolvedGap,
195
+ ...style,
196
+ };
197
+ useEffect(() => {
198
+ if (popover?.defaultOpen === undefined) return;
199
+ if (!isPopoverControlled) setInternalPopoverOpen(popover.defaultOpen);
200
+ }, [isPopoverControlled, popover?.defaultOpen]);
201
+
202
+ useEffect(() => {
203
+ const shouldHandleOutsideClick = popover;
204
+ if (!shouldHandleOutsideClick) return;
205
+ if (popover?.closeOnOutsideClick === false) return;
206
+ const onOutside = (e: PointerEvent) => {
207
+ const target = e.target as Node;
208
+ const element = e.target as Element | null;
209
+ const currentPopoverEl = document.querySelector(
210
+ `[data-popover-owner="${popoverOwnerId}"]`,
211
+ );
212
+ const clickedInsideModalPortal = !!element?.closest(
213
+ "[data-modal-portal]",
214
+ );
215
+ const clickedInsideHost = !!popoverRootRef.current?.contains(target);
216
+ const clickedInsideOwnedPopover = !!element?.closest(
217
+ `[data-popover-owner="${popoverOwnerId}"]`,
218
+ );
219
+ const clickedPopoverOwner = element
220
+ ?.closest("[data-popover-owner]")
221
+ ?.getAttribute("data-popover-owner");
222
+ const nestedPopoverTrigger = clickedPopoverOwner
223
+ ? document.querySelector(
224
+ `[data-popover-trigger-owner="${clickedPopoverOwner}"]`,
225
+ )
226
+ : null;
227
+ const clickedInsideNestedOwnedPopover =
228
+ !!nestedPopoverTrigger &&
229
+ (!!popoverRootRef.current?.contains(nestedPopoverTrigger) ||
230
+ !!currentPopoverEl?.contains(nestedPopoverTrigger));
231
+ if (
232
+ clickedInsideModalPortal ||
233
+ clickedInsideHost ||
234
+ clickedInsideOwnedPopover ||
235
+ clickedInsideNestedOwnedPopover
236
+ ) {
237
+ return;
238
+ }
239
+ if (popover) {
240
+ if (!isPopoverControlled) setInternalPopoverOpen(false);
241
+ popover.onOpenChange?.(false);
242
+ return;
243
+ }
244
+ };
245
+ document.addEventListener("pointerdown", onOutside);
246
+ return () => document.removeEventListener("pointerdown", onOutside);
247
+ }, [isPopoverControlled, popover, popoverOwnerId]);
248
+ const setPopoverOpen = (nextOpen: boolean) => {
249
+ if (!popover) return;
250
+ if (!isPopoverControlled) setInternalPopoverOpen(nextOpen);
251
+ popover.onOpenChange?.(nextOpen);
252
+ };
253
+ const handleMouseEnterInternal: React.MouseEventHandler = (event) => {
254
+ onMouseEnter?.(event);
255
+ };
256
+ const handleMouseLeaveInternal: React.MouseEventHandler = (event) => {
257
+ onMouseLeave?.(event);
258
+ };
259
+ const handleMouseDownInternal: React.MouseEventHandler = (event) => {
260
+ onMouseDown?.(event);
261
+ };
262
+ const handleMouseUpInternal: React.MouseEventHandler = (event) => {
263
+ onMouseUp?.(event);
264
+ };
265
+ const handlePointerDownInternal: React.PointerEventHandler = (event) => {
266
+ onPointerDown?.(event);
267
+ };
268
+ const handlePointerUpInternal: React.PointerEventHandler = (event) => {
269
+ onPointerUp?.(event);
270
+ };
271
+ const handlePointerCancelInternal: React.PointerEventHandler = (event) => {
272
+ onPointerCancel?.(event);
273
+ };
274
+ const handlePointerLeaveInternal: React.PointerEventHandler = (event) => {
275
+ onPointerLeave?.(event);
276
+ };
277
+ const handleTouchStartInternal: React.TouchEventHandler = (event) => {
278
+ onTouchStart?.(event);
279
+ };
280
+ const handleTouchEndInternal: React.TouchEventHandler = (event) => {
281
+ onTouchEnd?.(event);
282
+ };
283
+ const handleTouchCancelInternal: React.TouchEventHandler = (event) => {
284
+ onTouchCancel?.(event);
285
+ };
286
+ const handleContextMenuInternal: React.MouseEventHandler = (event) => {
287
+ onContextMenu?.(event);
288
+ };
289
+ const commonProps = {
290
+ "aria-label": resolvedAriaLabel,
291
+ "aria-labelledby": ariaLabelledBy,
292
+ "aria-describedby": resolvedAriaDescribedBy,
293
+ "aria-controls": popover ? ariaControls : undefined,
294
+ "aria-expanded": popover ? ariaExpanded : undefined,
295
+ "aria-haspopup": popover ? ariaHasPopup : undefined,
296
+ onMouseEnter: handleMouseEnterInternal,
297
+ onMouseLeave: handleMouseLeaveInternal,
298
+ onMouseDown: handleMouseDownInternal,
299
+ onMouseUp: handleMouseUpInternal,
300
+ onPointerDown: handlePointerDownInternal,
301
+ onPointerUp: handlePointerUpInternal,
302
+ onPointerCancel: handlePointerCancelInternal,
303
+ onPointerLeave: handlePointerLeaveInternal,
304
+ onTouchStart: handleTouchStartInternal,
305
+ onTouchEnd: handleTouchEndInternal,
306
+ onTouchCancel: handleTouchCancelInternal,
307
+ onContextMenu: handleContextMenuInternal,
308
+ onKeyUp,
309
+ };
310
+ const handleTriggerClick = (e: React.MouseEvent) => {
311
+ onClick?.(e);
312
+ if (e.defaultPrevented) return;
313
+ if (!popover || disabled) return;
314
+ const closeOnClickTrigger = popover.closeOnClickTrigger !== false;
315
+ if (popoverOpen && !closeOnClickTrigger) return;
316
+ setPopoverOpen(!popoverOpen);
317
+ };
318
+ const close = () => setPopoverOpen(false);
319
+ const setPopoverHostRef = (element: HTMLDivElement | null) => {
320
+ popoverRootRef.current = element;
321
+ setRefValue(ref, element);
322
+ };
323
+ const setContainerRef = (element: HTMLElement | null) => {
324
+ if (popover) return;
325
+ setRefValue(ref, element);
326
+ };
327
+ const withPopover = (trigger: React.ReactNode) => {
328
+ if (!popover) return trigger;
329
+ return (
330
+ <View
331
+ ref={setPopoverHostRef}
332
+ data-popover-trigger-owner={popoverOwnerId}
333
+ width="clamp(0px, 100%, 100%)"
334
+ style={{ position: "relative", overflow: "visible" }}
335
+ inline
336
+ >
337
+ <View ref={popoverAnchorRef} width="clamp(0px, 100%, 100%)" inline>
338
+ {trigger}
339
+ </View>
340
+ {popover && (
341
+ <Dialog
342
+ mode="popover"
343
+ open={popoverOpen}
344
+ onOpenChange={setPopoverOpen}
345
+ popover={{
346
+ anchorRef: popoverAnchorRef,
347
+ strategy: popover.strategy ?? "anchored",
348
+ ...(popover as any),
349
+ }}
350
+ >
351
+ <PopoverContext.Provider value={{ close }}>
352
+ {popover.content}
353
+ </PopoverContext.Provider>
354
+ </Dialog>
355
+ )}
356
+ </View>
357
+ );
358
+ };
359
+ const withForm = (trigger: React.ReactNode) => {
360
+ if (!form) return trigger;
361
+ return (
362
+ <form style={{ display: "contents" }} {...resolvedFormProps}>
363
+ {trigger}
364
+ </form>
365
+ );
366
+ };
367
+
368
+ if (href) {
369
+ const handleClick: React.MouseEventHandler = (e) => {
370
+ if (disabled) {
371
+ e.preventDefault();
372
+ e.stopPropagation();
373
+ return;
374
+ }
375
+ handleTriggerClick(e);
376
+ };
377
+
378
+ const shouldUseAnchor =
379
+ typeof href === "string" &&
380
+ (href.startsWith("//") ||
381
+ hasExternalScheme(href) ||
382
+ target === "_blank" ||
383
+ download !== undefined);
384
+ const nextHref = href;
385
+
386
+ if (disabled) {
387
+ const Element = (
388
+ isSquircle ? Squircle : motionProps ? motion.button : "button"
389
+ ) as any;
390
+ const extraProps = isSquircle
391
+ ? {
392
+ as: "button",
393
+ radius,
394
+ ...(motionProps ? { motion: motionProps } : {}),
395
+ }
396
+ : {};
397
+ return withPopover(
398
+ withForm(
399
+ <Element
400
+ ref={setContainerRef as any}
401
+ data-color-mode={dataColorMode}
402
+ className={commonClassName}
403
+ style={commonStyle}
404
+ title={nativeTitle}
405
+ type="button"
406
+ disabled
407
+ tabIndex={-1}
408
+ onKeyDown={onKeyDown}
409
+ {...(!isSquircle && motionProps ? motionProps : undefined)}
410
+ {...extraProps}
411
+ {...commonProps}
412
+ {...restProps}
413
+ >
414
+ {children}
415
+ </Element>,
416
+ ),
417
+ );
418
+ }
419
+ if (shouldUseAnchor) {
420
+ const Element = (
421
+ isSquircle ? Squircle : motionProps ? motion.a : "a"
422
+ ) as any;
423
+ const extraProps = isSquircle
424
+ ? { as: "a", radius, ...(motionProps ? { motion: motionProps } : {}) }
425
+ : {};
426
+ return withPopover(
427
+ withForm(
428
+ <Element
429
+ ref={setContainerRef as any}
430
+ data-color-mode={dataColorMode}
431
+ className={commonClassName}
432
+ style={commonStyle}
433
+ tabIndex={tabIndex}
434
+ href={href}
435
+ target={target}
436
+ rel={rel}
437
+ download={download}
438
+ title={nativeTitle}
439
+ onClick={handleClick}
440
+ onKeyDown={onKeyDown}
441
+ {...(!isSquircle && motionProps ? motionProps : undefined)}
442
+ {...extraProps}
443
+ {...commonProps}
444
+ {...restProps}
445
+ >
446
+ {children}
447
+ </Element>,
448
+ ),
449
+ );
450
+ }
451
+ const Element = (
452
+ isSquircle ? Squircle : motionProps ? MotionLink : Link
453
+ ) as any;
454
+ const extraProps = isSquircle
455
+ ? { as: Link, radius, ...(motionProps ? { motion: motionProps } : {}) }
456
+ : {};
457
+ return withPopover(
458
+ withForm(
459
+ <Element
460
+ ref={setContainerRef as any}
461
+ data-color-mode={dataColorMode}
462
+ className={commonClassName}
463
+ style={commonStyle}
464
+ tabIndex={tabIndex}
465
+ href={nextHref}
466
+ target={target}
467
+ rel={rel}
468
+ download={download}
469
+ title={nativeTitle}
470
+ onClick={handleClick}
471
+ onKeyDown={onKeyDown}
472
+ {...(!isSquircle && motionProps ? motionProps : undefined)}
473
+ {...extraProps}
474
+ {...commonProps}
475
+ {...restProps}
476
+ >
477
+ {children}
478
+ </Element>,
479
+ ),
480
+ );
481
+ }
482
+
483
+ if (isControlType) {
484
+ const resolvedControlPreset =
485
+ themePreset ?? (checked ? "BaseFull" : "UIPrimary");
486
+ const resolvedControlSelected = selected ?? checked;
487
+ const Element = (
488
+ isSquircle ? Squircle : motionProps ? motion.label : "label"
489
+ ) as any;
490
+ const extraProps = isSquircle
491
+ ? { as: "label", radius, ...(motionProps ? { motion: motionProps } : {}) }
492
+ : {};
493
+
494
+ return withPopover(
495
+ withForm(
496
+ <Element
497
+ ref={setContainerRef as any}
498
+ data-color-mode={dataColorMode}
499
+ className={clsx(
500
+ styles.Pressable,
501
+ ...resolveThemeClasses({
502
+ themePreset: resolvedControlPreset,
503
+ background,
504
+ color,
505
+ themeInteractive,
506
+ selected: resolvedControlSelected,
507
+ disabled,
508
+ readOnly,
509
+ isInteractive: true,
510
+ }),
511
+ Border(border),
512
+ className,
513
+ )}
514
+ style={{ position: "relative", cursor: "pointer", ...commonStyle }}
515
+ title={nativeTitle}
516
+ onKeyDown={onKeyDown}
517
+ {...(!isSquircle && motionProps ? motionProps : undefined)}
518
+ {...extraProps}
519
+ {...commonProps}
520
+ {...restProps}
521
+ >
522
+ <View>
523
+ <input
524
+ style={{
525
+ position: "absolute",
526
+ width: "1px",
527
+ height: "1px",
528
+ padding: 0,
529
+ margin: "-1px",
530
+ overflow: "hidden",
531
+ clip: "rect(0, 0, 0, 0)",
532
+ whiteSpace: "nowrap",
533
+ border: 0,
534
+ }}
535
+ type={type}
536
+ onChange={onChange}
537
+ checked={checked}
538
+ disabled={disabled}
539
+ value={value}
540
+ name={name}
541
+ aria-label={resolvedAriaLabel}
542
+ aria-labelledby={ariaLabelledBy}
543
+ aria-describedby={resolvedAriaDescribedBy}
544
+ />
545
+ {children}
546
+ </View>
547
+ </Element>,
548
+ ),
549
+ );
550
+ }
551
+
552
+ if (shouldRenderButton && insideButton) {
553
+ const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
554
+ onKeyDown?.(e);
555
+ if (disabled) return;
556
+ if (e.key === "Enter" || e.key === " ") {
557
+ e.preventDefault();
558
+ onClick?.(e as never);
559
+ if (popover) {
560
+ setPopoverOpen(!popoverOpen);
561
+ }
562
+ }
563
+ };
564
+ const Element = (isSquircle ? Squircle : View) as any;
565
+ const extraProps = isSquircle
566
+ ? { as: "div", radius, ...(motionProps ? { motion: motionProps } : {}) }
567
+ : { ...(motionProps ? { motion: motionProps } : {}) };
568
+ return withPopover(
569
+ withForm(
570
+ <Element
571
+ ref={setContainerRef}
572
+ data-color-mode={dataColorMode}
573
+ role="button"
574
+ aria-disabled={disabled || undefined}
575
+ data-disabled={disabled || undefined}
576
+ tabIndex={disabled ? -1 : (tabIndex ?? 0)}
577
+ className={commonClassName}
578
+ style={commonStyle}
579
+ title={nativeTitle}
580
+ onClick={disabled ? undefined : handleTriggerClick}
581
+ onKeyDown={handleKeyDown}
582
+ {...extraProps}
583
+ {...commonProps}
584
+ {...restProps}
585
+ >
586
+ {children}
587
+ </Element>,
588
+ ),
589
+ );
590
+ }
591
+
592
+ if (shouldRenderButton) {
593
+ const Element = (
594
+ isSquircle ? Squircle : motionProps ? motion.button : "button"
595
+ ) as any;
596
+ const extraProps = isSquircle
597
+ ? {
598
+ as: "button",
599
+ radius,
600
+ ...(motionProps ? { motion: motionProps } : {}),
601
+ }
602
+ : {};
603
+ return withPopover(
604
+ withForm(
605
+ <ButtonNestingContext.Provider value={true}>
606
+ <Element
607
+ ref={setContainerRef as any}
608
+ data-color-mode={dataColorMode}
609
+ onClick={handleTriggerClick}
610
+ className={commonClassName}
611
+ style={commonStyle}
612
+ title={nativeTitle}
613
+ type={isButtonType(type) ? type : "button"}
614
+ tabIndex={tabIndex}
615
+ disabled={disabled}
616
+ onKeyDown={onKeyDown}
617
+ {...(!isSquircle && motionProps ? motionProps : undefined)}
618
+ {...extraProps}
619
+ {...commonProps}
620
+ {...restProps}
621
+ >
622
+ {children}
623
+ </Element>
624
+ </ButtonNestingContext.Provider>,
625
+ ),
626
+ );
627
+ }
628
+
629
+ const FallbackElement = (isSquircle ? Squircle : View) as any;
630
+ const fallbackExtraProps = isSquircle
631
+ ? { as: "div", radius, ...(motionProps ? { motion: motionProps } : {}) }
632
+ : { ...(motionProps ? { motion: motionProps } : {}) };
633
+ return withPopover(
634
+ withForm(
635
+ <FallbackElement
636
+ ref={setContainerRef}
637
+ data-color-mode={dataColorMode}
638
+ className={commonClassName}
639
+ style={commonStyle}
640
+ title={nativeTitle}
641
+ onKeyDown={onKeyDown}
642
+ {...fallbackExtraProps}
643
+ {...commonProps}
644
+ {...restProps}
645
+ >
646
+ {children}
647
+ </FallbackElement>,
648
+ ),
649
+ );
650
+ });
651
+ export default Pressable;