Skip to content

Commit 09b26ee

Browse files
committed
Complete solid adapter
1 parent a5db8a3 commit 09b26ee

9 files changed

Lines changed: 118 additions & 27 deletions

File tree

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
- [x] Props merging
1010
- [x] State remembering
1111
- [x] History encryption
12-
- [x] Server-side rendering
1312
- [x] Polling
14-
- [ ] Simple frontend framework adapters
13+
- [x] Server-side rendering
14+
- [ ] Precache (PWA)
15+
- [x] Svelte adapter
16+
- [x] Vue adapter
17+
- [x] SolidJS adapter
18+
- [ ] React adapter
19+
- [ ] Angular adapter

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default defineConfig([
99
tseslint.configs.recommended,
1010
{
1111
rules: {
12+
"@typescript-eslint/no-namespace": "off",
1213
'@typescript-eslint/no-explicit-any': 'off',
1314
'@typescript-eslint/no-unused-vars': ['warn', {
1415
argsIgnorePattern: '^_',

package.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
"peerDependencies": {
4545
"@bprogress/core": "^1.0.0",
4646
"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0",
47-
"vue": "^3.0.0"
47+
"vue": "^3.0.0",
48+
"solid-js": "^1.0.0"
4849
},
4950
"files": [
5051
"dist"
@@ -65,9 +66,9 @@
6566
"require": "./dist/server.cjs"
6667
},
6768
"./inertia": {
68-
"types": "./dist/extensions/inertia.d.ts",
69-
"import": "./dist/extensions/inertia.js",
70-
"require": "./dist/extensions/inertia.cjs"
69+
"types": "./dist/extensions/inertia/index.d.ts",
70+
"import": "./dist/extensions/inertia/index.js",
71+
"require": "./dist/extensions/inertia/index.cjs"
7172
},
7273
"./bprogress": {
7374
"types": "./dist/extensions/bprogress.d.ts",
@@ -83,6 +84,11 @@
8384
"types": "./dist/adapters/vue.d.ts",
8485
"import": "./dist/adapters/vue.js",
8586
"require": "./dist/adapters/vue.cjs"
87+
},
88+
"./solid-js": {
89+
"types": "./dist/adapters/solid-js.d.ts",
90+
"import": "./dist/adapters/solid-js.js",
91+
"require": "./dist/adapters/solid-js.cjs"
8692
}
8793
}
8894
}

src/adapters/solid-js.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { getPage, subscribe, useForm as useVortexForm, useRemember as useVortexRemember, Page, link as vortexLink, visible as vortexVisible } from '../index';
2+
import { type Signal } from "../signals";
3+
import { type Action } from '../dom';
4+
import { createEffect, createSignal, onCleanup } from "solid-js";
5+
import { createMutable, modifyMutable, reconcile } from "solid-js/store";
6+
7+
8+
type ExtractAccessorReturn<F> = F extends (
9+
node: any,
10+
accessor: () => infer R
11+
) => any ? R : never;
12+
13+
export const [usePage] = convertSignal({ get: getPage, subscribe } as Signal<Page>)
14+
15+
export const link = convertActionToDirective(vortexLink)
16+
17+
export const visible = convertActionToDirective(vortexVisible)
18+
19+
declare module "solid-js" {
20+
namespace JSX {
21+
interface Directives {
22+
link?: ExtractAccessorReturn<typeof link>
23+
visible?: ExtractAccessorReturn<typeof visible>
24+
}
25+
}
26+
}
27+
28+
export function useForm<T extends object>(data: T | (() => T), rememberKey?: string) {
29+
return convertSignalToMutable(useVortexForm(data, rememberKey))
30+
}
31+
32+
export function useRemember<T extends object>(data: T, key: string = 'default') {
33+
return convertSignalToMutable(useVortexRemember(data, key))
34+
}
35+
36+
function convertSignal<T>({ get, subscribe }: Signal<T>) {
37+
const signal = createSignal(get())
38+
subscribe(signal[1])
39+
return signal
40+
}
41+
42+
function convertSignalToMutable<T extends object>({ get, subscribe }: Signal<T>) {
43+
const mutable = createMutable(get())
44+
subscribe((data) => modifyMutable(mutable, reconcile(data)))
45+
return mutable
46+
}
47+
48+
function convertActionToDirective<E extends HTMLElement,T>(action: Action<E, T>) {
49+
return (node: E, accessor: () => T) => {
50+
const current = action(node, accessor())
51+
52+
if (current?.destroy) {
53+
onCleanup(current.destroy)
54+
}
55+
56+
if (current?.update) {
57+
createEffect(() => {
58+
current?.update?.(accessor())
59+
})
60+
} else {
61+
createEffect(() => {
62+
accessor()
63+
})
64+
}
65+
}
66+
}

src/adapters/svelte.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getPage, subscribe, useForm as useVortexForm, useRemember as useVortexRemember } from '../index'
2-
import { readable, Writable } from 'svelte/store'
3-
import { Signal } from '../signals'
2+
import { readable, type Writable } from 'svelte/store'
3+
import { type Signal } from '../signals'
44
export { link, visible } from '../index'
55

66
export const page = readable(getPage(), subscribe)

src/adapters/vue.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1-
import { getPage, Page, subscribe, useForm as useVortexForm, useRemember as useVortexRemember } from '../index'
1+
import { getPage, Page, subscribe, useForm as useVortexForm, useRemember as useVortexRemember, link as vortexLink, visible as vortexVisible } from '../index'
22
import { reactive, onBeforeUnmount, Reactive, Directive, Plugin } from 'vue'
3-
import { Signal } from '../signals'
4-
import { link as vortexLink, visible as vortexVisible, Action } from '../dom'
3+
import { type Signal } from '../signals'
4+
import { type Action } from '../dom'
55

66
const link = convertActionToDirective(vortexLink)
77
const visible = convertActionToDirective(vortexVisible)
88

9+
declare module '@vue/runtime-core' {
10+
export interface GlobalDirectives {
11+
link: typeof link
12+
visible: typeof visible
13+
}
14+
}
15+
916
export const vortex: Plugin = {
1017
install: (app) => app.directive('link', link).directive('visible', visible)
1118
}
1219

13-
export function usePage() {
20+
export function usePage(): Page {
1421
return convertSignalToReactive({ get: getPage, subscribe } as Signal<Page>)
1522
}
1623

src/client.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ export async function createVortex(setup: (el: HTMLElement, page: Page, hydrate:
2929

3030
const dispose = await setup(element, page, !!element.dataset?.ssr);
3131

32-
delete element.dataset.page
33-
delete element.dataset.ssr
34-
3532
return () => {
3633
if (dispose instanceof Function) {
3734
dispose();

src/dom.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ type PrefetchLinkConfig = {
1414
cacheFor?: number | string | (number | string)[]
1515
}
1616

17-
export const link: Action<HTMLElement, RouterRequestConfig & PrefetchLinkConfig> = (node, options = {}) => {
17+
export const link: Action<HTMLElement, RouterRequestConfig & PrefetchLinkConfig | boolean> = (node, options = true) => {
18+
if (options === true) {
19+
options = {}
20+
}
21+
1822
function mergeOptions(options: RouterRequestConfig & PrefetchLinkConfig): { options: RouterRequestConfig } & PrefetchLinkConfig {
1923
options.method = options.method || 'get'
2024
options.url = options.url || (node as HTMLAnchorElement).href || ''
@@ -46,7 +50,7 @@ export const link: Action<HTMLElement, RouterRequestConfig & PrefetchLinkConfig>
4650

4751
function navigate(event) {
4852
event.preventDefault()
49-
axios.request(options)
53+
axios.request(options as RouterRequestConfig & PrefetchLinkConfig)
5054
}
5155

5256
const prefetch = () => axios.request({ ...options, prefetch: config.cacheFor })
@@ -81,14 +85,18 @@ export const link: Action<HTMLElement, RouterRequestConfig & PrefetchLinkConfig>
8185
}
8286
}
8387

84-
let config = mergeOptions(options)
88+
let config = mergeOptions(options as RouterRequestConfig & PrefetchLinkConfig)
8589
reinstallPrefetchEvents()
8690

8791
node.addEventListener('click', navigate)
8892

8993
return {
9094
update(newOptions) {
91-
config = mergeOptions(newOptions)
95+
if (newOptions === true) {
96+
newOptions = {}
97+
}
98+
99+
config = mergeOptions(newOptions as RouterRequestConfig & PrefetchLinkConfig)
92100
reinstallPrefetchEvents()
93101
},
94102
destroy() {
@@ -98,16 +106,16 @@ export const link: Action<HTMLElement, RouterRequestConfig & PrefetchLinkConfig>
98106
}
99107

100108
type VisibleConfig = {
101-
vortex: VortexConfig,
109+
vortex: VortexConfig | boolean,
102110
buffer?: number,
103111
always?: boolean,
104112
}
105113

106-
export const visible: Action<HTMLElement, VisibleConfig | VortexConfig> = (node, rawOptions) => {
107-
function mergeOptions(options: VisibleConfig | VortexConfig): VisibleConfig {
108-
return !options.vortex
109-
? { buffer: 0, always: false, vortex: options }
110-
: { buffer: 0, always: false, ...options as VisibleConfig }
114+
export const visible: Action<HTMLElement, VisibleConfig | VortexConfig | boolean> = (node, rawOptions = true) => {
115+
function mergeOptions(options: VisibleConfig | VortexConfig | boolean): VisibleConfig {
116+
return options === true || !(options as VortexConfig).vortex
117+
? { buffer: 0, always: true, vortex: options }
118+
: { buffer: 0, always: true, ...options as VisibleConfig }
111119
}
112120

113121
let options: VisibleConfig = mergeOptions(rawOptions)

vite.config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ export default defineConfig({
2121
"index": resolve(__dirname, 'src/index.ts'),
2222
"server": resolve(__dirname, 'src/server.ts'),
2323
// Extensions
24-
"extensions/inertia": resolve(__dirname, 'src/extensions/inertia/index.ts'),
24+
"extensions/inertia/index": resolve(__dirname, 'src/extensions/inertia/index.ts'),
2525
"extensions/bprogress": resolve(__dirname, 'src/extensions/bprogress.ts'),
2626
// Adapters
2727
"adapters/svelte": resolve(__dirname, 'src/adapters/svelte.ts'),
2828
"adapters/vue": resolve(__dirname, 'src/adapters/vue.ts'),
29+
"adapters/solid-js": resolve(__dirname, 'src/adapters/solid-js.ts'),
2930
},
3031
},
3132
rollupOptions: {
32-
external: [...builtinModules, /^node:/, 'axios', /^\@bprogress\/core/, 'svelte', 'vue'],
33+
external: [...builtinModules, /^node:/, 'axios', /^\@bprogress\/core/, /^svelte/, 'vue', /^solid\-js/],
3334
}
3435
},
3536
})

0 commit comments

Comments
 (0)