base-ui-vue 0.4.0 → 0.5.0

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 (187) hide show
  1. package/dist/arrow/TooltipArrow.cjs +609 -0
  2. package/dist/arrow/TooltipArrow.cjs.map +1 -0
  3. package/dist/arrow/TooltipArrow.js +478 -0
  4. package/dist/arrow/TooltipArrow.js.map +1 -0
  5. package/dist/button/Button.cjs +5 -317
  6. package/dist/button/Button.cjs.map +1 -1
  7. package/dist/button/Button.js +3 -249
  8. package/dist/button/Button.js.map +1 -1
  9. package/dist/button/ToolbarButton.cjs +13 -6
  10. package/dist/button/ToolbarButton.cjs.map +1 -1
  11. package/dist/button/ToolbarButton.js +3 -2
  12. package/dist/button/ToolbarButton.js.map +1 -1
  13. package/dist/checkbox/index.cjs +20 -9
  14. package/dist/checkbox/index.cjs.map +1 -1
  15. package/dist/checkbox/index.js +7 -2
  16. package/dist/checkbox/index.js.map +1 -1
  17. package/dist/checkbox-group/CheckboxGroup.cjs +14 -13
  18. package/dist/checkbox-group/CheckboxGroup.cjs.map +1 -1
  19. package/dist/checkbox-group/CheckboxGroup.js +2 -1
  20. package/dist/checkbox-group/CheckboxGroup.js.map +1 -1
  21. package/dist/components/FloatingPortal.cjs +66 -0
  22. package/dist/components/FloatingPortal.cjs.map +1 -0
  23. package/dist/components/FloatingPortal.js +55 -0
  24. package/dist/components/FloatingPortal.js.map +1 -0
  25. package/dist/components/FloatingRootStore.cjs +101 -0
  26. package/dist/components/FloatingRootStore.cjs.map +1 -0
  27. package/dist/components/FloatingRootStore.js +84 -0
  28. package/dist/components/FloatingRootStore.js.map +1 -0
  29. package/dist/components/FloatingTree.cjs +33 -0
  30. package/dist/components/FloatingTree.cjs.map +1 -0
  31. package/dist/components/FloatingTree.js +22 -0
  32. package/dist/components/FloatingTree.js.map +1 -0
  33. package/dist/composite/composite.cjs +6 -0
  34. package/dist/composite/composite.js +1 -1
  35. package/dist/content/ScrollAreaContent.cjs +3 -3
  36. package/dist/content/ScrollAreaContent.cjs.map +1 -1
  37. package/dist/content/ScrollAreaContent.js +1 -1
  38. package/dist/control/FieldControl.cjs +3 -3
  39. package/dist/control/FieldControl.cjs.map +1 -1
  40. package/dist/control/FieldControl.js +1 -1
  41. package/dist/control/SliderControl.cjs +3 -3
  42. package/dist/control/SliderControl.cjs.map +1 -1
  43. package/dist/control/SliderControl.js +1 -1
  44. package/dist/corner/ScrollAreaCorner.cjs +3 -3
  45. package/dist/corner/ScrollAreaCorner.cjs.map +1 -1
  46. package/dist/corner/ScrollAreaCorner.js +1 -1
  47. package/dist/decrement/NumberFieldDecrement.cjs +10 -3
  48. package/dist/decrement/NumberFieldDecrement.cjs.map +1 -1
  49. package/dist/decrement/NumberFieldDecrement.js +3 -2
  50. package/dist/decrement/NumberFieldDecrement.js.map +1 -1
  51. package/dist/description/FieldDescription.cjs +2 -2
  52. package/dist/description/FieldDescription.cjs.map +1 -1
  53. package/dist/description/FieldDescription.js +1 -1
  54. package/dist/error/FieldError.cjs +2 -2
  55. package/dist/error/FieldError.cjs.map +1 -1
  56. package/dist/error/FieldError.js +1 -1
  57. package/dist/fallback/AvatarFallback.cjs +2 -2
  58. package/dist/fallback/AvatarFallback.cjs.map +1 -1
  59. package/dist/fallback/AvatarFallback.js +1 -1
  60. package/dist/floating-ui-vue/index.js +638 -0
  61. package/dist/floating-ui-vue/index.js.map +1 -0
  62. package/dist/form/Form.cjs +3 -3
  63. package/dist/form/Form.cjs.map +1 -1
  64. package/dist/form/Form.js +1 -1
  65. package/dist/group/NumberFieldGroup.cjs +3 -3
  66. package/dist/group/NumberFieldGroup.cjs.map +1 -1
  67. package/dist/group/NumberFieldGroup.js +1 -1
  68. package/dist/group/ToolbarGroup.cjs +2 -2
  69. package/dist/group/ToolbarGroup.cjs.map +1 -1
  70. package/dist/group/ToolbarGroup.js +1 -1
  71. package/dist/header/AccordionHeader.cjs +2 -2
  72. package/dist/header/AccordionHeader.cjs.map +1 -1
  73. package/dist/header/AccordionHeader.js +1 -1
  74. package/dist/hooks/useDismiss.cjs +502 -0
  75. package/dist/hooks/useDismiss.cjs.map +1 -0
  76. package/dist/hooks/useHoverFloatingInteraction.cjs +233 -0
  77. package/dist/hooks/useHoverFloatingInteraction.cjs.map +1 -0
  78. package/dist/image/AvatarImage.cjs +4 -4
  79. package/dist/image/AvatarImage.cjs.map +1 -1
  80. package/dist/image/AvatarImage.js +1 -1
  81. package/dist/increment/NumberFieldIncrement.cjs +3 -2
  82. package/dist/increment/NumberFieldIncrement.cjs.map +1 -1
  83. package/dist/increment/NumberFieldIncrement.js +2 -1
  84. package/dist/increment/NumberFieldIncrement.js.map +1 -1
  85. package/dist/index.cjs +60 -7
  86. package/dist/index.d.cts +3838 -1726
  87. package/dist/index.d.cts.map +1 -1
  88. package/dist/index.d.ts +3838 -1726
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +4 -3
  91. package/dist/index2.cjs +7475 -3089
  92. package/dist/index2.cjs.map +1 -1
  93. package/dist/index2.js +7215 -3106
  94. package/dist/index2.js.map +1 -1
  95. package/dist/rolldown-runtime.js +36 -0
  96. package/package.json +1 -1
  97. package/src/floating-ui-vue/components/FloatingPortal.ts +171 -0
  98. package/src/floating-ui-vue/components/FloatingPortal.vue +259 -0
  99. package/src/floating-ui-vue/components/FloatingRootStore.ts +83 -0
  100. package/src/floating-ui-vue/components/FloatingTree.ts +64 -0
  101. package/src/floating-ui-vue/components/FloatingTreeStore.ts +21 -0
  102. package/src/floating-ui-vue/hooks/useDismiss.ts +689 -0
  103. package/src/floating-ui-vue/hooks/useHoverFloatingInteraction.ts +244 -0
  104. package/src/floating-ui-vue/hooks/useHoverInteractionSharedState.ts +125 -0
  105. package/src/floating-ui-vue/hooks/useHoverShared.ts +53 -0
  106. package/src/floating-ui-vue/index.ts +48 -0
  107. package/src/floating-ui-vue/middleware/arrow.ts +114 -0
  108. package/src/floating-ui-vue/types.ts +117 -0
  109. package/src/floating-ui-vue/utils/composite.ts +20 -0
  110. package/src/floating-ui-vue/utils/constants.ts +2 -0
  111. package/src/floating-ui-vue/utils/createAttribute.ts +3 -0
  112. package/src/floating-ui-vue/utils/createEventEmitter.ts +20 -0
  113. package/src/floating-ui-vue/utils/element.ts +59 -0
  114. package/src/floating-ui-vue/utils/event.ts +15 -0
  115. package/src/floating-ui-vue/utils/nodes.ts +14 -0
  116. package/src/floating-ui-vue/utils/tabbable.ts +309 -0
  117. package/src/index.ts +4 -0
  118. package/src/radio/index.ts +28 -0
  119. package/src/radio/indicator/RadioIndicator.vue +90 -0
  120. package/src/radio/indicator/RadioIndicatorDataAttributes.ts +54 -0
  121. package/src/radio/root/RadioRoot.vue +544 -0
  122. package/src/radio/root/RadioRootContext.ts +18 -0
  123. package/src/radio/root/RadioRootDataAttributes.ts +46 -0
  124. package/src/radio/utils/stateAttributesMapping.ts +29 -0
  125. package/src/radio-group/RadioGroup.vue +381 -0
  126. package/src/radio-group/RadioGroupContext.ts +42 -0
  127. package/src/radio-group/RadioGroupDataAttributes.ts +6 -0
  128. package/src/radio-group/index.ts +10 -0
  129. package/src/tabs/index.ts +38 -0
  130. package/src/tabs/indicator/TabsIndicator.vue +201 -0
  131. package/src/tabs/indicator/TabsIndicatorCssVars.ts +26 -0
  132. package/src/tabs/indicator/TabsIndicatorDataAttributes.ts +12 -0
  133. package/src/tabs/indicator/prehydrationScript.min.ts +5 -0
  134. package/src/tabs/indicator/prehydrationScript.template.js +87 -0
  135. package/src/tabs/list/TabsList.vue +201 -0
  136. package/src/tabs/list/TabsListContext.ts +29 -0
  137. package/src/tabs/list/TabsListDataAttributes.ts +12 -0
  138. package/src/tabs/panel/TabsPanel.vue +167 -0
  139. package/src/tabs/panel/TabsPanelDataAttributes.ts +28 -0
  140. package/src/tabs/root/TabsRoot.vue +468 -0
  141. package/src/tabs/root/TabsRootContext.ts +56 -0
  142. package/src/tabs/root/TabsRootDataAttributes.ts +12 -0
  143. package/src/tabs/root/stateAttributesMapping.ts +9 -0
  144. package/src/tabs/tab/TabsTab.vue +274 -0
  145. package/src/tabs/tab/TabsTabDataAttributes.ts +20 -0
  146. package/src/tabs/utils/areTabValuesEqual.ts +6 -0
  147. package/src/tooltip/arrow/TooltipArrow.vue +116 -0
  148. package/src/tooltip/arrow/TooltipArrowDataAttributes.ts +31 -0
  149. package/src/tooltip/index.ts +54 -0
  150. package/src/tooltip/popup/TooltipPopup.vue +142 -0
  151. package/src/tooltip/popup/TooltipPopupDataAttributes.ts +35 -0
  152. package/src/tooltip/portal/TooltipPortal.vue +83 -0
  153. package/src/tooltip/portal/TooltipPortalContext.ts +19 -0
  154. package/src/tooltip/positioner/TooltipPositioner.vue +221 -0
  155. package/src/tooltip/positioner/TooltipPositionerContext.ts +23 -0
  156. package/src/tooltip/positioner/TooltipPositionerCssVars.ts +27 -0
  157. package/src/tooltip/positioner/TooltipPositionerDataAttributes.ts +26 -0
  158. package/src/tooltip/provider/TooltipProvider.vue +78 -0
  159. package/src/tooltip/provider/TooltipProviderContext.ts +19 -0
  160. package/src/tooltip/root/TooltipRoot.vue +401 -0
  161. package/src/tooltip/root/TooltipRootContext.ts +71 -0
  162. package/src/tooltip/store/TooltipHandle.ts +215 -0
  163. package/src/tooltip/trigger/TooltipTrigger.vue +343 -0
  164. package/src/tooltip/trigger/TooltipTriggerDataAttributes.ts +12 -0
  165. package/src/tooltip/utils/constants.ts +2 -0
  166. package/src/tooltip/viewport/TooltipViewport.vue +149 -0
  167. package/src/tooltip/viewport/TooltipViewportCssVars.ts +14 -0
  168. package/src/tooltip/viewport/TooltipViewportDataAttributes.ts +26 -0
  169. package/src/utils/FloatingPortalLite.vue +66 -0
  170. package/src/utils/FocusGuard.vue +36 -0
  171. package/src/utils/adaptiveOriginMiddleware.ts +79 -0
  172. package/src/utils/addEventListener.ts +16 -0
  173. package/src/utils/constants.ts +11 -0
  174. package/src/utils/createBaseUIEventDetails.ts +2 -0
  175. package/src/utils/getCssDimensions.ts +19 -0
  176. package/src/utils/getDisabledMountTransitionStyles.ts +9 -0
  177. package/src/utils/hideMiddleware.ts +19 -0
  178. package/src/utils/mergeCleanups.ts +7 -0
  179. package/src/utils/platform.ts +18 -0
  180. package/src/utils/popupStateMapping.ts +103 -0
  181. package/src/utils/reasons.ts +4 -0
  182. package/src/utils/serializeValue.ts +17 -0
  183. package/src/utils/useAnchorPositioning.ts +644 -0
  184. package/src/utils/usePopupAutoResize.ts +254 -0
  185. package/src/utils/usePopupViewport.ts +398 -0
  186. package/src/utils/usePositioner.ts +61 -0
  187. package/src/utils/useRenderElement.ts +3 -0
