@betterportal/theme-embedded 10.6.17 → 10.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bp-resources/SKILL.md +3 -1
- package/bp-resources/page-template.tsx +2 -2
- package/bp-resources/ui-guide.md +29 -0
- package/lib/bp-contracts/org.betterportal.theme.embedded.json +4 -4
- package/lib/schemas/service-betterportal-theme-embedded.json +1 -1
- package/lib/schemas/service-betterportal-theme-embedded.plugin.json +1 -1
- package/package.json +4 -4
package/bp-resources/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: Build compact BetterPortal service UI for the Embedded theme.
|
|
|
5
5
|
|
|
6
6
|
# BetterPortal Embedded UI
|
|
7
7
|
|
|
8
|
-
1. Read `/llms-api.txt` and the Embedded UI guide.
|
|
8
|
+
1. Read `/llms-api.txt`, `/llms-ui.txt` and the Embedded UI guide.
|
|
9
9
|
2. Keep the view single-column and self-contained.
|
|
10
10
|
3. Use semantic HTML and server-rendered HTMX fragments.
|
|
11
11
|
4. In renderers, use `ctx.url.route()` for service calls and `ctx.url.uiRoute()` only for GET navigation. Pass a declared dependency alias as `serviceId` for another service.
|
|
@@ -13,3 +13,5 @@ description: Build compact BetterPortal service UI for the Embedded theme.
|
|
|
13
13
|
6. Verify keyboard use, labels, responsive wrapping and the published schemas.
|
|
14
14
|
|
|
15
15
|
Do not recreate Bootstrap components or a second app shell. Recommend Bootstrap1 when the requested interface genuinely needs those primitives.
|
|
16
|
+
|
|
17
|
+
Read the UI guide's colors/appearance section and linked BetterPortal documentation; use the active theme's semantic roles and installed API version. Before delivery, follow its view boundaries and defect-reporting rules. Keep domain work in handlers, never submit during initialization or draft restoration, and never register HTMX extensions from service markup. Preserve schema-backed HTML5 constraints: use native submission or `requestSubmit()`, gate custom triggers with `reportValidity()`, and never disable validation to post an invalid form. Use project reporting tools for reproducible theme/framework defects. Verify failed POST followed by navigation, preload, history and repeated swaps without mutation replay or duplicate listeners.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @jsxImportSource jsx-htmx */
|
|
2
|
-
import type {
|
|
2
|
+
import type { RegisteredViewRenderer } from "@betterportal/framework";
|
|
3
3
|
|
|
4
|
-
export const render:
|
|
4
|
+
export const render: RegisteredViewRenderer["render"] = (data) => (
|
|
5
5
|
<section aria-labelledby="page-title">
|
|
6
6
|
<h1 id="page-title">Page title</h1>
|
|
7
7
|
<p>Explain the task in one sentence.</p>
|
package/bp-resources/ui-guide.md
CHANGED
|
@@ -14,3 +14,32 @@ The Embedded theme renders BetterPortal service content inside a lightweight hos
|
|
|
14
14
|
- Do not add a SPA framework, iframe, client router, state library or hardcoded service URL.
|
|
15
15
|
|
|
16
16
|
The Embedded theme deliberately offers fewer visual primitives than Bootstrap1. If a workflow needs a complex application shell, use Bootstrap1 instead of recreating a shell inside service content.
|
|
17
|
+
|
|
18
|
+
## Colors and appearance
|
|
19
|
+
|
|
20
|
+
Embedded is a minimal host with a transparent document background. It does not declare the Bootstrap1/2 palette configuration or their `--bp-*` token contract. A `bootstrap5` component example or a brand hex value from another theme is not a portable Embedded styling API.
|
|
21
|
+
|
|
22
|
+
Use native controls and inherit available host typography/colors; keep necessary service-specific CSS local to the component. Do not load Bootstrap, add global branding, redefine document colors or install a separate appearance controller. If a richer palette/component contract is required, implement it in the owning theme or select a suitable theme, rather than reproducing its shell in a view.
|
|
23
|
+
|
|
24
|
+
Read the [BetterPortal theme contract](https://github.com/BetterCorp/BetterPortal/blob/master/docs/building/themes.md), [routes/views](https://github.com/BetterCorp/BetterPortal/blob/master/docs/building/routes-and-views.md) and active `/llms-ui.txt`. Match documentation examples to installed package versions; master may describe newer APIs.
|
|
25
|
+
|
|
26
|
+
## Form validation before requests
|
|
27
|
+
|
|
28
|
+
The backend input schema is the source of truth. Render its applicable HTML5 constraints (`type`, `required`, `min`, `max`, `step`, `minlength`, `maxlength`, `pattern`) and preserve them after swaps. The browser validates the returned HTML controls; it does not execute AnyVali/JSON schema automatically. Numeric inputs use range/step constraints, not `pattern`. Hidden inputs and controls barred from constraint validation are not checked by these APIs; validate computed payloads against the published input contract and always on the server.
|
|
29
|
+
|
|
30
|
+
Prefer native submit buttons or `form.requestSubmit(submitter)`. For a necessary custom trigger, stop if `form.reportValidity()` is false; `form.checkValidity()` checks without showing validation messages. Never bypass invalid controls with `form.submit()`, synthetic submit events, custom fetch/HTMX posts, `noValidate`/`formNoValidate`, `novalidate`/`formnovalidate` or disabled HTMX validation. Recalculation that accepts fewer fields needs a separate non-nested form/component with its own constraints, not a bypass on the full form. The backend validates every submission, including rules HTML cannot express.
|
|
31
|
+
|
|
32
|
+
Check invalid submissions by button, Enter and custom triggers: no POST is sent; a valid form submits once. See [HTML form validation and view guidance](https://github.com/BetterCorp/BetterPortal/blob/master/docs/building/themes.md#preserve-html5-form-validation).
|
|
33
|
+
|
|
34
|
+
## View boundaries and defect reporting
|
|
35
|
+
|
|
36
|
+
Read the shared `/llms-ui.txt` rules before implementing a view.
|
|
37
|
+
|
|
38
|
+
- Render typed handler data. Keep business defaults, validation, calculations, persistence and report generation in handlers/domain helpers; HTML constraints are presentation hints.
|
|
39
|
+
- Initialization, history navigation, prefetched insertion and draft restoration must not submit forms or replay mutations. Keep recalculation and final submission explicit; do not retain one-shot action flags after failure or cancellation.
|
|
40
|
+
- The shell owns HTMX 4 and its bundled `bp-shell, sse` extensions. Do not inject extension assets, register extensions or add unsupported `hx-ext` values. Use supported form encoding and report schema/serialization gaps upstream.
|
|
41
|
+
- Prefer native controls, HTMX triggers, `hx-indicator` and HTMX 4 `hx-disable`. Necessary local scripts use typed `js(() => ...)`, component-scoped selectors, idempotent binding and cleanup on removal. Do not add global submit functions or repeated document-wide listeners. HTMX 2 camelCase lifecycle events are incompatible with the installed HTMX 4 runtime.
|
|
42
|
+
- Browser drafts require an explicit schema, allowed fields, tenant/app/service/user scope, version, expiry and clearing rules. Validate restoration, exclude action/auth fields, and never generate hidden inputs from arbitrary stored keys. Restore without submitting; browser owner metadata is not authorization.
|
|
43
|
+
- Use project issue/reporting tools for reproducible theme/framework defects. Include versions, minimal reproduction, expected/actual behavior and relevant request initiators or computed styles without credentials or customer data. Check existing reports; if access is unavailable, provide a ready-to-file report. Do not replace theme defaults with hardcoded palettes, `!important` patches, duplicate navigation or runtime workarounds.
|
|
44
|
+
- Service errors use handler-side `ctx.diagnostic({ code, reason, attributes? })` before responses outside HTTP 200-399; the view displays a safe error state. Diagnostics do not replace upstream defect reports.
|
|
45
|
+
- Verify failed POST then navigation, Back/Forward, preload, repeated swaps and stale drafts. Inspect request initiators and confirm navigation/restoration never mutates or leaves controls disabled.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"pluginId": "org.betterportal.theme.embedded",
|
|
5
5
|
"title": "Embedded Theme",
|
|
6
6
|
"description": "Minimal htmx theme for embedding BetterPortal content without iframes.",
|
|
7
|
-
"version": "10.6.
|
|
7
|
+
"version": "10.6.19",
|
|
8
8
|
"category": "theme",
|
|
9
9
|
"deploymentModes": [
|
|
10
10
|
"self-hosted"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"title": "Embedded UI guide",
|
|
34
34
|
"description": "Compact layout, HTMX and accessibility rules for embedded views.",
|
|
35
35
|
"mediaType": "text/markdown; charset=utf-8",
|
|
36
|
-
"content": "# Embedded theme UI guide\n\nThe Embedded theme renders BetterPortal service content inside a lightweight host without an iframe. Keep UI narrow, self-contained and dependent only on native HTML, HTMX and the theme's existing variables.\n\n## Rules\n\n- Return service content only; the theme owns the host document and main outlet.\n- Use semantic HTML, visible labels, keyboard-operable controls and responsive wrapping.\n- Prefer one column. Avoid persistent navigation, wide tables, fixed positioning and viewport-sized panels.\n- In renderers, use `ctx.url.route()` for service requests. Use `ctx.url.uiRoute()` only for GET page navigation. Pass a declared dependency alias as `serviceId` when resolving another app-mounted service. Handler equivalents are `ctx.routeUrl()` and `ctx.uiRouteUrl()`.\n- Plain internal `<a href=\"/route\">` links and GET/POST forms are automatically upgraded to HTMX and routed through the owning service. A bare `<form>` posts to the current service view. Use `bp-no-override` or `data-bp-no-override` on an element or ancestor only when native browser behavior is intentional.\n- Use normal forms and HTMX swaps. Provide loading, empty, validation and error states.\n- Use `hx-download` for authenticated files and `HX-Trigger` events for passive refresh.\n- Do not add a SPA framework, iframe, client router, state library or hardcoded service URL.\n\nThe Embedded theme deliberately offers fewer visual primitives than Bootstrap1. If a workflow needs a complex application shell, use Bootstrap1 instead of recreating a shell inside service content.\n"
|
|
36
|
+
"content": "# Embedded theme UI guide\n\nThe Embedded theme renders BetterPortal service content inside a lightweight host without an iframe. Keep UI narrow, self-contained and dependent only on native HTML, HTMX and the theme's existing variables.\n\n## Rules\n\n- Return service content only; the theme owns the host document and main outlet.\n- Use semantic HTML, visible labels, keyboard-operable controls and responsive wrapping.\n- Prefer one column. Avoid persistent navigation, wide tables, fixed positioning and viewport-sized panels.\n- In renderers, use `ctx.url.route()` for service requests. Use `ctx.url.uiRoute()` only for GET page navigation. Pass a declared dependency alias as `serviceId` when resolving another app-mounted service. Handler equivalents are `ctx.routeUrl()` and `ctx.uiRouteUrl()`.\n- Plain internal `<a href=\"/route\">` links and GET/POST forms are automatically upgraded to HTMX and routed through the owning service. A bare `<form>` posts to the current service view. Use `bp-no-override` or `data-bp-no-override` on an element or ancestor only when native browser behavior is intentional.\n- Use normal forms and HTMX swaps. Provide loading, empty, validation and error states.\n- Use `hx-download` for authenticated files and `HX-Trigger` events for passive refresh.\n- Do not add a SPA framework, iframe, client router, state library or hardcoded service URL.\n\nThe Embedded theme deliberately offers fewer visual primitives than Bootstrap1. If a workflow needs a complex application shell, use Bootstrap1 instead of recreating a shell inside service content.\n\n## Colors and appearance\n\nEmbedded is a minimal host with a transparent document background. It does not declare the Bootstrap1/2 palette configuration or their `--bp-*` token contract. A `bootstrap5` component example or a brand hex value from another theme is not a portable Embedded styling API.\n\nUse native controls and inherit available host typography/colors; keep necessary service-specific CSS local to the component. Do not load Bootstrap, add global branding, redefine document colors or install a separate appearance controller. If a richer palette/component contract is required, implement it in the owning theme or select a suitable theme, rather than reproducing its shell in a view.\n\nRead the [BetterPortal theme contract](https://github.com/BetterCorp/BetterPortal/blob/master/docs/building/themes.md), [routes/views](https://github.com/BetterCorp/BetterPortal/blob/master/docs/building/routes-and-views.md) and active `/llms-ui.txt`. Match documentation examples to installed package versions; master may describe newer APIs.\n\n## Form validation before requests\n\nThe backend input schema is the source of truth. Render its applicable HTML5 constraints (`type`, `required`, `min`, `max`, `step`, `minlength`, `maxlength`, `pattern`) and preserve them after swaps. The browser validates the returned HTML controls; it does not execute AnyVali/JSON schema automatically. Numeric inputs use range/step constraints, not `pattern`. Hidden inputs and controls barred from constraint validation are not checked by these APIs; validate computed payloads against the published input contract and always on the server.\n\nPrefer native submit buttons or `form.requestSubmit(submitter)`. For a necessary custom trigger, stop if `form.reportValidity()` is false; `form.checkValidity()` checks without showing validation messages. Never bypass invalid controls with `form.submit()`, synthetic submit events, custom fetch/HTMX posts, `noValidate`/`formNoValidate`, `novalidate`/`formnovalidate` or disabled HTMX validation. Recalculation that accepts fewer fields needs a separate non-nested form/component with its own constraints, not a bypass on the full form. The backend validates every submission, including rules HTML cannot express.\n\nCheck invalid submissions by button, Enter and custom triggers: no POST is sent; a valid form submits once. See [HTML form validation and view guidance](https://github.com/BetterCorp/BetterPortal/blob/master/docs/building/themes.md#preserve-html5-form-validation).\n\n## View boundaries and defect reporting\n\nRead the shared `/llms-ui.txt` rules before implementing a view.\n\n- Render typed handler data. Keep business defaults, validation, calculations, persistence and report generation in handlers/domain helpers; HTML constraints are presentation hints.\n- Initialization, history navigation, prefetched insertion and draft restoration must not submit forms or replay mutations. Keep recalculation and final submission explicit; do not retain one-shot action flags after failure or cancellation.\n- The shell owns HTMX 4 and its bundled `bp-shell, sse` extensions. Do not inject extension assets, register extensions or add unsupported `hx-ext` values. Use supported form encoding and report schema/serialization gaps upstream.\n- Prefer native controls, HTMX triggers, `hx-indicator` and HTMX 4 `hx-disable`. Necessary local scripts use typed `js(() => ...)`, component-scoped selectors, idempotent binding and cleanup on removal. Do not add global submit functions or repeated document-wide listeners. HTMX 2 camelCase lifecycle events are incompatible with the installed HTMX 4 runtime.\n- Browser drafts require an explicit schema, allowed fields, tenant/app/service/user scope, version, expiry and clearing rules. Validate restoration, exclude action/auth fields, and never generate hidden inputs from arbitrary stored keys. Restore without submitting; browser owner metadata is not authorization.\n- Use project issue/reporting tools for reproducible theme/framework defects. Include versions, minimal reproduction, expected/actual behavior and relevant request initiators or computed styles without credentials or customer data. Check existing reports; if access is unavailable, provide a ready-to-file report. Do not replace theme defaults with hardcoded palettes, `!important` patches, duplicate navigation or runtime workarounds.\n- Service errors use handler-side `ctx.diagnostic({ code, reason, attributes? })` before responses outside HTTP 200-399; the view displays a safe error state. Diagnostics do not replace upstream defect reports.\n- Verify failed POST then navigation, Back/Forward, preload, repeated swaps and stale drafts. Inspect request initiators and confirm navigation/restoration never mutates or leaves controls disabled.\n"
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"id": "embedded.skill",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"title": "Embedded UI skill",
|
|
42
42
|
"description": "Agent workflow for producing Embedded-compatible service UI.",
|
|
43
43
|
"mediaType": "text/markdown; charset=utf-8",
|
|
44
|
-
"content": "---\nname: betterportal-embedded-ui\ndescription: Build compact BetterPortal service UI for the Embedded theme.\n---\n\n# BetterPortal Embedded UI\n\n1. Read `/llms-api.txt` and the Embedded UI guide.\n2. Keep the view single-column and self-contained.\n3. Use semantic HTML and server-rendered HTMX fragments.\n4. In renderers, use `ctx.url.route()` for service calls and `ctx.url.uiRoute()` only for GET navigation. Pass a declared dependency alias as `serviceId` for another service.\n5. Include loading, empty, validation and failure states.\n6. Verify keyboard use, labels, responsive wrapping and the published schemas.\n\nDo not recreate Bootstrap components or a second app shell. Recommend Bootstrap1 when the requested interface genuinely needs those primitives.\n"
|
|
44
|
+
"content": "---\nname: betterportal-embedded-ui\ndescription: Build compact BetterPortal service UI for the Embedded theme.\n---\n\n# BetterPortal Embedded UI\n\n1. Read `/llms-api.txt`, `/llms-ui.txt` and the Embedded UI guide.\n2. Keep the view single-column and self-contained.\n3. Use semantic HTML and server-rendered HTMX fragments.\n4. In renderers, use `ctx.url.route()` for service calls and `ctx.url.uiRoute()` only for GET navigation. Pass a declared dependency alias as `serviceId` for another service.\n5. Include loading, empty, validation and failure states.\n6. Verify keyboard use, labels, responsive wrapping and the published schemas.\n\nDo not recreate Bootstrap components or a second app shell. Recommend Bootstrap1 when the requested interface genuinely needs those primitives.\n\nRead the UI guide's colors/appearance section and linked BetterPortal documentation; use the active theme's semantic roles and installed API version. Before delivery, follow its view boundaries and defect-reporting rules. Keep domain work in handlers, never submit during initialization or draft restoration, and never register HTMX extensions from service markup. Preserve schema-backed HTML5 constraints: use native submission or `requestSubmit()`, gate custom triggers with `reportValidity()`, and never disable validation to post an invalid form. Use project reporting tools for reproducible theme/framework defects. Verify failed POST followed by navigation, preload, history and repeated swaps without mutation replay or duplicate listeners.\n"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"id": "embedded.page-template",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"description": "Minimal server-rendered JSX page structure.",
|
|
51
51
|
"mediaType": "text/plain; charset=utf-8",
|
|
52
52
|
"language": "typescript",
|
|
53
|
-
"content": "/** @jsxImportSource jsx-htmx */\nimport type {
|
|
53
|
+
"content": "/** @jsxImportSource jsx-htmx */\nimport type { RegisteredViewRenderer } from \"@betterportal/framework\";\n\nexport const render: RegisteredViewRenderer[\"render\"] = (data) => (\n <section aria-labelledby=\"page-title\">\n <h1 id=\"page-title\">Page title</h1>\n <p>Explain the task in one sentence.</p>\n <div>{JSON.stringify(data)}</div>\n </section>\n);\n"
|
|
54
54
|
}
|
|
55
55
|
],
|
|
56
56
|
"shell": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@betterportal/theme-embedded",
|
|
3
|
-
"version": "10.6.
|
|
3
|
+
"version": "10.6.19",
|
|
4
4
|
"description": "BetterPortal v10 embedded theme plugin for Node.js",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"typescript": "^6.0.3"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@betterportal/framework": "10.6.
|
|
36
|
-
"@betterportal/plugin-bsb": "10.6.
|
|
37
|
-
"@betterportal/theme-runtime": "10.6.
|
|
35
|
+
"@betterportal/framework": "10.6.19",
|
|
36
|
+
"@betterportal/plugin-bsb": "10.6.19",
|
|
37
|
+
"@betterportal/theme-runtime": "10.6.19",
|
|
38
38
|
"@bsb/base": "^9.7.0",
|
|
39
39
|
"anyvali": "^1.1.5",
|
|
40
40
|
"jsx-htmx": "4.0.0"
|