wp-typia 0.16.1 → 0.16.2
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/package.json +2 -2
- package/src/ui/README.md +19 -0
- package/src/ui/add-flow-model.ts +120 -0
- package/src/ui/add-flow.tsx +238 -163
- package/src/ui/create-flow-model.ts +125 -0
- package/src/ui/create-flow.tsx +163 -120
- package/src/ui/first-party-form-model.ts +62 -0
- package/src/ui/first-party-form.tsx +460 -0
- package/src/ui/migrate-flow-model.ts +126 -0
- package/src/ui/migrate-flow.tsx +169 -139
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT,
|
|
5
|
+
FIRST_PARTY_SELECT_FIELD_BODY_HEIGHT,
|
|
6
|
+
FIRST_PARTY_TEXT_FIELD_BODY_HEIGHT,
|
|
7
|
+
getFirstPartyScrollTop,
|
|
8
|
+
getFirstPartyViewportHeight,
|
|
9
|
+
} from "./first-party-form-model";
|
|
10
|
+
|
|
11
|
+
export const createFlowSchema = z.object({
|
|
12
|
+
"data-storage": z.string().optional(),
|
|
13
|
+
namespace: z.string().optional(),
|
|
14
|
+
"no-install": z.boolean().default(false),
|
|
15
|
+
"package-manager": z.string().optional(),
|
|
16
|
+
"persistence-policy": z.string().optional(),
|
|
17
|
+
"php-prefix": z.string().optional(),
|
|
18
|
+
"project-dir": z.string().min(1),
|
|
19
|
+
template: z.string().optional(),
|
|
20
|
+
"text-domain": z.string().optional(),
|
|
21
|
+
variant: z.string().optional(),
|
|
22
|
+
"with-migration-ui": z.boolean().default(false),
|
|
23
|
+
"with-test-preset": z.boolean().default(false),
|
|
24
|
+
"with-wp-env": z.boolean().default(false),
|
|
25
|
+
yes: z.boolean().default(false),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export type CreateFlowValues = z.infer<typeof createFlowSchema>;
|
|
29
|
+
|
|
30
|
+
export type CreateFieldName =
|
|
31
|
+
| "project-dir"
|
|
32
|
+
| "template"
|
|
33
|
+
| "package-manager"
|
|
34
|
+
| "namespace"
|
|
35
|
+
| "text-domain"
|
|
36
|
+
| "php-prefix"
|
|
37
|
+
| "data-storage"
|
|
38
|
+
| "persistence-policy"
|
|
39
|
+
| "no-install"
|
|
40
|
+
| "yes"
|
|
41
|
+
| "with-wp-env"
|
|
42
|
+
| "with-test-preset"
|
|
43
|
+
| "with-migration-ui";
|
|
44
|
+
|
|
45
|
+
export const CREATE_CHECKBOX_FIELD_NAMES = [
|
|
46
|
+
"no-install",
|
|
47
|
+
"yes",
|
|
48
|
+
"with-wp-env",
|
|
49
|
+
"with-test-preset",
|
|
50
|
+
"with-migration-ui",
|
|
51
|
+
] as const satisfies ReadonlyArray<CreateFieldName>;
|
|
52
|
+
|
|
53
|
+
export const CREATE_FIELD_ORDER = [
|
|
54
|
+
"project-dir",
|
|
55
|
+
"template",
|
|
56
|
+
"package-manager",
|
|
57
|
+
"namespace",
|
|
58
|
+
"text-domain",
|
|
59
|
+
"php-prefix",
|
|
60
|
+
"data-storage",
|
|
61
|
+
"persistence-policy",
|
|
62
|
+
...CREATE_CHECKBOX_FIELD_NAMES,
|
|
63
|
+
] as const satisfies ReadonlyArray<CreateFieldName>;
|
|
64
|
+
|
|
65
|
+
const CREATE_FIELD_HEIGHTS: Record<CreateFieldName, number> = {
|
|
66
|
+
"data-storage": FIRST_PARTY_SELECT_FIELD_BODY_HEIGHT,
|
|
67
|
+
namespace: FIRST_PARTY_TEXT_FIELD_BODY_HEIGHT,
|
|
68
|
+
"no-install": FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT,
|
|
69
|
+
"package-manager": FIRST_PARTY_SELECT_FIELD_BODY_HEIGHT,
|
|
70
|
+
"persistence-policy": FIRST_PARTY_SELECT_FIELD_BODY_HEIGHT,
|
|
71
|
+
"php-prefix": FIRST_PARTY_TEXT_FIELD_BODY_HEIGHT,
|
|
72
|
+
"project-dir": FIRST_PARTY_TEXT_FIELD_BODY_HEIGHT,
|
|
73
|
+
template: FIRST_PARTY_SELECT_FIELD_BODY_HEIGHT,
|
|
74
|
+
"text-domain": FIRST_PARTY_TEXT_FIELD_BODY_HEIGHT,
|
|
75
|
+
yes: FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT,
|
|
76
|
+
"with-migration-ui": FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT,
|
|
77
|
+
"with-test-preset": FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT,
|
|
78
|
+
"with-wp-env": FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export function isCreatePersistenceTemplate(template?: string): boolean {
|
|
82
|
+
return template === "persistence" || template === "compound";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getVisibleCreateFieldNames(
|
|
86
|
+
values: Partial<CreateFlowValues>,
|
|
87
|
+
): Array<CreateFieldName> {
|
|
88
|
+
return CREATE_FIELD_ORDER.filter((name) => {
|
|
89
|
+
if (name === "data-storage" || name === "persistence-policy") {
|
|
90
|
+
return isCreatePersistenceTemplate(values.template);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function getCreateViewportHeight(terminalHeight = 24): number {
|
|
98
|
+
return getFirstPartyViewportHeight(terminalHeight);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getCreateScrollTop(options: {
|
|
102
|
+
activeFieldName: string | null;
|
|
103
|
+
values: Partial<CreateFlowValues>;
|
|
104
|
+
viewportHeight: number;
|
|
105
|
+
}): number {
|
|
106
|
+
const { activeFieldName, values, viewportHeight } = options;
|
|
107
|
+
return getFirstPartyScrollTop({
|
|
108
|
+
activeFieldName,
|
|
109
|
+
fieldHeights: CREATE_FIELD_HEIGHTS,
|
|
110
|
+
visibleFieldNames: getVisibleCreateFieldNames(values),
|
|
111
|
+
viewportHeight,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function sanitizeCreateSubmitValues(values: CreateFlowValues): CreateFlowValues {
|
|
116
|
+
if (isCreatePersistenceTemplate(values.template)) {
|
|
117
|
+
return values;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
...values,
|
|
122
|
+
"data-storage": undefined,
|
|
123
|
+
"persistence-policy": undefined,
|
|
124
|
+
};
|
|
125
|
+
}
|
package/src/ui/create-flow.tsx
CHANGED
|
@@ -1,33 +1,165 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { createElement, useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Form,
|
|
5
|
+
type SelectOption,
|
|
6
|
+
useFormContext,
|
|
7
|
+
useTerminalDimensions,
|
|
8
|
+
} from "@bunli/tui";
|
|
3
9
|
|
|
4
10
|
import { executeCreateCommand } from "../runtime-bridge";
|
|
5
11
|
import { useAlternateBufferLifecycle } from "./alternate-buffer-lifecycle";
|
|
12
|
+
import {
|
|
13
|
+
type CreateFlowValues,
|
|
14
|
+
CREATE_CHECKBOX_FIELD_NAMES,
|
|
15
|
+
createFlowSchema,
|
|
16
|
+
getCreateScrollTop,
|
|
17
|
+
getCreateViewportHeight,
|
|
18
|
+
getVisibleCreateFieldNames,
|
|
19
|
+
isCreatePersistenceTemplate,
|
|
20
|
+
sanitizeCreateSubmitValues,
|
|
21
|
+
} from "./create-flow-model";
|
|
22
|
+
import {
|
|
23
|
+
FirstPartyCheckboxField,
|
|
24
|
+
FirstPartyScrollBox,
|
|
25
|
+
FirstPartySelectField,
|
|
26
|
+
FirstPartyTextField,
|
|
27
|
+
} from "./first-party-form";
|
|
28
|
+
import { getWrappedFieldNeighbors } from "./first-party-form-model";
|
|
29
|
+
|
|
30
|
+
const templateOptions: SelectOption[] = [
|
|
31
|
+
{ description: "Basic block scaffold", name: "basic", value: "basic" },
|
|
32
|
+
{ description: "Interactivity API block scaffold", name: "interactivity", value: "interactivity" },
|
|
33
|
+
{ description: "Persistence-enabled block scaffold", name: "persistence", value: "persistence" },
|
|
34
|
+
{ description: "Compound parent + child scaffold", name: "compound", value: "compound" },
|
|
35
|
+
{ description: "Official empty workspace template", name: "workspace", value: "workspace" },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const packageManagerOptions: SelectOption[] = [
|
|
39
|
+
{ description: "Use npm", name: "npm", value: "npm" },
|
|
40
|
+
{ description: "Use pnpm", name: "pnpm", value: "pnpm" },
|
|
41
|
+
{ description: "Use yarn", name: "yarn", value: "yarn" },
|
|
42
|
+
{ description: "Use bun", name: "bun", value: "bun" },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const dataStorageOptions: SelectOption[] = [
|
|
46
|
+
{ description: "Dedicated custom table storage", name: "custom-table", value: "custom-table" },
|
|
47
|
+
{ description: "Persist through post meta", name: "post-meta", value: "post-meta" },
|
|
48
|
+
];
|
|
6
49
|
|
|
7
|
-
const
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"package-manager": z.string().optional(),
|
|
12
|
-
"persistence-policy": z.string().optional(),
|
|
13
|
-
"php-prefix": z.string().optional(),
|
|
14
|
-
"project-dir": z.string().min(1),
|
|
15
|
-
template: z.string().optional(),
|
|
16
|
-
"text-domain": z.string().optional(),
|
|
17
|
-
variant: z.string().optional(),
|
|
18
|
-
"with-migration-ui": z.boolean().default(false),
|
|
19
|
-
"with-test-preset": z.boolean().default(false),
|
|
20
|
-
"with-wp-env": z.boolean().default(false),
|
|
21
|
-
yes: z.boolean().default(false),
|
|
22
|
-
});
|
|
50
|
+
const persistencePolicyOptions: SelectOption[] = [
|
|
51
|
+
{ description: "Authenticated write policy", name: "authenticated", value: "authenticated" },
|
|
52
|
+
{ description: "Public token policy", name: "public", value: "public" },
|
|
53
|
+
];
|
|
23
54
|
|
|
24
|
-
|
|
55
|
+
const checkboxLabels: Record<(typeof CREATE_CHECKBOX_FIELD_NAMES)[number], string> = {
|
|
56
|
+
"no-install": "Skip dependency install",
|
|
57
|
+
yes: "Use defaults without prompts",
|
|
58
|
+
"with-wp-env": "Add wp-env preset",
|
|
59
|
+
"with-test-preset": "Add test preset",
|
|
60
|
+
"with-migration-ui": "Add migration UI",
|
|
61
|
+
};
|
|
25
62
|
|
|
26
63
|
type CreateFlowProps = {
|
|
27
64
|
cwd: string;
|
|
28
65
|
initialValues: Partial<CreateFlowValues>;
|
|
29
66
|
};
|
|
30
67
|
|
|
68
|
+
type CreateSelectFieldName = {
|
|
69
|
+
[K in keyof CreateFlowValues]-?: CreateFlowValues[K] extends string | undefined ? K : never;
|
|
70
|
+
}[keyof CreateFlowValues];
|
|
71
|
+
|
|
72
|
+
function CreateFlowFields() {
|
|
73
|
+
const { activeFieldName, values } = useFormContext();
|
|
74
|
+
const { height: terminalHeight = 24 } = useTerminalDimensions();
|
|
75
|
+
const createValues = values as Partial<CreateFlowValues>;
|
|
76
|
+
const template = createValues.template;
|
|
77
|
+
const viewportHeight = getCreateViewportHeight(terminalHeight);
|
|
78
|
+
const visibleFields = useMemo(() => getVisibleCreateFieldNames(createValues), [createValues]);
|
|
79
|
+
const scrollValues = useMemo(() => ({ template }), [template]);
|
|
80
|
+
const scrollTop = useMemo(
|
|
81
|
+
() =>
|
|
82
|
+
getCreateScrollTop({
|
|
83
|
+
activeFieldName,
|
|
84
|
+
values: scrollValues,
|
|
85
|
+
viewportHeight,
|
|
86
|
+
}),
|
|
87
|
+
[activeFieldName, scrollValues, viewportHeight],
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return createElement(
|
|
91
|
+
FirstPartyScrollBox,
|
|
92
|
+
{ scrollTop, viewportHeight },
|
|
93
|
+
[
|
|
94
|
+
createElement(FirstPartyTextField, {
|
|
95
|
+
...getWrappedFieldNeighbors(visibleFields, "project-dir"),
|
|
96
|
+
key: "project-dir",
|
|
97
|
+
label: "Project directory",
|
|
98
|
+
name: "project-dir",
|
|
99
|
+
required: true,
|
|
100
|
+
}),
|
|
101
|
+
createElement(FirstPartySelectField, {
|
|
102
|
+
...getWrappedFieldNeighbors(visibleFields, "template"),
|
|
103
|
+
key: "template",
|
|
104
|
+
label: "Template",
|
|
105
|
+
name: "template" satisfies CreateSelectFieldName,
|
|
106
|
+
options: templateOptions,
|
|
107
|
+
}),
|
|
108
|
+
createElement(FirstPartySelectField, {
|
|
109
|
+
...getWrappedFieldNeighbors(visibleFields, "package-manager"),
|
|
110
|
+
key: "package-manager",
|
|
111
|
+
label: "Package manager",
|
|
112
|
+
name: "package-manager" satisfies CreateSelectFieldName,
|
|
113
|
+
options: packageManagerOptions,
|
|
114
|
+
}),
|
|
115
|
+
createElement(FirstPartyTextField, {
|
|
116
|
+
...getWrappedFieldNeighbors(visibleFields, "namespace"),
|
|
117
|
+
key: "namespace",
|
|
118
|
+
label: "Namespace",
|
|
119
|
+
name: "namespace",
|
|
120
|
+
}),
|
|
121
|
+
createElement(FirstPartyTextField, {
|
|
122
|
+
...getWrappedFieldNeighbors(visibleFields, "text-domain"),
|
|
123
|
+
key: "text-domain",
|
|
124
|
+
label: "Text domain",
|
|
125
|
+
name: "text-domain",
|
|
126
|
+
}),
|
|
127
|
+
createElement(FirstPartyTextField, {
|
|
128
|
+
...getWrappedFieldNeighbors(visibleFields, "php-prefix"),
|
|
129
|
+
key: "php-prefix",
|
|
130
|
+
label: "PHP prefix",
|
|
131
|
+
name: "php-prefix",
|
|
132
|
+
}),
|
|
133
|
+
isCreatePersistenceTemplate(template)
|
|
134
|
+
? createElement(FirstPartySelectField, {
|
|
135
|
+
...getWrappedFieldNeighbors(visibleFields, "data-storage"),
|
|
136
|
+
key: "data-storage",
|
|
137
|
+
label: "Data storage",
|
|
138
|
+
name: "data-storage" satisfies CreateSelectFieldName,
|
|
139
|
+
options: dataStorageOptions,
|
|
140
|
+
})
|
|
141
|
+
: null,
|
|
142
|
+
isCreatePersistenceTemplate(template)
|
|
143
|
+
? createElement(FirstPartySelectField, {
|
|
144
|
+
...getWrappedFieldNeighbors(visibleFields, "persistence-policy"),
|
|
145
|
+
key: "persistence-policy",
|
|
146
|
+
label: "Persistence policy",
|
|
147
|
+
name: "persistence-policy" satisfies CreateSelectFieldName,
|
|
148
|
+
options: persistencePolicyOptions,
|
|
149
|
+
})
|
|
150
|
+
: null,
|
|
151
|
+
...CREATE_CHECKBOX_FIELD_NAMES.map((name) =>
|
|
152
|
+
createElement(FirstPartyCheckboxField, {
|
|
153
|
+
...getWrappedFieldNeighbors(visibleFields, name),
|
|
154
|
+
key: name,
|
|
155
|
+
label: checkboxLabels[name],
|
|
156
|
+
name,
|
|
157
|
+
}),
|
|
158
|
+
),
|
|
159
|
+
],
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
31
163
|
export function CreateFlow({ cwd, initialValues }: CreateFlowProps) {
|
|
32
164
|
const { handleCancel, handleSubmit } = useAlternateBufferLifecycle("wp-typia create failed");
|
|
33
165
|
const defaultPrompt = {
|
|
@@ -42,114 +174,25 @@ export function CreateFlow({ cwd, initialValues }: CreateFlowProps) {
|
|
|
42
174
|
};
|
|
43
175
|
|
|
44
176
|
return (
|
|
45
|
-
<
|
|
46
|
-
fields={[
|
|
47
|
-
{ kind: "text", label: "Project directory", name: "project-dir", required: true },
|
|
48
|
-
{
|
|
49
|
-
kind: "select",
|
|
50
|
-
label: "Template",
|
|
51
|
-
name: "template",
|
|
52
|
-
options: [
|
|
53
|
-
{ name: "basic", description: "Basic block scaffold", value: "basic" },
|
|
54
|
-
{
|
|
55
|
-
name: "interactivity",
|
|
56
|
-
description: "Interactivity API block scaffold",
|
|
57
|
-
value: "interactivity",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: "persistence",
|
|
61
|
-
description: "Persistence-enabled block scaffold",
|
|
62
|
-
value: "persistence",
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
name: "compound",
|
|
66
|
-
description: "Compound parent + child scaffold",
|
|
67
|
-
value: "compound",
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: "@wp-typia/create-workspace-template",
|
|
71
|
-
description: "Official empty workspace template",
|
|
72
|
-
value: "@wp-typia/create-workspace-template",
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
kind: "select",
|
|
78
|
-
label: "Package manager",
|
|
79
|
-
name: "package-manager",
|
|
80
|
-
options: [
|
|
81
|
-
{ name: "npm", description: "Use npm", value: "npm" },
|
|
82
|
-
{ name: "pnpm", description: "Use pnpm", value: "pnpm" },
|
|
83
|
-
{ name: "yarn", description: "Use yarn", value: "yarn" },
|
|
84
|
-
{ name: "bun", description: "Use bun", value: "bun" },
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
{ kind: "text", label: "Namespace", name: "namespace" },
|
|
88
|
-
{ kind: "text", label: "Text domain", name: "text-domain" },
|
|
89
|
-
{ kind: "text", label: "PHP prefix", name: "php-prefix" },
|
|
90
|
-
{
|
|
91
|
-
kind: "select",
|
|
92
|
-
label: "Data storage",
|
|
93
|
-
name: "data-storage",
|
|
94
|
-
options: [
|
|
95
|
-
{
|
|
96
|
-
name: "custom-table",
|
|
97
|
-
description: "Dedicated custom table storage",
|
|
98
|
-
value: "custom-table",
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
name: "post-meta",
|
|
102
|
-
description: "Persist through post meta",
|
|
103
|
-
value: "post-meta",
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
visibleWhen: (values) =>
|
|
107
|
-
values.template === "persistence" || values.template === "compound",
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
kind: "select",
|
|
111
|
-
label: "Persistence policy",
|
|
112
|
-
name: "persistence-policy",
|
|
113
|
-
options: [
|
|
114
|
-
{
|
|
115
|
-
name: "authenticated",
|
|
116
|
-
description: "Authenticated write policy",
|
|
117
|
-
value: "authenticated",
|
|
118
|
-
},
|
|
119
|
-
{ name: "public", description: "Public token policy", value: "public" },
|
|
120
|
-
],
|
|
121
|
-
visibleWhen: (values) =>
|
|
122
|
-
values.template === "persistence" || values.template === "compound",
|
|
123
|
-
},
|
|
124
|
-
{ kind: "checkbox", label: "Skip dependency install", name: "no-install" },
|
|
125
|
-
{ kind: "checkbox", label: "Use defaults without prompts", name: "yes" },
|
|
126
|
-
{ kind: "checkbox", label: "Add wp-env preset", name: "with-wp-env" },
|
|
127
|
-
{
|
|
128
|
-
kind: "checkbox",
|
|
129
|
-
label: "Add test preset",
|
|
130
|
-
name: "with-test-preset",
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
kind: "checkbox",
|
|
134
|
-
label: "Add migration UI",
|
|
135
|
-
name: "with-migration-ui",
|
|
136
|
-
},
|
|
137
|
-
]}
|
|
177
|
+
<Form
|
|
138
178
|
initialValues={initialValues}
|
|
139
179
|
onCancel={handleCancel}
|
|
140
180
|
onSubmit={async (values) =>
|
|
141
181
|
handleSubmit(async () => {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
182
|
+
const flags = sanitizeCreateSubmitValues(values);
|
|
183
|
+
await executeCreateCommand({
|
|
184
|
+
cwd,
|
|
185
|
+
flags,
|
|
186
|
+
interactive: true,
|
|
187
|
+
projectDir: values["project-dir"],
|
|
188
|
+
prompt: defaultPrompt,
|
|
189
|
+
});
|
|
149
190
|
})
|
|
150
191
|
}
|
|
151
192
|
schema={createFlowSchema}
|
|
152
193
|
title="Create a wp-typia project"
|
|
153
|
-
|
|
194
|
+
>
|
|
195
|
+
<CreateFlowFields />
|
|
196
|
+
</Form>
|
|
154
197
|
);
|
|
155
198
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const FIRST_PARTY_FIELD_GAP = 1;
|
|
2
|
+
export const FIRST_PARTY_TEXT_FIELD_BODY_HEIGHT = 6;
|
|
3
|
+
export const FIRST_PARTY_CHECKBOX_FIELD_BODY_HEIGHT = 2;
|
|
4
|
+
export const FIRST_PARTY_SELECT_FIELD_LABEL_GAP = 1;
|
|
5
|
+
export const FIRST_PARTY_SELECT_FIELD_CONTROL_HEIGHT = 3;
|
|
6
|
+
export const FIRST_PARTY_SELECT_FIELD_BODY_HEIGHT =
|
|
7
|
+
1 + FIRST_PARTY_SELECT_FIELD_LABEL_GAP + FIRST_PARTY_SELECT_FIELD_CONTROL_HEIGHT + 1;
|
|
8
|
+
|
|
9
|
+
export type FirstPartyFieldHeights<TName extends string> = Record<TName, number>;
|
|
10
|
+
|
|
11
|
+
export function getWrappedFieldNeighbors<TName extends string>(
|
|
12
|
+
visibleFieldNames: ReadonlyArray<TName>,
|
|
13
|
+
fieldName: TName,
|
|
14
|
+
): {
|
|
15
|
+
nextFieldName?: TName;
|
|
16
|
+
previousFieldName?: TName;
|
|
17
|
+
} {
|
|
18
|
+
const index = visibleFieldNames.indexOf(fieldName);
|
|
19
|
+
if (index === -1 || visibleFieldNames.length < 2) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
nextFieldName: visibleFieldNames[(index + 1) % visibleFieldNames.length],
|
|
25
|
+
previousFieldName:
|
|
26
|
+
visibleFieldNames[(index - 1 + visibleFieldNames.length) % visibleFieldNames.length],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getFirstPartyViewportHeight(terminalHeight = 24): number {
|
|
31
|
+
return Math.max(8, Math.min(28, terminalHeight - 12));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getFirstPartyScrollTop<TName extends string>(options: {
|
|
35
|
+
activeFieldName: string | null;
|
|
36
|
+
fieldHeights: FirstPartyFieldHeights<TName>;
|
|
37
|
+
visibleFieldNames: ReadonlyArray<TName>;
|
|
38
|
+
viewportHeight: number;
|
|
39
|
+
}): number {
|
|
40
|
+
const { activeFieldName, fieldHeights, visibleFieldNames, viewportHeight } = options;
|
|
41
|
+
if (!activeFieldName) {
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let offset = 0;
|
|
46
|
+
for (const fieldName of visibleFieldNames) {
|
|
47
|
+
const fieldHeight = fieldHeights[fieldName];
|
|
48
|
+
if (fieldName === activeFieldName) {
|
|
49
|
+
const safeViewportHeight = Math.max(4, viewportHeight - 2);
|
|
50
|
+
const fieldBottom = offset + fieldHeight;
|
|
51
|
+
if (fieldBottom <= safeViewportHeight) {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return Math.max(0, fieldBottom - safeViewportHeight + 1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
offset += fieldHeight + FIRST_PARTY_FIELD_GAP;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return 0;
|
|
62
|
+
}
|