Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9436206

Browse files
committedOct 28, 2024·
feat: add svelte 5 package
1 parent cd07692 commit 9436206

File tree

8 files changed

+356
-2
lines changed

8 files changed

+356
-2
lines changed
 

‎package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
"packages/react-inertia",
88
"packages/vue",
99
"packages/vue-inertia",
10-
"packages/alpine"
10+
"packages/alpine",
11+
"packages/svelte"
1112
],
1213
"scripts": {
13-
"watch": "npx concurrently \"npm run watch --workspace=packages/core\" \"npm run watch --workspace=packages/react\" \"npm run watch --workspace=packages/react-inertia\" \"npm run watch --workspace=packages/vue\" \"npm run watch --workspace=packages/vue-inertia\" \"npm run watch --workspace=packages/alpine\" --names=core,react,react-inertia,vue,vue-inertia,alpine",
14+
"watch": "npx concurrently \"npm run watch --workspace=packages/core\" \"npm run watch --workspace=packages/react\" \"npm run watch --workspace=packages/react-inertia\" \"npm run watch --workspace=packages/vue\" \"npm run watch --workspace=packages/vue-inertia\" \"npm run watch --workspace=packages/alpine\" \"npm run watch --workspace=packages/svelte\" --names=core,react,react-inertia,vue,vue-inertia,alpine,svelte",
1415
"build": "npm run build --workspaces",
1516
"link": "npm link --workspaces",
1617
"typeCheck": "npm run typeCheck --workspaces",

‎packages/svelte/.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
node_modules
2+
3+
# Output
4+
.output
5+
.vercel
6+
/.svelte-kit
7+
/build
8+
/dist
9+
10+
# OS
11+
.DS_Store
12+
Thumbs.db
13+
14+
# Env
15+
.env
16+
.env.*
17+
!.env.example
18+
!.env.test
19+
20+
# Vite
21+
vite.config.js.timestamp-*
22+
vite.config.ts.timestamp-*
23+
24+
pnpm-lock.yaml

‎packages/svelte/LICENSE.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Taylor Otwell
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

‎packages/svelte/README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Laravel Precognition
2+
3+
<a href="https://github.com/laravel/precognition/actions"><img src="https://github.com/laravel/precognition/workflows/tests/badge.svg" alt="Test Status"></a>
4+
<a href="https://github.com/laravel/precognition/actions"><img src="https://github.com/laravel/precognition/workflows/build/badge.svg" alt="Build Status"></a>
5+
<a href="https://www.npmjs.com/package/laravel-precognition"><img src="https://img.shields.io/npm/dt/laravel-precognition" alt="Total Downloads"></a>
6+
<a href="https://www.npmjs.com/package/laravel-precognition"><img src="https://img.shields.io/npm/v/laravel-precognition" alt="Latest Stable Version"></a>
7+
<a href="https://www.npmjs.com/package/laravel-precognition"><img src="https://img.shields.io/npm/l/laravel-precognition" alt="License"></a>
8+
9+
## Introduction
10+
11+
Laravel Precognition allows you to anticipate the outcome of a future HTTP request. One of the primary use cases of Precognition is the ability to provide "live" validation in your frontend application.
12+
13+
## Official Documentation
14+
15+
Documentation for Laravel Precognition can be found on the [Laravel website](https://laravel.com/docs/precognition).
16+
17+
## Contributing
18+
19+
Thank you for considering contributing to Laravel Precognition! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
20+
21+
## Code of Conduct
22+
23+
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
24+
25+
## Security Vulnerabilities
26+
27+
Please review [our security policy](https://github.com/laravel/precognition/security/policy) on how to report security vulnerabilities.
28+
29+
## License
30+
31+
Laravel Precognition is open-sourced software licensed under the [MIT license](LICENSE.md).

‎packages/svelte/package.json

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "laravel-precognition-svelte",
3+
"version": "0.0.1",
4+
"description": "Laravel Precognition (Svelte).",
5+
"keywords": [
6+
"laravel",
7+
"precognition",
8+
"svelte"
9+
],
10+
"homepage": "https://github.com/laravel/precognition",
11+
"type": "module",
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/laravel/precognition"
15+
},
16+
"license": "MIT",
17+
"author": "Laravel",
18+
"main": "dist/index.svelte.js",
19+
"files": [
20+
"/dist"
21+
],
22+
"scripts": {
23+
"watch": "rm -rf dist && tsc --watch",
24+
"build": "rm -rf dist && tsc",
25+
"typeCheck": "tsc --noEmit",
26+
"prepublishOnly": "npm run build",
27+
"version": "npm pkg set dependencies.laravel-precognition=$npm_package_version"
28+
},
29+
"peerDependencies": {
30+
"svelte": "^5.0.0"
31+
},
32+
"dependencies": {
33+
"laravel-precognition": "0.5.11",
34+
"lodash-es": "^4.17.21"
35+
},
36+
"devDependencies": {
37+
"@types/lodash-es": "^4.17.12",
38+
"typescript": "^5.0.0"
39+
}
40+
}

‎packages/svelte/src/index.svelte.ts

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { get, cloneDeep, set } from 'lodash-es'
2+
3+
import {
4+
client,
5+
createValidator,
6+
type RequestMethod,
7+
resolveName,
8+
toSimpleValidationErrors,
9+
type ValidationConfig,
10+
resolveUrl,
11+
resolveMethod,
12+
} from 'laravel-precognition'
13+
14+
import { Form } from './types.js'
15+
16+
export { client }
17+
export const useForm = <Data extends Record<string, unknown>>(method: RequestMethod | (() => RequestMethod), url: string | (() => string), inputs: Data, config: ValidationConfig = {}): Data & Form<Data> => {
18+
/**
19+
* The original data.
20+
*/
21+
const originalData = cloneDeep(inputs)
22+
23+
/**
24+
* The original input names.
25+
*/
26+
const originalInputs: (keyof Data)[] = Object.keys(originalData)
27+
28+
/**
29+
* Reactive valid state.
30+
*/
31+
// @ts-ignore
32+
let valid = $state<string[]>([])
33+
34+
/**
35+
* Reactive touched state.
36+
*/
37+
// @ts-ignore
38+
let touched = $state<string[]>([])
39+
40+
/**
41+
* Reactive errors.
42+
*/
43+
// @ts-ignore
44+
let errors = $state<Record<string, any>>({})
45+
46+
/**
47+
* Reactive hasErrors.
48+
*/
49+
// @ts-ignore
50+
let hasErrors = $state<boolean>(false)
51+
52+
/**
53+
* Reactive Validating.
54+
*/
55+
// @ts-ignore
56+
let validating = $state<boolean>(false)
57+
58+
/**
59+
* Reactive Processing.
60+
*/
61+
// @ts-ignore
62+
let processing = $state<boolean>(false)
63+
64+
/**
65+
* Reactive Data state
66+
*/
67+
// @ts-ignore
68+
const data = $state<Data>(cloneDeep(originalData))
69+
70+
/**
71+
* The validator instance.
72+
*/
73+
const validator = createValidator((client) => client[resolveMethod(method)](resolveUrl(url), form.getData(), config), originalData)
74+
.on('validatingChanged', () => {
75+
validating = validator.validating()
76+
})
77+
.on('validatedChanged', () => {
78+
valid = validator.valid()
79+
})
80+
.on('touchedChanged', () => {
81+
touched = validator.touched()
82+
})
83+
.on('errorsChanged', () => {
84+
hasErrors = validator.hasErrors()
85+
errors = toSimpleValidationErrors(validator.errors())
86+
valid = validator.valid()
87+
})
88+
89+
/**
90+
* Resolve the config for a form submission.
91+
*/
92+
const resolveSubmitConfig = (config: any) => ({
93+
...config,
94+
precognitive: false,
95+
onStart: () => {
96+
processing = true
97+
config.onStart?.()
98+
},
99+
onFinish: () => {
100+
processing = false
101+
config.onFinish?.()
102+
},
103+
onValidationError: (response: any, error: any) => {
104+
validator.setErrors(response.data.errors)
105+
return config.onValidationError
106+
? config.onValidationError(response)
107+
// @ts-ignore
108+
: Promise.reject(error)
109+
},
110+
})
111+
112+
/**
113+
* Create a new form instance.
114+
*/
115+
const form: Record<string, any> = {
116+
data,
117+
setData(newData: Record<string, unknown>) {
118+
Object.keys(newData).forEach((input) => {
119+
// @ts-ignore
120+
data[input] = newData[input]
121+
})
122+
return form
123+
},
124+
touched(name: string) {
125+
return touched.includes(resolveName(name))
126+
},
127+
touch(name: string) {
128+
validator.touch(name)
129+
return form
130+
},
131+
validate(name: string | undefined, config: any) {
132+
if (name === undefined) {
133+
validator.validate(config)
134+
} else {
135+
validator.validate(name, get(data, name), config)
136+
}
137+
return form
138+
},
139+
valid(name: string) {
140+
return valid.includes(resolveName(name))
141+
},
142+
invalid(name: string) {
143+
return typeof form.errors[name] !== 'undefined'
144+
},
145+
setErrors(newErrors: any) {
146+
validator.setErrors(newErrors)
147+
return form
148+
},
149+
forgetError(name: string) {
150+
validator.forgetError(name)
151+
return form
152+
},
153+
reset(...names: string[]) {
154+
const original = cloneDeep(originalData)
155+
156+
if (names.length === 0) {
157+
originalInputs.forEach((name) => (data[name] = original[name]))
158+
} else {
159+
names.forEach((name : string) => set(data, name, get(original, name)))
160+
}
161+
162+
validator.reset(...names)
163+
164+
return form
165+
},
166+
setValidationTimeout(duration: number) {
167+
validator.setTimeout(duration)
168+
return form
169+
},
170+
submit(config = {}) {
171+
return client[resolveMethod(method)](resolveUrl(url), form.getData(), resolveSubmitConfig(config))
172+
},
173+
validateFiles() {
174+
validator.validateFiles()
175+
return form
176+
},
177+
validator() {
178+
return validator
179+
},
180+
get validating() {
181+
return validating
182+
},
183+
get processing() {
184+
return processing
185+
},
186+
get errors() {
187+
return errors
188+
},
189+
get hasErrors() {
190+
return hasErrors
191+
},
192+
getData() {
193+
return cloneDeep(data)
194+
},
195+
}
196+
197+
return form as Data & Form<Data>
198+
}

‎packages/svelte/src/types.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { client, type RequestMethod, type ValidationConfig, type Config, type NamedInputEvent, type Validator } from 'laravel-precognition'
2+
export { client }
3+
export interface Form<Data extends Record<string, unknown>> {
4+
processing: boolean;
5+
validating: boolean;
6+
errors: Partial<Record<keyof Data, string>>;
7+
hasErrors: boolean;
8+
touched(name: keyof Data): boolean;
9+
touch(name: string | NamedInputEvent | Array<string>): Data & Form<Data>;
10+
data: Data;
11+
setData(data: Record<string, unknown>): Data & Form<Data>;
12+
valid(name: keyof Data): boolean;
13+
invalid(name: keyof Data): boolean;
14+
validate(name?: (keyof Data | NamedInputEvent) | ValidationConfig, config?: ValidationConfig): Data & Form<Data>;
15+
setErrors(errors: Partial<Record<keyof Data, string | string[]>>): Data & Form<Data>;
16+
forgetError(string: keyof Data | NamedInputEvent): Data & Form<Data>;
17+
setValidationTimeout(duration: number): Data & Form<Data>;
18+
submit(config?: Config): Promise<unknown>;
19+
reset(...keys: (keyof Partial<Data>)[]): Data & Form<Data>;
20+
validateFiles(): Data & Form<Data>;
21+
validator(): Validator;
22+
getData(): Data;
23+
}
24+
export declare const useForm: <Data extends Record<string, unknown>>(method: RequestMethod | (() => RequestMethod), url: string | (() => string), inputs: Data, config?: ValidationConfig) => Data & Form<Data>

‎packages/svelte/tsconfig.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"outDir": "./dist",
4+
"target": "ES2020",
5+
"module": "ES2020",
6+
"moduleResolution": "node",
7+
"resolveJsonModule": true,
8+
"strict": true,
9+
"declaration": true,
10+
"esModuleInterop": true
11+
},
12+
"include": [
13+
"./src/index.svelte.ts"
14+
]
15+
}

0 commit comments

Comments
 (0)
Please sign in to comment.