@kirill.konshin/utils 0.0.17 → 0.0.19
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/.turbo/turbo-build.log +38 -38
- package/.turbo/turbo-test.log +37 -37
- package/CHANGELOG.md +12 -0
- package/dist/bootstrap/adaptiveContainer.d.ts +2 -1
- package/dist/bootstrap/adaptiveContainer.d.ts.map +1 -1
- package/dist/bootstrap/adaptiveContainer.js +2 -2
- package/dist/bootstrap/adaptiveContainer.js.map +1 -1
- package/dist/bootstrap/controls.d.ts +6 -6
- package/dist/bootstrap/controls.d.ts.map +1 -1
- package/dist/bootstrap/controls.js.map +1 -1
- package/dist/bootstrap/error.d.ts +4 -2
- package/dist/bootstrap/error.d.ts.map +1 -1
- package/dist/bootstrap/error.js +2 -7
- package/dist/bootstrap/error.js.map +1 -1
- package/dist/bootstrap/field.d.ts +4 -2
- package/dist/bootstrap/field.d.ts.map +1 -1
- package/dist/bootstrap/field.js +2 -2
- package/dist/bootstrap/field.js.map +1 -1
- package/dist/bootstrap/footer.d.ts +5 -5
- package/dist/bootstrap/footer.d.ts.map +1 -1
- package/dist/bootstrap/footer.js +9 -4
- package/dist/bootstrap/footer.js.map +1 -1
- package/dist/bootstrap/globalLoading.d.ts +4 -2
- package/dist/bootstrap/globalLoading.d.ts.map +1 -1
- package/dist/bootstrap/globalLoading.js +2 -2
- package/dist/bootstrap/globalLoading.js.map +1 -1
- package/dist/bootstrap/loading.d.ts +4 -2
- package/dist/bootstrap/loading.d.ts.map +1 -1
- package/dist/bootstrap/loading.js +3 -2
- package/dist/bootstrap/loading.js.map +1 -1
- package/dist/bootstrap/responsiveHelper.d.ts +2 -1
- package/dist/bootstrap/responsiveHelper.d.ts.map +1 -1
- package/dist/bootstrap/responsiveHelper.js +5 -5
- package/dist/bootstrap/responsiveHelper.js.map +1 -1
- package/dist/bootstrap/screen.d.ts +4 -2
- package/dist/bootstrap/screen.d.ts.map +1 -1
- package/dist/bootstrap/screen.js +3 -2
- package/dist/bootstrap/screen.js.map +1 -1
- package/dist/bootstrap/toaster.d.ts +4 -2
- package/dist/bootstrap/toaster.d.ts.map +1 -1
- package/dist/bootstrap/toaster.js +2 -5
- package/dist/bootstrap/toaster.js.map +1 -1
- package/dist/bootstrap/useModal.d.ts +2 -1
- package/dist/bootstrap/useModal.d.ts.map +1 -1
- package/dist/bootstrap/useModal.js +3 -3
- package/dist/bootstrap/useModal.js.map +1 -1
- package/dist/bootstrap/useWrappedForm.d.ts +1 -1
- package/dist/bootstrap/useWrappedForm.d.ts.map +1 -1
- package/dist/bootstrap/useWrappedForm.js.map +1 -1
- package/dist/core/cache.d.ts +2 -2
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/files.d.ts +2 -1
- package/dist/core/files.d.ts.map +1 -1
- package/dist/core/files.js +7 -3
- package/dist/core/files.js.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/ls.d.ts +1 -1
- package/dist/core/ls.d.ts.map +1 -1
- package/dist/core/ls.js.map +1 -1
- package/dist/core/measure.d.ts +4 -4
- package/dist/core/measure.d.ts.map +1 -1
- package/dist/core/measure.js +5 -1
- package/dist/core/measure.js.map +1 -1
- package/dist/core/worker.d.ts +3 -3
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/core/worker.js.map +1 -1
- package/dist/core/wrpc.d.ts +4 -4
- package/dist/core/wrpc.d.ts.map +1 -1
- package/dist/core/wrpc.fixture.d.ts +1 -4
- package/dist/core/wrpc.fixture.d.ts.map +1 -1
- package/dist/core/wrpc.js.map +1 -1
- package/dist/electron/createWindow.d.ts.map +1 -1
- package/dist/electron/createWindow.js.map +1 -1
- package/dist/electron/updater.d.ts +1 -1
- package/dist/electron/updater.d.ts.map +1 -1
- package/dist/electron/updater.js +1 -1
- package/dist/electron/updater.js.map +1 -1
- package/dist/electron-builder/images.d.ts.map +1 -1
- package/dist/electron-builder/images.js.map +1 -1
- package/dist/mui/formControlFieldset.d.ts +2 -2
- package/dist/mui/formControlFieldset.d.ts.map +1 -1
- package/dist/mui/formControlFieldset.js.map +1 -1
- package/dist/mui/formLabelLegend.d.ts +2 -2
- package/dist/mui/formLabelLegend.d.ts.map +1 -1
- package/dist/mui/formLabelLegend.js.map +1 -1
- package/dist/mui/genericControl.d.ts +2 -2
- package/dist/mui/genericControl.d.ts.map +1 -1
- package/dist/mui/genericControl.js.map +1 -1
- package/dist/mui/readOnly.d.ts +2 -2
- package/dist/mui/readOnly.d.ts.map +1 -1
- package/dist/mui/readOnly.js.map +1 -1
- package/dist/next/measure.d.ts.map +1 -1
- package/dist/next/measure.js.map +1 -1
- package/dist/next/noSSR.d.ts +27 -3
- package/dist/next/noSSR.d.ts.map +1 -1
- package/dist/next/noSSR.js +2 -4
- package/dist/next/noSSR.js.map +1 -1
- package/dist/react/form/client.d.ts.map +1 -1
- package/dist/react/form/client.js.map +1 -1
- package/dist/react/form/form.d.ts +22 -8
- package/dist/react/form/form.d.ts.map +1 -1
- package/dist/react/form/form.js +27 -7
- package/dist/react/form/form.js.map +1 -1
- package/dist/react/index.js +2 -1
- package/dist/react/keyboard.d.ts +5 -6
- package/dist/react/keyboard.d.ts.map +1 -1
- package/dist/react/keyboard.js.map +1 -1
- package/dist/react/useFetcher.d.ts.map +1 -1
- package/dist/react/useFetcher.js.map +1 -1
- package/dist/react-native/share.d.ts +1 -1
- package/dist/react-native/share.d.ts.map +1 -1
- package/dist/react-native/share.js.map +1 -1
- package/dist/react-native/update.d.ts +2 -3
- package/dist/react-native/update.d.ts.map +1 -1
- package/dist/react-native/update.js +2 -2
- package/dist/react-native/update.js.map +1 -1
- package/dist/react-native/useAppState.d.ts +1 -1
- package/dist/react-native/useAppState.d.ts.map +1 -1
- package/dist/react-native/useAppState.js.map +1 -1
- package/dist/tailwind/fullpage.d.ts +2 -6
- package/dist/tailwind/fullpage.d.ts.map +1 -1
- package/dist/tailwind/fullpage.js.map +1 -1
- package/dist/tailwind/responsiveHelper.d.ts +2 -1
- package/dist/tailwind/responsiveHelper.d.ts.map +1 -1
- package/dist/tailwind/responsiveHelper.js +2 -2
- package/dist/tailwind/responsiveHelper.js.map +1 -1
- package/package.json +1 -1
- package/src/bootstrap/adaptiveContainer.tsx +3 -3
- package/src/bootstrap/controls.stories.tsx +1 -1
- package/src/bootstrap/controls.tsx +12 -12
- package/src/bootstrap/error.tsx +7 -10
- package/src/bootstrap/field.tsx +11 -9
- package/src/bootstrap/footer.tsx +17 -5
- package/src/bootstrap/globalLoading.tsx +5 -3
- package/src/bootstrap/loading.tsx +10 -8
- package/src/bootstrap/responsiveHelper.tsx +11 -6
- package/src/bootstrap/screen.tsx +24 -22
- package/src/bootstrap/toaster.tsx +8 -6
- package/src/bootstrap/useModal.tsx +12 -7
- package/src/bootstrap/useWrappedForm.ts +9 -7
- package/src/core/cache.ts +15 -8
- package/src/core/errors.ts +4 -1
- package/src/core/files.ts +8 -4
- package/src/core/ls.ts +8 -4
- package/src/core/measure.ts +55 -7
- package/src/core/worker.ts +18 -11
- package/src/core/wrpc.fixture.ts +40 -6
- package/src/core/wrpc.ts +23 -5
- package/src/electron/createWindow.ts +3 -3
- package/src/electron/updater.ts +1 -1
- package/src/electron-builder/images.ts +1 -1
- package/src/mui/formControlFieldset.tsx +2 -2
- package/src/mui/formLabelLegend.tsx +2 -2
- package/src/mui/genericControl.tsx +2 -2
- package/src/mui/readOnly.tsx +2 -2
- package/src/next/measure.ts +19 -2
- package/src/next/noSSR.tsx +26 -7
- package/src/react/form/client.tsx +13 -2
- package/src/react/form/form.tsx +67 -18
- package/src/react/keyboard.tsx +9 -4
- package/src/react/useFetcher.ts +8 -3
- package/src/react-native/share.ts +1 -1
- package/src/react-native/update.tsx +3 -3
- package/src/react-native/useAppState.ts +1 -1
- package/src/tailwind/fullpage.tsx +2 -2
- package/src/tailwind/responsiveHelper.tsx +3 -3
- package/tsconfig.json +1 -0
package/src/core/worker.ts
CHANGED
|
@@ -44,7 +44,7 @@ function checkMessage(obj: any, message: any) {
|
|
|
44
44
|
// Classes
|
|
45
45
|
|
|
46
46
|
export class WorkerDialog<R extends RespondersBase<any>> {
|
|
47
|
-
readonly contexts
|
|
47
|
+
readonly contexts: Set<Context<R, keyof R>> = new Set();
|
|
48
48
|
protected closed = false;
|
|
49
49
|
protected currentId = 0; // IDs are intentionally not global
|
|
50
50
|
|
|
@@ -90,16 +90,16 @@ export class WorkerDialog<R extends RespondersBase<any>> {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
getID() {
|
|
93
|
+
getID(): string {
|
|
94
94
|
return (++this.currentId).toString();
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
close() {
|
|
97
|
+
close(): void {
|
|
98
98
|
for (const context of this.contexts) context.close('root');
|
|
99
99
|
this.contexts.clear();
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
withMessage<M extends keyof R>(message: M) {
|
|
102
|
+
withMessage<M extends keyof R>(message: M): RequestContext<R, M> {
|
|
103
103
|
return new RequestContext<R, M>(this, message, this.getID()); // always new context
|
|
104
104
|
}
|
|
105
105
|
}
|
|
@@ -116,7 +116,7 @@ export class RespondersBase<R> {
|
|
|
116
116
|
|
|
117
117
|
// can only be used to create actual contexts, carries the context data
|
|
118
118
|
abstract class Context<R, M extends keyof R> {
|
|
119
|
-
protected readonly unsub
|
|
119
|
+
protected readonly unsub: Set<() => void> = new Set();
|
|
120
120
|
protected closed = false;
|
|
121
121
|
|
|
122
122
|
constructor(
|
|
@@ -135,7 +135,7 @@ abstract class Context<R, M extends keyof R> {
|
|
|
135
135
|
|
|
136
136
|
abstract withMessage<M2 extends keyof R>(message: M2, id?: string): Context<R, M2>;
|
|
137
137
|
|
|
138
|
-
close(reason: string = 'external') {
|
|
138
|
+
close(reason: string = 'external'): void {
|
|
139
139
|
/* v8 ignore next */
|
|
140
140
|
if (this.dialog.debug >= 2) console.log('Closing', this.info, reason, this);
|
|
141
141
|
|
|
@@ -157,7 +157,14 @@ abstract class Context<R, M extends keyof R> {
|
|
|
157
157
|
return `${this.dialog.name}:${this.parent?.id ?? ALL}/${this.id}:${this.message.toString()}[${this.closed ? 'closed' : 'open'},${this.type}]`;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
get debugInfo() {
|
|
160
|
+
get debugInfo(): {
|
|
161
|
+
id?: string;
|
|
162
|
+
parentId?: string;
|
|
163
|
+
message: string | number | symbol;
|
|
164
|
+
closed: boolean;
|
|
165
|
+
type: string;
|
|
166
|
+
listeners: number;
|
|
167
|
+
} {
|
|
161
168
|
return {
|
|
162
169
|
id: this.id,
|
|
163
170
|
parentId: this.parent?.id,
|
|
@@ -170,7 +177,7 @@ abstract class Context<R, M extends keyof R> {
|
|
|
170
177
|
|
|
171
178
|
abstract type: 'request' | 'response' | string;
|
|
172
179
|
|
|
173
|
-
protected postMessage(data?: Data<R, M>, done = false) {
|
|
180
|
+
protected postMessage(data?: Data<R, M>, done = false): Data<R, M> | undefined {
|
|
174
181
|
checkClosed(this, 'postMessage');
|
|
175
182
|
|
|
176
183
|
const transfer = getTransferrable(data);
|
|
@@ -190,7 +197,7 @@ abstract class Context<R, M extends keyof R> {
|
|
|
190
197
|
return data;
|
|
191
198
|
}
|
|
192
199
|
|
|
193
|
-
send(data?: Data<R, M>, done = false) {
|
|
200
|
+
send(data?: Data<R, M>, done = false): Data<R, M> | undefined {
|
|
194
201
|
return this.postMessage(data, done);
|
|
195
202
|
}
|
|
196
203
|
|
|
@@ -303,11 +310,11 @@ class RequestContext<R, M extends keyof R> extends Context<R, M> {
|
|
|
303
310
|
return res[1];
|
|
304
311
|
}
|
|
305
312
|
|
|
306
|
-
protected async expect() {
|
|
313
|
+
protected async expect(): Promise<MethodReturn<R, M>> {
|
|
307
314
|
checkClosed(this, 'expect');
|
|
308
315
|
|
|
309
316
|
//FIXME Manual promise type
|
|
310
|
-
return new Promise
|
|
317
|
+
return new Promise((resolve, reject) => {
|
|
311
318
|
const responseListener = this.listen(async (data) => {
|
|
312
319
|
try {
|
|
313
320
|
if ((data as any) instanceof Error) throw data;
|
package/src/core/wrpc.fixture.ts
CHANGED
|
@@ -1,15 +1,47 @@
|
|
|
1
1
|
import { wrpc } from './wrpc';
|
|
2
2
|
|
|
3
|
-
export const responder
|
|
3
|
+
export const responder: {
|
|
4
|
+
responders: {
|
|
5
|
+
// note it's not async, and works properly
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
test: ({ buf, signal }?: { signal?: AbortSignal; buf?: ArrayBuffer }) => Generator<
|
|
8
|
+
{
|
|
9
|
+
progress: number;
|
|
10
|
+
aborted?: boolean;
|
|
11
|
+
},
|
|
12
|
+
string,
|
|
13
|
+
unknown
|
|
14
|
+
>;
|
|
15
|
+
// note it's not async, and works properly
|
|
16
|
+
returnYield: () => Generator<1 | 3 | 2, any, unknown>;
|
|
17
|
+
bidirectional: (prefix?: any) => Generator<string, string, number>;
|
|
18
|
+
|
|
19
|
+
error: () => AsyncGenerator<never, never, unknown>;
|
|
20
|
+
promise: () => Promise<{
|
|
21
|
+
test: string;
|
|
22
|
+
}>;
|
|
23
|
+
promiseError: () => Promise<never>;
|
|
24
|
+
setTimeout: ({ timeout }?: { timeout?: number }) => Promise<unknown>;
|
|
25
|
+
setInterval: ({ timeout }?: { timeout?: number }) => AsyncGenerator<any, never, unknown>;
|
|
26
|
+
};
|
|
27
|
+
stop: () => void;
|
|
28
|
+
} = wrpc().createResponder(self, {
|
|
4
29
|
// note it's not async, and works properly
|
|
5
|
-
test: function* ({ buf, signal }: { signal?: AbortSignal; buf?: ArrayBuffer } = {})
|
|
30
|
+
test: function* ({ buf, signal }: { signal?: AbortSignal; buf?: ArrayBuffer } = {}): Generator<
|
|
31
|
+
{
|
|
32
|
+
progress: number;
|
|
33
|
+
aborted?: boolean;
|
|
34
|
+
},
|
|
35
|
+
string,
|
|
36
|
+
unknown
|
|
37
|
+
> {
|
|
6
38
|
yield { progress: 0 };
|
|
7
39
|
yield { progress: 0.5 };
|
|
8
40
|
yield { progress: 1, aborted: !!signal?.aborted };
|
|
9
41
|
return 'foo';
|
|
10
42
|
},
|
|
11
43
|
// note it's not async, and works properly
|
|
12
|
-
returnYield: function* () {
|
|
44
|
+
returnYield: function* (): Generator<1 | 3 | 2, any, unknown> {
|
|
13
45
|
yield 1;
|
|
14
46
|
yield 2;
|
|
15
47
|
return yield 3;
|
|
@@ -23,13 +55,15 @@ export const responder = wrpc().createResponder(self, {
|
|
|
23
55
|
return 'done';
|
|
24
56
|
},
|
|
25
57
|
// eslint-disable-next-line require-yield
|
|
26
|
-
error: async function* () {
|
|
58
|
+
error: async function* (): AsyncGenerator<never, never, unknown> {
|
|
27
59
|
throw new Error('Test');
|
|
28
60
|
},
|
|
29
|
-
promise: async function () {
|
|
61
|
+
promise: async function (): Promise<{
|
|
62
|
+
test: string;
|
|
63
|
+
}> {
|
|
30
64
|
return { test: 'test' };
|
|
31
65
|
},
|
|
32
|
-
promiseError: async function () {
|
|
66
|
+
promiseError: async function (): Promise<never> {
|
|
33
67
|
throw new Error('Test');
|
|
34
68
|
},
|
|
35
69
|
setTimeout: async ({ timeout = 1000 }: { timeout?: number } = {}) =>
|
package/src/core/wrpc.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type WorkerLike = {
|
|
|
25
25
|
options?: { signal?: AbortSignal; once?: boolean },
|
|
26
26
|
) => void;
|
|
27
27
|
removeEventListener: (event: string, listener: (e: any) => void) => void;
|
|
28
|
-
};
|
|
28
|
+
} & any;
|
|
29
29
|
|
|
30
30
|
export enum LogLevel {
|
|
31
31
|
disabled = 0,
|
|
@@ -42,10 +42,10 @@ export function deriveController(signal?: AbortSignal): [AbortController, AbortS
|
|
|
42
42
|
return [controller, AbortSignal.any([controller.signal, signal].filter(Boolean) as AbortSignal[])];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function rejectOnSignal(promise: Promise<any>, signal: AbortSignal) {
|
|
45
|
+
export function rejectOnSignal(promise: Promise<any>, signal: AbortSignal): Promise<Event['data']> {
|
|
46
46
|
return Promise.race([
|
|
47
47
|
promise,
|
|
48
|
-
new Promise
|
|
48
|
+
new Promise((resolve, reject) => {
|
|
49
49
|
signal.addEventListener('abort', () => reject('RaceAborted:' + signal.reason), { once: true, signal });
|
|
50
50
|
}),
|
|
51
51
|
]);
|
|
@@ -56,7 +56,19 @@ export function rejectOnSignal(promise: Promise<any>, signal: AbortSignal) {
|
|
|
56
56
|
export function wrpc({
|
|
57
57
|
debug = LogLevel.disabled,
|
|
58
58
|
name = (globalThis as any).importScripts ? 'RESPONDER' : 'CALLER',
|
|
59
|
-
}
|
|
59
|
+
}: {
|
|
60
|
+
debug?: LogLevel;
|
|
61
|
+
name?: string;
|
|
62
|
+
} = {}): {
|
|
63
|
+
createResponder: <T extends Responders>(
|
|
64
|
+
worker: WorkerLike,
|
|
65
|
+
responders: T,
|
|
66
|
+
) => {
|
|
67
|
+
responders: T;
|
|
68
|
+
stop: () => void;
|
|
69
|
+
};
|
|
70
|
+
createCaller: <T extends Responders>(worker: WorkerLike, responders: T) => T;
|
|
71
|
+
} {
|
|
60
72
|
// Logger
|
|
61
73
|
|
|
62
74
|
function logger(type: string) {
|
|
@@ -130,7 +142,13 @@ export function wrpc({
|
|
|
130
142
|
// Responder
|
|
131
143
|
|
|
132
144
|
//TODO Name arg
|
|
133
|
-
function createResponder<T extends Responders>(
|
|
145
|
+
function createResponder<T extends Responders>(
|
|
146
|
+
worker: WorkerLike,
|
|
147
|
+
responders: T,
|
|
148
|
+
): {
|
|
149
|
+
responders: T;
|
|
150
|
+
stop: () => void;
|
|
151
|
+
} {
|
|
134
152
|
const mainController = new AbortController();
|
|
135
153
|
|
|
136
154
|
worker.addEventListener('messageerror', (e) => logError(LogLevel.error, null, 'MESSAGE ERROR', e), {
|
|
@@ -9,8 +9,8 @@ import defaultMenu from 'electron-default-menu';
|
|
|
9
9
|
import Store from 'electron-store';
|
|
10
10
|
import { checkForUpdates } from './updater.js';
|
|
11
11
|
|
|
12
|
-
export const isDev = process.env['NODE_ENV'] === 'development';
|
|
13
|
-
export const appPath = app.getAppPath();
|
|
12
|
+
export const isDev: boolean = process.env['NODE_ENV'] === 'development';
|
|
13
|
+
export const appPath: string = app.getAppPath();
|
|
14
14
|
|
|
15
15
|
// See https://cs.chromium.org/chromium/src/net/base/net_error_list.h
|
|
16
16
|
const FILE_NOT_FOUND = -6;
|
|
@@ -227,7 +227,7 @@ export function createWindow({
|
|
|
227
227
|
app.on('activate', () => BrowserWindow.getAllWindows().length === 0 && !mainWindow && createWindow());
|
|
228
228
|
|
|
229
229
|
return {
|
|
230
|
-
get mainWindow() {
|
|
230
|
+
get mainWindow(): BrowserWindow | null {
|
|
231
231
|
return mainWindow;
|
|
232
232
|
},
|
|
233
233
|
};
|
package/src/electron/updater.ts
CHANGED
|
@@ -47,7 +47,7 @@ autoUpdater.on('update-downloaded', async () => {
|
|
|
47
47
|
autoUpdater.quitAndInstall();
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
export function checkForUpdates(menuItem
|
|
50
|
+
export function checkForUpdates(menuItem: any): void {
|
|
51
51
|
updateButton = menuItem;
|
|
52
52
|
updateButton.enabled = false;
|
|
53
53
|
autoUpdater.checkForUpdates().catch((e) => console.error('Update error', e));
|
|
@@ -12,7 +12,7 @@ export async function generateImages({
|
|
|
12
12
|
dmgBackgroundPsdPath: string;
|
|
13
13
|
electronAssetsPath: string;
|
|
14
14
|
webPublicPath: string;
|
|
15
|
-
}) {
|
|
15
|
+
}): Promise<void> {
|
|
16
16
|
const iconPsd = await psd.open(iconPsdPath);
|
|
17
17
|
await iconPsd.image!.saveAsPng(path.join(electronAssetsPath, 'icon.png'));
|
|
18
18
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
2
|
import { GenericControl, GenericControlProps } from './genericControl';
|
|
3
3
|
import { inputClasses } from '@mui/material/Input';
|
|
4
4
|
|
|
5
5
|
export type FormControlFieldsetProps = GenericControlProps;
|
|
6
6
|
|
|
7
|
-
export const FormControlFieldset:
|
|
7
|
+
export const FormControlFieldset: FC<FormControlFieldsetProps> = function FormControlFieldset({
|
|
8
8
|
children,
|
|
9
9
|
sx,
|
|
10
10
|
...props
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
2
|
import { default as InputLabel, InputLabelProps } from '@mui/material/InputLabel';
|
|
3
3
|
|
|
4
|
-
export const FormLabelLegend:
|
|
4
|
+
export const FormLabelLegend: FC<InputLabelProps> = ({ children, ...props }) => {
|
|
5
5
|
return (
|
|
6
6
|
// sx={(theme) => theme.typography.caption}
|
|
7
7
|
<InputLabel {...props} shrink={true} component={'legend' as any}>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
2
|
import { FormControlProps, default as FormControl } from '@mui/material/FormControl';
|
|
3
3
|
import { inputClasses } from '@mui/material/Input';
|
|
4
4
|
|
|
5
5
|
export type GenericControlProps = FormControlProps & { children: any };
|
|
6
6
|
|
|
7
|
-
export const GenericControl:
|
|
7
|
+
export const GenericControl: FC<GenericControlProps> = ({ children, sx, ...props }) => (
|
|
8
8
|
<FormControl
|
|
9
9
|
variant="standard"
|
|
10
10
|
sx={{
|
package/src/mui/readOnly.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
2
|
import { default as Input, InputProps } from '@mui/material/Input';
|
|
3
3
|
|
|
4
|
-
export const ReadOnly:
|
|
4
|
+
export const ReadOnly: FC<InputProps & { children: any }> = ({ children, inputProps, ...props }) => (
|
|
5
5
|
<Input {...props} inputComponent={'div' as any} inputProps={{ ...inputProps, children }}></Input>
|
|
6
6
|
);
|
package/src/next/measure.ts
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { createMeasurer } from '../core/measure';
|
|
2
2
|
import { PHASE_PRODUCTION_BUILD, PHASE_PRODUCTION_SERVER } from 'next/constants';
|
|
3
3
|
|
|
4
|
-
export const isProd =
|
|
4
|
+
export const isProd: boolean =
|
|
5
5
|
process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD || process.env.NEXT_PHASE === PHASE_PRODUCTION_SERVER;
|
|
6
6
|
|
|
7
|
-
export const measurer
|
|
7
|
+
export const measurer: {
|
|
8
|
+
measure: (
|
|
9
|
+
what: string,
|
|
10
|
+
step: string,
|
|
11
|
+
supplemental?: string,
|
|
12
|
+
...args: any[]
|
|
13
|
+
) => {
|
|
14
|
+
done: (result?: string, ...args2: any[]) => void;
|
|
15
|
+
fail: (result?: string, ...args2: any[]) => void;
|
|
16
|
+
log: (...args2: any[]) => void;
|
|
17
|
+
};
|
|
18
|
+
important: (str: any) => any;
|
|
19
|
+
subject: (str: any) => any;
|
|
20
|
+
arg: (str: any) => any;
|
|
21
|
+
sup: (str: any) => any;
|
|
22
|
+
ok: (str: any) => any;
|
|
23
|
+
err: (str: any) => any;
|
|
24
|
+
} = createMeasurer({ colors: isProd });
|
package/src/next/noSSR.tsx
CHANGED
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { useLayoutEffect, useState } from 'react';
|
|
3
|
+
import React, { FC, JSX, useLayoutEffect, useState } from 'react';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Prefer using Next.js `dynamic()` import with `ssr: false` because this will also remove import from server bundle.
|
|
7
|
+
*
|
|
8
|
+
* ```tsx
|
|
9
|
+
* 'use client';
|
|
10
|
+
*
|
|
11
|
+
* import React from 'react';
|
|
12
|
+
* import dynamic from 'next/dynamic';
|
|
13
|
+
*
|
|
14
|
+
* const PageClient = dynamic(() => import('./pageClient'), { ssr: false });
|
|
15
|
+
*
|
|
16
|
+
* export default function Page() {
|
|
17
|
+
* return (
|
|
18
|
+
* <PageClient />
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* In other cases this component can be used to just prevent server rendering.
|
|
24
|
+
*
|
|
25
|
+
* @see https://github.com/kadirahq/react-no-ssr/blob/master/src/index.js
|
|
26
|
+
* @see https://nextjs.org/docs/messages/react-hydration-error#solution-1-using-useeffect-to-run-on-the-client-only
|
|
27
|
+
*/
|
|
28
|
+
export const NoSSR: FC<{ children: any; onSSR?: JSX.Element }> = function NoSSR({ children, onSSR = null }): any {
|
|
10
29
|
const [canRender, setCanRender] = useState(false);
|
|
11
30
|
|
|
12
31
|
useLayoutEffect(() => {
|
|
@@ -14,4 +33,4 @@ export function NoSSR({ children, onSSR = <DefaultOnSSR /> }) {
|
|
|
14
33
|
}, []);
|
|
15
34
|
|
|
16
35
|
return canRender ? children : onSSR;
|
|
17
|
-
}
|
|
36
|
+
};
|
|
@@ -6,7 +6,18 @@ import { z } from 'zod';
|
|
|
6
6
|
|
|
7
7
|
const FORM_DEBUG = process.env.NEXT_PUBLIC_FORM_DEBUG === 'true';
|
|
8
8
|
|
|
9
|
-
export function createClient<S extends z.ZodObject<any>>(
|
|
9
|
+
export function createClient<S extends z.ZodObject<any>>(
|
|
10
|
+
schema: S,
|
|
11
|
+
): {
|
|
12
|
+
useValidation: (
|
|
13
|
+
actionFn: (data: FormData) => Promise<Validation<S>>,
|
|
14
|
+
initialData?: MaybeTypeOf<S>,
|
|
15
|
+
) => [state: Validation<S>, dispatch: (payload: FormData) => void, isPending: boolean];
|
|
16
|
+
useValidationTransition: (
|
|
17
|
+
actionFn: (data: FormData) => Promise<Validation<S>>,
|
|
18
|
+
initialData?: MaybeTypeOf<S>,
|
|
19
|
+
) => [Validation<S>, (formData: FormData) => Promise<Validation<S>>, boolean];
|
|
20
|
+
} {
|
|
10
21
|
const { validate } = create(schema);
|
|
11
22
|
|
|
12
23
|
function useValidationCallback(
|
|
@@ -29,7 +40,7 @@ export function createClient<S extends z.ZodObject<any>>(schema: S) {
|
|
|
29
40
|
function useValidation(
|
|
30
41
|
actionFn: (data: FormData) => Promise<Validation<S>>,
|
|
31
42
|
initialData: MaybeTypeOf<S> = {} as MaybeTypeOf<S>,
|
|
32
|
-
) {
|
|
43
|
+
): [state: Validation<S>, dispatch: (payload: FormData) => void, isPending: boolean] {
|
|
33
44
|
const cb = useValidationCallback(actionFn);
|
|
34
45
|
|
|
35
46
|
return useActionState<Validation<S>, FormData>(async (_, data) => cb(data), {
|
package/src/react/form/form.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { typeToFlattenedError, z, SafeParseReturnType, TypeOf } from 'zod';
|
|
2
|
-
import { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import { Context, createContext, useContext, useMemo, JSX, FC, memo } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
5
|
const nonEmpty = 'This field cannot be empty';
|
|
6
6
|
|
|
7
|
-
export const stringRequired = () => z.string({ required_error: nonEmpty }).min(1, nonEmpty);
|
|
7
|
+
export const stringRequired = (): z.ZodString => z.string({ required_error: nonEmpty }).min(1, nonEmpty);
|
|
8
8
|
export const maxLength = (schema: z.ZodString): number => schema.maxLength || 0;
|
|
9
9
|
export const minLength = (schema: z.ZodString): number => schema.minLength || 0;
|
|
10
10
|
export const isRequired = (schema: z.ZodString): boolean => minLength(schema) > 0;
|
|
@@ -25,24 +25,65 @@ export type Validation<S extends ZodObject> =
|
|
|
25
25
|
errors?: Errors<S>;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export const FormContext
|
|
28
|
+
export const FormContext: Context<{
|
|
29
29
|
schema: ZodObject;
|
|
30
|
-
}>(null as never);
|
|
30
|
+
}> = createContext(null as never);
|
|
31
31
|
|
|
32
|
-
export
|
|
32
|
+
export interface FormProps<S extends ZodObject> {
|
|
33
|
+
schema: S;
|
|
34
|
+
children: any;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const Form: FC<FormProps<any>> = memo(function Form({ schema, children }) {
|
|
33
38
|
const value = useMemo(() => ({ schema }), [schema]);
|
|
34
39
|
return <FormContext.Provider value={value}>{children}</FormContext.Provider>;
|
|
35
|
-
};
|
|
40
|
+
});
|
|
36
41
|
|
|
37
42
|
const getShape = <S extends ZodObject>(schema: S) =>
|
|
38
43
|
(schema as z.ZodObject<any>).shape || (schema as z.ZodEffects<z.ZodObject<any>>).sourceType().shape;
|
|
39
44
|
|
|
40
|
-
export function create<S extends ZodObject>(
|
|
45
|
+
export function create<S extends ZodObject>(
|
|
46
|
+
schema: S,
|
|
47
|
+
): {
|
|
48
|
+
register: (
|
|
49
|
+
name: keyof TypeOf<S>,
|
|
50
|
+
data?: MaybeTypeOf<S>,
|
|
51
|
+
errors?: Errors<S>,
|
|
52
|
+
mui?: boolean,
|
|
53
|
+
) => {
|
|
54
|
+
label?: any;
|
|
55
|
+
helperText?: string;
|
|
56
|
+
error?: boolean;
|
|
57
|
+
name: keyof z.TypeOf<S>;
|
|
58
|
+
id: keyof z.TypeOf<S>;
|
|
59
|
+
required: boolean;
|
|
60
|
+
maxLength: number;
|
|
61
|
+
type: string;
|
|
62
|
+
defaultValue?: Partial<z.TypeOf<S>>[keyof z.TypeOf<S>];
|
|
63
|
+
};
|
|
64
|
+
validate: (formData: FormData) => Validation<S>;
|
|
65
|
+
validationError: (data: MaybeTypeOf<S>, errors: Errors<S>) => Validation<S>;
|
|
66
|
+
} {
|
|
41
67
|
if (!getShape(schema)) {
|
|
42
68
|
throw new Error('Invalid schema: only z.object() or z.object().refine() are supported');
|
|
43
69
|
}
|
|
44
70
|
|
|
45
|
-
function register(
|
|
71
|
+
function register(
|
|
72
|
+
name: keyof TypeOf<S>,
|
|
73
|
+
data?: MaybeTypeOf<S>,
|
|
74
|
+
errors?: Errors<S>,
|
|
75
|
+
mui: boolean = false,
|
|
76
|
+
): {
|
|
77
|
+
label?: any;
|
|
78
|
+
helperText?: string;
|
|
79
|
+
error?: boolean;
|
|
80
|
+
name: keyof z.TypeOf<S>;
|
|
81
|
+
id: keyof z.TypeOf<S>;
|
|
82
|
+
required: boolean;
|
|
83
|
+
maxLength: number;
|
|
84
|
+
type: string;
|
|
85
|
+
defaultValue?: Partial<z.TypeOf<S>>[keyof z.TypeOf<S>];
|
|
86
|
+
} {
|
|
46
87
|
const field = getShape(schema)[name];
|
|
47
88
|
return {
|
|
48
89
|
name,
|
|
@@ -87,7 +128,17 @@ export function create<S extends ZodObject>(schema: S) {
|
|
|
87
128
|
return { register, validate, validationError };
|
|
88
129
|
}
|
|
89
130
|
|
|
90
|
-
|
|
131
|
+
interface FieldProps<S extends ZodObject> {
|
|
132
|
+
children?: any;
|
|
133
|
+
name: keyof TypeOf<S>;
|
|
134
|
+
errors?: Validation<S>['errors'];
|
|
135
|
+
hint?: string;
|
|
136
|
+
className?: string;
|
|
137
|
+
labelProps?: any;
|
|
138
|
+
[key: string]: any;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export const Field: FC<FieldProps<any>> = memo(function Field({
|
|
91
142
|
children,
|
|
92
143
|
name,
|
|
93
144
|
errors,
|
|
@@ -95,13 +146,6 @@ function Field<S extends ZodObject>({
|
|
|
95
146
|
className,
|
|
96
147
|
labelProps,
|
|
97
148
|
...props
|
|
98
|
-
}: {
|
|
99
|
-
children?: any;
|
|
100
|
-
name: keyof TypeOf<S>;
|
|
101
|
-
errors?: Validation<S>['errors'];
|
|
102
|
-
hint?: string;
|
|
103
|
-
className?: string;
|
|
104
|
-
labelProps?: any;
|
|
105
149
|
}) {
|
|
106
150
|
const { schema } = useContext(FormContext);
|
|
107
151
|
const { description } = getShape(schema)[name];
|
|
@@ -122,8 +166,13 @@ function Field<S extends ZodObject>({
|
|
|
122
166
|
))}
|
|
123
167
|
</div>
|
|
124
168
|
);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
export interface HintProps {
|
|
172
|
+
children: any;
|
|
173
|
+
error?: boolean;
|
|
125
174
|
}
|
|
126
175
|
|
|
127
|
-
export
|
|
176
|
+
export const Hint: FC<HintProps> = memo(function Hint({ children, error }) {
|
|
128
177
|
return <div className={`hint ${error ? 'hint-error' : ''}`}>{children}</div>;
|
|
129
|
-
}
|
|
178
|
+
});
|
package/src/react/keyboard.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useEffect, createContext, useMemo, useState, Dispatch, SetStateAction, useContext } from 'react';
|
|
3
|
+
import { useEffect, createContext, useMemo, useState, Dispatch, SetStateAction, useContext, FC, Context } from 'react';
|
|
4
4
|
|
|
5
5
|
const isCtrlOrMeta = (e: KeyboardEvent) => e.metaKey || e.ctrlKey;
|
|
6
6
|
|
|
@@ -8,12 +8,17 @@ const EVENT = 'keydown';
|
|
|
8
8
|
|
|
9
9
|
export type Hotkeys = Record<KeyboardEvent['code'], (e: KeyboardEvent) => void>;
|
|
10
10
|
|
|
11
|
-
export
|
|
11
|
+
export type HotkeyContextType = {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
setEnabled: Dispatch<SetStateAction<boolean>>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const HotkeysContext: Context<HotkeyContextType> = createContext<{
|
|
12
17
|
enabled: boolean;
|
|
13
18
|
setEnabled: Dispatch<SetStateAction<boolean>>;
|
|
14
19
|
}>(null as never);
|
|
15
20
|
|
|
16
|
-
export const HotkeysProvider = ({ children }) => {
|
|
21
|
+
export const HotkeysProvider: FC<any> = ({ children }) => {
|
|
17
22
|
const [enabled, setEnabled] = useState(true);
|
|
18
23
|
|
|
19
24
|
const control = useMemo(() => ({ enabled, setEnabled }), [enabled, setEnabled]);
|
|
@@ -21,7 +26,7 @@ export const HotkeysProvider = ({ children }) => {
|
|
|
21
26
|
return <HotkeysContext.Provider value={control}>{children}</HotkeysContext.Provider>;
|
|
22
27
|
};
|
|
23
28
|
|
|
24
|
-
export const useHotkeys = (hotkeys: Hotkeys) => {
|
|
29
|
+
export const useHotkeys = (hotkeys: Hotkeys): void => {
|
|
25
30
|
const { enabled } = useContext(HotkeysContext);
|
|
26
31
|
|
|
27
32
|
useEffect(() => {
|
package/src/react/useFetcher.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
export function useFetcher<T = any>(
|
|
4
|
-
cb,
|
|
4
|
+
cb: any,
|
|
5
5
|
|
|
6
6
|
{ fetchOnMount = false, onError }: { fetchOnMount?: boolean; onError?: (e: Error) => void } = {},
|
|
7
|
-
) {
|
|
7
|
+
): {
|
|
8
|
+
loading: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
data: T | null;
|
|
11
|
+
trigger: (...args: any[]) => Promise<any>;
|
|
12
|
+
} {
|
|
8
13
|
const [loading, setLoading] = useState(fetchOnMount);
|
|
9
14
|
const [error, setError] = useState<Error | null>(null);
|
|
10
15
|
const [data, setData] = useState<T | null>(null);
|
|
@@ -12,7 +17,7 @@ export function useFetcher<T = any>(
|
|
|
12
17
|
const isMounted = useRef(false);
|
|
13
18
|
|
|
14
19
|
const trigger = useCallback(
|
|
15
|
-
async (...args) => {
|
|
20
|
+
async (...args: any[]): Promise<any> => {
|
|
16
21
|
try {
|
|
17
22
|
setLoading(true);
|
|
18
23
|
setError(null);
|
|
@@ -8,7 +8,7 @@ import * as Sharing from 'expo-sharing';
|
|
|
8
8
|
* @param fileName
|
|
9
9
|
* @returns {Promise<void>}
|
|
10
10
|
*/
|
|
11
|
-
export const shareDialog = async (base64, fileName) => {
|
|
11
|
+
export const shareDialog = async (base64: string, fileName: string): Promise<void> => {
|
|
12
12
|
const path = `${FileSystem.documentDirectory}/${fileName}`;
|
|
13
13
|
|
|
14
14
|
try {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as Updates from 'expo-updates';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { FC, useEffect, useState } from 'react';
|
|
3
3
|
import { Text } from 'react-native';
|
|
4
4
|
|
|
5
|
-
export function Update({ children }) {
|
|
5
|
+
export const Update: FC<any> = function Update({ children }) {
|
|
6
6
|
//FIXME useUpdates https://blog.expo.dev/feature-preview-updates-js-api-for-expo-updates-3b92beb40dab
|
|
7
7
|
const [updating, setUpdating] = useState(true);
|
|
8
8
|
|
|
@@ -37,4 +37,4 @@ export function Update({ children }) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
return children;
|
|
40
|
-
}
|
|
40
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { AppState } from 'react-native';
|
|
3
3
|
|
|
4
|
-
export function useAppState() {
|
|
4
|
+
export function useAppState(): 'active' | 'background' | 'inactive' | 'unknown' | 'extension' {
|
|
5
5
|
const [appState, setAppState] = useState(AppState.currentState);
|
|
6
6
|
|
|
7
7
|
useEffect(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
2
|
|
|
3
|
-
export const Fullpage = ({ divRef = null, className = '', children, ...props }) => (
|
|
3
|
+
export const Fullpage: FC<any> = ({ divRef = null, className = '', children, ...props }) => (
|
|
4
4
|
<div
|
|
5
5
|
ref={divRef}
|
|
6
6
|
{...props}
|