@@ -0,0 +1,79 @@
1
+ import type { Middleware } from '../floating-ui-vue'
2
+ import { getSide } from '@floating-ui/utils'
3
+ import { ownerDocument, ownerWindow } from './owner'
4
+
5
+ export const DEFAULT_SIDES = {
6
+ sideX: 'left',
7
+ sideY: 'top',
8
+ } as const
9
+
10
+ export const adaptiveOrigin: Middleware = {
11
+ name: 'adaptiveOrigin',
12
+ async fn(state) {
13
+ const {
14
+ x: rawX,
15
+ y: rawY,
16
+ rects: { floating: floatRect },
17
+ elements: { floating },
18
+ platform,
19
+ strategy,
20
+ placement,
21
+ } = state
22
+
23
+ const win = ownerWindow(floating)
24
+ const styles = win.getComputedStyle(floating)
25
+ const hasTransition = styles.transitionDuration !== '0s' && styles.transitionDuration !== ''
26
+
27
+ if (!hasTransition) {
28
+ return {
29
+ x: rawX,
30
+ y: rawY,
31
+ data: DEFAULT_SIDES,
32
+ }
33
+ }
34
+
35
+ const offsetParent = await platform.getOffsetParent?.(floating)
36
+
37
+ let offsetDimensions = { width: 0, height: 0 }
38
+
39
+ if (strategy === 'fixed' && win.visualViewport) {
40
+ offsetDimensions = {
41
+ width: win.visualViewport.width,
42
+ height: win.visualViewport.height,
43
+ }
44
+ }
45
+ else if (offsetParent === win) {
46
+ const doc = ownerDocument(floating)
47
+ offsetDimensions = {
48
+ width: doc?.documentElement.clientWidth ?? 0,
49
+ height: doc?.documentElement.clientHeight ?? 0,
50
+ }
51
+ }
52
+ else if (await platform.isElement?.(offsetParent)) {
53
+ offsetDimensions = await platform.getDimensions(offsetParent as Element)
54
+ }
55
+
56
+ const currentSide = getSide(placement)
57
+ let x = rawX
58
+ let y = rawY
59
+
60
+ if (currentSide === 'left') {
61
+ x = offsetDimensions.width - (rawX + floatRect.width)
62
+ }
63
+ if (currentSide === 'top') {
64
+ y = offsetDimensions.height - (rawY + floatRect.height)
65
+ }
66
+
67
+ const sideX = currentSide === 'left' ? 'right' : DEFAULT_SIDES.sideX
68
+ const sideY = currentSide === 'top' ? 'bottom' : DEFAULT_SIDES.sideY
69
+
70
+ return {
71
+ x,
72
+ y,
73
+ data: {
74
+ sideX,
75
+ sideY,
76
+ },
77
+ }
78
+ },
79
+ }
@@ -0,0 +1,16 @@
1
+ export function addEventListener<K extends keyof HTMLElementEventMap>(
2
+ target: HTMLElement | SVGElement | Document | Window | null | undefined,
3
+ type: K,
4
+ listener: (event: HTMLElementEventMap[K]) => void,
5
+ options?: AddEventListenerOptions | boolean,
6
+ ) {
7
+ if (!target) {
8
+ return undefined
9
+ }
10
+
11
+ target.addEventListener(type, listener as EventListener, options)
12
+
13
+ return () => {
14
+ target.removeEventListener(type, listener as EventListener, options)
15
+ }
16
+ }
@@ -1 +1,12 @@
1
+ import type { CSSProperties } from 'vue'
2
+
3
+ export const DISABLED_TRANSITIONS_STYLE = { style: { transition: 'none' } } as const
4
+
5
+ export const ownerVisuallyHidden: CSSProperties = {
6
+ clipPath: 'inset(50%)',
7
+ position: 'fixed',
8
+ top: 0,
9
+ left: 0,
10
+ }
11
+
1
12
  export { EMPTY_ARRAY, EMPTY_OBJECT } from './empty'
