betterstart-cli 0.0.112 → 0.0.113
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/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-slash-menu.ts +5 -3
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-source-mode.tsx +8 -2
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-table-add-controls.ts +3 -1
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor.ts +7 -3
- package/dist/assets/adapters/next/templates/init/hooks/use-upload.ts +7 -5
- package/dist/assets/adapters/next/templates/init/pages/profile/profile-form.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-endpoint-dialog.tsx +2 -2
- package/dist/cli.js +33 -4
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx
CHANGED
|
@@ -112,7 +112,7 @@ export function MediaUrlImporter({ onImportFromUrl, accept, className }: MediaUr
|
|
|
112
112
|
<form
|
|
113
113
|
autoComplete="off"
|
|
114
114
|
noValidate
|
|
115
|
-
onSubmit={form.handleSubmit(handleImport, handleInvalid)}
|
|
115
|
+
onSubmit={(event) => form.handleSubmit(handleImport, handleInvalid)(event)}
|
|
116
116
|
className="w-full"
|
|
117
117
|
>
|
|
118
118
|
<InputGroup className="mx-auto max-w-2xl bg-background">
|
|
@@ -23,9 +23,11 @@ export function useContentEditorSlashMenu(editorRef: React.RefObject<Editor | nu
|
|
|
23
23
|
const activeSlashIndex =
|
|
24
24
|
activeSlashIndexState >= filteredSlashCommands.length ? 0 : activeSlashIndexState
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
slashMenuRef.current = slashMenu
|
|
28
|
+
activeSlashIndexRef.current = activeSlashIndex
|
|
29
|
+
filteredSlashCommandsRef.current = filteredSlashCommands
|
|
30
|
+
})
|
|
29
31
|
|
|
30
32
|
const updateSlashMenu = React.useCallback((nextEditor: Editor) => {
|
|
31
33
|
const nextSlashMenu = getSlashMenuState(nextEditor)
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
// oxlint-disable react/refs -- the CodeMirror widget is constructed during render and compared by
|
|
4
|
+
// callback identity in `eq()`. Dropping the ref-backed callbacks would rebuild the widget DOM on
|
|
5
|
+
// every render, so it needs a verified refactor.
|
|
3
6
|
import * as React from 'react'
|
|
4
7
|
import type { ContentEditorSelectionRequest } from '@admin/utils/editor/content-editor-selection-request'
|
|
5
8
|
import type { MarkdownHeadingLevel } from '@admin/utils/editor/markdown-heading-level'
|
|
@@ -151,9 +154,12 @@ export function useContentEditorSourceMode({
|
|
|
151
154
|
const [canUndoMarkdownChange, setCanUndoMarkdownChange] = React.useState(false)
|
|
152
155
|
const [canRedoMarkdownChange, setCanRedoMarkdownChange] = React.useState(false)
|
|
153
156
|
const valueRef = React.useRef(value)
|
|
154
|
-
valueRef.current = value
|
|
155
157
|
const onChangeRef = React.useRef(onChange)
|
|
156
|
-
|
|
158
|
+
|
|
159
|
+
React.useEffect(() => {
|
|
160
|
+
valueRef.current = value
|
|
161
|
+
onChangeRef.current = onChange
|
|
162
|
+
})
|
|
157
163
|
|
|
158
164
|
const handleMediaSelected = React.useCallback(
|
|
159
165
|
(url: string) => {
|
|
@@ -25,7 +25,9 @@ export function useContentEditorTableAddControls(
|
|
|
25
25
|
const tableStateRef = React.useRef<TableAddControlsState | null>(null)
|
|
26
26
|
const isEditorViewMounted = Boolean(getMountedEditorView(editor))
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
tableStateRef.current = tableState
|
|
30
|
+
})
|
|
29
31
|
|
|
30
32
|
const setTable = React.useCallback((next: TableAddControlsState) => {
|
|
31
33
|
setTableState((current) => {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
// oxlint-disable react/refs -- `latestMarkdownRef` is both the synchronous markdown buffer that
|
|
4
|
+
// callbacks write and the value rendered as `sourceValue`. Splitting it into state changes when the
|
|
5
|
+
// buffer is observable and risks the Markdown round-trip, so it needs a verified refactor.
|
|
3
6
|
import * as React from 'react'
|
|
4
7
|
import type { ContentEditorMode } from '@admin/utils/editor/content-editor-mode'
|
|
5
8
|
import type { ContentEditorSelectionRequest } from '@admin/utils/editor/content-editor-selection-request'
|
|
@@ -75,8 +78,6 @@ export function useContentEditor({
|
|
|
75
78
|
updateSlashMenu
|
|
76
79
|
} = useContentEditorSlashMenu(editorRef)
|
|
77
80
|
|
|
78
|
-
isSlashMenuOpenRef.current = slashMenu !== null
|
|
79
|
-
|
|
80
81
|
if (value !== lastValuePropRef.current) {
|
|
81
82
|
lastValuePropRef.current = value
|
|
82
83
|
latestMarkdownRef.current = value
|
|
@@ -173,7 +174,10 @@ export function useContentEditor({
|
|
|
173
174
|
}
|
|
174
175
|
})
|
|
175
176
|
|
|
176
|
-
|
|
177
|
+
React.useEffect(() => {
|
|
178
|
+
editorRef.current = editor
|
|
179
|
+
isSlashMenuOpenRef.current = slashMenu !== null
|
|
180
|
+
})
|
|
177
181
|
|
|
178
182
|
const syncRichContent = React.useCallback(
|
|
179
183
|
(nextValue: string = latestMarkdownRef.current, selectionOffset?: number) => {
|
|
@@ -89,11 +89,13 @@ export function useUpload(options: UseUploadOptions = {}): UseUploadReturn {
|
|
|
89
89
|
const uploadAbortControllerRef = React.useRef<AbortController | null>(null)
|
|
90
90
|
const progressIntervalRef = React.useRef<ReturnType<typeof setInterval> | null>(null)
|
|
91
91
|
const progressResetTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
92
|
-
|
|
93
|
-
previousIsActiveRef.current
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
React.useEffect(() => {
|
|
93
|
+
if (previousIsActiveRef.current !== isActive) {
|
|
94
|
+
previousIsActiveRef.current = isActive
|
|
95
|
+
activeActivityIdRef.current += 1
|
|
96
|
+
}
|
|
97
|
+
activeRef.current = isActive
|
|
98
|
+
})
|
|
97
99
|
|
|
98
100
|
const clearProgressResetTimeout = React.useCallback(() => {
|
|
99
101
|
if (progressResetTimeoutRef.current) {
|
|
@@ -32,7 +32,7 @@ import { Input } from '@admin/components/ui/input'
|
|
|
32
32
|
import { Spinner } from '@admin/components/ui/spinner'
|
|
33
33
|
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
|
|
34
34
|
import { useRouter } from 'next/navigation'
|
|
35
|
-
import { useForm } from 'react-hook-form'
|
|
35
|
+
import { useForm, useWatch } from 'react-hook-form'
|
|
36
36
|
import { toast } from 'sonner'
|
|
37
37
|
import { z } from 'zod/v3'
|
|
38
38
|
|
|
@@ -94,8 +94,8 @@ export function ProfileForm({ user }: ProfileFormProps) {
|
|
|
94
94
|
reValidateMode: 'onChange'
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
const emailDirty = profileForm.
|
|
98
|
-
const imageValue = profileForm.
|
|
97
|
+
const emailDirty = useWatch({ control: profileForm.control, name: 'email' }) !== user.email
|
|
98
|
+
const imageValue = useWatch({ control: profileForm.control, name: 'image' })
|
|
99
99
|
|
|
100
100
|
function onProfileSubmit(values: ProfileValues) {
|
|
101
101
|
startProfileTransition(async () => {
|
package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-endpoint-dialog.tsx
CHANGED
|
@@ -35,7 +35,7 @@ import { webhookEventSources } from '@admin/data/webhook-events'
|
|
|
35
35
|
import { useWebhookSubscriptions } from '@admin/hooks/use-webhooks'
|
|
36
36
|
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
|
|
37
37
|
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
38
|
-
import { useForm } from 'react-hook-form'
|
|
38
|
+
import { useForm, useWatch } from 'react-hook-form'
|
|
39
39
|
import { toast } from 'sonner'
|
|
40
40
|
import { z } from 'zod/v3'
|
|
41
41
|
|
|
@@ -81,7 +81,7 @@ export function WebhookEndpointDialog({ webhook, open, onOpenChange }: WebhookEn
|
|
|
81
81
|
events: subscribedEvents
|
|
82
82
|
}
|
|
83
83
|
})
|
|
84
|
-
const events = form.
|
|
84
|
+
const events = useWatch({ control: form.control, name: 'events' })
|
|
85
85
|
|
|
86
86
|
React.useEffect(() => {
|
|
87
87
|
if (!open) return
|
package/dist/cli.js
CHANGED
|
@@ -15626,7 +15626,14 @@ function buildUiImports(ctx) {
|
|
|
15626
15626
|
if (ctx.hasSectionCardHeading) cardImports.push("CardHeader", "CardTitle");
|
|
15627
15627
|
const formImports = [
|
|
15628
15628
|
ctx.hasFormRoot === false ? "" : "Form",
|
|
15629
|
-
...ctx.hasFormControls === false ? [] : [
|
|
15629
|
+
...ctx.hasFormControls === false ? [] : [
|
|
15630
|
+
"FormControl",
|
|
15631
|
+
"FormDescription",
|
|
15632
|
+
"FormField",
|
|
15633
|
+
"FormItem",
|
|
15634
|
+
"FormLabel",
|
|
15635
|
+
ctx.hasFormMessage === false ? "" : "FormMessage"
|
|
15636
|
+
]
|
|
15630
15637
|
].filter(Boolean);
|
|
15631
15638
|
const uiImports = [
|
|
15632
15639
|
`import { ${cardImports.join(", ")} } from '@admin/components/ui/card'`,
|
|
@@ -16360,7 +16367,9 @@ ${defaultValues}
|
|
|
16360
16367
|
defaultValues
|
|
16361
16368
|
})
|
|
16362
16369
|
const defaultValuesRef = React.useRef(defaultValues)
|
|
16363
|
-
|
|
16370
|
+
React.useEffect(() => {
|
|
16371
|
+
defaultValuesRef.current = defaultValues
|
|
16372
|
+
})
|
|
16364
16373
|
React.useEffect(
|
|
16365
16374
|
() => () => {
|
|
16366
16375
|
form.reset(defaultValuesRef.current)
|
|
@@ -19575,6 +19584,7 @@ function generateForm(schema, pagesDir, options = {}) {
|
|
|
19575
19584
|
tabFieldNames
|
|
19576
19585
|
});
|
|
19577
19586
|
const formControlFreeFieldTypes = /* @__PURE__ */ new Set(["separator", "tabs"]);
|
|
19587
|
+
const formMessageFreeFieldTypes = /* @__PURE__ */ new Set(["boolean", "group", "section", "separator", "tabs"]);
|
|
19578
19588
|
const inputFreeFieldTypes = /* @__PURE__ */ new Set([
|
|
19579
19589
|
"boolean",
|
|
19580
19590
|
"image",
|
|
@@ -19638,6 +19648,10 @@ function generateForm(schema, pagesDir, options = {}) {
|
|
|
19638
19648
|
return false;
|
|
19639
19649
|
};
|
|
19640
19650
|
const contentHasRenderedIconPostfix = hasRenderedIconPostfix2(allFormFields);
|
|
19651
|
+
const contentUsesFormMessage = contentHasRenderedIconPostfix || flatFields.some((field) => {
|
|
19652
|
+
if (field.primaryKey || field.hidden) return false;
|
|
19653
|
+
return !formMessageFreeFieldTypes.has(field.type);
|
|
19654
|
+
});
|
|
19641
19655
|
const uiImports = buildUiImports({
|
|
19642
19656
|
hasBoolean,
|
|
19643
19657
|
hasTextarea,
|
|
@@ -19665,6 +19679,7 @@ function generateForm(schema, pagesDir, options = {}) {
|
|
|
19665
19679
|
hasFormRoot: true,
|
|
19666
19680
|
hasButton: hasRelationship || hasSelectCombobox || hasNestedList,
|
|
19667
19681
|
hasFormControls: contentUsesFormControls || contentHasRenderedIconPostfix,
|
|
19682
|
+
hasFormMessage: contentUsesFormMessage,
|
|
19668
19683
|
hasInput: contentUsesInput
|
|
19669
19684
|
});
|
|
19670
19685
|
const lucideIcons = [];
|
|
@@ -23010,6 +23025,7 @@ function generateSingleForm(schema, pagesDir, options = {}) {
|
|
|
23010
23025
|
"tabs"
|
|
23011
23026
|
]);
|
|
23012
23027
|
const formControlFreeFieldTypes = /* @__PURE__ */ new Set(["separator", "tabs"]);
|
|
23028
|
+
const formMessageFreeFieldTypes = /* @__PURE__ */ new Set(["boolean", "group", "section", "separator", "tabs"]);
|
|
23013
23029
|
const cardArtifacts = cardGroups.map((group2) => {
|
|
23014
23030
|
const analysis = analyzeGroup(group2.fields);
|
|
23015
23031
|
const groupFlatFields = group2.flatFields;
|
|
@@ -23040,6 +23056,10 @@ function generateSingleForm(schema, pagesDir, options = {}) {
|
|
|
23040
23056
|
if (field.type === "list" && (!field.fields || field.fields.length === 0)) return false;
|
|
23041
23057
|
return !formControlFreeFieldTypes.has(field.type);
|
|
23042
23058
|
}) || hasIconPostfix;
|
|
23059
|
+
const hasFormMessage = hasIconPostfix || groupFlatFields.some((field) => {
|
|
23060
|
+
if (field.primaryKey || field.hidden) return false;
|
|
23061
|
+
return !formMessageFreeFieldTypes.has(field.type);
|
|
23062
|
+
});
|
|
23043
23063
|
const groupUiImports = buildUiImports({
|
|
23044
23064
|
hasBoolean: hasFieldType(group2.fields, "boolean"),
|
|
23045
23065
|
hasTextarea: hasFieldType(group2.fields, "text"),
|
|
@@ -23065,6 +23085,7 @@ function generateSingleForm(schema, pagesDir, options = {}) {
|
|
|
23065
23085
|
hasCardContent: true,
|
|
23066
23086
|
hasSectionCardHeading: true,
|
|
23067
23087
|
hasFormRoot: true,
|
|
23088
|
+
hasFormMessage,
|
|
23068
23089
|
hasButton: true,
|
|
23069
23090
|
hasFormControls,
|
|
23070
23091
|
hasInput
|
|
@@ -33067,7 +33088,12 @@ function scaffoldOxfmt(cwd, linter, adminDir) {
|
|
|
33067
33088
|
"import/consistent-type-specifier-style": ["error", "prefer-top-level"]
|
|
33068
33089
|
},
|
|
33069
33090
|
// The generated admin vendors shadcn and Tiptap primitives whose a11y and hook shapes
|
|
33070
|
-
// BetterStart owns, so the rest of the project stays fully linted.
|
|
33091
|
+
// BetterStart owns, so the rest of the project stays fully linted. TanStack Table/Virtual
|
|
33092
|
+
// and react-hook-form expose no React Compiler-compatible alternative to the APIs the admin
|
|
33093
|
+
// is built on, so `react/incompatible-library` is scoped off there rather than per call site.
|
|
33094
|
+
// Admin state that tracks Tiptap, CodeMirror, scroll position, and DOM measurements is
|
|
33095
|
+
// synchronised from effects, which is what effects are for, so `react/set-state-in-effect`
|
|
33096
|
+
// is scoped off there too.
|
|
33071
33097
|
overrides: [
|
|
33072
33098
|
{
|
|
33073
33099
|
files: [`**/${admin}/**`, `**/(${namespace})/**`],
|
|
@@ -33076,6 +33102,8 @@ function scaffoldOxfmt(cwd, linter, adminDir) {
|
|
|
33076
33102
|
"jsx-a11y/no-autofocus": "off",
|
|
33077
33103
|
"jsx-a11y/anchor-has-content": "off",
|
|
33078
33104
|
"react-hooks/exhaustive-deps": "off",
|
|
33105
|
+
"react/incompatible-library": "off",
|
|
33106
|
+
"react/set-state-in-effect": "off",
|
|
33079
33107
|
"unicorn/no-new-array": "off",
|
|
33080
33108
|
"unicorn/no-empty-file": "off"
|
|
33081
33109
|
}
|
|
@@ -33083,7 +33111,8 @@ function scaffoldOxfmt(cwd, linter, adminDir) {
|
|
|
33083
33111
|
{
|
|
33084
33112
|
files: [`**/${admin}/components/ui/**`],
|
|
33085
33113
|
rules: {
|
|
33086
|
-
"react/no-multi-comp": "off"
|
|
33114
|
+
"react/no-multi-comp": "off",
|
|
33115
|
+
"react/set-state-in-effect": "off"
|
|
33087
33116
|
}
|
|
33088
33117
|
}
|
|
33089
33118
|
],
|