Skip to content

Form renderer: a defaultValues reset is not a user edit for memoized callers either - #5707

Merged
os-sales merged 2 commits into
mainfrom
claude/issue-5235-form-reset-notification-channels
Aug 22, 2026
Merged

Form renderer: a defaultValues reset is not a user edit for memoized callers either#5707
os-sales merged 2 commits into
mainfrom
claude/issue-5235-form-reset-notification-channels

Conversation

@os-sales

@os-sales os-sales commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Fixes #5235

The asymmetry this fixes

packages/components/src/renderers/form/form.tsx publishes three notification channels around a defaultValues reset, and they were driven two different ways:

channel how a reset was kept off it identity-independent?
onDirtyChange explicitly — the reset effect installs the new baseline, computes dirtiness against it and calls the host outright yes
onChange React effect ordering — every layout DESTROY runs before any layout CREATE, so a fresh callback tore the subscription down before the reset no
onAction({ type: 'form_change' }) same no

The load-bearing words in the old comments were "a fresh callback each render". The guarantee was delivered by the callback's identity changing. A caller wrapping the same callback in React.useCallback — taught everywhere as a semantically neutral performance optimization — keeps one identity, the effect never re-runs, the subscription survives the reset, and the whole loaded record comes back to the host as if the user had typed every field of it. That is the false "the user edited this" signal #2968 was filed about, arriving through a door no type, doc or call site mentions.

The change

One file, one ref. The reset now holds an explicit window (resetInFlightRef) across form.reset(defaultValues) and the re-application of carried input (part of the same operation), and the two subscriptions read it:

resetInFlightRef.current = true;
try {
  form.reset(defaultValues);
  for (const [name, value] of carried) form.setValue(name, value, { shouldValidate: false, shouldDirty: true });
} finally {
  resetInFlightRef.current = false;
}

react-hook-form delivers both to form.watch subscribers synchronously (measured on the pinned 7.85 — the baselineRef line directly above already relies on it), so the window shuts before anything else can run inside it. No subscription is added or removed: the form-onchange-wiring ratchet that a callback-free form establishes exactly one value subscription is untouched and still green.

onDirtyChange is deliberately left exactly as it was — it is the channel that was already correct, and this card fixes how the other two are driven, not what any of them mean.

What this does NOT decide

Whether a value channel should report a programmatic reset. #5235 left that fork open explicitly and it is a contract change; this only removes the existing answer's dependence on caller identity, so memoized and inline callers get the same one. The renderer comment says where the explicit call would go if that fork is ever answered "yes".

Also unchanged: the two form.reset() calls on submit/cancel (different operations, reported today, reported after this), and FormSchema.onChange's JSDoc in @object-ui/types, which is silent about programmatic resets — documenting it would pre-empt the open fork, and it is a different package.

Evidence

New test: packages/components/src/renderers/form/__tests__/form-reset-notification-channels.test.tsx. It mounts the form, drives the full script in a real render — user edit → record lands → user edit — and asserts the exact per-channel sequences and payloads, describe.each over both caller shapes against the same expectations. The symmetry is the pin: the two runs may not disagree.

✓ ... (memoized callbacks) — reports the user edit, stays silent through the record landing, then reports the next edit
✓ ... (inline callbacks)   — reports the user edit, stays silent through the record landing, then reports the next edit
Test Files  1 passed (1) · Tests  2 passed (2)

The gauge can fail, proven, not assumed. Ablation: with the fix committed, the renderer was checked out from origin/main (confirmed on disk: the resetInFlightRef marker count went 7 → 0 and the old comment text came back), then the same test re-run:

FAIL ... (memoized callbacks)
AssertionError: expected [ { name: 'Loaded', …(1) } ] to deeply equal []
+ [ { "name": "Loaded", "note": "from server" } ]      ← at expect(on('onChange', beforeReset))
Test Files  1 failed (1) · Tests  1 failed | 1 passed (2)

The memoized leg fails with exactly the payload #5235 measured; the inline leg stays green — the predicted direction, and the reason the old pins could not see this. The file was then restored by checking that same path back out of this branch (marker back to 7, git diff HEAD empty) before any further measurement, and every reading below was taken on the restored tree.

Gates run locally — all at e856c74a7 (tree clean against that commit)

