[REFERENCE] Move DateTime frontend from NeoWiki core to RedHerb#777
Draft
[REFERENCE] Move DateTime frontend from NeoWiki core to RedHerb#777
Conversation
10 tasks
Split Vite entry: src/public-api.ts is now the barrel that re-exports
runtime symbols MW-native extensions can require('ext.neowiki'). It
imports src/neowiki.ts for its mount side-effects.
Memoize NeoWikiExtension.getTypeSpecificComponentRegistry() and
PropertyTypeRegistry on Neo so every caller sees the same instance —
prerequisite for the extension-registration hook being added next,
which needs to mutate the registry that Vue later receives.
For #686
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extensions can now register custom property types at runtime:
1. PHP: implement NeoWikiGetFrontendModules to append their RL module
name to NeoWiki's module list for any page that loads ext.neowiki.
2. JS: subscribe to mw.hook('neowiki.registration') and call
registrar.registerPropertyType({...}) with a plain-object
PropertyTypeRegistration.
NeoWiki wraps incoming registrations via PropertyTypeAdapter into
BasePropertyType instances; FrontendRegistrar inserts them into the
memoized property-type and component registries.
Mount is deferred via queueMicrotask so extension init.js files get a
chance to subscribe before the hook fires. No consumer of the hook
exists yet — DateTime still lives in core and will move in a
follow-up commit.
For #686
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-export every TS module (via wildcard) and every Vue component under
resources/ext.neowiki/src/ from the public-api barrel. Extensions using
require('ext.neowiki') can now reach anything NeoWiki itself exposes -
domain types and services, application-layer lookups and repositories,
persistence serializers/deserializers, stores, composables, and the
full component library.
0.x / alpha stability contract: the surface is provisional and any
symbol may be renamed or removed without migration guidance. A
curation pass to narrow the public API is planned before production
stabilisation. Consumers should pin specific NeoWiki commits during
the alpha phase.
Bundle size impact: 240 KB -> 251 KB raw (+11 KB / +4%), 63 KB -> 66 KB
gzipped (+3 KB / +5%). Acceptable for the flexibility it provides
during alpha build-out.
Stacks on top of #754.
933e95e to
efc2dfc
Compare
f7e519a to
8b53959
Compare
This was referenced Apr 24, 2026
malberts
added a commit
that referenced
this pull request
Apr 25, 2026
First extension-provided property-type frontend built on the neowiki.registration hook surface. For #686. Stacks on #754. This is an alternative path to PR #777, not a stack on it. PR #777 is a reference-only example that moves the existing core DateTime frontend into RedHerb to demonstrate the migration path; the intent for DateTime itself is to remain in NeoWiki core as a built-in. This PR introduces Color as a permanent example of an extension-defined property type, i.e. the shape any third-party extension would take, without disturbing core's built-in types. What it adds: * ColorDisplay.vue renders a swatch + hex via a format-only check (intentionally tolerant of input-time constraints like allowedColors so previously-valid values keep rendering); falls back through I18nSlot for unparseable values. * ColorInput.vue is a cdx-text-input plus a live preview swatch and the type's start icon. Mirrors the useStringValueInput convention: invalid mid-typing stays visible to the user but does not propagate through update:modelValue or getCurrentValue(). * ColorAttributesEditor.vue wraps an optional allowedColors palette in NeoNestedField, with a drag-reorderable list via useSortable and a dirty marker driven by useChangeDetection. * RedHerbFrontendHook.php implements NeoWikiGetFrontendModules so the new ext.redherb ResourceLoader module loads alongside ext.neowiki. * ColorProperty gains an optional allowedColors attribute (validated as 6-digit hex strings), with round-trip coverage in tests/phpunit/RedHerb/ColorPropertyTest.php. Integration points exercised: * mw.hook('neowiki.registration') as a second consumer alongside core property types. * NeoWikiGetFrontendModules PHP hook. * NeoWikiServices.getPropertyTypeRegistry and NeoWikiServices.getComponentRegistry. * Composables: useValueValidation, useChangeDetection, useSortable. * Vue components from the public-API barrel: NeoNestedField, I18nSlot. NeoWikiHooksTest::testAddsCoreModuleWhenNoExtensionsHandleHook now clearHook()'s NeoWikiGetFrontendModules so it tests what its name claims regardless of which extensions the test environment loads. Known gaps: * Persistence-side schema validation rejects extension-defined type names; saves through the schema editor return hookaborted until the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry. See #779. * Pinia store sharing not directly probed in this PR; deferred to a Vitest integration test in NeoWiki core. * SchemaDeserializer / RestSchemaRepository / RestLayoutRepository do not have a natural fit in the Color flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each initialize*Page() in neowiki.ts previously called createPinia() and got its own root, so two Vue apps mounted on the same page could not observe each other's store state. Centralize ownership of the Pinia in NeoWikiExtension, expose getPinia(), and route every init through it. Tested via a behavioral spec that mutates a store via one consumer and reads it via another using the same Pinia, which is the actual contract the shared instance is meant to guarantee. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testAddsCoreModuleWhenNoExtensionsHandleHook asserts that only ext.neowiki is queued when no extension contributes via the NeoWikiGetFrontendModules hook. Real loaded extensions (such as RedHerb in CI) register handlers that contribute their own modules, so the assertion fails. Clear the hook at the start of the test so its premise holds regardless of which extensions are loaded. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
malberts
added a commit
that referenced
this pull request
Apr 27, 2026
First extension-provided property-type frontend built on the neowiki.registration hook surface. For #686. Stacks on #754. This is an alternative path to PR #777, not a stack on it. PR #777 is a reference-only example that moves the existing core DateTime frontend into RedHerb to demonstrate the migration path; the intent for DateTime itself is to remain in NeoWiki core as a built-in. This PR introduces Color as a permanent example of an extension-defined property type, i.e. the shape any third-party extension would take, without disturbing core's built-in types. What it adds: * ColorDisplay.vue renders a swatch + hex via a format-only check (intentionally tolerant of input-time constraints like allowedColors so previously-valid values keep rendering); falls back through I18nSlot for unparseable values. * ColorInput.vue is a cdx-text-input plus a live preview swatch and the type's start icon. Mirrors the useStringValueInput convention: invalid mid-typing stays visible to the user but does not propagate through update:modelValue or getCurrentValue(). * ColorAttributesEditor.vue wraps an optional allowedColors palette in NeoNestedField, with a drag-reorderable list via useSortable and a dirty marker driven by useChangeDetection. * RedHerbFrontendHook.php implements NeoWikiGetFrontendModules so the new ext.redherb ResourceLoader module loads alongside ext.neowiki. * ColorProperty gains an optional allowedColors attribute (validated as 6-digit hex strings), with round-trip coverage in tests/phpunit/RedHerb/ColorPropertyTest.php. Integration points exercised: * mw.hook('neowiki.registration') as a second consumer alongside core property types. * NeoWikiGetFrontendModules PHP hook. * NeoWikiServices.getPropertyTypeRegistry and NeoWikiServices.getComponentRegistry. * Composables: useValueValidation, useChangeDetection, useSortable. * Vue components from the public-API barrel: NeoNestedField, I18nSlot. NeoWikiHooksTest::testAddsCoreModuleWhenNoExtensionsHandleHook now clearHook()'s NeoWikiGetFrontendModules so it tests what its name claims regardless of which extensions the test environment loads. Known gaps: * Persistence-side schema validation rejects extension-defined type names; saves through the schema editor return hookaborted until the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry. See #779. * Pinia store sharing not directly probed in this PR; deferred to a Vitest integration test in NeoWiki core. * SchemaDeserializer / RestSchemaRepository / RestLayoutRepository do not have a natural fit in the Color flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deletes the DateTime TypeScript and Vue source files (plus their specs)
from ext.neowiki. DateTime is re-introduced in RedHerb as plain JS +
MW-native .vue SFCs (no bundler, no TypeScript), registered at runtime
via mw.hook('neowiki.registration'). RedHerb's ext.redherb RL module is
added to pages that load ext.neowiki via the new
NeoWikiGetFrontendModules PHP hook, implemented by RedHerbFrontendHook.
This serves as the first end-to-end consumer of the frontend
extensibility mechanism introduced in the previous commits and proves
that external extensions can contribute property types without
touching NeoWiki's source tree or bundler.
Component-level unit tests for the three rewritten SFCs are omitted:
Vitest + @vitejs/plugin-vue expects ES modules, and RedHerb is a test
extension rather than a production code path. The validation message
key 'neowiki-field-invalid-datetime' remains in core because the
'neowiki-field-*' prefix is a documented core-owned namespace dynamically
used by every property type's validation output.
For #686
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8b53959 to
999dac5
Compare
cf6af02 to
1635dc3
Compare
malberts
added a commit
that referenced
this pull request
Apr 29, 2026
First extension-provided property-type frontend built on the neowiki.registration hook surface. For #686. Stacks on #754. This is an alternative path to PR #777, not a stack on it. PR #777 is a reference-only example that moves the existing core DateTime frontend into RedHerb to demonstrate the migration path; the intent for DateTime itself is to remain in NeoWiki core as a built-in. This PR introduces Color as a permanent example of an extension-defined property type, i.e. the shape any third-party extension would take, without disturbing core's built-in types. What it adds: * ColorDisplay.vue renders a swatch + hex via a format-only check (intentionally tolerant of input-time constraints like allowedColors so previously-valid values keep rendering); falls back through I18nSlot for unparseable values. * ColorInput.vue is a cdx-text-input plus a live preview swatch and the type's start icon. Mirrors the useStringValueInput convention: invalid mid-typing stays visible to the user but does not propagate through update:modelValue or getCurrentValue(). * ColorAttributesEditor.vue wraps an optional allowedColors palette in NeoNestedField, with a drag-reorderable list via useSortable and a dirty marker driven by useChangeDetection. * RedHerbFrontendHook.php implements NeoWikiGetFrontendModules so the new ext.redherb ResourceLoader module loads alongside ext.neowiki. * ColorProperty gains an optional allowedColors attribute (validated as 6-digit hex strings), with round-trip coverage in tests/phpunit/RedHerb/ColorPropertyTest.php. Integration points exercised: * mw.hook('neowiki.registration') as a second consumer alongside core property types. * NeoWikiGetFrontendModules PHP hook. * NeoWikiServices.getPropertyTypeRegistry and NeoWikiServices.getComponentRegistry. * Composables: useValueValidation, useChangeDetection, useSortable. * Vue components from the public-API barrel: NeoNestedField, I18nSlot. NeoWikiHooksTest::testAddsCoreModuleWhenNoExtensionsHandleHook now clearHook()'s NeoWikiGetFrontendModules so it tests what its name claims regardless of which extensions the test environment loads. Known gaps: * Persistence-side schema validation rejects extension-defined type names; saves through the schema editor return hookaborted until the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry. See #779. * Pinia store sharing not directly probed in this PR; deferred to a Vitest integration test in NeoWiki core. * SchemaDeserializer / RestSchemaRepository / RestLayoutRepository do not have a natural fit in the Color flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
malberts
added a commit
that referenced
this pull request
Apr 29, 2026
First extension-provided property-type frontend built on the neowiki.registration hook surface. For #686. Stacks on #754. This is an alternative path to PR #777, not a stack on it. PR #777 is a reference-only example that moves the existing core DateTime frontend into RedHerb to demonstrate the migration path; the intent for DateTime itself is to remain in NeoWiki core as a built-in. This PR introduces Color as a permanent example of an extension-defined property type, i.e. the shape any third-party extension would take, without disturbing core's built-in types. What it adds: * ColorDisplay.vue renders a swatch + hex via a format-only check (intentionally tolerant of input-time constraints like allowedColors so previously-valid values keep rendering); falls back through I18nSlot for unparseable values. * ColorInput.vue is a cdx-text-input plus a live preview swatch and the type's start icon. Mirrors the useStringValueInput convention: invalid mid-typing stays visible to the user but does not propagate through update:modelValue or getCurrentValue(). * ColorAttributesEditor.vue wraps an optional allowedColors palette in NeoNestedField, with a drag-reorderable list via useSortable and a dirty marker driven by useChangeDetection. * RedHerbFrontendHook.php implements NeoWikiGetFrontendModules so the new ext.redherb ResourceLoader module loads alongside ext.neowiki. * ColorProperty gains an optional allowedColors attribute (validated as 6-digit hex strings), with round-trip coverage in tests/phpunit/RedHerb/ColorPropertyTest.php. Integration points exercised: * mw.hook('neowiki.registration') as a second consumer alongside core property types. * NeoWikiGetFrontendModules PHP hook. * NeoWikiServices.getPropertyTypeRegistry and NeoWikiServices.getComponentRegistry. * Composables: useValueValidation, useChangeDetection, useSortable. * Vue components from the public-API barrel: NeoNestedField, I18nSlot. NeoWikiHooksTest::testAddsCoreModuleWhenNoExtensionsHandleHook now clearHook()'s NeoWikiGetFrontendModules so it tests what its name claims regardless of which extensions the test environment loads. Known gaps: * Persistence-side schema validation rejects extension-defined type names; saves through the schema editor return hookaborted until the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry. See #779. * Pinia store sharing not directly probed in this PR; deferred to a Vitest integration test in NeoWiki core. * SchemaDeserializer / RestSchemaRepository / RestLayoutRepository do not have a natural fit in the Color flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JeroenDeDauw
pushed a commit
that referenced
this pull request
Apr 29, 2026
First extension-provided property-type frontend built on the neowiki.registration hook surface. For #686. Stacks on #754. This is an alternative path to PR #777, not a stack on it. PR #777 is a reference-only example that moves the existing core DateTime frontend into RedHerb to demonstrate the migration path; the intent for DateTime itself is to remain in NeoWiki core as a built-in. This PR introduces Color as a permanent example of an extension-defined property type, i.e. the shape any third-party extension would take, without disturbing core's built-in types. What it adds: * ColorDisplay.vue renders a swatch + hex via a format-only check (intentionally tolerant of input-time constraints like allowedColors so previously-valid values keep rendering); falls back through I18nSlot for unparseable values. * ColorInput.vue is a cdx-text-input plus a live preview swatch and the type's start icon. Mirrors the useStringValueInput convention: invalid mid-typing stays visible to the user but does not propagate through update:modelValue or getCurrentValue(). * ColorAttributesEditor.vue wraps an optional allowedColors palette in NeoNestedField, with a drag-reorderable list via useSortable and a dirty marker driven by useChangeDetection. * RedHerbFrontendHook.php implements NeoWikiGetFrontendModules so the new ext.redherb ResourceLoader module loads alongside ext.neowiki. * ColorProperty gains an optional allowedColors attribute (validated as 6-digit hex strings), with round-trip coverage in tests/phpunit/RedHerb/ColorPropertyTest.php. Integration points exercised: * mw.hook('neowiki.registration') as a second consumer alongside core property types. * NeoWikiGetFrontendModules PHP hook. * NeoWikiServices.getPropertyTypeRegistry and NeoWikiServices.getComponentRegistry. * Composables: useValueValidation, useChangeDetection, useSortable. * Vue components from the public-API barrel: NeoNestedField, I18nSlot. NeoWikiHooksTest::testAddsCoreModuleWhenNoExtensionsHandleHook now clearHook()'s NeoWikiGetFrontendModules so it tests what its name claims regardless of which extensions the test environment loads. Known gaps: * Persistence-side schema validation rejects extension-defined type names; saves through the schema editor return hookaborted until the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry. See #779. * Pinia store sharing not directly probed in this PR; deferred to a Vitest integration test in NeoWiki core. * SchemaDeserializer / RestSchemaRepository / RestLayoutRepository do not have a natural fit in the Color flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JeroenDeDauw
pushed a commit
that referenced
this pull request
Apr 29, 2026
First extension-provided property-type frontend built on the neowiki.registration hook surface. For #686. Stacks on #754. This is an alternative path to PR #777, not a stack on it. PR #777 is a reference-only example that moves the existing core DateTime frontend into RedHerb to demonstrate the migration path; the intent for DateTime itself is to remain in NeoWiki core as a built-in. This PR introduces Color as a permanent example of an extension-defined property type, i.e. the shape any third-party extension would take, without disturbing core's built-in types. What it adds: * ColorDisplay.vue renders a swatch + hex via a format-only check (intentionally tolerant of input-time constraints like allowedColors so previously-valid values keep rendering); falls back through I18nSlot for unparseable values. * ColorInput.vue is a cdx-text-input plus a live preview swatch and the type's start icon. Mirrors the useStringValueInput convention: invalid mid-typing stays visible to the user but does not propagate through update:modelValue or getCurrentValue(). * ColorAttributesEditor.vue wraps an optional allowedColors palette in NeoNestedField, with a drag-reorderable list via useSortable and a dirty marker driven by useChangeDetection. * RedHerbFrontendHook.php implements NeoWikiGetFrontendModules so the new ext.redherb ResourceLoader module loads alongside ext.neowiki. * ColorProperty gains an optional allowedColors attribute (validated as 6-digit hex strings), with round-trip coverage in tests/phpunit/RedHerb/ColorPropertyTest.php. Integration points exercised: * mw.hook('neowiki.registration') as a second consumer alongside core property types. * NeoWikiGetFrontendModules PHP hook. * NeoWikiServices.getPropertyTypeRegistry and NeoWikiServices.getComponentRegistry. * Composables: useValueValidation, useChangeDetection, useSortable. * Vue components from the public-API barrel: NeoNestedField, I18nSlot. NeoWikiHooksTest::testAddsCoreModuleWhenNoExtensionsHandleHook now clearHook()'s NeoWikiGetFrontendModules so it tests what its name claims regardless of which extensions the test environment loads. Known gaps: * Persistence-side schema validation rejects extension-defined type names; saves through the schema editor return hookaborted until the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry. See #779. * Pinia store sharing not directly probed in this PR; deferred to a Vitest integration test in NeoWiki core. * SchemaDeserializer / RestSchemaRepository / RestLayoutRepository do not have a natural fit in the Color flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reference PR. Not intended to merge.
Stacks on top of #754. Demonstrates what migrating an existing core property type into an extension looks like using the extension mechanism introduced in that PR.
Kept open while the team decides what permanent shape the "extension owns a real property type" story should take. The actual permanent forcing-function will be a Color property type in a separate PR (stacked on #754, not on this one). DateTime itself should stay in NeoWiki core long-term because:
What this PR does
Single commit on top of #754:
DateTime.ts,dateTimeConversion.ts, the three.vueSFCs, their Vitest specs.tests/RedHerb/resources/, with the same runtime behaviour:dateTimeConversion.js— host-TZ-awaretoLocalInputValue/fromLocalInputValue/formatDateTimeForDisplay.DateTimeDisplay.vue— semantic<time>element, TZ-suffixed format.DateTimeInput.vue—cdx-text-inputwith clock start-icon, live validation with host-local bound formatting (mirroring DateTimeInput: format min/max error bounds as host-local wall-clock #770).DateTimeAttributesEditor.vue— Codex text inputs, cross-validation (min > maxrejected), wire-format guard.init.js— subscribes tomw.hook('neowiki.registration')and registersdateTimewith the full validate/createPropertyDefinitionFromJson/getExampleValue implementation.RedHerbFrontendHook.php—NeoWikiGetFrontendModuleshandler addingext.redherb.extension.jsonon RedHerb gains the ext.redherb RL module with the full DateTime packageFiles set; NeoWiki core drops thecdxIconClockicon andneowiki-property-type-datetimemessage (still owned by core'sneowiki-field-*contract, butproperty-type-datetimebelongs with the property-type's label owner).Status
make tscigreen (688 tests)make phpunit filter=RedHerbgreenmake csphpcs + phpstan cleanWhy reference-only
Moving DateTime out and then immediately back would be pointless churn. The preferred path is: