Skip to content

Commit

Permalink
refactor: changes internal use of useForm
Browse files Browse the repository at this point in the history
  • Loading branch information
fenilli committed Nov 7, 2023
1 parent 96cf888 commit e28badb
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 194 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
"peerDependencies": {
"@formkit/vue": ">= 1.2.0",
"@inertiajs/core": ">= 1.0.0",
"@inertiajs/vue3": ">= 1.0.0",
"vue": ">= 3.0.0"
}
}
29 changes: 25 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions src/addons/formkit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { FormKitNode } from '@formkit/core';
import type { RequestPayload } from '@inertiajs/core';
import type { AddonExtension } from '../inertia';

import { reactive, watchEffect } from 'vue';
import { createMessage } from '@formkit/core';

export default <F extends RequestPayload>(initialFields?: F) => {
const state = reactive({
node: null as null | FormKitNode,
dirty: false as boolean | null,
errors: false as boolean | null,
valid: false as boolean | null,
});

return {
state,

addon: ((on) => {
on('start', (_, node) => {
node.store.set(createMessage({
key: 'loading',
visible: false,
value: true
}));

if (node.props.submitBehavior !== 'live') node.props.disabled = true;
});

on('error', (errors, node) => {
node.setErrors(node.name in errors ? errors[node.name] : [], errors);
});

on('finish', (_, node) => {
node.store.remove('loading');

if (node.props.submitBehavior !== 'live') node.props.disabled = false;
});
}) as AddonExtension,
plugin: (node: FormKitNode) => {
if (node.props.type !== 'form') return;

state.node = node;
node.input(initialFields);

node.on('created', () => {
watchEffect(() => {
state.dirty = node.context!.state.dirty;
state.valid = node.context!.state.valid;
state.errors = node.context!.state.errors;
});
});

return false;
}
}
};
2 changes: 2 additions & 0 deletions src/addons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as createFormkitAddon } from './formkit';
export { default as createStateAddon } from './state';
51 changes: 51 additions & 0 deletions src/addons/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { AddonExtension } from '../inertia';

import { reactive } from 'vue';

export default (recentlySuccessfulTimeoutTime = 2000) => {
let _recentlySuccessfulTimeoutId: ReturnType<typeof setTimeout> | undefined = undefined;

const state = reactive({
processing: false,
progress: 0,
recentlySuccessful: false,
wasSuccessful: false,
});

return {
state,

addon: ((on) => {
on('before', () => {
state.processing = false;
state.progress = 0;
state.recentlySuccessful = false;
state.wasSuccessful = false;

clearInterval(_recentlySuccessfulTimeoutId);
});

on('start', () => {
state.processing = true;
});

on('progress', (progress) => {
state.progress = progress?.percentage || 0;
});

on('success', () => {
state.recentlySuccessful = true;
state.wasSuccessful = true;

_recentlySuccessfulTimeoutId = setTimeout(() => {
state.recentlySuccessful = false;
}, recentlySuccessfulTimeoutTime);
});

on('finish', () => {
state.processing = false;
state.progress = 0;
});
}) as AddonExtension
};
}
70 changes: 0 additions & 70 deletions src/event.ts

This file was deleted.

49 changes: 49 additions & 0 deletions src/eventManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { FormKitNode } from '@formkit/core';
import type { GlobalEventsMap } from '@inertiajs/core';

export type EventCallback = {
[K in keyof Omit<GlobalEventsMap, 'navigate' | 'invalid' | 'exception'>]
: (...args: [...GlobalEventsMap[K]['parameters'], ...[node: FormKitNode]])
=> K extends 'success' | 'error'
? Promise<GlobalEventsMap[K]['result']> | GlobalEventsMap[K]['result']
: GlobalEventsMap[K]['result'];
} & {
cancelToken: (...args: [{ cancel: () => void }, ...[node: FormKitNode]]) => void;
};

export const createEventManager = () => {
const events: Partial<{
[K in keyof EventCallback]: EventCallback[K][];
}> = {};

const on = <T extends keyof EventCallback>(name: T, cb: EventCallback[T]) => {
if (typeof events[name] === 'undefined') events[name] = [];

events[name]?.push(cb);
};

const run = (name: keyof EventCallback, ...args: any): Promise<void> | void | boolean => {
let promiseResolver = Promise.resolve();

for (const event of events[name] || []) {
const res = event(...args);

if (name === 'before' && typeof res === 'boolean') return res;
else if (name === 'success' || name === 'finish') {
if (res instanceof Promise) {
promiseResolver = res;
} else {
promiseResolver = Promise.resolve(res);
}
}
}

if (name === 'success' || name === 'finish') return promiseResolver;
};

return {
events,
on,
run
}
}
5 changes: 1 addition & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
export type { EventCallback, OnFunction, CombineFunction, ExecuteFunction } from './event';
export { createEventCallbackManager } from './event';

export { useForm } from './inertia';
export { useForm, type AddonExtension } from './inertia';
Loading

0 comments on commit e28badb

Please sign in to comment.