check result
vitest run packages/components/ packages/fields/ packages/plugin-form/ (--maxWorkers=2) 351 files / 4068 tests passed, exit 0
pnpm --filter '@object-ui/components^...' build then pnpm --filter @object-ui/components type-check exit 0 (tsc --noEmit && tsc -p tsconfig.test.json, script name echoed)
eslint on both changed files (--format json) 2 files linted, 0 errors; form.tsx 60 warnings — identical to origin/main's copy of the same file measured the same way, delta 0
node scripts/check-changeset-presence.mjs ✅ 1 changeset for 1 released package

Why the test scope is a provable superset, not a guess. The gate can only alter behaviour while resetInFlightRef is true, i.e. inside the defaultValues reset window, and only for the two gated subscriptions — which require, respectively, an onAction prop on the form renderer or a schema-level onChange. Repo-wide: no non-test source passes either (form_change appears in no src/ outside this renderer; plugin-form's Modal/Drawer/Split/Wizard/Tabbed forms, app-shell and console build form schemas with onDirtyChange at most, and nothing forwards onAction to the form renderer — matching #5235's "no in-repo caller currently does both"). Every test that pairs a form schema with onAction is in packages/components (5 files); every test outside it that pairs a form schema with onChange is in packages/fields (4 files). plugin-form is included because it is the heaviest real driver of the reset path itself (record swaps, dirty guards). Callers passing inline arrows are bit-for-bit unaffected — their subscription was already torn down.

Lint narrowing is a measurement, not a skip: eslint.config.js enables no type-aware linting (no parserOptions.project / projectService) and no custom rule in eslint-rules/ reads another file, so a file's verdict is a function of its own text plus the shared config. My diff touches two files; both were linted, and the third piece — the before/after count on the same file — is above. The repo-wide run remains CI's.


Generated by Claude Code

… by callback identity

