From 0925170a95fa6cad848c684206d703433ec42f28 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 10:48:34 +0000 Subject: [PATCH 1/5] feat(fields): action-param and bulk-action dialogs draw the platform date picker fieldWidgetMap's `date` / `datetime` entries now load DatePickerField / DateTimePickerField, so getLazyFieldWidget (ActionParamDialog, the grid's BulkActionDialog, the console FormPage) and registerField (the record form) resolve the same face. FORM_FACE_LOADERS, the form-only override, is gone and registerField is back to the plain loader. The written value is unchanged. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01VKCrtATqjvhepLgQ12oShR --- packages/fields/src/index.tsx | 40 ++++++------------- .../widgets/date-picker/DatePickerField.tsx | 19 ++++----- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/packages/fields/src/index.tsx b/packages/fields/src/index.tsx index acef3f63e2..10b136640b 100644 --- a/packages/fields/src/index.tsx +++ b/packages/fields/src/index.tsx @@ -4315,8 +4315,15 @@ const fieldWidgetMap = { 'number': () => import('./widgets/NumberField.js').then(m => ({ default: m.NumberField })), 'boolean': () => import('./widgets/BooleanField.js').then(m => ({ default: m.BooleanField })), 'select': () => import('./widgets/SelectField.js').then(m => ({ default: m.SelectField })), - 'date': () => import('./widgets/DateField.js').then(m => ({ default: m.DateField })), - 'datetime': () => import('./widgets/DateTimeField.js').then(m => ({ default: m.DateTimeField })), + // The platform date picker (objectui#12622, objectui#12642): a text box in + // the display locale's format with a calendar popover, for every consumer of + // this map — the record form (`registerField`) and the action-param and + // bulk-action dialogs (`getLazyFieldWidget`) alike, so a field type has one + // face. It writes what the native input wrote: `YYYY-MM-DD` for `date`, an + // ISO instant for `datetime`. Its read-only face is `DateField` / + // `DateTimeField`'s own. + 'date': () => import('./widgets/date-picker/DatePickerField.js').then(m => ({ default: m.DatePickerField })), + 'datetime': () => import('./widgets/date-picker/DatePickerField.js').then(m => ({ default: m.DateTimePickerField })), 'time': () => import('./widgets/TimeField.js').then(m => ({ default: m.TimeField })), // Contact fields @@ -4483,9 +4490,8 @@ const lazyFieldWidgets = new Map>(); /** * Lazily-loaded form field widget for a field type. Shares the exact loaders - * of {@link fieldWidgetMap} (the components `registerField` registers for - * forms, except the form-only faces in `FORM_FACE_LOADERS`), wrapped in - * `React.lazy` and cached per type — so a consumer can + * of {@link fieldWidgetMap} (the same components `registerField` registers for + * forms), wrapped in `React.lazy` and cached per type — so a consumer can * render any form-supported field type without eagerly bundling every widget. * Render inside a `` boundary. Unknown types resolve to the `text` * widget via {@link resolveFormWidgetType}. @@ -4717,26 +4723,6 @@ export const FIELD_WIDGET_LABELLING: Record< 'permission-ref': 'control', }; -/** - * The FORM face of a field type, where it differs from the widget - * {@link fieldWidgetMap} loads (objectui#12622). - * - * A record form draws `date` / `datetime` with the platform date picker: a - * text box in the display locale's format, a calendar popover, clear, and - * today / tomorrow shortcuts. The ruling scopes it to record forms, so only - * the registry registration (what a form resolves `field:date` / - * `field:datetime` to) takes it. {@link getLazyFieldWidget} (the action-param - * and bulk-action dialogs) and the inline editors (`FieldEditWidget`, which - * imports `DateField` / `DateTimeField` directly) keep the native input. - * - * The value written is the native input's: `YYYY-MM-DD` for `date`, an ISO - * instant for `datetime` (see `widgets/date-picker/DatePickerField.tsx`). - */ -const FORM_FACE_LOADERS: Partial> = { - date: () => import('./widgets/date-picker/DatePickerField.js').then(m => ({ default: m.DatePickerField })), - datetime: () => import('./widgets/date-picker/DatePickerField.js').then(m => ({ default: m.DateTimePickerField })), -}; - export function registerField(fieldType: string): void { const loader = fieldWidgetLoaderByKey[fieldType]; if (!loader) { @@ -4745,9 +4731,7 @@ export function registerField(fieldType: string): void { } // Create lazy component - const LazyFieldWidget = React.lazy( - FORM_FACE_LOADERS[fieldType as RegisteredFieldWidgetType] ?? loader, - ); + const LazyFieldWidget = React.lazy(loader); // Register with field namespace. No LAYOUT wrapper — the form renderer owns // label/description/spacing. The only thing wrapped is the metadata carrier: diff --git a/packages/fields/src/widgets/date-picker/DatePickerField.tsx b/packages/fields/src/widgets/date-picker/DatePickerField.tsx index f8ea3e8fcb..49525643c3 100644 --- a/packages/fields/src/widgets/date-picker/DatePickerField.tsx +++ b/packages/fields/src/widgets/date-picker/DatePickerField.tsx @@ -30,11 +30,13 @@ import { import { useFieldTranslation } from '../useFieldTranslation.js'; /** - * The record form's date and date-time controls (objectui#12622). + * The `date` and date-time controls of the form field widgets + * (objectui#12622, objectui#12642). * - * The registry's `date` / `datetime` widgets — what a record form resolves - * `field:date` / `field:datetime` to — draw the platform picker instead of the - * browser's native input: a text box in the display locale's format (keyboard + * `fieldWidgetMap`'s `date` / `datetime` widgets — what a record form resolves + * `field:date` / `field:datetime` to, and what `getLazyFieldWidget` hands the + * action-param and bulk-action dialogs — draw the platform picker instead of + * the browser's native input: a text box in the display locale's format (keyboard * entry), a calendar popover (the same `Calendar` the calendar view's date * popover opens, localized by the same resolver), a clear button, and * today / tomorrow shortcuts. @@ -51,11 +53,10 @@ import { useFieldTranslation } from '../useFieldTranslation.js'; * * - The read-only face is `DateField` / `DateTimeField`'s own, rendered as is. * - The inline editors (`FieldEditWidget`: the grid / detail inline editors and - * the kanban required-fields dialog) import `DateField` / `DateTimeField` - * directly and keep the native input; this card's ruling is the record form. - * - `getLazyFieldWidget` (the action-param and bulk-action dialogs) loads the - * `date` / `datetime` widgets of `fieldWidgetMap`, which stay `DateField` / - * `DateTimeField`: only `registerField` takes this face. + * the kanban required-fields dialog; plugin-detail's `InlineFieldInput`) + * import `DateField` / `DateTimeField` directly and keep the native input. + * A popover inside a grid cell or a filter row is a different interaction, + * measured on its own (objectui#12642). * - A form whose `field:date` widget is not registered (no * `@object-ui/fields` loaded) falls back to the form renderer's own * ``, with the `inputType` `ObjectForm` maps. From 160dbc0e829150df35933877cecf9b73d809571c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 11:19:32 +0000 Subject: [PATCH 2/5] test: the dialog, bulk-dialog, FormPage and designer-preview pins draw the date picker ActionParamDialog, BulkActionDialog and the console FormPage now render `date` / `datetime` through the platform picker; their pins type into its text box and assert the same written value as before (`YYYY-MM-DD`, an ISO instant). The Action designer's preview mock draws a date-picker shape for both, so its "draws what the runtime draws" pin stays true. The plugin-detail zone pin's form control drives the picker too. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01VKCrtATqjvhepLgQ12oShR --- .../FormPage.sharedWidgets-10179.test.tsx | 3 ++ .../src/views/ActionParamDialog.test.tsx | 24 +++++++--- .../ActionDesigner.paramVocabulary.test.tsx | 19 ++++---- .../metadata-admin/previews/ActionPreview.tsx | 11 ++++- ...ieldInput.dateOnlyWriteZone-12206.test.tsx | 8 +++- .../__tests__/bulkActionDialogParams.test.tsx | 45 ++++++++++++++----- 6 files changed, 80 insertions(+), 30 deletions(-) diff --git a/apps/console/src/components/FormPage.sharedWidgets-10179.test.tsx b/apps/console/src/components/FormPage.sharedWidgets-10179.test.tsx index 2a916d13f3..e6efefc299 100644 --- a/apps/console/src/components/FormPage.sharedWidgets-10179.test.tsx +++ b/apps/console/src/components/FormPage.sharedWidgets-10179.test.tsx @@ -189,7 +189,10 @@ describe('value shapes — what the shared widgets emit is what the page submits it('submits a date string, a number, a multiselect array and a lookup id', async () => { await renderForm(); + // `date` is the platform picker (objectui#12642): its text box commits on + // blur, and an ISO day reads in every locale. fireEvent.change(screen.getByLabelText('Due'), { target: { value: '2026-03-04' } }); + fireEvent.blur(screen.getByLabelText('Due')); fireEvent.change(screen.getByLabelText('Quantity'), { target: { value: '7' } }); const tags = screen.getByRole('group', { name: 'Tags' }); diff --git a/packages/app-shell/src/views/ActionParamDialog.test.tsx b/packages/app-shell/src/views/ActionParamDialog.test.tsx index 62c01c3e88..419f0f5634 100644 --- a/packages/app-shell/src/views/ActionParamDialog.test.tsx +++ b/packages/app-shell/src/views/ActionParamDialog.test.tsx @@ -454,11 +454,18 @@ describe('ActionParamDialog — shared field-widget rendering (ADR-0059)', () => expect(await screen.findByRole('combobox')).toBeTruthy(); }); - it('renders a date param through the shared DateField (native date input)', async () => { + // objectui#12642: the dialog draws the platform date picker the record form + // draws (one face per field type), not the browser's native input, whose + // placeholder and digit order are the machine's. The value is unchanged. + it('renders a date param through the platform date picker and resolves the YYYY-MM-DD day', async () => { const resolve = openDialog([def({ name: 'due', type: 'date' })]); - const input = await screen.findByLabelText('Param One'); - expect(input.getAttribute('type')).toBe('date'); - fireEvent.change(input, { target: { value: '2026-07-19' } }); + const input = (await screen.findByLabelText('Param One')) as HTMLInputElement; + expect(input.closest('[data-slot="date-picker"]'), 'date picker not rendered').not.toBeNull(); + expect(input.type).toBe('text'); + expect(input.placeholder).toBe('MM/DD/YYYY'); + expect(document.querySelector('input[type="date"]')).toBeNull(); + fireEvent.change(input, { target: { value: '07/19/2026' } }); + fireEvent.blur(input); confirm(); await waitFor(() => expect(resolve).toHaveBeenCalledWith({ due: '2026-07-19' })); }); @@ -611,9 +618,12 @@ describe('emitted value-shape parity (contract-tied render proofs, #2714)', () = it('datetime param emits a zoned ISO instant the platform validator accepts', async () => { const param = def({ name: 'when', type: 'datetime' }); const resolve = openDialog([param]); - const input = await screen.findByLabelText('Param One'); - expect(input.getAttribute('type')).toBe('datetime-local'); - fireEvent.change(input, { target: { value: '2026-07-20T14:30' } }); + const input = (await screen.findByLabelText('Param One')) as HTMLInputElement; + // objectui#12642: the platform picker, typed in the display locale's format. + expect(input.closest('[data-slot="date-picker"]'), 'date picker not rendered').not.toBeNull(); + expect(document.querySelector('input[type="datetime-local"]')).toBeNull(); + fireEvent.change(input, { target: { value: '07/20/2026 14:30' } }); + fireEvent.blur(input); confirm(); await waitFor(() => expect(resolve).toHaveBeenCalled()); const emitted = resolve.mock.calls[0][0].when; diff --git a/packages/app-shell/src/views/metadata-admin/ActionDesigner.paramVocabulary.test.tsx b/packages/app-shell/src/views/metadata-admin/ActionDesigner.paramVocabulary.test.tsx index 2d549539ce..da7a077506 100644 --- a/packages/app-shell/src/views/metadata-admin/ActionDesigner.paramVocabulary.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/ActionDesigner.paramVocabulary.test.tsx @@ -22,7 +22,8 @@ * ## Why the expectations are hand-declared AND cross-checked * * `EXPECTED` below is read out of the runtime by a human: `datetime` renders - * `DateTimeField`, so its mock must be a datetime control, not a text box. If + * the platform date picker (`DateTimePickerField`, objectui#12642), so its mock + * must be a date picker, not a plain text box. If * the test DERIVED each expectation from the same resolver the preview calls, * it could never catch the preview calling the resolver wrongly — the pin would * assert the implementation against itself. So the per-case expectation is @@ -85,13 +86,14 @@ const OFFERED: readonly string[] = PARAM_TYPE_OPTS.map((o) => o.value); * `input:*` is the DOM `type` of the rendered ``; `record-picker` is the * disabled combobox the preview mocks a `LookupField` with, the one that pops * a dialog; `select` is the shared `Select`'s trigger, the combobox that pops - * none, which `SelectField` draws too (objectui#11865). + * none, which `SelectField` draws too (objectui#11865); `date-picker` is the + * text box inside a `data-slot="date-picker"` wrapper, the shape the platform + * date picker draws for `date` and `datetime` (objectui#12642). */ type MockControl = | 'input:text' | 'input:number' - | 'input:date' - | 'input:datetime-local' + | 'date-picker' | 'input:checkbox' | 'textarea' | 'select' @@ -109,8 +111,8 @@ const MOCK_FOR_RUNTIME_WIDGET: Readonly> = { number: 'input:number', boolean: 'input:checkbox', select: 'select', - date: 'input:date', - datetime: 'input:datetime-local', + date: 'date-picker', + datetime: 'date-picker', lookup: 'record-picker', }; @@ -146,8 +148,8 @@ const CASES: readonly Case[] = [ expected: 'select', why: 'SelectField renders an EMPTY picker with a placeholder — not a text box', }, - { spelling: 'date', expected: 'input:date', why: 'DateField' }, - { spelling: 'datetime', expected: 'input:datetime-local', why: 'DateTimeField' }, + { spelling: 'date', expected: 'date-picker', why: 'DatePickerField, the platform date picker' }, + { spelling: 'datetime', expected: 'date-picker', why: 'DateTimePickerField, the platform date picker' }, { spelling: 'lookup', extra: { reference: 'account' }, @@ -212,6 +214,7 @@ function drawnControl(container: HTMLElement): MockControl { if (tag === 'select') return 'select'; if (tag === 'textarea') return 'textarea'; if (tag === 'button') return el.getAttribute('aria-haspopup') === 'dialog' ? 'record-picker' : 'select'; + if (el.closest('[data-slot="date-picker"]')) return 'date-picker'; return `input:${(el as HTMLInputElement).type}` as MockControl; } diff --git a/packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx b/packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx index 984fec6a70..9914907e98 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx +++ b/packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx @@ -28,6 +28,7 @@ import * as React from 'react'; import { AlertTriangle, Bot, + CalendarDays, Code2, Eye, Globe, @@ -661,9 +662,15 @@ function renderFieldMock(p: ActionParam, fieldLabel: string, locale?: string): R case 'number': return inputMock('number'); case 'date': - return inputMock('date'); case 'datetime': - return inputMock('datetime-local'); + // The dialog draws the platform date picker for both (objectui#12642): + // a text box with a calendar button, not the browser's native input. + return ( +
+ + +
+ ); case 'lookup': // `LookupField` is a combobox that opens a record picker — mocked with // the same disabled-combobox shape the designer's other pickers use, so diff --git a/packages/plugin-detail/src/__tests__/InlineFieldInput.dateOnlyWriteZone-12206.test.tsx b/packages/plugin-detail/src/__tests__/InlineFieldInput.dateOnlyWriteZone-12206.test.tsx index 29ebcf7bdf..14042eabd1 100644 --- a/packages/plugin-detail/src/__tests__/InlineFieldInput.dateOnlyWriteZone-12206.test.tsx +++ b/packages/plugin-detail/src/__tests__/InlineFieldInput.dateOnlyWriteZone-12206.test.tsx @@ -121,8 +121,12 @@ async function formPick(day: string): Promise { , ); - await waitFor(() => expect(container.querySelector('input[type="date"]')).not.toBeNull()); - fireEvent.change(container.querySelector('input[type="date"]')!, { target: { value: day } }); + // The form's `date` widget is the platform date picker (objectui#12642): a + // text box that commits on blur, and an ISO day reads in every locale. + const box = '[data-slot="date-picker"] input'; + await waitFor(() => expect(container.querySelector(box)).not.toBeNull()); + fireEvent.change(container.querySelector(box)!, { target: { value: day } }); + fireEvent.blur(container.querySelector(box)!); expect(onChange).toHaveBeenCalledTimes(1); cleanup(); return onChange.mock.calls[0][0]; diff --git a/packages/plugin-grid/src/__tests__/bulkActionDialogParams.test.tsx b/packages/plugin-grid/src/__tests__/bulkActionDialogParams.test.tsx index b434ddfc1b..8b52fe2960 100644 --- a/packages/plugin-grid/src/__tests__/bulkActionDialogParams.test.tsx +++ b/packages/plugin-grid/src/__tests__/bulkActionDialogParams.test.tsx @@ -13,7 +13,7 @@ * many → array patch → label preview) and the date widget. Since the ADR-0059 * migration (#3064) params render through the SHARED form field widgets * (`@object-ui/fields` via `bulkParamToField`), so these tests now assert the - * form-widget DOM (multiselect toggle chips, native date input) — and the new + * form-widget DOM (multiselect toggle chips, the platform date picker) — and the new * lookup suite pins the #3064 contract itself: no eager candidate prefetch, * fetch errors surfaced with a Retry affordance, and no failure caching * (reopening the picker refetches). @@ -120,15 +120,15 @@ describe('BulkActionDialog — multi-select param produces an array patch', () = }); }); -describe('BulkActionDialog — date param renders a date picker', () => { - it('renders a native date input rather than a free-text box', async () => { +// objectui#12642: a `date` / `datetime` param draws the platform date picker +// the record form draws (one face per field type), not the browser's native +// input, whose placeholder and digit order are the machine's. The patch each +// row receives is unchanged: `YYYY-MM-DD` for `date`, an ISO instant for +// `datetime`. +describe('BulkActionDialog — date params render the platform date picker', () => { + async function runWith(param: Record, typed: string) { const ds = makeDataSource(); - const def: any = { - name: 'set_due', - label: 'Set due date', - operation: 'update', - params: [{ name: 'due', label: 'Due', type: 'date' }], - }; + const def: any = { name: 'set_it', label: 'Set it', operation: 'update', params: [param] }; render( { />, ); // Radix Dialog portals to document.body, and the widget loads lazily. - await waitFor(() => { - expect(document.querySelector('input[type="date"]')).toBeInTheDocument(); + const input = await waitFor(() => { + const el = document.querySelector('[data-slot="date-picker"] input'); + if (!el) throw new Error('date picker not rendered'); + return el as HTMLInputElement; }); + expect(input.type).toBe('text'); + expect(input.placeholder).toMatch(/^MM\/DD\/YYYY/); + expect(document.querySelector('input[type="date"], input[type="datetime-local"]')).toBeNull(); + fireEvent.change(input, { target: { value: typed } }); + fireEvent.blur(input); + const next = screen.getByRole('button', { name: 'Next' }); + await waitFor(() => expect(next).toBeEnabled()); + fireEvent.click(next); + fireEvent.click(await screen.findByRole('button', { name: 'Run' })); + await waitFor(() => expect(ds.update).toHaveBeenCalledTimes(1)); + return ds.update.mock.calls[0]; + } + + it('a `date` param writes the YYYY-MM-DD day', async () => { + const call = await runWith({ name: 'due', label: 'Due', type: 'date', required: true }, '10/20/2026'); + expect(call).toEqual(['thing', 'r1', { due: '2026-10-20' }]); + }); + + it('a `datetime` param writes the ISO instant of the typed local wall clock', async () => { + const call = await runWith({ name: 'at', label: 'At', type: 'datetime', required: true }, '10/20/2026 14:30'); + expect(call).toEqual(['thing', 'r1', { at: new Date(2026, 9, 20, 14, 30).toISOString() }]); }); }); From 626ad92adbc1512018522d21e98ee61e9008e137 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 11:36:08 +0000 Subject: [PATCH 3/5] chore(changeset): dialogs draw the platform date picker Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01VKCrtATqjvhepLgQ12oShR --- .changeset/12642-dialog-date-picker.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/12642-dialog-date-picker.md diff --git a/.changeset/12642-dialog-date-picker.md b/.changeset/12642-dialog-date-picker.md new file mode 100644 index 0000000000..eb42051064 --- /dev/null +++ b/.changeset/12642-dialog-date-picker.md @@ -0,0 +1,13 @@ +--- +'@object-ui/fields': patch +'@object-ui/app-shell': patch +--- + +Action-param and bulk-action dialogs draw `date` and `datetime` params with the platform date picker, the same face record forms draw since objectui#12622 (objectui#12642). + +The native input took its placeholder and digit order from the machine's locale, not the console's. Now one field type has one face in forms and dialogs. + +- **Where it applies.** Everything that resolves a field widget through `getLazyFieldWidget` or `registerField` / `registerAllFields`: the record form, `ActionParamDialog`, the grid's `BulkActionDialog`, and the console's form page. The inline editors (`FieldEditWidget`, the detail inline editor) and the list filters keep the native input. +- **The value written is unchanged.** A `date` param writes `YYYY-MM-DD` and a `datetime` param writes an ISO instant, as the native inputs did. +- **The Action designer's preview** draws a date-picker shape for `date` / `datetime` params, matching the dialog. +- **No public surface changes.** No type, prop, export or language-pack key is added or removed (Clause-②: no). `getLazyFieldWidget('date' | 'datetime')` returns another component with the same props. From c184df4fb03da85abc9b9dd4271bfc92059d2e94 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 12:29:02 +0000 Subject: [PATCH 4/5] chore(changeset): the 12622 entry no longer says the dialogs keep the native date input Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01VKCrtATqjvhepLgQ12oShR --- .changeset/12622-form-date-picker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/12622-form-date-picker.md b/.changeset/12622-form-date-picker.md index 83587ef9e1..14f6eb2c59 100644 --- a/.changeset/12622-form-date-picker.md +++ b/.changeset/12622-form-date-picker.md @@ -8,5 +8,5 @@ Record forms draw `date` and `datetime` fields with the platform date picker ins The picker is a text box in the display locale's format (`10/16/2026` in English, `2026/10/16` in Chinese), with a calendar popover, keyboard entry, a clear button, and Today / Tomorrow shortcuts. The native input took its placeholder and digit order from the machine, so an English console could show a Chinese machine's placeholder. - **The value written is unchanged.** A `date` field writes `YYYY-MM-DD` and a `datetime` field writes an ISO instant, as the native inputs did. Clearing writes an empty value, as before. Typed text that names no date is not written: the box is marked invalid and a notice names the expected format. -- **Where it applies.** The form registration of `field:date` / `field:datetime` (what `registerField` / `registerAllFields` register) takes the picker. The inline editors (`FieldEditWidget`, the detail inline editor, the kanban required-fields dialog), `getLazyFieldWidget` (the action-param and bulk-action dialogs), and a form without `@object-ui/fields` registered keep the native input. The read-only face is unchanged. +- **Where it applies.** The form registration of `field:date` / `field:datetime` (what `registerField` / `registerAllFields` register) takes the picker, and so does `getLazyFieldWidget` (the action-param and bulk-action dialogs, objectui#12642). The inline editors (`FieldEditWidget`, the detail inline editor, the kanban required-fields dialog) and a form without `@object-ui/fields` registered keep the native input. The read-only face is unchanged. - **New language-pack keys** in all ten packs: `fields.datePicker.today`, `tomorrow`, `clear`, `openCalendar` and `invalid`. From bf6bcbec6966d0a7b97d249d6d1a73c71d1ba90a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 13:00:41 +0000 Subject: [PATCH 5/5] chore(console): DateField / DateTimeField leave the defeated-lazy-import ledger fieldWidgetMap now loads the date picker for `date` / `datetime`, so the map no longer dynamically imports DateField / DateTimeField (which FieldEditWidget imports statically). Their INEFFECTIVE_DYNAMIC_IMPORT warnings stopped firing; the ledger asks for the two entries to be deleted. 43 -> 41. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01VKCrtATqjvhepLgQ12oShR --- scripts/vite-ineffective-dynamic-imports.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/vite-ineffective-dynamic-imports.ts b/scripts/vite-ineffective-dynamic-imports.ts index f7f252e0c7..2cd07dcebe 100644 --- a/scripts/vite-ineffective-dynamic-imports.ts +++ b/scripts/vite-ineffective-dynamic-imports.ts @@ -183,8 +183,6 @@ export const DEFEATED_LAZY_FIELD_WIDGETS: readonly string[] = Object.freeze([ 'packages/fields/src/widgets/CodeField.tsx', 'packages/fields/src/widgets/ColorField.tsx', 'packages/fields/src/widgets/CurrencyField.tsx', - 'packages/fields/src/widgets/DateField.tsx', - 'packages/fields/src/widgets/DateTimeField.tsx', 'packages/fields/src/widgets/EmailField.tsx', 'packages/fields/src/widgets/FileField.tsx', 'packages/fields/src/widgets/FilterConditionField.tsx',