@@ -3,6 +3,8 @@ import { EMPTY_OBJECT } from './empty'
3
3
 
4
4
  interface ReasonToEventMap {
5
5
  [REASONS.none]: Event
6
+ [REASONS.initial]: Event
7
+ [REASONS.missing]: Event
6
8
 
7
9
  [REASONS.triggerPress]: MouseEvent | PointerEvent | TouchEvent | KeyboardEvent
8
10
  [REASONS.triggerHover]: MouseEvent
@@ -0,0 +1,19 @@
1
+ import type { Dimensions } from '@floating-ui/utils'
2
+ import { round } from '@floating-ui/utils'
3
+ import { getComputedStyle, isHTMLElement } from '@floating-ui/utils/dom'
4
+
5
+ export function getCssDimensions(element: Element): Dimensions {
6
+ const css = getComputedStyle(element)
7
+ let width = Number.parseFloat(css.width) || 0
8
+ let height = Number.parseFloat(css.height) || 0
9
+ const hasOffset = isHTMLElement(element)
10
+ const offsetWidth = hasOffset ? element.offsetWidth : width
11
+ const offsetHeight = hasOffset ? element.offsetHeight : height
12
+
13
+ if (round(width) !== offsetWidth || round(height) !== offsetHeight) {
14
+ width = offsetWidth
15
+ height = offsetHeight
16
+ }
17
+
18
+ return { width, height }
19
+ }
@@ -0,0 +1,9 @@
1
+ import type { StyleValue } from 'vue'
2
+ import type { TransitionStatus } from './useTransitionStatus'
3
+ import { DISABLED_TRANSITIONS_STYLE, EMPTY_OBJECT } from './constants'
4
+
5
+ export function getDisabledMountTransitionStyles(transitionStatus: TransitionStatus): {
6
+ style?: StyleValue
7
+ } {
8
+ return transitionStatus === 'starting' ? DISABLED_TRANSITIONS_STYLE : EMPTY_OBJECT
9
+ }
@@ -0,0 +1,19 @@
1
+ import type { Middleware } from '@floating-ui/vue'
2
+ import { hide as nativeHide } from '@floating-ui/vue'
3
+
4
+ const nativeHideFn = nativeHide().fn
5
+
6
+ export const hide: Middleware = {
7
+ name: 'hide',
8
+ async fn(state) {
9
+ const { width, height, x, y } = state.rects.reference
10
+ const anchorHidden = width === 0 && height === 0 && x === 0 && y === 0
11
+ const nativeHideResult = await nativeHideFn(state)
12
+
13
+ return {
14
+ data: {
15
+ referenceHidden: nativeHideResult.data?.referenceHidden || anchorHidden,
16
+ },
17
+ }
18
+ },
19
+ }
@@ -0,0 +1,7 @@
1
+ export function mergeCleanups(...cleanups: Array<(() => void) | undefined>) {
2
+ return () => {
3
+ for (const cleanup of cleanups) {
4
+ cleanup?.()
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,18 @@
1
+ import { isIOS, isWebKit } from './detectBrowser'
2
+
3
+ const platformName = typeof navigator !== 'undefined' ? navigator.platform : ''
4
+ const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : ''
5
+
6
+ const isApplePlatform
7
+ = isIOS
8
+ || /mac/i.test(platformName)
9
+ || /\b(?:macintosh|iphone|ipad|ipod)\b/i.test(userAgent)
10
+
11
+ export const platform = {
12
+ engine: {
13
+ webkit: isWebKit,
14
+ },
15
+ screenReader: {
16
+ voiceOver: isApplePlatform,
17
+ },
18
+ } as const
@@ -0,0 +1,103 @@
1
+ import type { StateAttributesMapping } from './getStateAttributesProps'
2
+
3
+ export enum CommonPopupDataAttributes {
4
+ /**
5
+ * Present when the popup is open.
6
+ */
7
+ open = 'data-open',
8
+ /**
9
+ * Present when the popup is closed.
10
+ */
11
+ closed = 'data-closed',
12
+ /**
13
+ * Present when the popup is animating in.
14
+ */
15
+ startingStyle = 'data-starting-style',
16
+ /**
17
+ * Present when the popup is animating out.
18
+ */
19
+ endingStyle = 'data-ending-style',
20
+ /**
21
+ * Present when the anchor is hidden.
22
+ */
23
+ anchorHidden = 'data-anchor-hidden',
24
+ /**
25
+ * Indicates which side the popup is positioned relative to the trigger.
26
+ */
27
+ side = 'data-side',
28
+ /**
29
+ * Indicates how the popup is aligned relative to the specified side.
30
+ */
31
+ align = 'data-align',
32
+ /**
33
+ * Present when animations should be skipped.
34
+ */
35
+ instant = 'data-instant',
36
+ }
37
+
38
+ export enum CommonTriggerDataAttributes {
39
+ /**
40
+ * Present when the popup is open.
41
+ */
42
+ popupOpen = 'data-popup-open',
43
+ /**
44
+ * Present when the trigger is disabled.
45
+ */
46
+ triggerDisabled = 'data-trigger-disabled',
47
+ }
48
+
49
+ const POPUP_OPEN_HOOK = {
50
+ [CommonPopupDataAttributes.open]: '',
51
+ }
52
+
53
+ const POPUP_CLOSED_HOOK = {
54
+ [CommonPopupDataAttributes.closed]: '',
55
+ }
56
+
57
+ const ANCHOR_HIDDEN_HOOK = {
58
+ [CommonPopupDataAttributes.anchorHidden]: '',
59
+ }
60
+
61
+ const TRIGGER_OPEN_HOOK = {
62
+ [CommonTriggerDataAttributes.popupOpen]: '',
63
+ }
64
+
65
+ const TRIGGER_DISABLED_HOOK = {
66
+ [CommonTriggerDataAttributes.triggerDisabled]: '',
67
+ }
68
+
69
+ export const popupStateMapping = {
70
+ open(value) {
71
+ return value ? POPUP_OPEN_HOOK : POPUP_CLOSED_HOOK
72
+ },
73
+ anchorHidden(value) {
74
+ return value ? ANCHOR_HIDDEN_HOOK : null
75
+ },
76
+ side(value) {
77
+ return value ? { [CommonPopupDataAttributes.side]: value } : null
78
+ },
79
+ align(value) {
80
+ return value ? { [CommonPopupDataAttributes.align]: value } : null
81
+ },
82
+ instant(value) {
83
+ return value ? { [CommonPopupDataAttributes.instant]: value } : null
84
+ },
85
+ } satisfies StateAttributesMapping<{
86
+ open: boolean
87
+ anchorHidden?: boolean
88
+ side?: string
89
+ align?: string
90
+ instant?: string
91
+ }>
92
+
93
+ export const triggerStateMapping = {
94
+ open(value) {
95
+ return value ? TRIGGER_OPEN_HOOK : null
96
+ },
97
+ disabled(value) {
98
+ return value ? TRIGGER_DISABLED_HOOK : null
99
+ },
100
+ } satisfies StateAttributesMapping<{
101
+ open: boolean
102
+ disabled: boolean
103
+ }>
@@ -1,4 +1,6 @@
1
1
  export const none = 'none' as const
2
+ export const initial = 'initial' as const
3
+ export const missing = 'missing' as const
2
4
  export const triggerPress = 'trigger-press' as const
3
5
  export const triggerHover = 'trigger-hover' as const
4
6
  export const triggerFocus = 'trigger-focus' as const
@@ -34,6 +36,8 @@ export const windowResize = 'window-resize' as const
34
36
 
35
37
  export const REASONS = {
36
38
  none,
39
+ initial,
40
+ missing,
37
41
  triggerPress,
38
42
  triggerHover,
39
43
  triggerFocus,
@@ -0,0 +1,17 @@
1
+ export function serializeValue(value: unknown): string {
2
+ if (value == null) {
3
+ return ''
4
+ }
5
+
6
+ if (typeof value === 'string') {
7
+ return value
8
+ }
9
+
10
+ try {
11
+ const serializedValue = JSON.stringify(value)
12
+ return serializedValue === undefined ? 'null' : serializedValue
13
+ }
14
+ catch {
15
+ return String(value)
16
+ }
17
+ }