Skip to content

Add Color property type frontend in RedHerb#780

Open
malberts wants to merge 1 commit intofrontend-extensibilityfrom
redherb-color-property-type
Open

Add Color property type frontend in RedHerb#780
malberts wants to merge 1 commit intofrontend-extensibilityfrom
redherb-color-property-type

Conversation

@malberts
Copy link
Copy Markdown
Collaborator

@malberts malberts commented 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.vuecdx-text-input plus a live preview swatch and the type's start icon. Mirrors useStringValueInput's 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 using 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') — registration via PropertyTypeRegistration as a second consumer alongside core property types.
  • NeoWikiGetFrontendModules PHP hook.
  • NeoWikiServices.getPropertyTypeRegistry() and NeoWikiServices.getComponentRegistry() (the latter for getIcon('color')).
  • Composables: useValueValidation, useChangeDetection, useSortable.
  • Vue components from the public-API barrel: NeoNestedField, I18nSlot.

Known gaps

  • Persistence-side schema validation rejects extension-defined type names. A schema with "type": "color" round-trips through ?action=raw only after the JSON Schema in src/Persistence/MediaWiki/schemaContentSchema.json is loosened or built from the registry — see Schema content validator's type enum blocks extension-defined property types #779. This is the only thing blocking an end-to-end UI round-trip; everything else works.
  • Pinia store sharing not directly probed in this PR. The integration assumes one Vue app + one Pinia, and the public-API barrel re-exports the same useSubjectStore symbol NeoWiki uses internally. A Vitest integration test that asserts cross-mount state visibility belongs in NeoWiki core's own test suite, not in RedHerb. Filed as a follow-up.
  • SchemaDeserializer / RestSchemaRepository / RestLayoutRepository — no natural fit in the Color flow; left for a dedicated extension-integration-tests PR.

Verification

  • make tsci — 771 Vitest tests pass; lint clean.
  • make phpunit filter=ColorProperty — 14 tests, 21 assertions, green.
  • make cs — phpcs and phpstan clean.
  • curl 'http://localhost:8484/load.php?modules=ext.redherb&only=scripts&lang=en&debug=true' — 200, ext.redherb status ready, all three Color SFCs in payload.
  • Browser: in Special:Schemas → Create, the Color type appears in the property-type picker with a highlighter icon. Selecting it renders ColorAttributesEditor with a sortable palette (rows have drag handle with "Drag to reorder" tooltip, swatch, hex input, "Remove color" delete button; "+" adds entries; dirty marker * on the label). The Initial value ColorInput shows the type's highlighter start-icon. Save round-trip blocked at the persistence layer per Schema content validator's type enum blocks extension-defined property types #779.

🤖 Generated with Claude Code

@malberts
Copy link
Copy Markdown
Collaborator Author

Screenshot_20260425_224546

@malberts malberts marked this pull request as ready for review April 25, 2026 20:51
@malberts
Copy link
Copy Markdown
Collaborator Author

I did not manually review the code here. This PR is meant for proving that we can reuse some core NeoWiki code in an extension. This might not necessarily be the best way of writing the extension logic, though.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant