You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is no way to consume Cratis's Arc-binding behavior without also taking a UI kit and its licence.
@cratis/components is the only package that carries the command/query binding surface consumers actually build screens with — CommandDialog, CommandForm fields, DataPage, the query-driven tables, Notifications. Every one of those arrives through a package whose peer set is PrimeReact 11, which is PrimeTek's commercial PrimeUI (see #161). A consumer who has their own design system, or who cannot accept a commercial peer, has no supported entry point — they either take the licence or reimplement the binding layer.
This is not a new idea; it is the generalization of one already stated in this repository.#109 says it for tables:
"The seam's value is that the UI library is a swappable detail. Today the abstraction that delivers that (TableRenderer + bindQuery) lives inside the PrimeReact library it is meant to abstract away … Moving it there would let a Cratis app bind Arc queries to its own table with no PrimeReact dependency, and leave @cratis/components as purely a rendering library — one implementation of the contract, not its owner."
That principle is right and it is not table-specific. This issue asks to apply it library-wide.
Evidence
Measured against the published @cratis/components@3.4.0 artifact (dist/esm.js + .d.ts), with primereact@11.1.0:
171 emitted modules; 45 import primereact/*, @primereact/* or @primeuix/*.
30.d.ts files import a PrimeReact/PrimeUIX type; 29 are reachable from a public entry point.
27 distinct PrimeReact symbols are public API: 18 types reachable only through the pt/ptOptions pass-through (one mechanical pattern across ~56 declaration sites), 8 semantic types, and 1 runtime value.
The encouraging half of the same measurement — the work is already substantially done:
~75+ exports are already PrimeReact-free: all of Toolbar, all of Filter, all of PivotViewer (pixi.js-based), the TimeMachine core, and the Cratis-owned Column / StepperPanel / MenuItem / DataTableSelectionChangeEvent / DataTableFilterMeta markers.
~40 exports are thin — a single widget behind Cratis-owned props (all of Display, 13 of 15 CommandForm fields, Button, Dialog, Tooltip, DatePickerInput, TablePaginator).
The v10→v11 migration already produced most of the neutral vocabulary as a side effect.
@cratis/arc.react is already fully headless — react is its only peer, and it contains zero PrimeReact references. asCommandFormField / WrappedFieldProps<T> already live there, exactly as Prove a renderer-neutral Arc React query/table state seam #109 observes.
So the coupling that blocks a UI-kit-free entry point is concentrated, not diffuse. Four places carry it:
CratisComponentsConfig = Partial<PrimeReactProps> — the configuration surface is PrimeReact's (filed separately).
The styled subpath — styledMode + primeReactStyles (74 @primereact/styles/* imports) + CratisPreset. PrimeTek's token system by construction; correctly adapter-owned.
toast, re-exported verbatim from primereact/toaster (filed separately).
The data-table filter/selection engine — DataTableCore + ColumnFilterMenu (filed separately).
What it costs a consumer
Real, and paid in both licensing and maintenance cost.
A consumer with an existing custom-token design system pays for a UI kit it replaces. Even after direct primereact/* usage is reduced to a bounded adapter surface and enforced by lint rules, the application still installs PrimeReact and still needs a key because the binding layer only ships inside the PrimeReact package.
Publish a UI-kit-free entry point carrying behavior only — command execution and validation state, observable-query binding, paging/sort/filter state, dialog and stepper orchestration, toast dispatch, locale plumbing, error mapping, and the neutral marker types that already exist. Whether it lands as @cratis/arc.react (where asCommandFormField and useQueryWithPaging already are, and where Prove a renderer-neutral Arc React query/table state seam #109 proposes putting TableRenderer/bindQuery) or as a new @cratis/components.core is an implementation choice this issue takes no position on. The requirement is that it installs with no UI-kit peer and no licence obligation.
Keep @cratis/components as exactly what Prove a renderer-neutral Arc React query/table state seam #109 names it — one implementation of that contract. Its public API stops naming PrimeReact types (the four items above), and PrimeReact becomes an adapter-local detail rather than a library-wide one.
Document the headless contract to the standard an adapter would have been documented to, so "bring your own UI kit" is a supported path rather than an inference.
Consider shipping a conformance suite any UI implementation can run to prove it satisfies the contract.
The smallest useful first step is the one #109 already identifies: relocate the pure contract types, which carry no PrimeReact and therefore no circular-dependency problem.
What is explicitly not being asked for
Not additional first-party UI adapter packages. Public evidence is strongly against a small team maintaining several: React Admin shipped one UI package (ra-ui-materialui) in ~10 years while shipping 50+ data providers under the same adapter pattern, and put its second UI story (shadcn-admin-kit) in a separate repository. Refine shipped four UI adapters and they carry 13 / 5 / 2 / 0 adapter hooks respectively, with @refinedev/chakra-ui at 1,665 weekly downloads and @refinedev/mantine at 1,092 against a core at 148,342 — a 48:1 skew between first and fourth. One adapter, plus recipes for anyone else, is what the evidence supports.
Not dropping, replacing or vendoring PrimeReact, and not reverting the peer-dependency change.
Not any change to PrimeTek's licensing, or any mechanism that suppresses the licence banner.
What happens
There is no way to consume Cratis's Arc-binding behavior without also taking a UI kit and its licence.
@cratis/componentsis the only package that carries the command/query binding surface consumers actually build screens with —CommandDialog,CommandFormfields,DataPage, the query-driven tables,Notifications. Every one of those arrives through a package whose peer set is PrimeReact 11, which is PrimeTek's commercial PrimeUI (see #161). A consumer who has their own design system, or who cannot accept a commercial peer, has no supported entry point — they either take the licence or reimplement the binding layer.This is not a new idea; it is the generalization of one already stated in this repository. #109 says it for tables:
That principle is right and it is not table-specific. This issue asks to apply it library-wide.
Evidence
Measured against the published
@cratis/components@3.4.0artifact (dist/esm.js+.d.ts), withprimereact@11.1.0:primereact/*,@primereact/*or@primeuix/*..d.tsfiles import a PrimeReact/PrimeUIX type; 29 are reachable from a public entry point.pt/ptOptionspass-through (one mechanical pattern across ~56 declaration sites), 8 semantic types, and 1 runtime value.The encouraging half of the same measurement — the work is already substantially done:
Toolbar, all ofFilter, all ofPivotViewer(pixi.js-based), theTimeMachinecore, and the Cratis-ownedColumn/StepperPanel/MenuItem/DataTableSelectionChangeEvent/DataTableFilterMetamarkers.Display, 13 of 15CommandFormfields,Button,Dialog,Tooltip,DatePickerInput,TablePaginator).@cratis/arc.reactis already fully headless —reactis its only peer, and it contains zero PrimeReact references.asCommandFormField/WrappedFieldProps<T>already live there, exactly as Prove a renderer-neutral Arc React query/table state seam #109 observes.So the coupling that blocks a UI-kit-free entry point is concentrated, not diffuse. Four places carry it:
CratisComponentsConfig = Partial<PrimeReactProps>— the configuration surface is PrimeReact's (filed separately).styledsubpath —styledMode+primeReactStyles(74@primereact/styles/*imports) +CratisPreset. PrimeTek's token system by construction; correctly adapter-owned.toast, re-exported verbatim fromprimereact/toaster(filed separately).DataTableCore+ColumnFilterMenu(filed separately).What it costs a consumer
Real, and paid in both licensing and maintenance cost.
primereact/*usage is reduced to a bounded adapter surface and enforced by lint rules, the application still installs PrimeReact and still needs a key because the binding layer only ships inside the PrimeReact package.Suggested fix — the seam
Generalize #109 from tables to the library:
@cratis/arc.react(whereasCommandFormFieldanduseQueryWithPagingalready are, and where Prove a renderer-neutral Arc React query/table state seam #109 proposes puttingTableRenderer/bindQuery) or as a new@cratis/components.coreis an implementation choice this issue takes no position on. The requirement is that it installs with no UI-kit peer and no licence obligation.@cratis/componentsas exactly what Prove a renderer-neutral Arc React query/table state seam #109 names it — one implementation of that contract. Its public API stops naming PrimeReact types (the four items above), and PrimeReact becomes an adapter-local detail rather than a library-wide one.The smallest useful first step is the one #109 already identifies: relocate the pure contract types, which carry no PrimeReact and therefore no circular-dependency problem.
What is explicitly not being asked for
ra-ui-materialui) in ~10 years while shipping 50+ data providers under the same adapter pattern, and put its second UI story (shadcn-admin-kit) in a separate repository. Refine shipped four UI adapters and they carry 13 / 5 / 2 / 0 adapter hooks respectively, with@refinedev/chakra-uiat 1,665 weekly downloads and@refinedev/mantineat 1,092 against a core at 148,342 — a 48:1 skew between first and fourth. One adapter, plus recipes for anyone else, is what the evidence supports.DataTableForQuery/DataTableForObservableQuery/CommandDialogpublic props — the same non-breaking constraint Prove a renderer-neutral Arc React query/table state seam #109 sets for itself.