diff --git a/Documentation/blueprints/getting-started.md b/Documentation/blueprints/getting-started.md index be5d708..64dd807 100644 --- a/Documentation/blueprints/getting-started.md +++ b/Documentation/blueprints/getting-started.md @@ -11,12 +11,11 @@ You need a React application, `@cratis/scene.react`, and the blueprint itself. ## Install and load the stylesheet -The blueprint's shell is hand-written CSS - PrimeReact 10 has no application-shell primitive to lean on - +The blueprint's shell is hand-written CSS - it predates any application-shell primitive to lean on - so the stylesheet has to be loaded once, at your entry point, along with PrimeReact's own. ```ts -import 'primereact/resources/primereact.min.css'; -import 'primereact/resources/themes/lara-light-indigo/theme.css'; +import 'primeicons/primeicons.css'; import 'primeicons/primeicons.css'; import '@cratis/scene.blueprint.default/styles'; ``` diff --git a/Documentation/components-package/theming.md b/Documentation/components-package/theming.md index 4d86aae..3725d42 100644 --- a/Documentation/components-package/theming.md +++ b/Documentation/components-package/theming.md @@ -89,13 +89,13 @@ CSS custom property: it splits on `.`, kebab-cases each part, and prefixes `--sc ## A theme still has to be loaded The bridge tints the surfaces the Cratis wrappers own. It does not, on its own, skin PrimeReact's widgets: -in PrimeReact 10 every widget's *structural* CSS — padding, borders, the dialog frame, focus rings — ships +in PrimeReact 11 every widget's *structural* CSS — padding, borders, the dialog frame, focus rings — comes inside the theme file, and there is no separate primitives stylesheet. An application that loads no PrimeReact theme has no structural CSS, and its components render as raw HTML primitives whatever the tokens say. So load a PrimeReact theme underneath, and use Scene tokens to move it to your palette. The -[PrimeReact package](../primereact-package/index.md) ships every free PrimeReact 10 theme as a Scene theme, +[PrimeReact package](../primereact-package/index.md) ships 24 themes built on PrimeTek's `@primeuix/themes` presets as Scene themes, with its tokens read verbatim out of the theme's own `:root` block — so the token layer always agrees with what the stylesheet renders. Its [theme reference](../primereact-package/theme-reference.md) lists the values each theme carries for the thirteen tokens above. diff --git a/Documentation/primereact-package/component-reference.md b/Documentation/primereact-package/component-reference.md index 45a3d32..36c73e2 100644 --- a/Documentation/primereact-package/component-reference.md +++ b/Documentation/primereact-package/component-reference.md @@ -1,262 +1,180 @@ --- title: Component reference -description: Every abstract component name the PrimeReact package declares, the PrimeReact 10 component behind it, and what is deliberately not covered. +description: Every abstract component name the PrimeReact package declares, the adapter that implements it, and what backs it in PrimeReact 11. --- -87 abstract names across ten families. Every name is `lowerCamelCase`; every registry key is +**83** abstract names across ten families. Every name is `lowerCamelCase`; every registry key is `PrimeReact:`. -## Form +The **Backed by** column is generated from the adapters' own imports — followed one level into a sibling +component, so a name that delegates still reports what it really builds on. It cannot drift from what the +code does. Three kinds of entry appear: -| Name | PrimeReact 10 component | Import | -| --- | --- | --- | -| `inputText` | `InputText` | `primereact/inputtext` | -| `inputTextarea` | `InputTextarea` | `primereact/inputtextarea` | -| `inputNumber` | `InputNumber` | `primereact/inputnumber` | -| `password` | `Password` | `primereact/password` | -| `inputMask` | `InputMask` | `primereact/inputmask` | -| `floatLabel` | `FloatLabel` + `InputText` | `primereact/floatlabel`, `primereact/inputtext` | -| `iconField` | `IconField` + `InputIcon` + `InputText` | `primereact/iconfield`, `primereact/inputicon`, `primereact/inputtext` | -| `dropdown` | `Dropdown` | `primereact/dropdown` | -| `multiSelect` | `MultiSelect` | `primereact/multiselect` | -| `listBox` | `ListBox` | `primereact/listbox` | -| `selectButton` | `SelectButton` | `primereact/selectbutton` | -| `checkbox` | `Checkbox` | `primereact/checkbox` | -| `radioButton` | `RadioButton` | `primereact/radiobutton` | -| `toggleSwitch` | `InputSwitch` | `primereact/inputswitch` | -| `slider` | `Slider` | `primereact/slider` | -| `rating` | `Rating` | `primereact/rating` | -| `knob` | `Knob` | `primereact/knob` | -| `calendar` | `Calendar` | `primereact/calendar` | -| `colorPicker` | `ColorPicker` | `primereact/colorpicker` | -| `chips` | `Chips` | `primereact/chips` | -| `autoComplete` | `AutoComplete` | `primereact/autocomplete` | -| `treeSelect` | `TreeSelect` | `primereact/treeselect` | -| `cascadeSelect` | `CascadeSelect` | `primereact/cascadeselect` | +- a `primereact/*` module — the name maps onto a real PrimeReact 11 component; +- a `@primereact/headless/*` hook marked **(headless)** — v11 ships the behavior but no presentation, so + this package renders it; +- **Cratis-owned** — PrimeReact 11 removed the component outright and this package implements it. Such a + name may still list `primereact/*` modules: an owned replacement is usually composed from surviving v11 + primitives (`confirmDialog` is built from `Dialog` and `Button`). See + [the migration record](./primereact-11-migration.md#names-that-lost-their-component). -`radioButton` renders the whole group from its `options`, sharing one `name` so the browser enforces -exclusivity — a lone radio button is never what a screen means, the choice is the group. +## Form -`autoComplete` filters the authored `options` case-insensitively. PrimeReact asks the host for suggestions -through `completeMethod` because in a real application that is a server call, and a Scene element cannot -express one. +| Name | Adapter | Backed by | +| --- | --- | --- | +| `inputText` | `form/PrimeInputText.tsx` | `primereact/inputtext` | +| `inputTextarea` | `form/PrimeInputTextarea.tsx` | `primereact/textarea` | +| `inputNumber` | `form/PrimeInputNumber.tsx` | `primereact/inputnumber` | +| `password` | `form/PrimePassword.tsx` | `primereact/inputpassword` | +| `floatLabel` | `form/PrimeFloatLabel.tsx` | `primereact/floatlabel`, `primereact/inputtext` | +| `iconField` | `form/PrimeIconField.tsx` | `primereact/iconfield`, `primereact/inputtext` | +| `dropdown` | `form/PrimeDropdown.tsx` | `primereact/select` | +| `multiSelect` | `form/PrimeMultiSelect.tsx` | `primereact/select` | +| `listBox` | `form/PrimeListBox.tsx` | `primereact/listbox` | +| `selectButton` | `form/PrimeSelectButton.tsx` | `primereact/togglebutton`, `primereact/togglebuttongroup` | +| `checkbox` | `form/PrimeCheckbox.tsx` | `primereact/checkbox` | +| `radioButton` | `form/PrimeRadioButton.tsx` | `primereact/radiobutton` | +| `toggleSwitch` | `form/PrimeToggleSwitch.tsx` | `primereact/toggleswitch` | +| `slider` | `form/PrimeSlider.tsx` | `primereact/slider` | +| `rating` | `form/PrimeRating.tsx` | `primereact/rating` | +| `knob` | `form/PrimeKnob.tsx` | `primereact/knob` | +| `calendar` | `form/PrimeCalendar.tsx` | `primereact/datepicker`, `primereact/inputtext` | +| `colorPicker` | `form/PrimeColorPicker.tsx` | `primereact/inputcolor` | +| `chips` | `form/PrimeChips.tsx` | `primereact/inputtags` | +| `autoComplete` | `form/PrimeAutoComplete.tsx` | `primereact/autocomplete` | +| `treeSelect` | `form/PrimeTreeSelect.tsx` | `primereact/popover`, `primereact/tree` + **Cratis-owned** | ## Button -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `button` | `Button` | `primereact/button` | -| `splitButton` | `SplitButton` | `primereact/splitbutton` | -| `speedDial` | `SpeedDial` | `primereact/speeddial` | -| `buttonGroup` | `ButtonGroup` + `Button` | `primereact/buttongroup`, `primereact/button` | - -`button` deliberately shares its name with `core` — see -[Understanding name resolution](./understanding-name-resolution.md). +| `button` | `button/PrimeButton.tsx` | `primereact/button` | +| `splitButton` | `button/PrimeSplitButton.tsx` | `primereact/button`, `primereact/popover` + **Cratis-owned** | +| `speedDial` | `button/PrimeSpeedDial.tsx` | `primereact/speeddial` | +| `buttonGroup` | `button/PrimeButtonGroup.tsx` | `primereact/button`, `primereact/buttongroup` | ## Data -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `dataTable` | `DataTable` + `Column` | `primereact/datatable`, `primereact/column` | -| `table` | `DataTable` + `Column` (the same adapter as `dataTable`) | `primereact/datatable`, `primereact/column` | -| `column` | `Column` | `primereact/column` | -| `dataView` | `DataView` | `primereact/dataview` | -| `tree` | `Tree` | `primereact/tree` | -| `treeTable` | `TreeTable` + `Column` | `primereact/treetable`, `primereact/column` | -| `timeline` | `Timeline` | `primereact/timeline` | -| `paginator` | `Paginator` | `primereact/paginator` | -| `orderList` | `OrderList` | `primereact/orderlist` | -| `pickList` | `PickList` | `primereact/picklist` | -| `organizationChart` | `OrganizationChart` | `primereact/organizationchart` | -| `virtualScroller` | `VirtualScroller` | `primereact/virtualscroller` | - -A table works out its columns in order of how explicitly the screen stated them: nested `column` children -first, then a `columns` property, then the keys of the first row. That last step matters more than it looks -— a table given rows and no column configuration is the most common thing an author writes first, and -inferring the columns means it renders their data instead of an empty grid. - -> [!NOTE] -> `column` renders nothing on its own. That is PrimeReact's own semantics — a bare `` outside a -> `DataTable` renders nothing either. When nested under `dataTable` or `table`, the table reads its -> `field`, `header` and `sortable` off the **model** rather than the rendered node, because PrimeReact -> identifies its columns by React element type and a Scene adapter wrapping one would not be recognized. - -`organizationChart` renders empty when no nodes are authored. PrimeReact's own `OrganizationChart` reads -the root node's `expanded` flag without checking there is a root and throws on an empty value; an element -whose data has not been authored yet is an ordinary state on a screen under construction, and taking the -whole screen down for it would be the wrong failure. +| `dataTable` | `data/PrimeDataTable.tsx` | `primereact/datatable` | +| `table` | `data/PrimeDataTable.tsx` | `primereact/datatable` | +| `column` | `data/PrimeColumn.tsx` | **Cratis-owned** | +| `dataView` | `data/PrimeDataView.tsx` | `primereact/dataview`, `primereact/paginator` | +| `tree` | `data/PrimeTree.tsx` | `primereact/tree` | +| `timeline` | `data/PrimeTimeline.tsx` | `primereact/timeline` | +| `paginator` | `data/PrimePaginator.tsx` | `primereact/paginator` | +| `orderList` | `data/PrimeOrderList.tsx` | `@primereact/headless/orderlist` (headless) | +| `pickList` | `data/PrimePickList.tsx` | `@primereact/headless/picklist` (headless) | +| `organizationChart` | `data/PrimeOrganizationChart.tsx` | `primereact/organizationchart` | ## Panel -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `card` | `Card` | `primereact/card` | -| `panel` | `Panel` | `primereact/panel` | -| `accordion` | `Accordion` + `AccordionTab` | `primereact/accordion` | -| `fieldset` | `Fieldset` | `primereact/fieldset` | -| `divider` | `Divider` | `primereact/divider` | -| `splitter` | `Splitter` + `SplitterPanel` | `primereact/splitter` | -| `scrollPanel` | `ScrollPanel` | `primereact/scrollpanel` | -| `tabView` | `TabView` + `TabPanel` | `primereact/tabview` | -| `toolbar` | `Toolbar` | `primereact/toolbar` | -| `stepper` | `Stepper` + `StepperPanel` + `Button` | `primereact/stepper`, `primereact/stepperpanel`, `primereact/button` | - -`accordion`, `tabView`, `splitter` and `stepper` all pair a `headers` property with the `content` slot by -position — a screen puts as many children in the slot as it lists headers. This is for the same reason -`column` is read from the model: PrimeReact identifies these sections by React element type. - -`stepper` renders its own Back and Next buttons. PrimeReact's `Stepper` advances only when something calls -`nextCallback`/`prevCallback` on its ref, and a stepper that cannot step is not a stepper. - -`toolbar` takes `start`, `center` and `end` slots rather than properties, because what goes in them is other -components — buttons, a search field, a menu — not values. +| `card` | `panel/PrimeCard.tsx` | `primereact/card` | +| `panel` | `panel/PrimePanel.tsx` | `primereact/panel` | +| `accordion` | `panel/PrimeAccordion.tsx` | `primereact/accordion` | +| `fieldset` | `panel/PrimeFieldset.tsx` | `primereact/fieldset` | +| `divider` | `panel/PrimeDivider.tsx` | `primereact/divider` | +| `splitter` | `panel/PrimeSplitter.tsx` | `primereact/splitter` | +| `scrollPanel` | `panel/PrimeScrollPanel.tsx` | `primereact/scrollarea` | +| `tabView` | `panel/PrimeTabView.tsx` | `primereact/tabs` | +| `toolbar` | `panel/PrimeToolbar.tsx` | `primereact/toolbar` | +| `stepper` | `panel/PrimeStepper.tsx` | `primereact/button`, `primereact/stepper` | ## Overlay -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `dialog` | `Dialog` + `Button` | `primereact/dialog`, `primereact/button` | -| `confirmDialog` | `ConfirmDialog` + `Button` | `primereact/confirmdialog`, `primereact/button` | -| `overlayPanel` | `OverlayPanel` + `Button` | `primereact/overlaypanel`, `primereact/button` | -| `sidebar` | `Sidebar` + `Button` | `primereact/sidebar`, `primereact/button` | -| `tooltip` | `Tooltip` | `primereact/tooltip` | - -Each of these renders its own trigger. An overlay is only interesting while it is open, and "the user -closed it" is state a Scene element has nowhere to record — so the adapter owns visibility locally and keeps -a way back. Without the trigger, dismissing a previewed dialog would leave a permanently blank spot. +| `dialog` | `overlay/PrimeDialog.tsx` | `primereact/button`, `primereact/dialog` | +| `confirmDialog` | `overlay/PrimeConfirmDialog.tsx` | `primereact/button`, `primereact/dialog` + **Cratis-owned** | +| `overlayPanel` | `overlay/PrimeOverlayPanel.tsx` | `primereact/button`, `primereact/popover` | +| `sidebar` | `overlay/PrimeSidebar.tsx` | `primereact/button`, `primereact/drawer` | +| `tooltip` | `overlay/PrimeTooltip.tsx` | `primereact/tooltip` | ## Menu -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `menu` | `Menu` | `primereact/menu` | -| `menubar` | `Menubar` | `primereact/menubar` | -| `breadcrumb` | `BreadCrumb` | `primereact/breadcrumb` | -| `tabMenu` | `TabMenu` | `primereact/tabmenu` | -| `steps` | `Steps` | `primereact/steps` | -| `tieredMenu` | `TieredMenu` | `primereact/tieredmenu` | -| `panelMenu` | `PanelMenu` | `primereact/panelmenu` | -| `contextMenu` | `ContextMenu` | `primereact/contextmenu` | -| `megaMenu` | `MegaMenu` | `primereact/megamenu` | -| `dock` | `Dock` | `primereact/dock` | - -All ten read the same nested `{ label, icon, url, disabled, separator, items }` model to any depth, so one -authored menu can be shown as a menubar, a tiered menu or a dock without being restructured. +| `menu` | `menu/PrimeMenu.tsx` | `primereact/menu` | +| `menubar` | `menu/PrimeMenubar.tsx` | **Cratis-owned** | +| `breadcrumb` | `menu/PrimeBreadcrumb.tsx` | `primereact/breadcrumb` | +| `tabMenu` | `menu/PrimeTabMenu.tsx` | **Cratis-owned** | +| `steps` | `menu/PrimeSteps.tsx` | **Cratis-owned** | +| `tieredMenu` | `menu/PrimeTieredMenu.tsx` | **Cratis-owned** | +| `panelMenu` | `menu/PrimePanelMenu.tsx` | `primereact/accordion` + **Cratis-owned** | +| `contextMenu` | `menu/PrimeContextMenu.tsx` | `primereact/contextmenu` | +| `megaMenu` | `menu/PrimeMegaMenu.tsx` | **Cratis-owned** | +| `dock` | `menu/PrimeDock.tsx` | **Cratis-owned** | ## Messages -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `message` | `Message`, full width | `primereact/message` | -| `inlineMessage` | `Message`, sized to content | `primereact/message` | -| `toast` | `Toast` | `primereact/toast` | - -`message` and `inlineMessage` share one PrimeReact component but mean different things on a screen — one is -about a region, the other about the field beside it — and the width is the difference a reader sees. - -`toast` shows its message once on mount from the element's own properties. PrimeReact's `Toast` is purely -imperative and renders nothing until someone calls `show`; a Scene element cannot make that call, so the -element reads as "this screen announces this" rather than as a component that renders nothing. +| `message` | `messages/PrimeMessage.tsx` | `primereact/message` | +| `inlineMessage` | `messages/PrimeInlineMessage.tsx` | `primereact/message` | +| `toast` | `messages/PrimeToast.tsx` | `primereact/toast`, `primereact/toaster` | ## Media -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `image` | `Image` | `primereact/image` | -| `galleria` | `Galleria` | `primereact/galleria` | -| `carousel` | `Carousel` | `primereact/carousel` | - -`galleria` and `carousel` ship no default item template, so each adapter supplies one built from the fields -the element names. Without it every item renders empty and the component looks broken rather than -unconfigured. +| `image` | `media/PrimeImage.tsx` | `primereact/dialog` + **Cratis-owned** | +| `galleria` | `media/PrimeGalleria.tsx` | `primereact/gallery` | +| `carousel` | `media/PrimeCarousel.tsx` | `primereact/carousel` | ## Misc -| Name | PrimeReact 10 component | Import | +| Name | Adapter | Backed by | | --- | --- | --- | -| `avatar` | `Avatar` | `primereact/avatar` | -| `badge` | `Badge` | `primereact/badge` | -| `chip` | `Chip` | `primereact/chip` | -| `tag` | `Tag` | `primereact/tag` | -| `progressBar` | `ProgressBar` | `primereact/progressbar` | -| `progressSpinner` | `ProgressSpinner` | `primereact/progressspinner` | -| `skeleton` | `Skeleton` | `primereact/skeleton` | -| `scrollTop` | `ScrollTop` | `primereact/scrolltop` | -| `blockUI` | `BlockUI` | `primereact/blockui` | -| `inplace` | `Inplace` + `InplaceDisplay` + `InplaceContent` | `primereact/inplace` | -| `terminal` | `Terminal` | `primereact/terminal` | - -`progressBar` follows whether a `value` was given at all: progress you cannot measure is exactly what -indeterminate mode is for, so an element with no value animates rather than sitting at zero. - -`terminal` accepts input and answers nothing until the hosting application subscribes to PrimeReact's -`TerminalService`. Responding to a command is application behavior, not something a Scene element can -express — this is the honest shape of a terminal with no backend, not a broken one. - -## Screen - -Screenplay's screen vocabulary, plus `text`. - -| Name | Renders | PrimeReact 10 component | +| `avatar` | `misc/PrimeAvatar.tsx` | `primereact/avatar` | +| `badge` | `misc/PrimeBadge.tsx` | `primereact/badge` | +| `chip` | `misc/PrimeChip.tsx` | `primereact/chip` | +| `tag` | `misc/PrimeTag.tsx` | `primereact/tag` | +| `progressBar` | `misc/PrimeProgressBar.tsx` | `primereact/progressbar` | +| `progressSpinner` | `misc/PrimeProgressSpinner.tsx` | `primereact/progressspinner` | +| `skeleton` | `misc/PrimeSkeleton.tsx` | `primereact/skeleton` | +| `scrollTop` | `misc/PrimeScrollTop.tsx` | `primereact/button` + **Cratis-owned** | +| `blockUI` | `misc/PrimeBlockUI.tsx` | **Cratis-owned** | +| `inplace` | `misc/PrimeInplace.tsx` | `primereact/inplace` | +| `terminal` | `misc/PrimeTerminal.tsx` | `primereact/terminal` | + +## Screen directives + +| Name | Adapter | Backed by | | --- | --- | --- | -| `text` | a themed `` | (none — written directly) | -| `title` | a real `