A `defaultValues` reset kept off `onChange` and off the `form_change`
`onAction` only for callers who do NOT memoize: the guarantee rode on React
running every layout DESTROY before any layout CREATE, so it was delivered by
the callback's identity changing. `React.useCallback` kept one identity, the
effect never re-ran, the subscription survived the reset, and a landing record
came back to the host as a user edit (objectui#2968, measured in objectui#5235).

The reset now holds an explicit window that those two channels read, the shape
`onDirtyChange` already had beside them. Inline-arrow callers are unaffected;
memoized callers stop receiving a phantom edit. Whether a value channel SHOULD
report a programmatic reset is a contract question and stays open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012u2pRjcqAYtoEjgr3wwhnK

Copy link
Copy Markdown
Collaborator Author

Seat review — accepted on its merits. HELD only on #5705, which is a red base, not this diff.

This found a sharper defect than the card described, and the distinction matters.

The card said the two value channels "ride on incidental state changes". The measured mechanism is more specific and worse: the guarantee was delivered by the callback's identity changing. React runs every layout DESTROY before any layout CREATE, so a caller passing a fresh inline arrow each render had its subscription torn down before the reset and re-established after — and the reset went unreported. A caller who wraps the same callback in React.useCallback keeps one identity, the effect never re-runs, the subscription stays live across the reset, and the record landing is delivered as if the user had edited every field it filled.

So React.useCallback — taught everywhere as a pure performance optimization — silently changed behaviour, and, as the diff notes, "Nothing in the type, the docs or this renderer said 'do not memoize this callback'." That is the shape of defect that survives review indefinitely, because the code that triggers it looks like good practice.

The out-of-scope line I drew at dispatch was honoured, and — better — it is now written into the source rather than living only in a card:

⛔ NOT decided here (#5235, explicitly left open): whether a value channel SHOULD report a programmatic reset. That is a contract change. This only makes the answer the file already gives identity-independent — the same for memoized and inline callers. If it is ever answered "yes", the explicit call belongs beside the onDirtyChangeProp?.(...) one below, not back in a subscription's teardown ordering.

That last clause is the valuable half: it tells whoever answers the open question where the answer goes, so the next person cannot re-implement this as effect-ordering by accident.

The obvious objection to an in-flight boolean — that it could swallow a real edit — is addressed by measurement rather than by assertion: RHF delivers both reset() and the carried-value re-application to form.watch subscribers synchronously (measured on 7.85), so the window shuts before anything else can run in it. The try/finally means it shuts even if the re-application throws. And the carried values are correctly treated as part of the same reset — "no more a user edit than the reset is" — which is the subtle half a narrower fix would have missed.

Renders and asserts the channel payloads rather than the types, per the dispatch: "reports the user edit, stays silent through the record landing, then reports the next edit" — the full sequence, not just the silence.

Held pending #5705 (main red: console.ai.pendingDrafts missing from eight locale packs). Nothing about this PR needs to change; it merges when the base is green.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 52 chunks) 3913.6 KB 3990.2 KB
Main entry chunk (gzip) 152.3 KB 350 KB
Entry file index-Bxn3Fg5V.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 10.04KB 3.72KB
app-shell (runtime-config.js) 12.80KB 4.47KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 29.34KB 7.05KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 6.35KB 2.43KB
auth (index.js) 2.77KB 1.22KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.02KB 0.89KB
auth (useIsWorkspaceAdmin.js) 3.04KB 1.45KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 507.01KB 113.85KB
core (index.js) 4.92KB 1.97KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 160.15KB 44.52KB
fields (index.js) 238.40KB 59.89KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.44KB 1.39KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 23.13KB 7.63KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 33.40KB 8.71KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.95KB 10.97KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.55KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useResponsiveConfig.js) 1.37KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 9.53KB 3.38KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 4.64KB 1.50KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 1.93KB 0.88KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.62KB 12.83KB
plugin-charts (index.js) 64.65KB 18.32KB
plugin-chatbot (index.js) 181.41KB 43.22KB
plugin-dashboard (index.js) 128.41KB 32.95KB
plugin-designer (index.js) 212.30KB 42.80KB
plugin-detail (index.js) 242.34KB 60.98KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 125.63KB 30.64KB
plugin-gantt (index.js) 164.10KB 39.87KB
plugin-grid (index.js) 200.79KB 54.26KB
plugin-kanban (index.js) 52.93KB 14.60KB
plugin-list (index.js) 111.80KB 27.20KB
plugin-map (index.js) 20.06KB 6.62KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 43.49KB 11.93KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.61KB 20.74KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 43.66KB 14.77KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.33KB 0.69KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (index.js) 4.77KB 2.16KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 10.76KB 3.17KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 6.92KB 2.40KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.59KB 1.79KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 52 chunks) 3914.3 KB 3990.2 KB
Main entry chunk (gzip) 152.2 KB 350 KB
Entry file index-AmuAx78x.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 10.04KB 3.72KB
app-shell (runtime-config.js) 12.80KB 4.47KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 29.34KB 7.05KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 6.35KB 2.43KB
auth (index.js) 2.77KB 1.22KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.02KB 0.89KB
auth (useIsWorkspaceAdmin.js) 3.04KB 1.45KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 507.01KB 113.85KB
core (index.js) 4.92KB 1.97KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 160.15KB 44.52KB
fields (index.js) 238.40KB 59.89KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.44KB 1.39KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 23.13KB 7.63KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 33.40KB 8.71KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.95KB 10.97KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.55KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useResponsiveConfig.js) 1.37KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 9.53KB 3.38KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 4.64KB 1.50KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 1.93KB 0.88KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.62KB 12.83KB
plugin-charts (index.js) 64.65KB 18.32KB
plugin-chatbot (index.js) 181.41KB 43.22KB
plugin-dashboard (index.js) 128.41KB 32.95KB
plugin-designer (index.js) 212.30KB 42.80KB
plugin-detail (index.js) 242.34KB 60.98KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 125.63KB 30.64KB
plugin-gantt (index.js) 164.10KB 39.87KB
plugin-grid (index.js) 200.79KB 54.26KB
plugin-kanban (index.js) 52.93KB 14.60KB
plugin-list (index.js) 111.80KB 27.20KB
plugin-map (index.js) 20.06KB 6.62KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 43.49KB 11.93KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.61KB 20.74KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 43.66KB 14.77KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.33KB 0.69KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (index.js) 4.77KB 2.16KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 10.76KB 3.17KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 6.92KB 2.40KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.59KB 1.79KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-sales
os-sales marked this pull request as ready for review August 22, 2026 13:12
@os-sales
os-sales added this pull request to the merge queue Aug 22, 2026
Merged via the queue into main with commit 485f096 Aug 22, 2026
23 checks passed
@os-sales
os-sales deleted the claude/issue-5235-form-reset-notification-channels branch August 22, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Form renderer: "a defaultValues reset is not a user edit" holds only for callers who do NOT memoize the callback

2 participants