@knkcs/contenthub-ui 0.0.0-stage → 0.1.0
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/CHANGELOG.md +30 -0
- package/LICENSE +30 -0
- package/README.md +25 -2
- package/dist/branch-content-fields-WBpviLQg.js +86 -0
- package/dist/branch-content-fields-WBpviLQg.js.map +1 -0
- package/dist/branch-form-kit-BIZbBl1B.js +11 -0
- package/dist/branch-form-kit-BIZbBl1B.js.map +1 -0
- package/dist/content-data-fields-CGJTea3s.js +19 -0
- package/dist/content-data-fields-CGJTea3s.js.map +1 -0
- package/dist/content-library-B2eauvHt.js +2494 -0
- package/dist/content-library-B2eauvHt.js.map +1 -0
- package/dist/heads-Brd2Gtjm.js +124 -0
- package/dist/heads-Brd2Gtjm.js.map +1 -0
- package/dist/index.d.ts +5729 -0
- package/dist/index.js +7180 -0
- package/dist/index.js.map +1 -0
- package/dist/testing.d.ts +1555 -0
- package/dist/testing.js +1801 -0
- package/dist/testing.js.map +1 -0
- package/package.json +100 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-10-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* **ui:** ContenthubPaths.blockReasons is gone; a host passes contenthubSettings, the path of contenthub's settings page.
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **api:** filter ListContents by blueprint_ids and page both ListReferrers ([#207](https://github.com/knkCS/contenthub/issues/207)) ([e2c869e](https://github.com/knkCS/contenthub/commit/e2c869e71ffe6e372ee688c71395f03d748e6b25))
|
|
13
|
+
* **attributes:** content assignees, Block and Archive ([#138](https://github.com/knkCS/contenthub/issues/138)) ([a711fa7](https://github.com/knkCS/contenthub/commit/a711fa7cc1e6f1ad136caf0f1c2c5238909ca1d2))
|
|
14
|
+
* **changesets:** rename a change set and edit its source after creation ([#212](https://github.com/knkCS/contenthub/issues/212)) ([2bc68b6](https://github.com/knkCS/contenthub/commit/2bc68b6c3cb97e8f58aaa50931defc4e03db634d)), closes [#126](https://github.com/knkCS/contenthub/issues/126)
|
|
15
|
+
* narrow who records a Required Check (recorder grants API and settings UI) ([#159](https://github.com/knkCS/contenthub/issues/159)) ([1399999](https://github.com/knkCS/contenthub/commit/139999916b0db2ab9e347819a5036adf1472834e)), closes [#157](https://github.com/knkCS/contenthub/issues/157)
|
|
16
|
+
* **publish:** let saves leave required fields empty and refuse them at publish ([#216](https://github.com/knkCS/contenthub/issues/216)) ([53e9045](https://github.com/knkCS/contenthub/commit/53e9045f47d5153582b3d4e0e45d759cf10f760b))
|
|
17
|
+
* **ui:** change set releases and checks tabs, rail actions and the publish review ([#143](https://github.com/knkCS/contenthub/issues/143)) ([5266ffe](https://github.com/knkCS/contenthub/commit/5266ffee9989a8f42d579a4e4e9ca8a31dbd4686))
|
|
18
|
+
* **ui:** change sets index and change set page with general and contents tabs ([#125](https://github.com/knkCS/contenthub/issues/125)) ([b5fb6d7](https://github.com/knkCS/contenthub/commit/b5fb6d7eb7d00b661cf4c7e2858640255c71d63e))
|
|
19
|
+
* **ui:** content library with the collection tree, filters and new content ([#128](https://github.com/knkCS/contenthub/issues/128)) ([be8b648](https://github.com/knkCS/contenthub/commit/be8b64841551603fa3477ab3cdf34001d56ed0f0))
|
|
20
|
+
* **ui:** content page with tabs, filing save and rail actions ([#144](https://github.com/knkCS/contenthub/issues/144)) ([2d20878](https://github.com/knkCS/contenthub/commit/2d20878ea2799fac2d567921e98379e2c94929c4))
|
|
21
|
+
* **ui:** contenthub-ui package and harness with the Block Reasons settings screen ([#99](https://github.com/knkCS/contenthub/issues/99)) ([9a49d6f](https://github.com/knkCS/contenthub/commit/9a49d6fefe82246479594d462f924ee79a81f263))
|
|
22
|
+
* **ui:** settings page for Required Checks, Block Reasons and Collections ([#156](https://github.com/knkCS/contenthub/issues/156)) ([48bd167](https://github.com/knkCS/contenthub/commit/48bd167f4f23710cd6e526d6ba372b0676d79cfd))
|
|
23
|
+
* **ui:** the branch editor with its content tab and one header save ([#165](https://github.com/knkCS/contenthub/issues/165)) ([871618e](https://github.com/knkCS/contenthub/commit/871618e10b0d465eb175e6598623095ef3aec023)), closes [#86](https://github.com/knkCS/contenthub/issues/86)
|
|
24
|
+
* **ui:** the branch editor's release, compare and references tabs, and its rail ([#167](https://github.com/knkCS/contenthub/issues/167)) ([2eb9654](https://github.com/knkCS/contenthub/commit/2eb9654c49b0f9f311c0e69fe596a59619aef87c))
|
|
25
|
+
* **ui:** typed restriction and withheld-work refusals, and a settings path ([#208](https://github.com/knkCS/contenthub/issues/208)) ([cf9e110](https://github.com/knkCS/contenthub/commit/cf9e110b2293ca6707fb707000ff47412925d4c7))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
* **publish:** report media_unavailable when mediahub refuses the token ([#214](https://github.com/knkCS/contenthub/issues/214)) ([3318cdb](https://github.com/knkCS/contenthub/commit/3318cdb20b33ed1c33d0168c9d06ad2f778763a9)), closes [#150](https://github.com/knkCS/contenthub/issues/150)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Copyright (c) 2026 knk Gruppe (https://knk.de/)
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
proprietary property of knk Gruppe and its subsidiaries.
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted to employees and contractors of knk Gruppe and
|
|
9
|
+
its subsidiary companies to use, copy, modify, and distribute the Software
|
|
10
|
+
solely for internal business purposes within the knk group of companies.
|
|
11
|
+
|
|
12
|
+
The following restrictions apply:
|
|
13
|
+
|
|
14
|
+
1. The Software may not be used, copied, modified, merged, published,
|
|
15
|
+
distributed, sublicensed, or sold by any person or entity outside of
|
|
16
|
+
the knk group of companies without prior written consent from knk Gruppe.
|
|
17
|
+
|
|
18
|
+
2. The Software may not be incorporated into products or services offered
|
|
19
|
+
to third parties outside of the knk group of companies.
|
|
20
|
+
|
|
21
|
+
3. This license notice shall be included in all copies or substantial
|
|
22
|
+
portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @knkcs/contenthub-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
contenthub's screens for knk hosts (contenthub ADR 0020, knkcms/core ADR 0003). Core mounts them under its own page frame; contenthub's harness (`web/` in this repo) mounts the same screens in anker's `AppShell`.
|
|
4
|
+
|
|
5
|
+
The package exports screens only, never routes:
|
|
6
|
+
|
|
7
|
+
- `ContenthubSettings`: the workspace's configuration on one settings page of three tabs, chosen by `?tab=` (`required-checks`, `block-reasons`, `collections`), so it needs a router. Required Checks are declared and edited in a Modal (name, scope, Blueprints by accessor or every one, independent); who records each is read from contenthub (every member, until narrowed) and narrowed from its row to named members from the host's members, adding oneself (break-glass) included, or opened to every member again; in `authz.mode: workspace` every member records every check, and the tab says so and offers no recorders editor. Block Reasons are listed, created, renamed and removed. Collections are the tree in order, created, renamed, moved and removed; restricted (making the admin its owner) and unrestricted, each confirmed, the unrestrict as an acknowledged disclosure; and a Restricted Collection's grants are managed from the host's members, granting oneself (break-glass) included. In `authz.mode: workspace` contenthub refuses restriction, and the tab then says it needs guardian mode.
|
|
8
|
+
- `BlockReasonsSettings`: the Block Reasons on a page of their own, for a host that mounts them apart from `ContenthubSettings`.
|
|
9
|
+
- `ContentLibrary`: the Collection tree in `SubNavLayout.Nav` beside the Content table, narrowing together with the toolbar's search, view (Main, In Force, a Change Set) and Blueprint filters; the selected Collection is the URL's `?collection=`, so it needs a router. Rows call `onOpenContent({ contentId, changeSetId? })`; New Content creates a Content in an open or new Change Set and calls `onOpenBranch`.
|
|
10
|
+
- `ContentPage`: one Content, read on Main or (`changeSetId`) inside the Change Set it was born in, in tabs Data (read-only, through fieldkit's read mode, loaded lazily), Releases, Revisions (with Compare), References, Change Sets and Filing. The header's one Save sets Filing (Collections, assignees) and never writes a Revision. Its rail offers Start editing, Duplicate, Repeal or Withdraw, Block or Unblock, and Archive (only once nothing is In Force today or later) or Unarchive; Start editing and Duplicate end in `onOpenBranch`, and `onOpenContent` and `onOpenChangeSet` open the rows of its References and Change Sets tabs. It needs `@knkcs/fieldkit` as a peer.
|
|
11
|
+
- `ChangeSetsIndex`: the workspace's Change Sets, narrowed by state and assignee, created in a Modal; `onOpenChangeSet(id)` opens one, a new one too.
|
|
12
|
+
- `ChangeSetPage`: one Change Set, its General tab (name and Source while it is open, status label, assignees, dependencies) saved from the header's one Save; its Contents tab, whose rows call `onOpenBranch({ changeSetId, contentId, branchId })`; its Releases tab (Planned Releases, proposals read-only, the Releases they cover) and its Checks tab (each Required Check's latest result, stale or not, and Record). Its rail holds Publish, Update from Main and Discard, and an About section with the readiness tile (`ValidatePublish` at the current heads), the status label and the Source; Publish opens a review that publishes exactly the heads it shows. `onPublished` and `onDiscarded` tell the host. Its leave guard needs a data router (react-router's `useBlocker`).
|
|
13
|
+
- `BranchEditor`: one Content inside a Change Set at one Branch (`changeSetId`, `contentId`, `branchId`), its header tabs chosen by `?tab=`. The Content tab renders the Blueprint Release's form through fieldkit's `SpecForm`, with knkeditor for rich text, both loaded lazily; reference fields search contenthub, media fields use the `MediaSource` port. The forms above the tabs are the drafts (fieldkit's "Consumer-owned Save across unmounting tabs"): the Content's, and the Release tab's Planned Release (Validity Period, supersedes, Release Spec values; the Change Set's proposals beside it, read-only). The header's one Save persists every changed tab: one `SaveRevision` on the head the editor loaded, with a field mask of what changed, then `PlanRelease` or `UpdatePlannedRelease`; a refused save sends no plan, and a refused plan leaves only the Release tab changed. A moved head is refused with Reload, never merged; the leave guard needs a data router. Compare shows the head against its fork or Main, References its outgoing edges and outdated pins. The rail offers Update from Main and the merge resolution it may leave, Compare to the fork, Preview, Append a Branch (`onOpenBranch` opens it) and Drop Chain (`onDeleted` leaves), and shows the fork Release, the effective date, the Chain position and the head. It needs `@knkcs/fieldkit` (0.18), `@knkcms/knkeditor-editor` and `@knkcms/knkeditor-vocabulary` (GitHub Packages) as peers.
|
|
14
|
+
- `MediaSource`, the port a host fills with mediahub, in fieldkit's media-adapter shape (ADR 0020). Without it a media field offers nothing to pick.
|
|
15
|
+
- `StatusSource`, the port a host fills with statushub for Change Set status labels (ADR 0020). Without it the screens show the bare slug and offer no status picker.
|
|
16
|
+
- `BlueprintSource`, the port a host fills with blueprinthub: content Blueprints and their Releases (ADR 0020). Without it the Library names Blueprints by id, has no Blueprint filter, and keeps New Content disabled, saying why.
|
|
17
|
+
- `ContenthubClient`, the port every screen takes, and `createConnectContenthubClient({ baseUrl, fetch })`, its Connect implementation. `baseUrl` is `""` when contenthub serves the page, the mount prefix (`/api/contenthub`) under core.
|
|
18
|
+
- `ContenthubPathsProvider` and `ContenthubPaths`: where the host mounts the screens, for the breadcrumbs and links they draw. `contenthubSettings` is the settings page, whose tabs are `?tab=`; `contenthubSettingsPath(paths, tab)` builds a link to one.
|
|
19
|
+
- `contenthubTranslations`, the `{ namespace, resources }` a host merges (en and de), with `CONTENTHUB_UI_NS` for its namespace list (core ADR 0005).
|
|
20
|
+
- `@knkcs/contenthub-ui/testing`: `createStubContenthubClient()`, an in-memory workspace that applies the service's rules (with `publishBlockers` for the blockers it can't derive, `authzMode`, `collectionGrants`, `memberIds` and `admin` for restriction and grants, and `withheld` for Change Sets holding work the caller can't see), its fixtures, `stubBlocker()`, `createStubStatusSource()` over statushub's seed catalogue, `createStubBlueprintSource()` over a few Blueprints and their Releases, and `stubIdentity()` for anker's `TestHost`.
|
|
21
|
+
|
|
22
|
+
Screens read who is looking through anker's host contract (`useHostIdentity`) and report their title, breadcrumbs and actions through it, so a host needs `HostProvider` (or `AppShell`), a TanStack `QueryClientProvider`, a router and i18next with the package's translations.
|
|
23
|
+
|
|
24
|
+
## Develop
|
|
25
|
+
|
|
26
|
+
From the repo root, after `npm ci`: `npm run typecheck:ui`, `npm run lint:ui`, `npm run test:ui`, `npm run build:ui`.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { r as e } from "./content-library-B2eauvHt.js";
|
|
2
|
+
import { useMemo as t } from "react";
|
|
3
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
4
|
+
import { FieldKitProvider as r, SpecForm as i } from "@knkcs/fieldkit/renderer";
|
|
5
|
+
import { knkRichTextPlugin as a } from "@knkcs/fieldkit/rich-text";
|
|
6
|
+
import { builtInFieldTypes as o } from "@knkcs/fieldkit/schema";
|
|
7
|
+
//#region src/screens/branch-adapters.ts
|
|
8
|
+
var s = 200;
|
|
9
|
+
function c(t, n, r) {
|
|
10
|
+
return {
|
|
11
|
+
id: t,
|
|
12
|
+
display_name: e(r) || t,
|
|
13
|
+
blueprint_id: n
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function l({ client: e, changeSetId: t, mediaSource: n }) {
|
|
17
|
+
return {
|
|
18
|
+
reference: {
|
|
19
|
+
async search({ query: t, blueprintIds: n, excludeIds: r, page: i, page_size: a }) {
|
|
20
|
+
let o = Math.min(s, Math.max(1, i) * Math.max(1, a)), l = await e.listContents({
|
|
21
|
+
search: t.trim() || void 0,
|
|
22
|
+
blueprintIds: n.length > 0 ? n : void 0,
|
|
23
|
+
pageSize: o
|
|
24
|
+
}), u = new Set(r ?? []), d = /* @__PURE__ */ new Set(), f = [];
|
|
25
|
+
for (let e of l.contents) d.has(e.id) || u.has(e.id) || (d.add(e.id), f.push(c(e.id, e.blueprintId, e.data)));
|
|
26
|
+
let p = (Math.max(1, i) - 1) * a, m = l.nextPageToken ? f.length + 1 : f.length;
|
|
27
|
+
return {
|
|
28
|
+
items: f.slice(p, p + a),
|
|
29
|
+
total: m
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
async fetch(n) {
|
|
33
|
+
return Promise.all(n.map(async (n) => {
|
|
34
|
+
let r = await e.getContent({ id: n }).catch(() => e.getContent({
|
|
35
|
+
id: n,
|
|
36
|
+
changeSetId: t
|
|
37
|
+
})).catch(() => void 0);
|
|
38
|
+
return r ? c(n, r.content.blueprintId, r.content.data) : {
|
|
39
|
+
id: n,
|
|
40
|
+
display_name: n
|
|
41
|
+
};
|
|
42
|
+
}));
|
|
43
|
+
},
|
|
44
|
+
async listPinTargets(t) {
|
|
45
|
+
return [...(await e.getTimeline(t)).entries].reverse().map((e) => ({
|
|
46
|
+
id: e.releaseId,
|
|
47
|
+
label: `#${e.ordinal}`,
|
|
48
|
+
description: e.validityPeriod ? `${e.validityPeriod.firstDay} – ${e.validityPeriod.lastDay || "…"}` : e.publishTime.slice(0, 10)
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
media: n ? {
|
|
53
|
+
upload: (e) => n.upload(e),
|
|
54
|
+
browse: (e) => n.browse(e)
|
|
55
|
+
} : void 0
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/screens/branch-content-fields.tsx
|
|
60
|
+
var u = o.map((e) => e.id === "rich_text" ? a : e);
|
|
61
|
+
function d({ client: e, changeSetId: a, branchId: o, fields: s, parts: c, labels: d, readOnly: f, mediaSource: p }) {
|
|
62
|
+
let m = t(() => l({
|
|
63
|
+
client: e,
|
|
64
|
+
changeSetId: a,
|
|
65
|
+
mediaSource: p
|
|
66
|
+
}), [
|
|
67
|
+
e,
|
|
68
|
+
a,
|
|
69
|
+
p
|
|
70
|
+
]);
|
|
71
|
+
return /* @__PURE__ */ n(r, {
|
|
72
|
+
plugins: u,
|
|
73
|
+
adapters: m,
|
|
74
|
+
parts: c,
|
|
75
|
+
children: /* @__PURE__ */ n(i, {
|
|
76
|
+
schema: s,
|
|
77
|
+
labels: d,
|
|
78
|
+
readOnly: f,
|
|
79
|
+
recordKey: o
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { d as default };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=branch-content-fields-WBpviLQg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-content-fields-WBpviLQg.js","names":["contentLabel","MAX_PAGE","itemOf","data","id","blueprintId","branchAdapters","wanted","page","page_size","list","client","query","blueprintIds","excluded","excludeIds","seen","items","c","start","total","ids","detail","contentId","mediaSource","file","filter","plugins","builtInFieldTypes","p","knkRichTextPlugin","BranchContentFields","adapters","useMemo","changeSetId","FieldKitProvider","SpecForm","fields","branchId"],"sources":["../src/screens/branch-adapters.ts","../src/screens/branch-content-fields.tsx"],"sourcesContent":["// fieldkit's adapters for the Branch editor (ADR 0020): references from\n// contenthub's own reads, media through the host's MediaSource port. Types\n// only from fieldkit, so this module adds nothing to the root bundle.\nimport type { FieldKitAdapters, PinTarget, ReferenceItem } from \"@knkcs/fieldkit/renderer\";\nimport type { ContenthubClient } from \"../client/contenthub-client\";\nimport type { MediaSource } from \"../types\";\nimport { contentLabel } from \"./content-library\";\n\n/** The most rows one search asks for: ListContents' own cap. */\nconst MAX_PAGE = 200;\n\n/** What a picker shows for a Content: its label, or its id when its data has none. */\nfunction itemOf(id: string, blueprintId: string, data: Record<string, unknown>): ReferenceItem {\n\treturn { id, display_name: contentLabel(data) || id, blueprint_id: blueprintId };\n}\n\n/**\n * The adapters a Branch's form gets: `reference` searches contenthub's\n * Editor Search on Main (which reads open Branch heads too, so Content born\n * in an open Change Set is found), names a referenced Content from its read\n * and offers its Releases to pin; `media` is the host's MediaSource, absent\n * when the host has none, which leaves a media field nothing to pick.\n */\nexport function branchAdapters({\n\tclient,\n\tchangeSetId,\n\tmediaSource,\n}: {\n\tclient: ContenthubClient;\n\tchangeSetId: string;\n\tmediaSource?: MediaSource;\n}): FieldKitAdapters {\n\treturn {\n\t\treference: {\n\t\t\tasync search({ query, blueprintIds, excludeIds, page, page_size }) {\n\t\t\t\tconst wanted = Math.min(MAX_PAGE, Math.max(1, page) * Math.max(1, page_size));\n\t\t\t\t// Every target Blueprint at once: the service narrows the page, so\n\t\t\t\t// it holds only what the Field may point at, and paging stays exact.\n\t\t\t\tconst list = await client.listContents({\n\t\t\t\t\tsearch: query.trim() || undefined,\n\t\t\t\t\tblueprintIds: blueprintIds.length > 0 ? blueprintIds : undefined,\n\t\t\t\t\tpageSize: wanted,\n\t\t\t\t});\n\t\t\t\tconst excluded = new Set(excludeIds ?? []);\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst items: ReferenceItem[] = [];\n\t\t\t\t// A search lists a Content once per head that matched: one row each.\n\t\t\t\tfor (const c of list.contents) {\n\t\t\t\t\tif (seen.has(c.id) || excluded.has(c.id)) continue;\n\t\t\t\t\tseen.add(c.id);\n\t\t\t\t\titems.push(itemOf(c.id, c.blueprintId, c.data));\n\t\t\t\t}\n\t\t\t\tconst start = (Math.max(1, page) - 1) * page_size;\n\t\t\t\t// The total is exact on the last page; otherwise there is at least one more.\n\t\t\t\tconst total = list.nextPageToken ? items.length + 1 : items.length;\n\t\t\t\treturn { items: items.slice(start, start + page_size), total };\n\t\t\t},\n\t\t\tasync fetch(ids) {\n\t\t\t\treturn Promise.all(\n\t\t\t\t\tids.map(async (id) => {\n\t\t\t\t\t\t// Published Content reads on Main; Content born in this\n\t\t\t\t\t\t// Change Set exists only there.\n\t\t\t\t\t\tconst detail = await client\n\t\t\t\t\t\t\t.getContent({ id })\n\t\t\t\t\t\t\t.catch(() => client.getContent({ id, changeSetId }))\n\t\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\t\treturn detail\n\t\t\t\t\t\t\t? itemOf(id, detail.content.blueprintId, detail.content.data)\n\t\t\t\t\t\t\t: { id, display_name: id };\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t},\n\t\t\t// A Pin names a Release (the one pinning kind fieldkit has), newest first.\n\t\t\tasync listPinTargets(contentId) {\n\t\t\t\tconst timeline = await client.getTimeline(contentId);\n\t\t\t\treturn [...timeline.entries].reverse().map(\n\t\t\t\t\t(e): PinTarget => ({\n\t\t\t\t\t\tid: e.releaseId,\n\t\t\t\t\t\tlabel: `#${e.ordinal}`,\n\t\t\t\t\t\tdescription: e.validityPeriod\n\t\t\t\t\t\t\t? `${e.validityPeriod.firstDay} – ${e.validityPeriod.lastDay || \"…\"}`\n\t\t\t\t\t\t\t: e.publishTime.slice(0, 10),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t},\n\t\t},\n\t\tmedia: mediaSource\n\t\t\t? {\n\t\t\t\t\tupload: (file) => mediaSource.upload(file),\n\t\t\t\t\tbrowse: (filter) => mediaSource.browse(filter),\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n}\n","// fieldkit's renderer with knkeditor for rich text, behind a lazily loaded\n// module: both load the first time a Branch's Content tab is shown, never\n// with the rest of the package (spec #56; branch-editor-bundle.test.ts).\nimport { FieldKitProvider, SpecForm, type SpecFormLabels } from \"@knkcs/fieldkit/renderer\";\nimport { knkRichTextPlugin } from \"@knkcs/fieldkit/rich-text\";\nimport { builtInFieldTypes, type FieldTypePlugin, type Schema } from \"@knkcs/fieldkit/schema\";\nimport { useMemo } from \"react\";\nimport type { ContenthubClient } from \"../client/contenthub-client\";\nimport type { MediaSource, ResolvedField } from \"../types\";\nimport { branchAdapters } from \"./branch-adapters\";\n\n// rich_text through knkeditor (fieldkit ADR-0026); every other type as built in.\nconst plugins: FieldTypePlugin[] = builtInFieldTypes.map((p) =>\n\tp.id === \"rich_text\" ? (knkRichTextPlugin as FieldTypePlugin) : p,\n);\n\nexport interface BranchContentFieldsProps {\n\tclient: ContenthubClient;\n\tchangeSetId: string;\n\t/** The record the form holds, so SpecForm's remembered section is this Branch's. */\n\tbranchId: string;\n\tfields: ResolvedField[];\n\t/** The Resolved Release's parts: the Text Types its rich_text fields pin. */\n\tparts: Record<string, Record<string, unknown>>;\n\tlabels: SpecFormLabels;\n\treadOnly: boolean;\n\tmediaSource?: MediaSource;\n}\n\n/**\n * The Branch's data as the Blueprint Release lays it out, editable: its\n * sections, orientation and cards as fieldkit draws them, over the form the\n * editor holds above its tabs (fieldkit's spec-form.mdx, \"A Consumer-owned\n * Save across unmounting tabs\"). SpecForm keeps no draft of its own.\n */\nexport default function BranchContentFields({\n\tclient,\n\tchangeSetId,\n\tbranchId,\n\tfields,\n\tparts,\n\tlabels,\n\treadOnly,\n\tmediaSource,\n}: BranchContentFieldsProps) {\n\tconst adapters = useMemo(\n\t\t() => branchAdapters({ client, changeSetId, mediaSource }),\n\t\t[client, changeSetId, mediaSource],\n\t);\n\treturn (\n\t\t<FieldKitProvider plugins={plugins} adapters={adapters} parts={parts}>\n\t\t\t<SpecForm\n\t\t\t\tschema={fields as unknown as Schema}\n\t\t\t\tlabels={labels}\n\t\t\t\treadOnly={readOnly}\n\t\t\t\trecordKey={branchId}\n\t\t\t/>\n\t\t</FieldKitProvider>\n\t);\n}\n"],"mappings":";;;;;;;AASA,IAAMC,IAAW;AAGjB,SAASC,EAAO,GAAY,GAAqB,GAA8C;CAC9F,OAAO;EAAE;EAAI,cAAcF,EAAaG,CAAI,KAAKC;EAAI,cAAcC;CAAY;AAChF;AASA,SAAgBC,EAAe,EAC9B,WACA,gBACA,kBAKoB;CACpB,OAAO;EACN,WAAW;GACV,MAAM,OAAO,EAAE,UAAO,iBAAc,eAAY,SAAM,gBAAa;IAClE,IAAMC,IAAS,KAAK,IAAIN,GAAU,KAAK,IAAI,GAAGO,CAAI,IAAI,KAAK,IAAI,GAAGC,CAAS,CAAC,GAGtEC,IAAO,MAAMC,EAAO,aAAa;KACtC,QAAQC,EAAM,KAAK,KAAK,KAAA;KACxB,cAAcC,EAAa,SAAS,IAAIA,IAAe,KAAA;KACvD,UAAUN;IACX,CAAC,GACKO,IAAW,IAAI,IAAIC,KAAc,CAAC,CAAC,GACnCC,oBAAO,IAAI,IAAY,GACvBC,IAAyB,CAAC;IAEhC,KAAK,IAAMC,KAAKR,EAAK,UACpB,AAAIM,EAAK,IAAIE,EAAE,EAAE,KAAKJ,EAAS,IAAII,EAAE,EAAE,MACvCF,EAAK,IAAIE,EAAE,EAAE,GACbD,EAAM,KAAKf,EAAOgB,EAAE,IAAIA,EAAE,aAAaA,EAAE,IAAI,CAAC;IAE/C,IAAMC,KAAS,KAAK,IAAI,GAAGX,CAAI,IAAI,KAAKC,GAElCW,IAAQV,EAAK,gBAAgBO,EAAM,SAAS,IAAIA,EAAM;IAC5D,OAAO;KAAE,OAAOA,EAAM,MAAME,GAAOA,IAAQV,CAAS;KAAG;IAAM;GAC9D;GACA,MAAM,MAAM,GAAK;IAChB,OAAO,QAAQ,IACdY,EAAI,IAAI,OAAO,MAAO;KAGrB,IAAMC,IAAS,MAAMX,EACnB,WAAW,EAAE,MAAG,CAAC,CAAC,CAClB,YAAYA,EAAO,WAAW;MAAE;MAAI;KAAY,CAAC,CAAC,CAAC,CACnD,YAAY,KAAA,CAAS;KACvB,OAAOW,IACJpB,EAAOE,GAAIkB,EAAO,QAAQ,aAAaA,EAAO,QAAQ,IAAI,IAC1D;MAAE;MAAI,cAAclB;KAAG;IAC3B,CAAC,CACF;GACD;GAEA,MAAM,eAAe,GAAW;IAE/B,OAAO,CAAC,IAAG,MADYO,EAAO,YAAYY,CAAS,EAAA,CAC/B,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,KACrC,OAAkB;KAClB,IAAI,EAAE;KACN,OAAO,IAAI,EAAE;KACb,aAAa,EAAE,iBACZ,GAAG,EAAE,eAAe,SAAS,KAAK,EAAE,eAAe,WAAW,QAC9D,EAAE,YAAY,MAAM,GAAG,EAAE;IAC7B,EACD;GACD;EACD;EACA,OAAOC,IACJ;GACA,SAAS,MAASA,EAAY,OAAOC,CAAI;GACzC,SAAS,MAAWD,EAAY,OAAOE,CAAM;EAC9C,IACC,KAAA;CACJ;AACD;;;ACjFA,IAAMC,IAA6BC,EAAkB,KAAK,MACzDC,EAAE,OAAO,cAAeC,IAAwCD,CACjE;AAqBA,SAAwBE,EAAoB,EAC3C,WACA,gBACA,aACA,WACA,UACA,WACA,aACA,kBAC4B;CAC5B,IAAMC,IAAWC,QACV3B,EAAe;EAAE;EAAQ;EAAa;CAAY,CAAC,GACzD;EAACK;EAAQuB;EAAaV;CAAW,CAClC;CACA,OACC,kBAACW,GAAD;EAA2B;EAAmB;EAAiB;EAC9D,UAAA,kBAACC,GAAD;GACC,QAAQC;GACA;GACE;GACV,WAAWC;EACX,CAAA;CACgB,CAAA;AAEpB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { zodResolver as e } from "@hookform/resolvers/zod";
|
|
2
|
+
import { builtInFieldTypes as t, formDefaults as n, specToZodSchema as r } from "@knkcs/fieldkit/schema";
|
|
3
|
+
//#region src/screens/branch-form-kit.ts
|
|
4
|
+
var i = t, a = {
|
|
5
|
+
defaults: (e, t) => n(e, t, i),
|
|
6
|
+
resolver: (t) => e(r(t, i))
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { a as branchFormKit };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=branch-form-kit-BIZbBl1B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-form-kit-BIZbBl1B.js","names":["plugins","builtInFieldTypes","branchFormKit","formDefaults","fields","stored","zodResolver","specToZodSchema"],"sources":["../src/screens/branch-form-kit.ts"],"sourcesContent":["// fieldkit's schema layer for the Branch editor's form, behind a lazily\n// loaded module: `@knkcs/fieldkit/schema` carries every field type's\n// components, so importing it statically would put the renderer in the root\n// bundle. The editor loads it once, the first time a Branch opens.\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n\tbuiltInFieldTypes,\n\tformDefaults,\n\ttype Schema,\n\tspecToZodSchema,\n} from \"@knkcs/fieldkit/schema\";\nimport type { FieldValues, Resolver } from \"react-hook-form\";\nimport type { ResolvedField } from \"../types\";\n\nexport interface BranchFormKit {\n\t/** The form's seed for stored data: fieldkit's `formDefaults`, row ids minted. */\n\tdefaults(fields: ResolvedField[], stored: Record<string, unknown>): Record<string, unknown>;\n\t/** The form's validation, which is contenthub's to own (fieldkit's spec-form.mdx). */\n\tresolver(fields: ResolvedField[]): Resolver<FieldValues>;\n}\n\n// The built-in types: knkeditor's rich_text plugin differs only in its\n// components, so seeding and validation read the same either way, and this\n// module stays free of knkeditor.\nconst plugins = builtInFieldTypes;\n\nexport const branchFormKit: BranchFormKit = {\n\tdefaults: (fields, stored) => formDefaults(fields as unknown as Schema, stored, plugins),\n\tresolver: (fields) =>\n\t\tzodResolver(specToZodSchema(fields as unknown as Schema, plugins)) as Resolver<FieldValues>,\n};\n"],"mappings":";;;AAwBA,IAAMA,IAAUC,GAEHC,IAA+B;CAC3C,WAAW,GAAQ,MAAWC,EAAaC,GAA6BC,GAAQL,CAAO;CACvF,WAAW,MACVM,EAAYC,EAAgBH,GAA6BJ,CAAO,CAAC;AACnE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { FieldKitProvider as t, SpecForm as n } from "@knkcs/fieldkit/renderer";
|
|
3
|
+
import { builtInFieldTypes as r } from "@knkcs/fieldkit/schema";
|
|
4
|
+
//#region src/screens/content-data-fields.tsx
|
|
5
|
+
function i({ fields: i, data: a, labels: o }) {
|
|
6
|
+
return /* @__PURE__ */ e(t, {
|
|
7
|
+
plugins: r,
|
|
8
|
+
children: /* @__PURE__ */ e(n, {
|
|
9
|
+
schema: i,
|
|
10
|
+
mode: "read",
|
|
11
|
+
values: a,
|
|
12
|
+
labels: o
|
|
13
|
+
})
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { i as default };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=content-data-fields-CGJTea3s.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-data-fields-CGJTea3s.js","names":["ContentDataFields","FieldKitProvider","builtInFieldTypes","SpecForm","fields","data"],"sources":["../src/screens/content-data-fields.tsx"],"sourcesContent":["// fieldkit's renderer, in read mode, behind a lazily loaded module: the\n// renderer and its field plugins load only when a Data tab is first shown,\n// never with the rest of the package (spec #56: the fieldkit renderer behind\n// a lazily loaded entry).\nimport { FieldKitProvider, SpecForm, type SpecFormLabels } from \"@knkcs/fieldkit/renderer\";\nimport { builtInFieldTypes, type Schema } from \"@knkcs/fieldkit/schema\";\nimport type { ResolvedField } from \"../types\";\n\nexport interface ContentDataFieldsProps {\n\tfields: ResolvedField[];\n\tdata: Record<string, unknown>;\n\tlabels: SpecFormLabels;\n}\n\n/**\n * The Revision's data as the Blueprint Release lays it out, read-only.\n * fieldkit's read mode takes the values as they are and needs no form, so\n * it waits on nothing of the controlled renderer the Branch editor needs\n * (fieldkit#329).\n */\nexport default function ContentDataFields({ fields, data, labels }: ContentDataFieldsProps) {\n\treturn (\n\t\t<FieldKitProvider plugins={builtInFieldTypes}>\n\t\t\t<SpecForm schema={fields as unknown as Schema} mode=\"read\" values={data} labels={labels} />\n\t\t</FieldKitProvider>\n\t);\n}\n"],"mappings":";;;;AAoBA,SAAwBA,EAAkB,EAAE,WAAQ,SAAM,aAAkC;CAC3F,OACC,kBAACC,GAAD;EAAkB,SAASC;EAC1B,UAAA,kBAACC,GAAD;GAAU,QAAQC;GAA6B,MAAK;GAAO,QAAQC;GAAc;EAAS,CAAA;CACzE,CAAA;AAEpB"}
|