From d7937cb357d0d151ba2d7a5c06be01d3662997a6 Mon Sep 17 00:00:00 2001 From: delchev Date: Tue, 7 Jul 2026 22:38:43 +0300 Subject: [PATCH 1/2] docs: improvement requests from the Eclipse Dirigible integration Captures the framework gaps hit while migrating Eclipse Dirigible from Harmonia 1.24.2 to 2.1.0, each with the workaround used and a concrete proposal: - Charts: add polarArea + radar types (blocks dropping Chart.js in Dirigible). - Charts: an export/print API (DOM/CSS charts have no canvas to snapshot). - Lucide: react to a changing :data-lucide (currently read once; toggled icons must be split into x-show pairs). - Pickers: a first-class read-only/display mode (only disabled input works today). - Built-in icons: add inbox, eye (and an upload alias of import). Also records why harmonia-i18next was not adopted (a platform catalog-model fit issue, not a Harmonia gap) so it is not re-investigated. Co-Authored-By: Claude Opus 4.8 --- docs/dirigible-integration-feedback.md | 104 +++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 docs/dirigible-integration-feedback.md diff --git a/docs/dirigible-integration-feedback.md b/docs/dirigible-integration-feedback.md new file mode 100644 index 0000000..66648be --- /dev/null +++ b/docs/dirigible-integration-feedback.md @@ -0,0 +1,104 @@ +# Harmonia improvement requests - from the Eclipse Dirigible integration + +Feedback gathered while migrating the Eclipse Dirigible platform (its application +shells and code-generation templates) from Harmonia `1.24.2` to `2.1.0`. Both +projects are built by the same team; this list captures the framework gaps the +migration hit, with the workaround used and a concrete proposal, so Harmonia +itself can absorb them and the workarounds can be dropped later. + +Ordered roughly by impact. + +## 1. Charts: add `polarArea` and `radar` types + +**Gap.** Native charts cover `bar`, `line`, `pie`, `doughnut`, `scatter`. There +is no `polarArea` and no `radar`. + +**Why it matters.** Dirigible's report/chart feature (and its intent DSL) accepts +`bar | line | pie | doughnut | polarArea | radar`. The first four map cleanly onto +`x-h-chart-*`, but `polarArea`/`radar` have no native equivalent, so the platform +cannot fully drop its Chart.js dependency - a mixed Chart.js + Harmonia setup is +the only alternative, which defeats the migration. + +**Workaround.** Migration of the report charts to `x-h-chart-*` is **blocked/deferred**; +Chart.js is retained for now. + +**Proposal.** Add `x-h-chart-polar-area` (or `x-h-chart-polararea`) and +`x-h-chart-radar`, config-compatible with the existing chart family +(`series` + `labels`, theme-aware, accessible figure + hidden table). + +## 2. Charts: an export / print API + +**Gap.** Charts render as DOM/CSS (`createElement`, conic-gradient pie - no +``/`` root) and expose no way to get an image or drive printing. + +**Why it matters.** The platform's report "Print" snapshots the chart with +`canvas.toDataURL('image/png')` into a print window. With DOM/CSS charts there is +no canvas to snapshot, so that print path cannot be reproduced when migrating to +`x-h-chart-*`. + +**Workaround.** None yet - another reason the chart migration is deferred. + +**Proposal.** A small export/print surface on the chart element, e.g. a +`chart.toImage()` / `toDataURL()` method (rasterize the rendered DOM) or a +`chart.print()` helper that opens a print view with the chart + Harmonia CSS. + +## 3. Lucide plugin: react to a changing `data-lucide` + +**Gap.** `x-h-lucide` reads the icon name **once** at init. A bound +`:data-lucide` whose value later changes does not re-render (the tip in the docs +confirms this and suggests re-creating the element). + +**Why it matters.** Icons that flip at runtime (a chart/table toggle button, a +play/pause control, a theme sun/moon) are natural with a single bound +`:data-lucide` - but that silently freezes on the first value. + +**Workaround.** Every toggled icon was rewritten as **two `` +elements switched with `x-show`** (or re-created via `x-if`). Correct, but verbose +and easy to get wrong (an `` with another directive throws). + +**Proposal.** Make `:data-lucide` reactive - re-render the icon when the bound +name changes - matching the behaviour `x-h-icon` already has for its reactive +`data-icon`. That would let a single placeholder cover the dynamic-name case. + +## 4. Pickers: a first-class read-only / display mode + +**Gap.** Date / Datetime / Time pickers have no documented read-only or +display-only mode. Only a `disabled` inner input works (via the +`has-[input:disabled]` styling), which greys the control out. + +**Why it matters.** Generated forms have a preview / read-only mode where every +field is shown non-editable. A greyed-out (`disabled`) picker reads as "unavailable" +rather than "this is the value" - a plain read-only display of the formatted value +would be clearer. + +**Workaround.** `disabled` is set on the picker's inner `` in read-only +generation. + +**Proposal.** A `readonly` (or `data-readonly`) mode that renders the formatted +value non-interactively without the disabled/greyed styling - ideally shared +across date / datetime / time (and consistent with other form controls). + +## 5. Built-in icon set: a few common names are missing + +**Gap.** The built-in `x-h-icon` set has no `inbox`, `eye`, or `upload`. + +**Why it matters.** These are common in CRUD/app chrome (an inbox empty state, a +row "preview/view" action, an upload affordance). + +**Workaround.** `upload` was mapped to the existing built-in `import`; `inbox` and +`eye` were rendered via Lucide instead. + +**Proposal.** Consider adding `inbox`, `eye` (and an explicit `upload` alias of +`import`) to the built-in icon set, so common app chrome does not need Lucide. + +--- + +## Not a gap (recorded to avoid re-investigation): i18next plugin + +The platform did **not** adopt `harmonia-i18next`, but this is **not** a Harmonia +shortcoming - the platform i18n is deeply tied to its own catalog model (it +aggregates each project's `i18n//*.json` from the registry via an +extension service, loads namespaces on demand, and uses baked English literals for +the default language, skipping i18next entirely). A generic `window.i18next` +binder cannot own that pipeline, and both driving `window.i18next` would collide. +No change requested; noted so the question is not reopened. From 531326a7306ad82204b2f918f5f92b3193e6cb04 Mon Sep 17 00:00:00 2001 From: delchev Date: Tue, 7 Jul 2026 22:47:43 +0300 Subject: [PATCH 2/2] docs: frame each request as a general Harmonia capability (any consumer), not a Dirigible-only ask Add a 'Who it helps' angle to every item so the reusable, framework-wide value is explicit; keep the Dirigible use case as the concrete example only. Co-Authored-By: Claude Opus 4.8 --- docs/dirigible-integration-feedback.md | 134 ++++++++++++++----------- 1 file changed, 75 insertions(+), 59 deletions(-) diff --git a/docs/dirigible-integration-feedback.md b/docs/dirigible-integration-feedback.md index 66648be..24b0c73 100644 --- a/docs/dirigible-integration-feedback.md +++ b/docs/dirigible-integration-feedback.md @@ -1,10 +1,12 @@ -# Harmonia improvement requests - from the Eclipse Dirigible integration +# Harmonia improvement requests - surfaced by the Eclipse Dirigible integration -Feedback gathered while migrating the Eclipse Dirigible platform (its application -shells and code-generation templates) from Harmonia `1.24.2` to `2.1.0`. Both -projects are built by the same team; this list captures the framework gaps the -migration hit, with the workaround used and a concrete proposal, so Harmonia -itself can absorb them and the workarounds can be dropped later. +These are **general Harmonia capabilities** - things any consumer of the library +benefits from - that the Eclipse Dirigible integration happened to surface while +migrating from Harmonia `1.24.2` to `2.1.0`. Both projects are built by the same +team, but each request below is written as a reusable framework feature: the +"Who it helps" line states the general case, and "Dirigible example" is only the +concrete motivator, not the sole beneficiary. Each item also lists the workaround +used today so it can be dropped once Harmonia absorbs the feature. Ordered roughly by impact. @@ -13,92 +15,106 @@ Ordered roughly by impact. **Gap.** Native charts cover `bar`, `line`, `pie`, `doughnut`, `scatter`. There is no `polarArea` and no `radar`. -**Why it matters.** Dirigible's report/chart feature (and its intent DSL) accepts -`bar | line | pie | doughnut | polarArea | radar`. The first four map cleanly onto -`x-h-chart-*`, but `polarArea`/`radar` have no native equivalent, so the platform -cannot fully drop its Chart.js dependency - a mixed Chart.js + Harmonia setup is -the only alternative, which defeats the migration. +**Who it helps.** Any consumer building dashboards/analytics: `polarArea` and +`radar` are part of the standard chart vocabulary (Chart.js, ECharts, D3 all have +them). Their absence forces those consumers to keep a second charting library +just for two chart types. -**Workaround.** Migration of the report charts to `x-h-chart-*` is **blocked/deferred**; -Chart.js is retained for now. +**Dirigible example.** Its report feature accepts +`bar | line | pie | doughnut | polarArea | radar`; the first four map onto +`x-h-chart-*`, but the last two have no equivalent, so Chart.js cannot be dropped. -**Proposal.** Add `x-h-chart-polar-area` (or `x-h-chart-polararea`) and -`x-h-chart-radar`, config-compatible with the existing chart family -(`series` + `labels`, theme-aware, accessible figure + hidden table). +**Workaround.** Chart migration to `x-h-chart-*` is deferred; Chart.js is kept. + +**Proposal.** Add `x-h-chart-polar-area` and `x-h-chart-radar`, config-compatible +with the existing chart family (`series` + `labels`, theme-aware, accessible +figure + hidden data table). ## 2. Charts: an export / print API **Gap.** Charts render as DOM/CSS (`createElement`, conic-gradient pie - no ``/`` root) and expose no way to get an image or drive printing. -**Why it matters.** The platform's report "Print" snapshots the chart with -`canvas.toDataURL('image/png')` into a print window. With DOM/CSS charts there is -no canvas to snapshot, so that print path cannot be reproduced when migrating to -`x-h-chart-*`. +**Who it helps.** Practically every charting consumer eventually needs "download +this chart as an image" or "print this report" - a share/export button is table +stakes for dashboards. With a canvas library it is `toDataURL()`; with Harmonia's +DOM charts there is currently no equivalent, so no consumer can offer it. + +**Dirigible example.** Its report "Print" snapshots the chart with +`canvas.toDataURL('image/png')` into a print window - impossible to reproduce on +DOM/CSS charts. -**Workaround.** None yet - another reason the chart migration is deferred. +**Workaround.** None - another reason the chart migration is deferred. -**Proposal.** A small export/print surface on the chart element, e.g. a -`chart.toImage()` / `toDataURL()` method (rasterize the rendered DOM) or a +**Proposal.** A small export/print surface on the chart element, e.g. +`chart.toImage()` / `toDataURL()` (rasterize the rendered DOM) or a `chart.print()` helper that opens a print view with the chart + Harmonia CSS. ## 3. Lucide plugin: react to a changing `data-lucide` -**Gap.** `x-h-lucide` reads the icon name **once** at init. A bound -`:data-lucide` whose value later changes does not re-render (the tip in the docs -confirms this and suggests re-creating the element). +**Gap.** `x-h-lucide` reads the icon name **once** at init; a bound +`:data-lucide` whose value later changes does not re-render (the docs confirm this +and suggest re-creating the element). -**Why it matters.** Icons that flip at runtime (a chart/table toggle button, a -play/pause control, a theme sun/moon) are natural with a single bound -`:data-lucide` - but that silently freezes on the first value. +**Who it helps.** Any reactive UI with state-driven icons - toggle buttons, +status indicators, expand/collapse chevrons, theme switchers. In a reactive +library the natural expectation is that binding the name updates the icon; the +read-once behaviour is a surprise every consumer has to learn and work around. -**Workaround.** Every toggled icon was rewritten as **two `` -elements switched with `x-show`** (or re-created via `x-if`). Correct, but verbose -and easy to get wrong (an `` with another directive throws). +**Dirigible example.** A chart/table toggle, a play/pause control, and a theme +sun/moon each had to be rewritten as two `` elements switched with +`x-show`, because a single bound `:data-lucide` froze on its first value. -**Proposal.** Make `:data-lucide` reactive - re-render the icon when the bound -name changes - matching the behaviour `x-h-icon` already has for its reactive -`data-icon`. That would let a single placeholder cover the dynamic-name case. +**Workaround.** Two `` + `x-show` per toggled icon (or `x-if` +re-creation). + +**Proposal.** Make `:data-lucide` reactive (re-render on change), matching the +reactive `data-icon` that `x-h-icon` already supports, so one placeholder covers +the dynamic-name case. ## 4. Pickers: a first-class read-only / display mode **Gap.** Date / Datetime / Time pickers have no documented read-only or -display-only mode. Only a `disabled` inner input works (via the -`has-[input:disabled]` styling), which greys the control out. +display-only mode; only a `disabled` inner input works (via `has-[input:disabled]`), +which greys the control out. + +**Who it helps.** Any app with view-vs-edit states: detail pages, view-only forms, +permission-gated fields, audit/history screens. A `disabled` control signals +"unavailable" rather than "here is the value", so every consumer showing a +read-only date wants a cleaner display mode. (The same argument applies to the +other form controls, for consistency.) -**Why it matters.** Generated forms have a preview / read-only mode where every -field is shown non-editable. A greyed-out (`disabled`) picker reads as "unavailable" -rather than "this is the value" - a plain read-only display of the formatted value -would be clearer. +**Dirigible example.** Generated forms have a preview mode where all fields are +non-editable; a greyed-out picker reads wrong there. -**Workaround.** `disabled` is set on the picker's inner `