`–`

` at the authored level | (none — written directly) | -| `field` | a labeled value bound by `aria-labelledby` | (none — written directly) | -| `section` | a real `
` with a heading and a rule | `Divider` | -| `summary` | a description list of label/value pairs | `Card` | -| `action` | a button whose intent maps to a severity | `Button` | +| `text` | `screen/PrimeText.tsx` | _renders plain markup_ | +| `title` | `screen/PrimeTitle.tsx` | _renders plain markup_ | +| `field` | `screen/PrimeField.tsx` | _renders plain markup_ | +| `section` | `screen/PrimeSection.tsx` | `primereact/divider` | +| `summary` | `screen/PrimeSummary.tsx` | `primereact/card` | +| `action` | `screen/PrimeAction.tsx` | `primereact/button` | -`title` clamps its level to 1–6. Heading level is the document outline a screen reader navigates by, so it -is not a styling choice — and an out-of-range value must degrade to a valid heading, not an invalid tag. +## Names that are no longer declared -`action` maps intent to severity in one place: +Four names were dropped in the PrimeReact 11 migration, because v11 removed the component with no +equivalent and no headless hook to rebuild it from. `validatePackageBundle` still passes — they were +removed from the manifest and the registry together. -| `intent` | PrimeReact `severity` | +| Dropped name | Use instead | | --- | --- | -| `primary` | (default) | -| `secondary` | `secondary`, outlined | -| `destructive`, `danger` | `danger` | -| `positive`, `success` | `success` | - -## Reading properties +| `cascadeSelect` | `dropdown` with grouped options, or `treeSelect` for a hierarchy | +| `inputMask` | `inputText` with validation | +| `treeTable` | `tree` for hierarchy, `dataTable` for tabular data | +| `virtualScroller` | `dataTable`'s own scrolling for long lists | -Element properties arrive as untyped JSON. Every adapter narrows through the same readers, so a wrongly -typed property behaves exactly like a missing one instead of reaching PrimeReact and failing there: - -```ts -import { arrayProperty, booleanProperty, numberProperty, optionsProperty, stringProperty } from '@cratis/scene.primereact'; - -stringProperty(element, 'label'); // string | undefined -stringProperty(element, 'label', 'Save'); // string -booleanProperty(element, 'disabled', false); // boolean -numberProperty(element, 'rows', 4); // number -arrayProperty(element, 'items'); // unknown[] - never undefined -optionsProperty(element, 'options'); // SelectOption[] -``` - -`optionsProperty` accepts both shapes an author might reasonably write — `['Draft', 'Published']` and -`[{ label: 'Draft', value: 'draft' }]` — and flattens them to one type. `numberProperty` rejects `NaN` -alongside non-numbers: it is a number by `typeof` but never a usable size, count or bound. - -## Interactive state - -PrimeReact's inputs are controlled, and a Scene element has nowhere to put "what the user has typed so far" -— `properties` is authored design-time configuration. Every interactive adapter therefore holds that state -locally, seeded from its properties. The consequence is deliberate: a preview is genuinely typeable rather -than frozen, and the value stays local to the rendered component rather than being pushed back into the -model. - -## Deliberately not covered +## Not covered | Component | Why | | --- | --- | -| `chart` | PrimeReact's `Chart` is a thin wrapper over Chart.js and does nothing without `chart.js` installed and a full Chart.js configuration object. Adding a charting library as a dependency of a component-mapping package is out of scope, and charting deserves its own Scene package with its own vocabulary. | +| `chart` | PrimeReact's `Chart` is a thin wrapper over Chart.js and does nothing without `chart.js` installed and a full Chart.js configuration object. Adding a charting library as a dependency of a component-mapping package is out of scope; charting deserves its own Scene package with its own vocabulary. | | `editor` | `Editor` wraps Quill and needs `quill` installed. Same reasoning — a rich-text editor is a product decision, not a mapping. | -Both are genuinely useful, and both are omissions rather than oversights. A profile needing them should +Both are genuinely useful and both are deliberate omissions, not oversights. A profile needing them should activate a package that owns that dependency. -## Next - -See [Theme reference](./theme-reference.md) for the themes, or -[Migrating to PrimeReact 11](./primereact-11-migration.md) for what changes when the version moves. +Also worth knowing: `column` renders nothing on its own. That is deliberate — since PrimeReact 11 removed +`primereact/column`, `column` is a Cratis-owned declaration component that returns `null`, and the table +reads its `field`/`header`/`sortable` off the *model* (`element.slots`) rather than the rendered node. +Nesting a `column` element under `dataTable` or `table` is what gives it meaning. diff --git a/Documentation/primereact-package/index.md b/Documentation/primereact-package/index.md index 8439dde..6ec5db8 100644 --- a/Documentation/primereact-package/index.md +++ b/Documentation/primereact-package/index.md @@ -6,7 +6,7 @@ description: The Scene package that maps abstract component names onto real Prim A screen written in Screenplay says `button`. It does not say `PrimeReact.Button`, and it does not import anything. Something has to turn that name into a real React component — and that something is a package. -`@cratis/scene.primereact` is the package that turns Scene's abstract names into PrimeReact 10 components. +`@cratis/scene.primereact` is the package that turns Scene's abstract names into PrimeReact 11 components. Add `PrimeReact` to a `ui profile` and 87 names become resolvable, 25 themes become selectable, and every screen you have already written renders through a real, themed component library without a single edit. @@ -47,7 +47,7 @@ why that is the mechanism and not a collision. import { primeReactPackageManifest } from '@cratis/scene.primereact'; primeReactPackageManifest.name; // 'PrimeReact' -primeReactPackageManifest.version; // '10.9.8' +primeReactPackageManifest.version; // '11.1.0' primeReactPackageManifest.kind; // PackageKind.ComponentLibrary primeReactPackageManifest.dependencies; // [{ name: 'Tailwind' }] primeReactPackageManifest.components; // 87 abstract names @@ -68,25 +68,26 @@ supplies the layout and the templates themselves. See [Blueprints](../blueprints ## The two halves of theming -A PrimeReact 10 theme is a pre-compiled CSS file, not a set of runtime variables. So theming a Scene screen -that uses this package takes two things working together: +A PrimeReact 11 theme is a `@primeuix/themes` preset object, which `@primeuix/styled` turns into `--p-*` +custom properties at runtime. So theming a Scene screen that uses this package takes two things working +together: ```mermaid flowchart LR Theme["Scene Theme
(name + 13 tokens)"] Hook["usePrimeReactTheme"] Provider["SceneThemeProvider"] - Link["<link id='theme-link'>
theme.css"] + Preset["PrimeReactProvider
--p-* properties"] Tokens["--scene-* on the
theme root element"] - Prime["PrimeReact components
(.p-* elements)"] + Prime["PrimeReact components
(read --p-*)"] Wrappers["Scene wrappers, core,
layout CSS"] - Theme --> Hook --> Link --> Prime + Theme --> Hook --> Preset --> Prime Theme --> Provider --> Tokens --> Wrappers Tokens -.->|primeReactTheme.css
bridges back| Prime ``` -Neither half is enough alone: drop the hook and PrimeReact's components keep the old skin; drop the provider +Neither half is enough alone: drop the hook and PrimeReact's components render unstyled; drop the provider and the wrappers around them do not follow. [Switch themes live](./switch-themes-live.md) shows the wiring, and [Understanding design tokens](./understanding-design-tokens.md) explains the bridge in the middle. diff --git a/Documentation/primereact-package/primereact-11-migration.md b/Documentation/primereact-package/primereact-11-migration.md index 0f5bd48..1b422d4 100644 --- a/Documentation/primereact-package/primereact-11-migration.md +++ b/Documentation/primereact-package/primereact-11-migration.md @@ -1,32 +1,49 @@ --- -title: Migrating to PrimeReact 11 -description: The renames, removals and hook conversions PrimeReact 11 brings, and what each one means for the abstract names this package declares. +title: The PrimeReact 11 migration +description: What the port from PrimeReact 10 to 11 changed in this package - the renames, the names that lost their component, and what was built, converted or dropped for each. --- -This package targets PrimeReact **10.9.8** and must keep doing so: Cratis Studio pins `primereact` to -`10.9.8` through a root `resolutions` entry, and `@cratis/components` depends on exactly that version. -Import from `primereact/*` only — never `@primereact/*` or `@primeuix/themes`. +This package targets PrimeReact **11.1.0**. This page is the record of the port from 10.9.8 — what moved, +what disappeared, and what was decided for each name that lost its component. -PrimeReact 11 exists, and the port will happen eventually. This page records what changes so it is a known -quantity rather than a discovery. +> [!IMPORTANT] +> **PrimeReact 11 is not MIT.** The relicensing is the single most consequential part of this upgrade and +> it is not a theming detail. See [Licensing](#licensing) at the foot of this page before adopting it. ## The trap, first > [!CAUTION] > **`Sidebar` is not `Sidebar`.** PrimeReact 10's `Sidebar` — a panel that slides in from an edge of the -> viewport — becomes `Drawer` in v11. Separately, v11 introduces a **brand-new, unrelated `Sidebar`** for +> viewport — is `Drawer` in v11. Separately, v11 introduces a **brand-new, unrelated `Sidebar`** for > application-shell navigation. > > A port that follows the name rather than the behavior silently swaps a slide-in overlay for a static -> shell element. **It will compile.** Nothing fails until someone opens the screen. +> shell element. **It compiles.** Nothing fails until someone opens the screen. -The abstract name this package declares is `sidebar`, and it means the overlay. When the port happens, it -maps to v11's `Drawer`. +The abstract name this package declares is `sidebar`, and it means the overlay. It maps to v11's +`Drawer`, in `overlay/PrimeSidebar.tsx`. The same trap was live in `@cratis/scene.blueprint.default`, whose +`shell/ConfigPanel.tsx` used the v10 `Sidebar` — and which was made nastier still by a *local* component +of the same name in the same folder. Both are on `primereact/drawer`. + +## What the surface looks like now + +PrimeReact 11 ships **80** modules where 10.9.8 shipped 117. Measured against the 87 `primereact/*` paths +this package imported: + +| Outcome | Count | +| --- | --- | +| Survives under the same name | 45 | +| Renamed | 13 | +| Survives only as a headless hook | 2 | +| Gone with no equivalent anywhere | 20 | +| Infrastructure module, removed | 6 | + +The manifest declared **87** abstract names before the port and declares **83** after. ## Renames -Each of these is a one-line import change in a single adapter file. The abstract name does not move — that -is the point of having one. +Each of these is an import change in a single adapter file. The abstract name does not move — that is the +point of having one. | Abstract name | PrimeReact 10 | PrimeReact 11 | | --- | --- | --- | @@ -44,80 +61,188 @@ is the point of having one. | `scrollPanel` | `ScrollPanel` | `ScrollArea` | | `selectButton` | `SelectButton` | `ToggleButtonGroup` | -Note how many of the abstract names already match the v11 name — `toggleSwitch`, `selectButton`. That is -not luck. A Scene name follows what a component *is*, not what one library calls it this major version, so -the abstract vocabulary tends to survive a rename that the library's own does not. +Note how many abstract names already matched the v11 name — `toggleSwitch`, `selectButton`. That is not +luck. A Scene name follows what a component *is*, not what one library calls it this major version, so the +abstract vocabulary tends to survive a rename that the library's own does not. + +A rename is rarely only an import, because **v11 is compositional**. `primereact/select` exports +`Select.Root` / `Trigger` / `Value` / `Portal` / `Positioner` / `Popup` / `List` / `Option` and you +assemble them: -`tabView` is the one rename that is more than an import: `TabView` + `TabPanel` collapse into a single -`Tabs` component, so the header/content pairing in `panel/PrimeTabView.tsx` has to be rebuilt against the -new shape. +```tsx +import { Select } from 'primereact/select'; -## Became hooks + setValue(event.value)}> + + + + + + + + + + + + +``` -These stop being components in v11 and become hooks. Each needs a rewrite, not a rename. +## Names that lost their component -| Abstract name | PrimeReact 10 component | +Twenty of the modules this package imported are gone from v11 with no rename and no equivalent. Every one +was decided deliberately; none was left declared-but-unimplemented. + +### Built as Cratis-owned components + +The component is gone, the abstract name is worth keeping, so this package now owns a small +implementation. Each is a real component in this package's source, not a stub. + +| Abstract name | Built as | Notes | +| --- | --- | --- | +| `menubar` | `menu/Menubar.tsx` | Follows the pattern `@cratis/components` used for its own `ActionMenubar`. | +| `megaMenu` | `menu/MegaMenu.tsx` | A menubar whose panel lays children out in columns. | +| `tieredMenu` | `menu/TieredMenu.tsx` | Vertical menu with submenus opening to the side. | +| `panelMenu` | `menu/PanelMenu.tsx` | Accordion-style vertical menu. | +| `tabMenu` | `menu/TabMenu.tsx` | Tab-styled horizontal navigation. | +| `steps` | `menu/Steps.tsx` | Read-only numbered progress indicator, distinct from the interactive `stepper`. | +| `dock` | `menu/Dock.tsx` | Icon dock anchored to an edge. | +| `splitButton` | `button/SplitButton.tsx` | Primary action plus a popover menu. | +| `confirmDialog` | `overlay/ConfirmDialog.tsx` | Composed from v11's `Dialog` + `Button`. The v10 imperative `confirmDialog()` service API is not carried over. | +| `column` | `data/Column.tsx` | A declaration the table reads. v10 extras (`editor`, `frozen`, `footer`, `colSpan`, `expander`) are not carried over. | +| `treeSelect` | `form/TreeSelect.tsx` | `Popover` + `Tree`. Single selection only; no checkbox multi-select, no filtering. | +| `blockUI` | `misc/BlockUI.tsx` | Overlay with `aria-busy`. | +| `scrollTop` | `misc/ScrollTop.tsx` | Threshold button; removes its scroll listener on unmount. | +| `image` | `media/Image.tsx` | `` with optional click-to-preview. | + +### Converted to headless hooks + +`orderlist` and `picklist` survive in `@primereact/headless` but ship no presentation, so this package +renders them. + +| Abstract name | Hook | | --- | --- | -| `inputMask` | `InputMask` | -| `scrollTop` | `ScrollTop` | -| `orderList` | `OrderList` | -| `pickList` | `PickList` | +| `orderList` | `useOrderList` from `@primereact/headless/orderlist` | +| `pickList` | `usePickList` from `@primereact/headless/picklist` | + +### Re-expressed over another component -`KeyFilter` is on the same list upstream but this package does not map it, so it costs nothing. +| Abstract name | Now | Notes | +| --- | --- | --- | +| `multiSelect` | `Select` with `multiple` | v11's `Select` does take a `multiple` prop (`SelectRootProps`, `@primereact/types` 11.1.0). v11 renders the selection through its value slot, so v10's `display` / `maxSelectedLabels` comma-and-chip modes and label collapse are gone. | -## Removed +### Dropped from the manifest -v11 removes these outright. Four are mapped here, and each needs either a replacement built from what -remains or the abstract name retired from the manifest. +Four names no longer exist in this package. `validatePackageBundle` still passes because they were removed +from the manifest and the registry together. -| Abstract name | PrimeReact 10 component | Status | +| Dropped name | Why | Use instead | | --- | --- | --- | -| `blockUI` | `BlockUI` | Mapped — needs a replacement | -| `panelMenu` | `PanelMenu` | Mapped — needs a replacement | -| `tabMenu` | `TabMenu` | Mapped — navigation tabs are built from `Tabs` in v11 | -| `dock` | `Dock` | Mapped — needs a replacement | +| `cascadeSelect` | Removed from v11 with no equivalent and no headless hook. A faithful replacement is a substantial component in its own right. | `dropdown` with grouped options, or `treeSelect` for a hierarchy. | +| `inputMask` | Exists in neither `primereact/*` nor `@primereact/headless/*`. | `inputText` with validation. | +| `treeTable` | Removed from v11 with no equivalent and no headless hook. | `tree` for hierarchy, `dataTable` for tabular data. | +| `virtualScroller` | Removed from v11 with no equivalent. | `dataTable`'s own scrolling for long lists. | -Also removed upstream, and not mapped here, so no cost: `ConfirmPopup`, `DeferredContent`, `DataScroller`, -`TriStateCheckbox`, `MultiStateCheckbox`, `SlideMenu`, `Mention` and `Ripple`. +### Infrastructure modules -`ConfirmDialog` survives — only its `ConfirmPopup` sibling goes — so `confirmDialog` is unaffected. +Six imports were not components at all and are gone from v11: `api`, `menuitem`, `treenode`, `resources`, +`images` and `stepperpanel`. -## Moved to commercial packages +Two of them carried **types** ten adapters shared, so those types are Scene's now: -`Chart` and `Editor` move to the commercial `@primeuipro/*` packages and have **no React release yet**. +- `MenuItem` — was `primereact/menuitem`, now `MenuItem.ts` in this package. +- `TreeNode` — was `primereact/treenode`, now `TreeNode.ts` in this package. -This package maps neither of them, and the reasoning that kept them out for v10 holds for v11 as well: -`chart` would drag in Chart.js and `editor` would drag in Quill, and neither belongs in a package whose job -is mapping names. See the [Component reference](./component-reference.md#deliberately-not-covered). +Owning them is the better arrangement rather than a consolation: the authored `{ label, icon, items }` +shape is Scene's vocabulary — it is what a `.play` file writes — and never needed to be defined by +whichever component library happened to render it. It also means a Cratis-owned replacement for a removed +PrimeReact menu takes the same items the PrimeReact-backed ones do. -## Icons +## Theming was rebuilt, not ported -v11 components ship **no icons**. Every `icon` property this package passes through assumes `primeicons` is -loaded, which stays true in v11 — but v11's own components no longer bundle their internal ones, so any -component that relied on a built-in icon needs one supplied. +This was the long pole of the migration, and nothing of the v10 mechanism survived. -## Themes +**PrimeReact 11 ships zero CSS.** There is no `primereact/resources` directory: no +`resources/themes//theme.css`, no `resources/primereact.css`. A look comes from a `@primeuix/themes` +preset handed to `PrimeReactProvider`, which `@primeuix/styled` turns into `--p-*` custom properties at +runtime. -PrimeReact 11 replaces the compiled per-theme CSS files with `@primeuix/themes`, a runtime design-token -system. That is a larger change than the component renames, and it changes the shape of theming rather than -its names: +What that removed from this package: -- `primeReactThemeStylesheet` and `applyPrimeReactTheme` become meaningless — there is no stylesheet to - swap. -- `usePrimeReactTheme` would set design tokens directly instead of replacing a ``. -- The Scene token vocabulary and `SceneThemeProvider` are **unaffected**. That is exactly what the - indirection was for: the thirteen tokens in - [Understanding design tokens](./understanding-design-tokens.md) stay the same, and only the bridge file - underneath them is rewritten. -- Attribution stays required either way — see [Theme reference](./theme-reference.md). +- `applyPrimeReactTheme` — swapped the theme `` element. Gone; there is no stylesheet to swap. +- `primeReactThemeStylesheet` — resolved a theme name to a CSS path. Gone; replaced by + `primeReactThemePreset`, which resolves a theme name to a preset **object**. -## Checklist for the port +`usePrimeReactTheme` survives by name and is considerably less machinery: it returns the configuration +`PrimeReactProvider` needs, and switching theme is re-rendering a provider rather than locating a ``, +rewriting one path segment of its URL and swapping in a replacement element. Nothing is fetched, so there +is no unstyled flash on switch and no way for a theme to 404. -1. Bump `primereact` and its peer range, and confirm Studio's `resolutions` entry moved with it. -2. Apply the 13 renames — 12 are import-only; rebuild `tabView` against `Tabs`. -3. Rewrite the 4 hook conversions. -4. Decide, for each of the 4 removals, whether to rebuild or to retire the abstract name. -5. Rewrite `theme/` against `@primeuix/themes`, keeping the token vocabulary and the attribution. -6. Check every `icon` property still resolves, now that v11 ships none. -7. Re-run the specs: `validatePackageBundle` proves the manifest and registry still agree, and the - attribution specs prove no credit was dropped along the way. +```tsx +const [theme, setTheme] = useState(primeReactTheme('lara-light-blue')); +const configuration = usePrimeReactTheme(theme); + +return ( + + {children} + +); +``` + +The catalog changed shape too — 25 v10 themes became 24 built on four preset families. See +[Theme reference](./theme-reference.md) for the full list, the attribution table, and the themes that did +not survive. + +### The token bridge got simpler + +`primeReactTheme.css` is the seam between Scene's `--scene-*` tokens and PrimeReact's own, and the port +made it **smaller**. + +In v10 the right-hand side of each mapping was whatever the theme's SCSS happened to call it, so the bridge +had to know an ad-hoc vocabulary: `--primary-color` but `--primary-color-text`, `--surface-ground` but +`--surface-card`, `--highlight-bg` but `--highlight-text-color`, `--text-color-secondary`, +`--border-radius`. Those names shared no scheme and could only be learned by reading compiled stylesheets. + +In v11 `@primeuix/styled` emits one flat, systematic `--p-*` namespace derived from the preset's token +paths, so every mapping is the same mechanical `token.path` → `--p-token-path` transformation: + +```css +:root { + --scene-primary-color: var(--p-primary-color); + --scene-surface-card: var(--p-content-background); + --scene-text-muted-color: var(--p-text-muted-color); + /* … */ +} +``` + +This is the mechanism the bridge always assumed. It just finally exists. + +## Licensing + +PrimeReact 10 was MIT. PrimeReact 11 is not, and neither is anything around it: + +| Package | v10 | v11 | +| --- | --- | --- | +| `primereact` | MIT | PrimeUI commercial | +| `primeicons` | MIT (7.x) | PrimeUI commercial (8.x) | +| `@primereact/core`, `@primereact/headless` | — | PrimeUI commercial | +| `@primeuix/themes`, `@primeuix/styled` | — | PrimeUI commercial | + +**A key is required regardless of how you style.** The check runs in `PrimeReactProvider` on mount, with an +empty dependency array and no condition on `unstyled`, on `theme`, or on `NODE_ENV`. Without a valid key +you get a console warning and a fixed *"Invalid PrimeUI License"* banner, in development **and** +production. + +- **[Community License](https://primeui.dev/licenses/community)** — free for individuals, students, + non-profits and non-commercial open source. For organizations: under $1M USD annual gross revenue, fewer + than 5 developers, fewer than 10 employees, under $3M USD outside funding. Up to 4 developers, renewed + annually. +- **[Commercial License](https://primeui.dev/licenses/commercial)** — per developer, perpetual, one year of + updates. + +If you publish a library or tool others build with, read v11's restrictions clause — *"Redistributing the +software so that third parties can develop with it requires a separate OEM License"* — and check your +position with PrimeTek. Nothing here is legal advice. + +`@cratis/components` 2.x remains on PrimeReact 10 and is fully MIT, for projects where a commercial +dependency is not acceptable. diff --git a/Documentation/primereact-package/switch-themes-live.md b/Documentation/primereact-package/switch-themes-live.md index 68640b5..93f0ba5 100644 --- a/Documentation/primereact-package/switch-themes-live.md +++ b/Documentation/primereact-package/switch-themes-live.md @@ -1,6 +1,6 @@ --- title: Switch themes live -description: Wire a theme picker that swaps the PrimeReact stylesheet and the Scene tokens together, with no reload and no lost state. +description: Wire a theme picker that swaps the PrimeReact preset and the Scene tokens together, with no reload and no lost state. --- This guide wires a theme picker that changes the whole appearance of a rendered Scene screen without a @@ -9,139 +9,109 @@ reload, without remounting the subtree, and without losing what the user has typ ## Before you start You need a React application already rendering Scene screens through `SceneElementView` with the -`primeReactComponents` registry, and PrimeReact's stylesheets loaded. +`primeReactComponents` registry. -## Load the stylesheets in the right order +> [!IMPORTANT] +> PrimeReact 11 requires a PrimeUI license key. Without one every page shows an *"Invalid PrimeUI +> License"* banner, in development and production alike — this is not specific to theming, it is checked +> whenever `PrimeReactProvider` mounts. See [the licensing +> section](./primereact-11-migration.md#licensing). -PrimeReact's structural CSS and one compiled theme come first; the token bridge comes after, because it -reads the theme's variables. +## Load the stylesheets + +There is far less to load than there was on PrimeReact 10. **v11 ships no CSS at all** — there is no +`primereact/resources` directory, so there is no structural stylesheet and no compiled theme to import. +What remains is the icon font and the Scene token bridge: ```ts -import 'primereact/resources/themes/lara-light-blue/theme.css'; -import 'primereact/resources/primereact.css'; import 'primeicons/primeicons.css'; import '@cratis/scene.primereact/primeReactTheme.css'; ``` -If your build serves the themes as static files rather than importing them, declare the initial theme as a -`` in your HTML and give it the id `theme-link`: +The `` arrangement PrimeReact 10 used is gone with the stylesheets it pointed at. A +theme is no longer a file that can be served from a path you choose; it is an object you hand to a +provider. -```html - -``` +## Wire the two halves -Either works. The `` form gives you control over where themes are served from, and the swap keeps -whatever path shape you wrote. +Theming a Scene screen still takes two pieces, but the first one changed completely. -## Wire the two halves +`usePrimeReactTheme` resolves a Scene `Theme` to the configuration `PrimeReactProvider` needs — a +`@primeuix/themes` preset plus its dark-mode selector. That is what makes `@primeuix/styled` emit the +`--p-*` custom properties PrimeReact's own components read. -A PrimeReact 10 theme is a pre-compiled CSS file, so there is nothing to *set* — only a different file to -load. That is why theming takes two pieces: `usePrimeReactTheme` swaps the stylesheet that skins PrimeReact's -components, and `SceneThemeProvider` writes the same theme's semantic tokens onto the wrapping element, -which is what reaches this package's own wrappers, `core`'s primitives, and any layout CSS reading -`--scene-*`. +`SceneThemeProvider` writes the same theme's semantic tokens onto the wrapping element, which is what +reaches this package's own wrappers, `core`'s primitives, and any layout CSS reading `--scene-*`. ```tsx import { useState } from 'react'; -import { SceneElement, Theme } from '@cratis/scene.model'; -import { SceneElementView, SceneThemeProvider } from '@cratis/scene.react'; -import { primeReactComponents, primeReactThemes, usePrimeReactTheme } from '@cratis/scene.primereact'; +import { PrimeReactProvider } from '@primereact/core'; +import { SceneThemeProvider } from '@cratis/scene.react'; +import { primeReactTheme, primeReactThemes, usePrimeReactTheme } from '@cratis/scene.primereact'; -export const ThemedScreen = ({ element }: { element: SceneElement }) => { - const [theme, setTheme] = useState(primeReactThemes[0]); - usePrimeReactTheme(theme); +export const ThemedScreen = ({ children }: { children: React.ReactNode }) => { + const [theme, setTheme] = useState(primeReactTheme('lara-light-blue')); + const configuration = usePrimeReactTheme(theme); return ( - <> - + - undefined} /> + + {children} - + ); }; ``` -Drop the hook and PrimeReact's components keep the old skin. Drop the provider and the wrappers around them -do not follow. Both, and the whole screen moves together. +Switching is live: nothing reloads, nothing below the provider remounts, and no state is lost. -## What the swap actually does +## Why this got simpler -`usePrimeReactTheme` follows the mechanism PrimeReact 10.9.8 implements in `PrimeReactContext.changeTheme`: -find the `` by id, build a new URL, create a **replacement** `` element, and swap it into the -same position. Creating a new element rather than assigning to `href` matters — some browsers do not -reliably re-fetch a stylesheet whose `href` is mutated in place. +On PrimeReact 10 this page had to explain a `` element, an element id, why the swap created a +*replacement* element rather than assigning to `href` (some browsers will not re-fetch a mutated `href`), +and how to keep the application in charge of where theme files were served from. -Two things differ from PrimeReact's own implementation, both deliberately: +None of that survives, because none of it has anything to swap any more: -| PrimeReact 10.9.8 | This package | +| PrimeReact 10 | PrimeReact 11 | | --- | --- | -| String-replaces the old theme name anywhere in the URL | Replaces the theme *folder segment*, so an application served from `/nano/` can leave the `nano` theme without corrupting its own path | -| Throws when the `` is missing | Creates it, because a host embedding a preview has no reason to have pre-declared one | - -## Group the picker by scheme +| `applyPrimeReactTheme(name)` swapped a `` | Removed — there is no stylesheet | +| `primeReactThemeStylesheet(name)` returned a CSS path | `primeReactThemePreset(name)` returns a preset object | +| A theme could 404 | A theme cannot 404 — it is a value, not a fetch | +| Switching could flash unstyled while the new sheet loaded | No fetch, so no flash | -Every theme says whether it is dark, so a picker can group rather than making the reader guess from the name: +`usePrimeReactTheme` kept its name because it kept its job — keep PrimeReact's half of the theme in step +with the Scene theme — but it returns a value now instead of performing a DOM side effect. -```tsx -import { primeReactThemes } from '@cratis/scene.primereact'; - -const light = primeReactThemes.filter((theme) => !theme.isDark); -const dark = primeReactThemes.filter((theme) => theme.isDark); -``` +## Dark themes -## Credit the author in the picker - -Every theme in this package is PrimeTek's work, and the `Theme` fields carry the attribution so a picker can -show it: +`@primeuix/themes` resolves every `light-dark()` token pair against a CSS selector rather than the +operating system preference, so something has to put that selector on the page. `usePrimeReactTheme` hands +the preset `.scene-dark` as its `darkModeSelector`; add that class to an ancestor when the active theme is +a dark one: ```tsx - - {theme.author} -{' '} -· {theme.license} +
``` -Do this. It is one line, the data is already there, and it is the difference between using someone's work -and passing it off as your own. The full table is in [Theme reference](./theme-reference.md). - -## Switch to a theme by name +Every theme in the catalog reports `isDark`, so a picker can do this without a lookup table. -When the theme comes from configuration rather than a picker, look it up — an unknown name returns -`undefined` rather than a plausible-looking value: +## Themes from another package -```ts -import { primeReactTheme, primeReactThemeStylesheet } from '@cratis/scene.primereact'; - -primeReactTheme('soho-dark'); // the Theme -primeReactThemeStylesheet('soho-dark'); // 'primereact/resources/themes/soho-dark/theme.css' -primeReactThemeStylesheet('lara-light-chartreuse'); // undefined -``` - -## Swap outside React - -`applyPrimeReactTheme` is the same operation without the hook, for a theme chosen before React mounts or by -code that is not a component: - -```ts -import { applyPrimeReactTheme } from '@cratis/scene.primereact'; - -applyPrimeReactTheme('lara-dark-teal'); // true when it swapped, false when the theme is unknown -``` +`usePrimeReactTheme` returns `undefined` for a theme this package does not ship, rather than falling back +to a default preset. That is deliberate: silently theming a screen as something other than what was asked +for is much harder to notice than nothing happening. A profile mixing in a theme from another package +leaves PrimeReact's own styling to whichever package owns that theme. -## Next +## See also -Look up what a name maps to in the [Component reference](./component-reference.md), or see every theme in -the [Theme reference](./theme-reference.md). +- [Theme reference](./theme-reference.md) — the 24 themes, their preset families and the attribution table. +- [Understanding design tokens](./understanding-design-tokens.md) — what the thirteen Scene tokens mean and + how the bridge resolves them. diff --git a/Documentation/primereact-package/theme-reference.md b/Documentation/primereact-package/theme-reference.md index aad0938..f479e95 100644 --- a/Documentation/primereact-package/theme-reference.md +++ b/Documentation/primereact-package/theme-reference.md @@ -1,115 +1,117 @@ --- title: Theme reference -description: The 25 free PrimeTek themes the PrimeReact package ships, with their color scheme, author, source and license. +description: The 24 themes the PrimeReact package ships, with their preset family, color scheme, author, source and license. --- -Every theme here is PrimeTek's work, shipped under the MIT license that covers the whole `primereact` -package, and **none of them are ours**. `Theme`'s `author`, `authorUrl` and `license` fields exist so that -stays visible wherever a theme is listed — show them in any picker you build. +Every theme here is built on one of PrimeTek's `@primeuix/themes` presets, and **none of them are ours**. +`Theme`'s `author`, `authorUrl` and `license` fields exist so that stays visible wherever a theme is +listed — show them in any picker you build. -## Attribution +> [!IMPORTANT] +> **These themes are not MIT.** PrimeReact 10 and its themes were MIT. PrimeReact 11 relicensed the whole +> stack — `primereact`, `@primereact/core`, `@primereact/headless`, `primeicons`, `@primeuix/themes` and +> `@primeuix/styled` — under the commercial **PrimeUI license**, which requires a license key. Without one, +> `PrimeReactProvider` writes a console warning and injects an *"Invalid PrimeUI License"* banner, in +> development **and** production. See [Licensing](#licensing) below. -Verified in `node_modules/primereact/LICENSE.md`: *"The MIT License (MIT), Copyright (c) 2016-2025 -PrimeTek"*. The `primereact` package's own `package.json` reports `"license": "MIT"`. +## Attribution | Theme | Scheme | Description | Author | Source | License | | --- | --- | --- | --- | --- | --- | -| `lara-light-blue` | Light | The PrimeReact default: a clean, roomy light theme on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-dark-blue` | Dark | The Lara family in dark, on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-light-indigo` | Light | Lara light with an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-dark-indigo` | Dark | Lara dark with an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-light-purple` | Light | Lara light with a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-dark-purple` | Dark | Lara dark with a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-light-teal` | Light | Lara light with a teal accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `lara-dark-teal` | Dark | Lara dark with a teal accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `saga-blue` | Light | PrimeTek's earlier light theme: tighter spacing and smaller radii than Lara. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `vela-blue` | Dark | Saga's dark counterpart, on a desaturated blue-grey ground. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `arya-blue` | Dark | Saga's near-black dark counterpart, for high-contrast dark surfaces. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `bootstrap4-light-blue` | Light | PrimeTek's interpretation of the Bootstrap 4 look, in light. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `bootstrap4-dark-blue` | Dark | PrimeTek's interpretation of the Bootstrap 4 look, in dark. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `soho-light` | Light | A soft, low-contrast light theme on a violet accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `soho-dark` | Dark | Soho in dark, on the same violet accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `viva-light` | Light | A neutral, understated light theme on a muted indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `viva-dark` | Dark | Viva in dark, on a near-black blue-grey ground. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `md-light-indigo` | Light | PrimeTek's interpretation of Material Design, in light on indigo. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `md-dark-indigo` | Dark | PrimeTek's interpretation of Material Design, in dark on indigo. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `mdc-light-indigo` | Light | The Material interpretation with compact density, in light. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `mdc-dark-indigo` | Dark | The Material interpretation with compact density, in dark. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `nano` | Light | A dense, near-square theme for information-heavy screens. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `mira` | Light | A calm light theme on a Nord-inspired blue-grey palette. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `fluent-light` | Light | PrimeTek's interpretation of the Microsoft Fluent look, in light. | PrimeTek | [primereact.org](https://primereact.org) | MIT | -| `tailwind-light` | Light | PrimeTek's interpretation of the Tailwind UI look, in light. | PrimeTek | [primereact.org](https://primereact.org) | MIT | - -Several of these are PrimeTek's interpretation of someone else's design language — Bootstrap, Material -Design, Fluent, Tailwind UI. The compiled CSS is still PrimeTek's own work, so PrimeTek is still the author; -the lineage is recorded in the description rather than by misattributing the file. +| `aura-light-blue` | Light | Aura, the flagship PrimeReact 11 design language, in light on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-dark-blue` | Dark | Aura, the flagship PrimeReact 11 design language, in dark on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-light-indigo` | Light | Aura, the flagship PrimeReact 11 design language, in light on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-dark-indigo` | Dark | Aura, the flagship PrimeReact 11 design language, in dark on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-light-purple` | Light | Aura, the flagship PrimeReact 11 design language, in light on a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-dark-purple` | Dark | Aura, the flagship PrimeReact 11 design language, in dark on a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-light-teal` | Light | Aura, the flagship PrimeReact 11 design language, in light on a teal accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `aura-dark-teal` | Dark | Aura, the flagship PrimeReact 11 design language, in dark on a teal accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-light-blue` | Light | Lara, the roomy family Scene shipped on PrimeReact 10, in light on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-dark-blue` | Dark | Lara, the roomy family Scene shipped on PrimeReact 10, in dark on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-light-indigo` | Light | Lara, the roomy family Scene shipped on PrimeReact 10, in light on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-dark-indigo` | Dark | Lara, the roomy family Scene shipped on PrimeReact 10, in dark on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-light-purple` | Light | Lara, the roomy family Scene shipped on PrimeReact 10, in light on a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-dark-purple` | Dark | Lara, the roomy family Scene shipped on PrimeReact 10, in dark on a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-light-teal` | Light | Lara, the roomy family Scene shipped on PrimeReact 10, in light on a teal accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `lara-dark-teal` | Dark | Lara, the roomy family Scene shipped on PrimeReact 10, in dark on a teal accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `nora-light-blue` | Light | Nora, a tighter, squarer, more compact family, in light on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `nora-dark-blue` | Dark | Nora, a tighter, squarer, more compact family, in dark on a blue accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `nora-light-indigo` | Light | Nora, a tighter, squarer, more compact family, in light on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `nora-dark-indigo` | Dark | Nora, a tighter, squarer, more compact family, in dark on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `material-light-indigo` | Light | Material, the PrimeTek reading of Material Design, in light on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `material-dark-indigo` | Dark | Material, the PrimeTek reading of Material Design, in dark on an indigo accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `material-light-purple` | Light | Material, the PrimeTek reading of Material Design, in light on a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +| `material-dark-purple` | Dark | Material, the PrimeTek reading of Material Design, in dark on a purple accent. | PrimeTek | [primereact.org](https://primereact.org) | PrimeUI Commercial | +## What a Scene theme actually is + +A PrimeReact 10 theme was a **file** — a compiled stylesheet under `primereact/resources/themes//`. +A PrimeReact 11 theme is an **object**: a `@primeuix/themes` preset handed to `PrimeReactProvider`, which +`@primeuix/styled` turns into `--p-*` custom properties at runtime. + +So a Scene theme is now a preset family plus an accent: + +| Family | Themes | Character | +| --- | --- | --- | +| Aura | 8 | PrimeTek's flagship design language for v11; softer radii, lower-contrast surfaces. | +| Lara | 8 | The family Scene shipped throughout PrimeReact 10 — the closest continuity with a v10 look. | +| Nora | 4 | Tighter spacing, squarer corners, heavier borders. The most compact of the four. | +| Material | 4 | PrimeTek's reading of Material Design; the nearest thing v11 has to the v10 `md-*`/`mdc-*` themes. | + +The accent is bound by overriding the preset's `primary` scale with a primitive color ramp the preset +already ships, so `lara-light-teal` is genuinely Lara with Lara's own teal rather than an approximation +mixed by Scene. + +## Themes that did not survive the v11 port + +PrimeReact 11 ships four preset families. The v10 themes with no counterpart among them are **gone**, not +renamed: + +`saga-blue`, `vela-blue`, `arya-blue`, `bootstrap4-light-blue`, `bootstrap4-dark-blue`, `soho-light`, +`soho-dark`, `viva-light`, `viva-dark`, `nano`, `mira`, `fluent-light`, `tailwind-light`. + +Renaming a Lara onto `soho-dark` would have kept the catalog's length at the cost of its honesty — the +attribution table above would then have been describing something the theme is not. The closest +replacements are `lara-*` for `saga`/`vela`/`arya`, `material-*` for `md-*`/`mdc-*`, and `nora-*` for +`nano`. ## Where a theme's values come from -Token values are read verbatim from each theme's own `theme.css` `:root` block, so a Scene token always -agrees with what the PrimeReact stylesheet actually renders. That fidelity is the point of the bridge, and -it is kept even where a theme's own values are odd: `lara-light-teal` really does ship the same color for -`--highlight-bg` and `--highlight-text-color`, and mirroring it keeps the token layer honest about what the -component skin will do. - -> [!NOTE] -> There is exactly one deliberate deviation. PrimeReact 10.9.8 ships `viva-dark` with an unresolved SCSS -> expression, `rgba($primaryColor, 0.08)`, for `--surface-hover`. That is not valid CSS and resolves to -> nothing at all, so it cannot be mirrored; the intended value — the theme's primary color at 8% — is used -> instead. - -A theme's `isDark` is taken from this catalog rather than parsed from the stylesheet's `color-scheme` -declaration, because that declaration is not a reliable signal: `vela-blue` declares `color-scheme: light -dark` although every surface it defines is dark. - -## Tokens - -Every theme carries the same thirteen tokens, and only those thirteen — see -[Understanding design tokens](./understanding-design-tokens.md) for what each one means. - -```ts -import { primeReactTheme } from '@cratis/scene.primereact'; - -primeReactTheme('lara-light-blue')!.tokens; -// { -// 'primary.color': '#3b82f6', -// 'primary.contrastColor': '#ffffff', -// 'surface.background': '#f9fafb', -// 'surface.card': '#ffffff', -// 'surface.border': '#dfe7ef', -// 'surface.hover': '#f6f9fc', -// 'surface.overlay': '#ffffff', -// 'text.color': '#4b5563', -// 'text.mutedColor': '#6b7280', -// 'highlight.background': '#eff6ff', -// 'highlight.color': '#1d4ed8', -// 'content.borderRadius': '6px', -// 'focus.ring': '0 0 0 0.2rem #bfdbfe' -// } -``` +The v10 catalog transcribed token values by hand out of each theme's compiled `theme.css` `:root` block. +A v11 preset has no such block: its values are token *references* — `{emerald.500}`, +`light-dark({surface.0}, {surface.900})` — that `@primeuix/styled` resolves at runtime. Transcribing those +by hand would mean re-implementing the resolver in one's head, once per theme. -## Compatibility +So the values in `themePresets.ts` are **generated**: each preset is loaded, its `primary` scale bound to +the chosen color ramp, and the thirteen Scene tokens resolved through the same `light-dark()` and `{path}` +rules `@primeuix/styled` applies. What is committed is the output of that resolution, so the catalog stays +plain data a theme picker can read without booting a theme engine — while still agreeing, value for value, +with what the preset actually renders. -Every theme declares `compatibleWith: ['PrimeReact', 'Tailwind', 'core']`. +A spec (`for_primeReactThemes/when_checking_the_token_vocabulary.ts`) fails the build if any token still +contains an unresolved `{...}` reference or an unpicked `light-dark(...)`, so a resolver that silently gave +up cannot reach the catalog. -`core` is listed deliberately, not by reflex. `ThemeCompatibility` has no implicit exemption for it, so a -theme that leaves it out is reported incompatible for every profile that lists `core` — which for a theme -that really does apply would be a false alarm on nearly every profile there is. And these themes do apply: -the compiled stylesheet only ever matches `.p-*` elements, but the semantic token layer -`SceneThemeProvider` writes reaches everything under the theme root, `core`'s unstyled primitives included. +## Licensing -## Stylesheet paths +PrimeReact 11's `LICENSE.md` states: *"A valid license key is required to use this software. A missing, +invalid, or expired key may cause the software to display a license notice."* -```ts -import { primeReactThemeStylesheet } from '@cratis/scene.primereact'; +The check runs in `PrimeReactProvider` on mount, with an empty dependency array and **no condition** on +`unstyled`, on `theme`, or on `NODE_ENV`. Every styling path reaches it. Supply your key through the +provider: -primeReactThemeStylesheet('mira'); // 'primereact/resources/themes/mira/theme.css' +```tsx + ``` -A theme's `name` **is** its folder under `primereact/resources/themes`, which is what makes this a direct -lookup rather than a table that could fall out of step with the files on disk. An unknown name returns -`undefined` rather than a plausible-looking path that would 404 at load time. - -## Next - -Wire a picker in [Switch themes live](./switch-themes-live.md). +- **[Community License](https://primeui.dev/licenses/community)** — free, and covers individuals, students, + non-profits and non-commercial open source. For organizations it requires *all* of: under $1M USD annual + gross revenue, fewer than 5 developers, fewer than 10 employees, and under $3M USD in outside funding. It + supports up to 4 developers and must be renewed annually. +- **[Commercial License](https://primeui.dev/licenses/commercial)** — for everyone else. Per developer, + perpetual, one year of updates included. + +If you publish a library or tool that others build with, read PrimeReact 11's restrictions clause +carefully — *"Redistributing the software so that third parties can develop with it requires a separate OEM +License"* — and check your position with PrimeTek. Nothing here is legal advice; the authoritative terms +are at the links above. diff --git a/Documentation/primereact-package/understanding-design-tokens.md b/Documentation/primereact-package/understanding-design-tokens.md index f75469f..a619de2 100644 --- a/Documentation/primereact-package/understanding-design-tokens.md +++ b/Documentation/primereact-package/understanding-design-tokens.md @@ -1,6 +1,6 @@ --- title: Understanding design tokens -description: The thirteen semantic tokens every Scene package agrees on, and the stylesheet that bridges them onto PrimeReact 10's CSS variables in both directions. +description: The thirteen semantic tokens every Scene package agrees on, and the stylesheet that bridges them onto PrimeReact 11's design tokens in both directions. --- Write one rule that says `color: var(--text-color)` and you have quietly married your layout to PrimeReact. @@ -48,13 +48,13 @@ name appear together. It bridges them in **both** directions, and the scoping is ```mermaid flowchart TD subgraph root [":root"] - PT["PrimeReact theme.css
--primary-color, --surface-card, ..."] + PT["@primeuix/styled runtime
--p-primary-color, --p-content-background, ..."] ST["--scene-* fall back to them"] PT --> ST end subgraph themed ["[data-scene-theme-root]"] Inline["SceneThemeProvider writes the
theme's tokens inline"] - Back["--primary-color, --surface-card, ...
read from --scene-*"] + Back["--p-primary-color, --p-content-background, ...
read from --scene-*"] Inline --> Back end ST -.->|inherits when the theme
defines no token| Inline @@ -62,12 +62,12 @@ flowchart TD ``` **Downward, on `:root`:** every Scene token falls back to whatever PrimeReact theme is loaded. An -application that loads `lara-light-blue/theme.css` and applies no Scene theme at all still gets meaningful +application that hands `PrimeReactProvider` a preset and applies no Scene theme at all still gets meaningful values for all thirteen tokens. ```css :root { - --scene-primary-color: var(--primary-color); + --scene-primary-color: var(--p-primary-color); --scene-surface-card: var(--surface-card); --scene-text-color: var(--text-color); } @@ -78,7 +78,7 @@ theme re-tints PrimeReact's own components and not only Scene's wrappers. ```css [data-scene-theme-root] { - --primary-color: var(--scene-primary-color); + --p-primary-color: var(--scene-primary-color); --surface-card: var(--scene-surface-card); --text-color: var(--scene-text-color); } @@ -128,7 +128,7 @@ incompatiblePackages(primeReactTheme('soho-dark')!, profile); // [] Every theme in this package lists `['PrimeReact', 'Tailwind', 'core']`, and the `core` entry is a precise claim rather than a courtesy. A theme reaches a screen in two layers, and only one of them is universal: -- **The compiled PrimeReact stylesheet** matches `.p-*` elements. It does nothing for `core`'s bare +- **The preset's `--p-*` properties** are read by PrimeReact's own components. They do nothing for `core`'s bare `` and `