@nikala-ui/core 0.9.2 → 0.9.4
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.
- package/package.json +1 -1
- package/registry/create-active-element.json +7 -4
- package/registry/create-audio.json +0 -3
- package/registry/create-battery.json +7 -4
- package/registry/create-click-outside.json +7 -4
- package/registry/create-clipboard.json +7 -4
- package/registry/create-color-mode.json +7 -4
- package/registry/create-controllable-signal.json +7 -4
- package/registry/create-debounce.json +7 -4
- package/registry/create-disclosure.json +7 -4
- package/registry/create-document-title.json +7 -4
- package/registry/create-event-source.json +7 -4
- package/registry/create-favicon.json +7 -4
- package/registry/create-fetch.json +7 -4
- package/registry/create-focus-trap.json +7 -4
- package/registry/create-form.json +7 -4
- package/registry/create-fullscreen.json +7 -4
- package/registry/create-geolocation.json +7 -4
- package/registry/create-hover.json +7 -4
- package/registry/create-idle.json +7 -4
- package/registry/create-infinite-scroll.json +7 -4
- package/registry/create-input-mask.json +7 -4
- package/registry/create-intersection-observer.json +7 -4
- package/registry/create-keybindings.json +7 -4
- package/registry/create-lock-scroll.json +7 -4
- package/registry/create-long-press.json +7 -4
- package/registry/create-media-query.json +7 -4
- package/registry/create-mouse-position.json +7 -4
- package/registry/create-network-status.json +7 -4
- package/registry/create-orientation.json +7 -4
- package/registry/create-permission.json +7 -4
- package/registry/create-previous.json +7 -4
- package/registry/create-resize-observer.json +7 -4
- package/registry/create-scroll-into-view.json +7 -4
- package/registry/create-scroll-position.json +7 -4
- package/registry/create-storage.json +7 -4
- package/registry/create-timer.json +7 -4
- package/registry/create-undo-redo.json +7 -4
- package/registry/create-web-notification.json +7 -4
- package/registry/create-websocket.json +7 -4
- package/registry/create-window-size.json +7 -4
- package/registry/index.json +40 -160
- package/src/registry/metadata.ts +0 -40
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createMousePosition",
|
|
4
4
|
"description": "SolidJS reactive primitive for tracking global and element-relative mouse pointer coordinates",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-mouse-position.ts",
|
|
9
|
+
"content": "import { createEffect, createSignal, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateMousePositionOptions {\n /** Target element to calculate element-relative mouse coordinates for. Defaults to window. */\n target?: HTMLElement | Window | Accessor<HTMLElement | Window | undefined>;\n}\n\nexport interface CreateMousePositionReturn {\n /** Accessor for global page X mouse position */\n x: Accessor<number>;\n /** Accessor for global page Y mouse position */\n y: Accessor<number>;\n /** Accessor for element-relative X mouse coordinate */\n elementX: Accessor<number>;\n /** Accessor for element-relative Y mouse coordinate */\n elementY: Accessor<number>;\n /** Accessor indicating if mouse pointer is inside target element bounds */\n isInside: Accessor<boolean>;\n}\n\n/**\n * SolidJS reactive primitive for tracking global and element-relative mouse pointer coordinates.\n *\n * @param options Configuration options including target element.\n */\nexport function createMousePosition(\n options: CreateMousePositionOptions = {}\n): CreateMousePositionReturn {\n const [x, setX] = createSignal(0);\n const [y, setY] = createSignal(0);\n const [elementX, setElementX] = createSignal(0);\n const [elementY, setElementY] = createSignal(0);\n const [isInside, setIsInside] = createSignal(false);\n\n const getTarget = (): HTMLElement | Window | undefined => {\n if (typeof window === \"undefined\") return undefined;\n if (!options.target) return window;\n if (typeof options.target === \"function\") {\n return (options.target as Accessor<HTMLElement | Window | undefined>)();\n }\n return options.target;\n };\n\n const handleMouseMove = (event: MouseEvent) => {\n const pageX = event.pageX;\n const pageY = event.pageY;\n\n setX(pageX);\n setY(pageY);\n\n const target = getTarget();\n if (target && target !== window) {\n const el = target as HTMLElement;\n const rect = el.getBoundingClientRect();\n const relX = event.clientX - rect.left;\n const relY = event.clientY - rect.top;\n\n setElementX(relX);\n setElementY(relY);\n\n const inside =\n relX >= 0 && relX <= rect.width && relY >= 0 && relY <= rect.height;\n setIsInside(inside);\n } else {\n setElementX(pageX);\n setElementY(pageY);\n setIsInside(true);\n }\n };\n\n createEffect(() => {\n if (typeof window === \"undefined\") return;\n\n window.addEventListener(\"mousemove\", handleMouseMove, { passive: true });\n onCleanup(() => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n });\n });\n\n return {\n x,\n y,\n elementX,\n elementY,\n isInside,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createNetworkStatus",
|
|
4
4
|
"description": "SolidJS reactive primitives for tracking browser network connectivity and connection quality metrics",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-network-status.ts",
|
|
9
|
+
"content": "import { createEffect, createSignal, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateNetworkStatusReturn {\n /** Accessor indicating if browser is currently connected to the network */\n isOnline: Accessor<boolean>;\n /** Date timestamp when network went offline, if applicable */\n offlineAt: Accessor<Date | undefined>;\n /** Date timestamp when network re-connected online, if applicable */\n onlineAt: Accessor<Date | undefined>;\n /** Network connection estimated downlink speed in Mbps */\n downlink: Accessor<number | undefined>;\n /** Network connection estimated round-trip time in ms */\n rtt: Accessor<number | undefined>;\n /** Network connection data saver mode enabled status */\n saveData: Accessor<boolean | undefined>;\n /** Network connection effective type ('slow-2g', '2g', '3g', '4g') */\n effectiveType: Accessor<\"slow-2g\" | \"2g\" | \"3g\" | \"4g\" | undefined>;\n}\n\n/**\n * SolidJS reactive primitive for tracking browser network connectivity and connection quality metrics.\n */\nexport function createNetworkStatus(): CreateNetworkStatusReturn {\n const getInitialOnline = () => (typeof navigator !== \"undefined\" ? navigator.onLine : true);\n\n const [isOnline, setIsOnline] = createSignal(getInitialOnline());\n const [offlineAt, setOfflineAt] = createSignal<Date | undefined>(undefined);\n const [onlineAt, setOnlineAt] = createSignal<Date | undefined>(undefined);\n\n const getNetworkConnection = () => {\n if (typeof navigator === \"undefined\") return undefined;\n return (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection;\n };\n\n const conn = getNetworkConnection();\n\n const [downlink, setDownlink] = createSignal<number | undefined>(conn?.downlink);\n const [rtt, setRtt] = createSignal<number | undefined>(conn?.rtt);\n const [saveData, setSaveData] = createSignal<boolean | undefined>(conn?.saveData);\n const [effectiveType, setEffectiveType] = createSignal<\"slow-2g\" | \"2g\" | \"3g\" | \"4g\" | undefined>(conn?.effectiveType);\n\n const updateNetworkInfo = () => {\n const currentConn = getNetworkConnection();\n if (currentConn) {\n setDownlink(currentConn.downlink);\n setRtt(currentConn.rtt);\n setSaveData(currentConn.saveData);\n setEffectiveType(currentConn.effectiveType);\n }\n };\n\n const handleOnline = () => {\n setIsOnline(true);\n setOnlineAt(new Date());\n updateNetworkInfo();\n };\n\n const handleOffline = () => {\n setIsOnline(false);\n setOfflineAt(new Date());\n };\n\n createEffect(() => {\n if (typeof window === \"undefined\") return;\n\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n\n const currentConn = getNetworkConnection();\n if (currentConn && currentConn.addEventListener) {\n currentConn.addEventListener(\"change\", updateNetworkInfo);\n }\n\n onCleanup(() => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n if (currentConn && currentConn.removeEventListener) {\n currentConn.removeEventListener(\"change\", updateNetworkInfo);\n }\n });\n });\n\n return {\n isOnline,\n offlineAt,\n onlineAt,\n downlink,\n rtt,\n saveData,\n effectiveType,\n };\n}\n\n/**\n * SolidJS reactive primitive for checking if browser is connected online.\n */\nexport function createOnline(): Accessor<boolean> {\n const { isOnline } = createNetworkStatus();\n return isOnline;\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createOrientation",
|
|
4
4
|
"description": "SolidJS reactive primitive for observing mobile and desktop screen orientation changes and rotation angles",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-orientation.ts",
|
|
9
|
+
"content": "import { createSignal, createEffect, onCleanup, type Accessor } from \"solid-js\";\n\nexport type ScreenOrientationType =\n | \"portrait-primary\"\n | \"portrait-secondary\"\n | \"landscape-primary\"\n | \"landscape-secondary\"\n | \"portrait\"\n | \"landscape\"\n | \"unknown\";\n\nexport interface CreateOrientationOptions {\n /** Callback fired when screen orientation changes. */\n onChange?: (orientation: ScreenOrientationType, angle: number) => void;\n}\n\nexport interface CreateOrientationReturn {\n /** Signal indicating current orientation type. */\n type: Accessor<ScreenOrientationType>;\n /** Signal indicating current orientation angle in degrees (0, 90, 180, 270). */\n angle: Accessor<number>;\n /** Signal indicating if device screen is in portrait mode. */\n isPortrait: Accessor<boolean>;\n /** Signal indicating if device screen is in landscape mode. */\n isLandscape: Accessor<boolean>;\n /** Lock screen orientation if supported by device/browser. */\n lock: (orientation: string) => Promise<void>;\n /** Unlock screen orientation. */\n unlock: () => void;\n}\n\n/**\n * SolidJS reactive primitive for observing mobile/desktop screen orientation and angle.\n */\nexport function createOrientation(\n options: CreateOrientationOptions = {}\n): CreateOrientationReturn {\n const [type, setType] = createSignal<ScreenOrientationType>(\"unknown\");\n const [angle, setAngle] = createSignal<number>(0);\n\n const getOrientationState = (): { type: ScreenOrientationType; angle: number } => {\n if (typeof window === \"undefined\") {\n return { type: \"unknown\", angle: 0 };\n }\n\n if (window.screen?.orientation) {\n return {\n type: window.screen.orientation.type as ScreenOrientationType,\n angle: window.screen.orientation.angle || 0,\n };\n }\n\n /* Fallback for older browsers using window.orientation */\n const legacyAngle = (window as unknown as { orientation?: number }).orientation ?? 0;\n const isPortraitMode = Math.abs(legacyAngle) !== 90;\n return {\n type: isPortraitMode ? \"portrait\" : \"landscape\",\n angle: Number(legacyAngle),\n };\n };\n\n createEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const updateState = (): void => {\n const state = getOrientationState();\n setType(state.type);\n setAngle(state.angle);\n options.onChange?.(state.type, state.angle);\n };\n\n updateState();\n\n if (window.screen?.orientation) {\n window.screen.orientation.addEventListener(\"change\", updateState);\n onCleanup(() => {\n window.screen.orientation.removeEventListener(\"change\", updateState);\n });\n } else {\n window.addEventListener(\"orientationchange\", updateState);\n window.addEventListener(\"resize\", updateState);\n onCleanup(() => {\n window.removeEventListener(\"orientationchange\", updateState);\n window.removeEventListener(\"resize\", updateState);\n });\n }\n });\n\n const isPortrait = (): boolean => {\n const currentType = type();\n return currentType.startsWith(\"portrait\");\n };\n\n const isLandscape = (): boolean => {\n const currentType = type();\n return currentType.startsWith(\"landscape\");\n };\n\n const lock = async (orientation: string): Promise<void> => {\n if (typeof window !== \"undefined\" && window.screen?.orientation) {\n const orientationApi = window.screen.orientation as unknown as {\n lock?: (orient: string) => Promise<void>;\n };\n if (typeof orientationApi.lock === \"function\") {\n await orientationApi.lock(orientation);\n }\n }\n };\n\n const unlock = (): void => {\n if (typeof window !== \"undefined\" && window.screen?.orientation) {\n const orientationApi = window.screen.orientation as unknown as {\n unlock?: () => void;\n };\n if (typeof orientationApi.unlock === \"function\") {\n orientationApi.unlock();\n }\n }\n };\n\n return {\n type,\n angle,\n isPortrait,\n isLandscape,\n lock,\n unlock,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createPermission",
|
|
4
4
|
"description": "SolidJS reactive primitive for querying and observing browser permission status changes",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-permission.ts",
|
|
9
|
+
"content": "import { createSignal, createEffect, onCleanup, type Accessor } from \"solid-js\";\n\nexport type PermissionNameType =\n | \"geolocation\"\n | \"notifications\"\n | \"persistent-storage\"\n | \"push\"\n | \"screen-wake-lock\"\n | \"clipboard-read\"\n | \"clipboard-write\"\n | \"camera\"\n | \"microphone\"\n | (string & {});\n\nexport type PermissionStatusState = \"granted\" | \"denied\" | \"prompt\" | \"unknown\";\n\nexport interface CreatePermissionOptions {\n /** Permission descriptor or name to query. */\n name: PermissionNameType;\n}\n\nexport interface CreatePermissionReturn {\n /** Signal accessor containing current permission status ('granted', 'denied', 'prompt', 'unknown'). */\n state: Accessor<PermissionStatusState>;\n /** Signal accessor indicating whether Permissions API is supported in browser environment. */\n isSupported: Accessor<boolean>;\n /** Imperative function to re-query permission status manually. */\n query: () => Promise<PermissionStatusState>;\n}\n\n/**\n * SolidJS reactive primitive for querying and observing browser permission status changes.\n */\nexport function createPermission(\n options: PermissionNameType | CreatePermissionOptions\n): CreatePermissionReturn {\n const [state, setState] = createSignal<PermissionStatusState>(\"unknown\");\n\n const permissionName = typeof options === \"string\" ? options : options.name;\n\n const isSupported = (): boolean =>\n typeof window !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n \"permissions\" in navigator;\n\n let permissionStatus: PermissionStatus | null = null;\n\n const query = async (): Promise<PermissionStatusState> => {\n if (!isSupported()) {\n setState(\"unknown\");\n return \"unknown\";\n }\n\n try {\n const status = await navigator.permissions.query({\n name: permissionName as PermissionName,\n });\n\n permissionStatus = status;\n const currentState = status.state as PermissionStatusState;\n setState(currentState);\n\n status.onchange = () => {\n setState(status.state as PermissionStatusState);\n };\n\n return currentState;\n } catch {\n setState(\"unknown\");\n return \"unknown\";\n }\n };\n\n createEffect(() => {\n if (!isSupported()) return;\n\n query();\n\n onCleanup(() => {\n if (permissionStatus) {\n permissionStatus.onchange = null;\n }\n });\n });\n\n return {\n state,\n isSupported,\n query,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createPrevious",
|
|
4
4
|
"description": "SolidJS reactive primitive for tracking previous value of a signal accessor",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-previous.ts",
|
|
9
|
+
"content": "import { createEffect, createSignal, type Accessor } from \"solid-js\";\n\n/**\n * SolidJS reactive primitive for tracking previous value of a signal accessor.\n *\n * @param source Target reactive signal accessor to observe.\n */\nexport function createPrevious<T>(source: Accessor<T>): Accessor<T | undefined> {\n const [previous, setPrevious] = createSignal<T | undefined>(undefined);\n let current: T = source();\n\n createEffect(() => {\n const next = source();\n if (current !== next) {\n setPrevious(() => current);\n current = next;\n }\n });\n\n return previous;\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createResizeObserver",
|
|
4
4
|
"description": "SolidJS reactive primitives for tracking element width and height dimensions dynamically",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-resize-observer.ts",
|
|
9
|
+
"content": "import { createEffect, createSignal, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateResizeObserverOptions extends ResizeObserverOptions {\n /** Whether the observer is active. Defaults to true. */\n enabled?: boolean | Accessor<boolean>;\n}\n\n/**\n * SolidJS reactive primitive for observing element size changes via ResizeObserver.\n *\n * @param target Target element or accessor returning HTML element.\n * @param callback Observer callback invoked on element resize events.\n * @param options ResizeObserver options (box, enabled).\n */\nexport function createResizeObserver(\n target: HTMLElement | Accessor<HTMLElement | undefined>,\n callback: ResizeObserverCallback,\n options: CreateResizeObserverOptions = {}\n): void {\n const getTarget = (): HTMLElement | undefined => {\n if (typeof target === \"function\") {\n return (target as Accessor<HTMLElement | undefined>)();\n }\n return target;\n };\n\n const isEnabled = (): boolean => {\n if (typeof options.enabled === \"function\") {\n return options.enabled();\n }\n return options.enabled ?? true;\n };\n\n createEffect(() => {\n if (typeof window === \"undefined\" || !window.ResizeObserver) {\n return;\n }\n\n if (!isEnabled()) return;\n\n const el = getTarget();\n if (!el) return;\n\n const observer = new ResizeObserver(callback);\n observer.observe(el, { box: options.box });\n\n onCleanup(() => {\n observer.disconnect();\n });\n });\n}\n\nexport interface CreateElementSizeReturn {\n /** Accessor for element width in pixels */\n width: Accessor<number>;\n /** Accessor for element height in pixels */\n height: Accessor<number>;\n}\n\n/**\n * SolidJS reactive primitive returning width and height accessors for a target HTML element.\n *\n * @param target Target element or accessor returning HTML element.\n * @param options ResizeObserver options.\n */\nexport function createElementSize(\n target: HTMLElement | Accessor<HTMLElement | undefined>,\n options: CreateResizeObserverOptions = {}\n): CreateElementSizeReturn {\n const [width, setWidth] = createSignal(0);\n const [height, setHeight] = createSignal(0);\n\n createResizeObserver(\n target,\n (entries) => {\n const entry = entries[0];\n if (entry) {\n setWidth(entry.contentRect.width);\n setHeight(entry.contentRect.height);\n }\n },\n options\n );\n\n return {\n width,\n height,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createScrollIntoView",
|
|
4
4
|
"description": "SolidJS reactive primitive for scrolling a target element into view smooth or auto behavior",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-scroll-into-view.ts",
|
|
9
|
+
"content": "import { createEffect, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateScrollIntoViewOptions extends ScrollIntoViewOptions {\n /** Whether the element should scroll into view automatically. Defaults to true. */\n enabled?: boolean | Accessor<boolean>;\n /** Delay in milliseconds before executing scrollIntoView. Defaults to 0. */\n delay?: number;\n}\n\n/**\n * SolidJS reactive primitive for scrolling a target element into view smooth or auto behavior.\n */\nexport function createScrollIntoView(\n target: HTMLElement | Accessor<HTMLElement | null | undefined> | null | undefined,\n options: CreateScrollIntoViewOptions = {}\n): void {\n const getTarget = (): HTMLElement | null | undefined => {\n if (typeof target === \"function\") {\n return target();\n }\n return target;\n };\n\n const isEnabled = (): boolean => {\n if (typeof options.enabled === \"function\") {\n return options.enabled();\n }\n return options.enabled ?? true;\n };\n\n createEffect(() => {\n if (!isEnabled()) return;\n\n const el = getTarget();\n if (!el || typeof window === \"undefined\") return;\n\n const scrollOptions: ScrollIntoViewOptions = {\n behavior: options.behavior ?? \"smooth\",\n block: options.block ?? \"nearest\",\n inline: options.inline ?? \"nearest\",\n };\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n if (options.delay && options.delay > 0) {\n timer = setTimeout(() => {\n el.scrollIntoView(scrollOptions);\n }, options.delay);\n } else {\n el.scrollIntoView(scrollOptions);\n }\n\n onCleanup(() => {\n if (timer) clearTimeout(timer);\n });\n });\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createScrollPosition",
|
|
4
4
|
"description": "SolidJS reactive primitive for tracking scroll position, scroll direction, and container bounds",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-scroll-position.ts",
|
|
9
|
+
"content": "import { createEffect, createSignal, onCleanup, type Accessor } from \"solid-js\";\n\nexport type ScrollDirection = \"up\" | \"down\" | \"left\" | \"right\" | \"none\";\n\nexport interface CreateScrollPositionOptions {\n /** Target element to observe scroll events on. Defaults to window. */\n target?: HTMLElement | Window | Accessor<HTMLElement | Window | undefined>;\n}\n\nexport interface CreateScrollPositionReturn {\n /** Accessor for horizontal scroll position (scrollLeft / pageXOffset) */\n x: Accessor<number>;\n /** Accessor for vertical scroll position (scrollTop / pageYOffset) */\n y: Accessor<number>;\n /** Accessor indicating if element is actively scrolling */\n isScrolling: Accessor<boolean>;\n /** Accessor for current scroll direction ('up', 'down', 'left', 'right', 'none') */\n direction: Accessor<ScrollDirection>;\n /** Accessor indicating if scroll is at top (y <= 0) */\n isAtTop: Accessor<boolean>;\n /** Accessor indicating if scroll is at bottom of container */\n isAtBottom: Accessor<boolean>;\n /** Function to programmatically scroll target element */\n scrollTo: (options: ScrollToOptions) => void;\n}\n\n/**\n * SolidJS reactive primitive for tracking target element or window scroll position and scroll metrics.\n *\n * @param options Configuration options including target element.\n */\nexport function createScrollPosition(\n options: CreateScrollPositionOptions = {}\n): CreateScrollPositionReturn {\n const [x, setX] = createSignal(0);\n const [y, setY] = createSignal(0);\n const [isScrolling, setIsScrolling] = createSignal(false);\n const [direction, setDirection] = createSignal<ScrollDirection>(\"none\");\n const [isAtTop, setIsAtTop] = createSignal(true);\n const [isAtBottom, setIsAtBottom] = createSignal(false);\n\n let scrollTimeout: ReturnType<typeof setTimeout> | undefined;\n let lastX = 0;\n let lastY = 0;\n\n const getTarget = (): HTMLElement | Window | undefined => {\n if (typeof window === \"undefined\") return undefined;\n if (!options.target) return window;\n if (typeof options.target === \"function\") {\n return (options.target as Accessor<HTMLElement | Window | undefined>)();\n }\n return options.target;\n };\n\n const updateScroll = () => {\n const target = getTarget();\n if (!target) return;\n\n let currentX = 0;\n let currentY = 0;\n let maxScrollY = 0;\n\n if (target === window) {\n currentX = window.scrollX || window.pageXOffset;\n currentY = window.scrollY || window.pageYOffset;\n maxScrollY = document.documentElement.scrollHeight - window.innerHeight;\n } else {\n const el = target as HTMLElement;\n currentX = el.scrollLeft;\n currentY = el.scrollTop;\n maxScrollY = el.scrollHeight - el.clientHeight;\n }\n\n // Determine direction\n const deltaX = currentX - lastX;\n const deltaY = currentY - lastY;\n\n if (Math.abs(deltaY) > Math.abs(deltaX)) {\n if (deltaY > 0) setDirection(\"down\");\n else if (deltaY < 0) setDirection(\"up\");\n } else if (Math.abs(deltaX) > 0) {\n if (deltaX > 0) setDirection(\"right\");\n else if (deltaX < 0) setDirection(\"left\");\n }\n\n lastX = currentX;\n lastY = currentY;\n\n setX(currentX);\n setY(currentY);\n setIsAtTop(currentY <= 0);\n setIsAtBottom(maxScrollY > 0 && currentY >= maxScrollY - 1);\n setIsScrolling(true);\n\n if (scrollTimeout) clearTimeout(scrollTimeout);\n scrollTimeout = setTimeout(() => {\n setIsScrolling(false);\n }, 150);\n };\n\n createEffect(() => {\n const target = getTarget();\n if (!target) return;\n\n updateScroll();\n\n target.addEventListener(\"scroll\", updateScroll, { passive: true });\n onCleanup(() => {\n target.removeEventListener(\"scroll\", updateScroll);\n if (scrollTimeout) clearTimeout(scrollTimeout);\n });\n });\n\n const scrollTo = (scrollOptions: ScrollToOptions) => {\n const target = getTarget();\n if (!target) return;\n target.scrollTo(scrollOptions);\n };\n\n return {\n x,\n y,\n isScrolling,\n direction,\n isAtTop,\n isAtBottom,\n scrollTo,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createLocalStorage",
|
|
4
4
|
"description": "SolidJS reactive primitives for Web Storage state synchronization across components and browser tabs",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-storage.ts",
|
|
9
|
+
"content": "import { createSignal, onMount, onCleanup, type Accessor } from \"solid-js\";\n\nexport type StorageType = \"local\" | \"session\";\n\n/**\n * Helper to safely read item from Web Storage.\n */\nfunction readStorage<T>(key: string, storage: Storage | undefined, fallback: T): T {\n if (!storage) return fallback;\n try {\n const item = storage.getItem(key);\n return item !== null ? JSON.parse(item) : fallback;\n } catch (error) {\n console.warn(`[nikala-ui/hooks] Error reading storage key \"${key}\":`, error);\n return fallback;\n }\n}\n\n/**\n * SolidJS reactive primitive for Web Storage (localStorage / sessionStorage) synchronization.\n *\n * @param key Storage key name.\n * @param initialValue Default initial value if key doesn't exist.\n * @param type Storage type: \"local\" (default) or \"session\".\n */\nexport function createStorage<T>(\n key: string,\n initialValue: T | Accessor<T>,\n type: StorageType = \"local\"\n): [value: Accessor<T>, setValue: (val: T | ((prev: T) => T)) => void, remove: () => void] {\n const getStorage = (): Storage | undefined => {\n if (typeof window === \"undefined\") return undefined;\n return type === \"local\" ? window.localStorage : window.sessionStorage;\n };\n\n const getFallback = (): T => (typeof initialValue === \"function\" ? (initialValue as Accessor<T>)() : initialValue);\n\n const [value, setInternalValue] = createSignal<T>(getFallback());\n\n const setValue = (val: T | ((prev: T) => T)) => {\n const storage = getStorage();\n const currentValue = value();\n const nextValue = typeof val === \"function\" ? (val as (prev: T) => T)(currentValue) : val;\n\n setInternalValue(() => nextValue);\n\n if (storage) {\n try {\n storage.setItem(key, JSON.stringify(nextValue));\n } catch (error) {\n console.warn(`[nikala-ui/hooks] Error setting storage key \"${key}\":`, error);\n }\n }\n };\n\n const remove = () => {\n const storage = getStorage();\n setInternalValue(() => getFallback());\n if (storage) {\n storage.removeItem(key);\n }\n };\n\n onMount(() => {\n if (typeof window === \"undefined\") return;\n\n const storage = getStorage();\n if (storage) {\n const stored = readStorage<T>(key, storage, getFallback());\n setInternalValue(() => stored);\n }\n\n const handleStorageChange = (event: StorageEvent) => {\n if (event.key === key) {\n setInternalValue(() => (event.newValue !== null ? JSON.parse(event.newValue) : getFallback()));\n }\n };\n\n window.addEventListener(\"storage\", handleStorageChange);\n onCleanup(() => {\n window.removeEventListener(\"storage\", handleStorageChange);\n });\n });\n\n return [value, setValue, remove];\n}\n\n/**\n * SolidJS reactive primitive for localStorage synchronization across components and browser tabs.\n */\nexport function createLocalStorage<T>(\n key: string,\n initialValue: T | Accessor<T>\n): [value: Accessor<T>, setValue: (val: T | ((prev: T) => T)) => void, remove: () => void] {\n return createStorage<T>(key, initialValue, \"local\");\n}\n\n/**\n * SolidJS reactive primitive for sessionStorage synchronization.\n */\nexport function createSessionStorage<T>(\n key: string,\n initialValue: T | Accessor<T>\n): [value: Accessor<T>, setValue: (val: T | ((prev: T) => T)) => void, remove: () => void] {\n return createStorage<T>(key, initialValue, \"session\");\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createTimer",
|
|
4
4
|
"description": "SolidJS reactive primitives for recurring interval ticks and formatted countdown timers",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-timer.ts",
|
|
9
|
+
"content": "import { createEffect, createSignal, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateTimerOptions {\n /** Whether the timer starts running automatically on mount. Defaults to false. */\n autostart?: boolean;\n}\n\nexport interface CreateTimerReturn {\n /** Accessor indicating if timer is actively running */\n isRunning: Accessor<boolean>;\n /** Function to start or resume the timer */\n start: () => void;\n /** Function to pause/stop the timer */\n stop: () => void;\n /** Function to reset and restart the timer */\n reset: () => void;\n /** Function to toggle running state */\n toggle: () => void;\n}\n\n/**\n * SolidJS reactive primitive for recurring interval timers.\n *\n * @param intervalMs Interval duration in milliseconds.\n * @param callback Function to execute on each interval tick.\n * @param options Configuration options including autostart.\n */\nexport function createTimer(\n intervalMs: number | Accessor<number>,\n callback: () => void,\n options: CreateTimerOptions = {}\n): CreateTimerReturn {\n const [isRunning, setIsRunning] = createSignal<boolean>(options.autostart ?? false);\n let timerId: ReturnType<typeof setInterval> | undefined;\n\n const getInterval = () => (typeof intervalMs === \"function\" ? intervalMs() : intervalMs);\n\n const stop = () => {\n if (timerId) {\n clearInterval(timerId);\n timerId = undefined;\n }\n setIsRunning(false);\n };\n\n const start = () => {\n stop();\n const delay = getInterval();\n if (delay <= 0) return;\n\n setIsRunning(true);\n timerId = setInterval(() => {\n callback();\n }, delay);\n };\n\n const reset = () => {\n start();\n };\n\n const toggle = () => {\n if (isRunning()) {\n stop();\n } else {\n start();\n }\n };\n\n createEffect(() => {\n if (isRunning()) {\n start();\n }\n });\n\n onCleanup(() => {\n stop();\n });\n\n return {\n isRunning,\n start,\n stop,\n reset,\n toggle,\n };\n}\n\nexport interface CreateCountdownOptions extends CreateTimerOptions {\n /** Callback fired when countdown reaches zero */\n onComplete?: () => void;\n}\n\nexport interface CreateCountdownReturn extends CreateTimerReturn {\n /** Accessor for remaining seconds */\n remainingSeconds: Accessor<number>;\n /** Accessor for formatted time string (MM:SS) */\n formatted: Accessor<string>;\n}\n\n/**\n * SolidJS reactive primitive for countdown timers.\n *\n * @param durationSeconds Total countdown duration in seconds.\n * @param options Configuration options including autostart and onComplete callback.\n */\nexport function createCountdown(\n durationSeconds: number | Accessor<number>,\n options: CreateCountdownOptions = {}\n): CreateCountdownReturn {\n const getInitialDuration = () =>\n typeof durationSeconds === \"function\" ? durationSeconds() : durationSeconds;\n\n const [remaining, setRemaining] = createSignal<number>(getInitialDuration());\n\n const timer = createTimer(\n 1000,\n () => {\n setRemaining((prev) => {\n if (prev <= 1) {\n timer.stop();\n options.onComplete?.();\n return 0;\n }\n return prev - 1;\n });\n },\n { autostart: options.autostart }\n );\n\n const reset = () => {\n setRemaining(getInitialDuration());\n timer.start();\n };\n\n const formatted = (): string => {\n const total = remaining();\n const minutes = Math.floor(total / 60);\n const seconds = total % 60;\n const mm = String(minutes).padStart(2, \"0\");\n const ss = String(seconds).padStart(2, \"0\");\n return `${mm}:${ss}`;\n };\n\n return {\n ...timer,\n remainingSeconds: remaining,\n formatted,\n reset,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createUndoRedo",
|
|
4
4
|
"description": "SolidJS reactive primitive for undo/redo state history management, history stack tracking, and reverting actions",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-undo-redo.ts",
|
|
9
|
+
"content": "import { createSignal, type Accessor } from \"solid-js\";\n\nexport interface CreateUndoRedoOptions<T> {\n /** Maximum number of history states to retain. Defaults to 50. */\n maxHistory?: number;\n}\n\nexport interface CreateUndoRedoReturn<T> {\n /** Signal containing the current state value. */\n state: Accessor<T>;\n /** Update state value and append to history. */\n set: (nextState: T | ((prev: T) => T)) => void;\n /** Revert to previous state history entry. */\n undo: () => void;\n /** Advance to next state history entry. */\n redo: () => void;\n /** Signal indicating whether undo is available. */\n canUndo: Accessor<boolean>;\n /** Signal indicating whether redo is available. */\n canRedo: Accessor<boolean>;\n /** History stack of past states. */\n history: Accessor<T[]>;\n /** Reset history to initial state value. */\n reset: (initialState?: T) => void;\n}\n\n/**\n * SolidJS reactive primitive for undo/redo state history management.\n */\nexport function createUndoRedo<T>(\n initialValue: T | Accessor<T>,\n options: CreateUndoRedoOptions<T> = {}\n): CreateUndoRedoReturn<T> {\n const getInitial = (): T => {\n return typeof initialValue === \"function\"\n ? (initialValue as Accessor<T>)()\n : initialValue;\n };\n\n const maxHistory = options.maxHistory ?? 50;\n\n const [history, setHistory] = createSignal<T[]>([getInitial()]);\n const [pointer, setPointer] = createSignal<number>(0);\n\n const state = (): T => history()[pointer()] ?? getInitial();\n\n const canUndo = (): boolean => pointer() > 0;\n const canRedo = (): boolean => pointer() < history().length - 1;\n\n const set = (nextState: T | ((prev: T) => T)): void => {\n const current = state();\n const resolved =\n typeof nextState === \"function\"\n ? (nextState as (prev: T) => T)(current)\n : nextState;\n\n if (Object.is(resolved, current)) return;\n\n /* Slice history up to current pointer and push new state */\n const sliced = history().slice(0, pointer() + 1);\n const updated = [...sliced, resolved];\n\n /* Trim to maxHistory limit */\n if (updated.length > maxHistory) {\n updated.shift();\n }\n\n setHistory(updated);\n setPointer(updated.length - 1);\n };\n\n const undo = (): void => {\n if (canUndo()) {\n setPointer((p) => p - 1);\n }\n };\n\n const redo = (): void => {\n if (canRedo()) {\n setPointer((p) => p + 1);\n }\n };\n\n const reset = (newInitial?: T): void => {\n const init = newInitial !== undefined ? newInitial : getInitial();\n setHistory([init]);\n setPointer(0);\n };\n\n return {\n state,\n set,\n undo,\n redo,\n canUndo,\n canRedo,\n history,\n reset,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createWebNotification",
|
|
4
4
|
"description": "SolidJS reactive primitive for sending browser desktop notifications and managing notification permissions",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-web-notification.ts",
|
|
9
|
+
"content": "import { createSignal, createEffect, type Accessor } from \"solid-js\";\n\nexport interface CreateWebNotificationOptions extends NotificationOptions {\n /** Title of the notification. */\n title?: string;\n /** Callback fired when notification is clicked. */\n onClick?: (event: Event) => void;\n /** Callback fired when notification is closed. */\n onClose?: (event: Event) => void;\n /** Callback fired when notification error occurs. */\n onError?: (event: Event) => void;\n /** Callback fired when notification is shown. */\n onShow?: (event: Event) => void;\n}\n\nexport interface CreateWebNotificationReturn {\n /** Signal accessor containing current Notification permission state. */\n permission: Accessor<NotificationPermission>;\n /** Signal accessor indicating whether Web Notifications API is supported in browser environment. */\n isSupported: Accessor<boolean>;\n /** Function to show a web notification. */\n show: (overrideTitle?: string, overrideOptions?: NotificationOptions) => Notification | null;\n /** Request notification permission from browser. */\n requestPermission: () => Promise<NotificationPermission>;\n /** Close active notification. */\n close: () => void;\n}\n\n/**\n * SolidJS reactive primitive for sending browser desktop notifications and managing notification permissions.\n */\nexport function createWebNotification(\n defaultOptions: CreateWebNotificationOptions = {}\n): CreateWebNotificationReturn {\n const [permission, setPermission] = createSignal<NotificationPermission>(\"default\");\n\n const isSupported = (): boolean =>\n typeof window !== \"undefined\" &&\n \"Notification\" in window;\n\n let activeNotification: Notification | null = null;\n\n const updatePermission = (): void => {\n if (isSupported()) {\n setPermission(Notification.permission);\n } else {\n setPermission(\"denied\");\n }\n };\n\n const requestPermission = async (): Promise<NotificationPermission> => {\n if (!isSupported()) return \"denied\";\n\n try {\n const result = await Notification.requestPermission();\n setPermission(result);\n return result;\n } catch {\n updatePermission();\n return permission();\n }\n };\n\n const close = (): void => {\n if (activeNotification) {\n activeNotification.close();\n activeNotification = null;\n }\n };\n\n const show = (\n overrideTitle?: string,\n overrideOptions?: NotificationOptions\n ): Notification | null => {\n if (!isSupported() || permission() !== \"granted\") return null;\n\n const title = overrideTitle ?? defaultOptions.title ?? \"Notification\";\n const options: NotificationOptions = {\n ...defaultOptions,\n ...overrideOptions,\n };\n\n close();\n\n try {\n const notification = new Notification(title, options);\n activeNotification = notification;\n\n if (defaultOptions.onClick) notification.onclick = (e) => defaultOptions.onClick?.(e);\n if (defaultOptions.onClose) notification.onclose = (e) => defaultOptions.onClose?.(e);\n if (defaultOptions.onError) notification.onerror = (e) => defaultOptions.onError?.(e);\n if (defaultOptions.onShow) notification.onshow = (e) => defaultOptions.onShow?.(e);\n\n return notification;\n } catch {\n return null;\n }\n };\n\n createEffect(() => {\n updatePermission();\n });\n\n return {\n permission,\n isSupported,\n show,\n requestPermission,\n close,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createWebSocket",
|
|
4
4
|
"description": "SolidJS reactive primitive for WebSocket client connections, auto-reconnection, and message passing",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-websocket.ts",
|
|
9
|
+
"content": "import { createSignal, createEffect, onCleanup, type Accessor } from \"solid-js\";\n\nexport type WebSocketReadyState = \"CONNECTING\" | \"OPEN\" | \"CLOSING\" | \"CLOSED\";\n\nexport interface CreateWebSocketOptions {\n /** Subprotocol or list of subprotocols. */\n protocols?: string | string[];\n /** Whether to automatically reconnect upon disconnect. Defaults to true. */\n autoReconnect?: boolean;\n /** Reconnection delay in milliseconds. Defaults to 3000ms. */\n reconnectInterval?: number;\n /** Maximum reconnection attempts. Defaults to 5. */\n maxReconnectAttempts?: number;\n /** Whether to open connection immediately upon initialization. Defaults to true. */\n immediate?: boolean;\n /** Callback fired when WebSocket connection opens. */\n onConnected?: (ws: WebSocket) => void;\n /** Callback fired when WebSocket connection closes. */\n onDisconnected?: (event: CloseEvent) => void;\n /** Callback fired when WebSocket receives a message. */\n onMessage?: (event: MessageEvent) => void;\n /** Callback fired when WebSocket encounters an error. */\n onError?: (event: Event) => void;\n}\n\nexport interface CreateWebSocketReturn<T = unknown> {\n /** Signal accessor containing latest received message data (parsed if JSON). */\n data: Accessor<T | null>;\n /** Signal accessor containing current WebSocket ready state. */\n readyState: Accessor<WebSocketReadyState>;\n /** Signal accessor containing last raw MessageEvent. */\n lastMessage: Accessor<MessageEvent | null>;\n /** Send string data or object payload (auto JSON stringified). */\n send: (data: string | object | ArrayBufferLike | Blob) => boolean;\n /** Open or reconnect WebSocket connection. */\n open: () => void;\n /** Close active WebSocket connection. */\n close: (code?: number, reason?: string) => void;\n /** Signal accessor indicating whether WebSocket is supported in browser environment. */\n isSupported: Accessor<boolean>;\n}\n\n/**\n * SolidJS reactive primitive for WebSocket client connections, auto-reconnection, and message passing.\n */\nexport function createWebSocket<T = unknown>(\n url: string | Accessor<string>,\n options: CreateWebSocketOptions = {}\n): CreateWebSocketReturn<T> {\n const [data, setData] = createSignal<T | null>(null);\n const [lastMessage, setLastMessage] = createSignal<MessageEvent | null>(null);\n const [readyState, setReadyState] = createSignal<WebSocketReadyState>(\"CLOSED\");\n\n const getUrl = (): string => (typeof url === \"function\" ? url() : url);\n\n const isSupported = (): boolean =>\n typeof window !== \"undefined\" && \"WebSocket\" in window;\n\n let ws: WebSocket | null = null;\n let reconnectCount = 0;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\n const mapReadyState = (state: number): WebSocketReadyState => {\n switch (state) {\n case WebSocket.CONNECTING:\n return \"CONNECTING\";\n case WebSocket.OPEN:\n return \"OPEN\";\n case WebSocket.CLOSING:\n return \"CLOSING\";\n case WebSocket.CLOSED:\n default:\n return \"CLOSED\";\n }\n };\n\n const close = (code?: number, reason?: string): void => {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (ws) {\n const socket = ws;\n ws = null;\n socket.close(code, reason);\n setReadyState(\"CLOSED\");\n }\n };\n\n const send = (payload: string | object | ArrayBufferLike | Blob): boolean => {\n if (!ws || ws.readyState !== WebSocket.OPEN) return false;\n\n try {\n if (typeof payload === \"object\" && !(payload instanceof ArrayBuffer) && !(payload instanceof Blob)) {\n ws.send(JSON.stringify(payload));\n } else {\n ws.send(payload as any);\n }\n return true;\n } catch {\n return false;\n }\n };\n\n const open = (): void => {\n if (!isSupported()) return;\n\n if (ws) {\n ws.close();\n ws = null;\n }\n\n setReadyState(\"CONNECTING\");\n\n try {\n const targetUrl = getUrl();\n const socket = new WebSocket(targetUrl, options.protocols);\n ws = socket;\n\n socket.onopen = () => {\n reconnectCount = 0;\n setReadyState(\"OPEN\");\n options.onConnected?.(socket);\n };\n\n socket.onmessage = (event: MessageEvent) => {\n setLastMessage(() => event);\n try {\n const parsed = JSON.parse(event.data);\n setData(() => parsed);\n } catch {\n setData(() => event.data as unknown as T);\n }\n options.onMessage?.(event);\n };\n\n socket.onerror = (event: Event) => {\n options.onError?.(event);\n };\n\n socket.onclose = (event: CloseEvent) => {\n setReadyState(\"CLOSED\");\n ws = null;\n options.onDisconnected?.(event);\n\n if (\n (options.autoReconnect ?? false) &&\n reconnectCount < (options.maxReconnectAttempts ?? 5)\n ) {\n reconnectCount++;\n reconnectTimer = setTimeout(open, options.reconnectInterval ?? 3000);\n }\n };\n } catch {\n setReadyState(\"CLOSED\");\n ws = null;\n }\n };\n\n createEffect(() => {\n if (options.immediate ?? true) {\n open();\n }\n\n onCleanup(() => {\n close();\n });\n });\n\n return {\n data,\n readyState,\n lastMessage,\n send,\n open,\n close,\n isSupported,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
"title": "createWindowSize",
|
|
4
4
|
"description": "SolidJS reactive primitive for tracking window viewport inner width and height",
|
|
5
5
|
"type": "registry:hook",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-window-size.ts",
|
|
9
|
+
"content": "import { createSignal, onMount, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateWindowSizeReturn {\n /** Accessor for current window inner width in pixels */\n width: Accessor<number>;\n /** Accessor for current window inner height in pixels */\n height: Accessor<number>;\n}\n\n/**\n * SolidJS reactive primitive for tracking window viewport dimensions (width and height).\n */\nexport function createWindowSize(): CreateWindowSizeReturn {\n const [width, setWidth] = createSignal<number>(\n typeof window !== \"undefined\" ? window.innerWidth : 0\n );\n const [height, setHeight] = createSignal<number>(\n typeof window !== \"undefined\" ? window.innerHeight : 0\n );\n\n onMount(() => {\n if (typeof window === \"undefined\") return;\n\n const handleResize = () => {\n setWidth(window.innerWidth);\n setHeight(window.innerHeight);\n };\n\n handleResize();\n\n window.addEventListener(\"resize\", handleResize);\n onCleanup(() => {\n window.removeEventListener(\"resize\", handleResize);\n });\n });\n\n return {\n width,\n height,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
10
13
|
}
|