12 Commits

Author SHA1 Message Date
Julien Valverdé
7aef7ae796 Form work
All checks were successful
Lint / lint (push) Successful in 17s
2025-04-17 01:09:01 +02:00
Julien Valverdé
1bfbeba934 Form work
Some checks failed
Lint / lint (push) Failing after 14s
2025-04-16 04:35:22 +02:00
Julien Valverdé
fc4295894f Form work
Some checks failed
Lint / lint (push) Failing after 15s
2025-04-16 00:44:01 +02:00
Julien Valverdé
ab0dce107d Form work
Some checks failed
Lint / lint (push) Failing after 15s
2025-04-15 23:55:50 +02:00
Julien Valverdé
9436602443 Form work
All checks were successful
Lint / lint (push) Successful in 59s
2025-04-15 04:25:06 +02:00
Julien Valverdé
66de31706c Form work
Some checks failed
Lint / lint (push) Failing after 14s
2025-04-15 01:32:48 +02:00
Julien Valverdé
8925fe6336 Guards work
All checks were successful
Lint / lint (push) Successful in 14s
2025-04-14 03:40:58 +02:00
Julien Valverdé
fe8ca23d37 Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-04-14 02:55:33 +02:00
Julien Valverdé
d48f20a59d Schema guards
All checks were successful
Lint / lint (push) Successful in 14s
2025-04-14 02:49:50 +02:00
Julien Valverdé
b7b4abcbe2 Merge branch 'next' into form
All checks were successful
Lint / lint (push) Successful in 14s
2025-04-14 01:00:38 +02:00
Julien Valverdé
129ab04ea7 Form
All checks were successful
Lint / lint (push) Successful in 15s
2025-04-13 01:03:40 +02:00
Julien Valverdé
870fe479c3 Form package
All checks were successful
Lint / lint (push) Successful in 14s
2025-04-13 00:23:40 +02:00
11 changed files with 222 additions and 5 deletions

View File

@@ -46,9 +46,21 @@
"vite": "^6.2.6", "vite": "^6.2.6",
}, },
}, },
"packages/extension-form": {
"name": "@reffuse/extension-form",
"version": "0.1.0",
"devDependencies": {
"reffuse": "workspace:*",
},
"peerDependencies": {
"effect": "^3.13.0",
"react": "^19.0.0",
"reffuse": "^0.1.6",
},
},
"packages/extension-lazyref": { "packages/extension-lazyref": {
"name": "@reffuse/extension-lazyref", "name": "@reffuse/extension-lazyref",
"version": "0.1.1", "version": "0.1.2",
"devDependencies": { "devDependencies": {
"reffuse": "workspace:*", "reffuse": "workspace:*",
}, },
@@ -57,12 +69,12 @@
"@types/react": "^19.0.0", "@types/react": "^19.0.0",
"effect": "^3.13.0", "effect": "^3.13.0",
"react": "^19.0.0", "react": "^19.0.0",
"reffuse": "^0.1.4", "reffuse": "^0.1.6",
}, },
}, },
"packages/extension-query": { "packages/extension-query": {
"name": "@reffuse/extension-query", "name": "@reffuse/extension-query",
"version": "0.1.2", "version": "0.1.3",
"devDependencies": { "devDependencies": {
"reffuse": "workspace:*", "reffuse": "workspace:*",
}, },
@@ -73,12 +85,12 @@
"@types/react": "^19.0.0", "@types/react": "^19.0.0",
"effect": "^3.13.0", "effect": "^3.13.0",
"react": "^19.0.0", "react": "^19.0.0",
"reffuse": "^0.1.4", "reffuse": "^0.1.6",
}, },
}, },
"packages/reffuse": { "packages/reffuse": {
"name": "reffuse", "name": "reffuse",
"version": "0.1.5", "version": "0.1.6",
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.0.0", "@types/react": "^19.0.0",
"effect": "^3.13.0", "effect": "^3.13.0",
@@ -363,6 +375,8 @@
"@reffuse/example": ["@reffuse/example@workspace:packages/example"], "@reffuse/example": ["@reffuse/example@workspace:packages/example"],
"@reffuse/extension-form": ["@reffuse/extension-form@workspace:packages/extension-form"],
"@reffuse/extension-lazyref": ["@reffuse/extension-lazyref@workspace:packages/extension-lazyref"], "@reffuse/extension-lazyref": ["@reffuse/extension-lazyref@workspace:packages/extension-lazyref"],
"@reffuse/extension-query": ["@reffuse/extension-query@workspace:packages/extension-query"], "@reffuse/extension-query": ["@reffuse/extension-query@workspace:packages/extension-query"],

View File

@@ -0,0 +1,9 @@
# LazyRef extension for Reffuse
Extension to integrate `@typed/lazy-ref` with Reffuse.
## Peer dependencies
- `@typed/lazy-ref`
- `reffuse` 0.1.3+
- `effect` 3.13+
- `react` & `@types/react` 19+

View File

@@ -0,0 +1,40 @@
{
"name": "@reffuse/extension-form",
"version": "0.1.0",
"type": "module",
"files": [
"./README.md",
"./dist"
],
"license": "MIT",
"repository": {
"url": "git+https://github.com/Thiladev/reffuse.git"
},
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./*": {
"types": "./dist/*.d.ts",
"default": "./dist/*.js"
}
},
"scripts": {
"build": "tsc",
"lint:tsc": "tsc --noEmit",
"pack": "npm pack",
"clean:cache": "rm -f tsconfig.tsbuildinfo",
"clean:dist": "rm -rf dist",
"clean:node": "rm -rf node_modules"
},
"devDependencies": {
"reffuse": "workspace:*"
},
"peerDependencies": {
"effect": "^3.13.0",
"react": "^19.0.0",
"reffuse": "^0.1.7"
}
}

View File

@@ -0,0 +1,9 @@
import { ReffuseExtension, type ReffuseNamespace } from "reffuse"
export const FormExtension = ReffuseExtension.make(() => ({
useForm<A, E, R>(
this: ReffuseNamespace.ReffuseNamespace<R>,
) {
},
}))

View File

@@ -0,0 +1 @@
export * from "./FormExtension.js"

View File

@@ -0,0 +1,6 @@
import { Schema } from "effect"
export interface Form<A, I, R> {
readonly schema: Schema.Schema<A, I, R>
}

View File

@@ -0,0 +1,44 @@
import type { Schema } from "effect"
import type * as FormTree from "./FormTree.ts"
export interface FormField<S extends Schema.Schema.Any> {
readonly schema: S
}
export interface GenericFormField<S extends Schema.Schema.Any> extends FormField<S> {
readonly _tag: "GenericFormField"
readonly value: S["Type"]
}
export interface TupleFormField<S extends Schema.Tuple<readonly Schema.Schema.Any[]>> extends FormField<S> {
readonly _tag: "TupleFormField"
readonly elements: { readonly [K in keyof S["elements"]]: FormTree.FormTree<
S["elements"][K] extends Schema.Schema.Any
? S["elements"][K]
: never
> }
}
export interface Tuple2FormField<S extends Schema.Tuple2<Schema.Schema.Any, Schema.Schema.Any>> extends FormField<S> {
readonly _tag: "Tuple2FormField"
readonly elements: { readonly [K in keyof S["elements"]]: FormTree.FormTree<
S["elements"][K] extends Schema.Schema.Any
? S["elements"][K]
: never
> }
}
export interface ArrayFormField<S extends Schema.Array$<Schema.Schema.AnyNoContext>> extends FormField<S> {
readonly _tag: "ArrayFormField"
readonly elements: readonly FormTree.FormTree<S["value"]>[]
}
export interface StructFormField<S extends Schema.Struct<{
readonly [x: string]: Schema.Schema.AnyNoContext
readonly [x: number]: Schema.Schema.AnyNoContext
readonly [x: symbol]: Schema.Schema.AnyNoContext
}>> extends FormField<S> {
readonly _tag: "StructFormField"
readonly fields: { readonly [K in keyof S["fields"]]: FormTree.FormTree<S["fields"][K]> }
}

View File

@@ -0,0 +1,23 @@
import { Schema } from "effect"
import type * as FormField from "./FormField.js"
export type FormTree<S extends Schema.Schema.Any> = (
S extends Schema.Tuple<any> ? FormField.TupleFormField<S> :
S extends Schema.Tuple2<any, any> ? FormField.Tuple2FormField<S> :
S extends Schema.Array$<any> ? FormField.ArrayFormField<S> :
S extends Schema.Struct<any> ? FormField.StructFormField<S> :
FormField.GenericFormField<S>
)
const User = Schema.Struct({
name: Schema.String,
roles: Schema.Tuple(Schema.Literal("Admin"), Schema.Literal("Moderator"), Schema.Literal("User")),
values: Schema.Array(Schema.String),
})
type TestFormTree = FormTree<typeof User>
declare const testFormTree: TestFormTree
testFormTree.fields.roles.elements

View File

@@ -0,0 +1,37 @@
import { Array, Predicate, Record, Schema, Tuple } from "effect"
export const isTupleSchema = (u: unknown): u is Schema.Tuple<any> => (
Schema.isSchema(u) &&
Predicate.hasProperty(u, "elements") && Array.isArray(u.elements) &&
Predicate.hasProperty(u, "rest") && Array.isArray(u.rest)
)
export const isArraySchema = (u: unknown): u is Schema.Array$<any> => (
Schema.isSchema(u) &&
Predicate.hasProperty(u, "elements") && Array.isArray(u.elements) && Array.isEmptyArray(u.elements) &&
Predicate.hasProperty(u, "rest") && Array.isArray(u.rest) && Tuple.isTupleOf(u.rest, 1) &&
Predicate.hasProperty(u, "value")
)
export const isStructSchema = (u: unknown): u is Schema.Struct<any> => (
Schema.isSchema(u) &&
Predicate.hasProperty(u, "fields") && Predicate.isObject(u.fields) &&
Predicate.hasProperty(u, "records") && Array.isArray(u.records) && Array.isEmptyArray(u.records)
)
export const isRecordSchema = (u: unknown): u is Schema.Record$<any, any> => (
Schema.isSchema(u) &&
Predicate.hasProperty(u, "fields") && Predicate.isObject(u.fields) && Record.isEmptyRecord(u.fields) &&
Predicate.hasProperty(u, "records") && Array.isArray(u.records) &&
Predicate.hasProperty(u, "key") &&
Predicate.hasProperty(u, "value")
)
const myTuple = Schema.Tuple(Schema.String)
const myArray = Schema.Array(Schema.String)
const myStruct = Schema.Struct({})
const myRecord = Schema.Record({ key: Schema.String, value: Schema.String })
console.log(isArraySchema(myTuple))

View File

@@ -0,0 +1 @@
export * as Form from "./Form.js"

View File

@@ -0,0 +1,33 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "NodeNext",
"moduleDetection": "force",
"jsx": "react-jsx",
// "allowJs": true,
// Bundler mode
"moduleResolution": "NodeNext",
// "allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
// "noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false,
// Build
"outDir": "./dist",
"declaration": true
},
"include": ["./src"]
}