@phis/ui 0.4.1 → 0.4.3
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/components/cms/phi-cms-layout-renderer.js +4 -3
- package/components/cms/phi-cms-page-render-scope.d.ts +4 -5
- package/components/cms/phi-cms-page-render-scope.js +43 -22
- package/components/cms/phi-cms-render-diagnostic-client.js +7 -3
- package/components/cms/phi-cms-render-error-boundary.js +2 -1
- package/components/controls/phi-bullet-list-control.js +31 -2
- package/components/controls/phi-ribbon-control.d.ts +29 -0
- package/components/controls/phi-ribbon-control.js +53 -0
- package/components/controls/phi-table-control.d.ts +3 -0
- package/components/controls/phi-table-control.js +13 -1
- package/components/controls/phi-tree-control.js +3 -3
- package/components/forms/shared-form-provider-registry.js +1 -4
- package/components/media/asset-collection-runtime.js +6 -16
- package/components/media/media-font-metrics.d.ts +3 -0
- package/components/media/media-font-metrics.js +43 -0
- package/components/media/phi-area-upload-widget.js +53 -97
- package/components/media/phi-image-preview-data.d.ts +13 -0
- package/components/media/phi-image-preview-data.js +184 -9
- package/components/media/phi-media-picker-binding.js +16 -13
- package/components/media/phi-media-upload.d.ts +15 -8
- package/components/media/phi-media-upload.js +18 -9
- package/components/media/phi-site-font-assets.js +7 -8
- package/components/overlays/phi-overlay-container-client.js +16 -1
- package/components/regions/presets/phi-settings-page-shell-tree.js +48 -1
- package/components/runtime/runtime-controller-materialization.js +12 -1
- package/components/state/scoped-state-store.js +20 -3
- package/components/tables/client/phi-table-binding.d.ts +2 -1
- package/components/tables/client/phi-table-binding.js +45 -21
- package/components/trees/client/phi-tree-binding.js +19 -11
- package/components/widgets/client/bullet-list-entries-editor.d.ts +26 -0
- package/components/widgets/client/bullet-list-entries-editor.js +103 -0
- package/components/widgets/config/choice-shared.js +12 -13
- package/components/widgets/config/command-buttons.d.ts +5 -1
- package/components/widgets/config/command-buttons.js +38 -81
- package/components/widgets/config/control-signal-config.d.ts +3 -1
- package/components/widgets/config/control-signal-config.js +19 -17
- package/components/widgets/config/image-source-parser.d.ts +1 -0
- package/components/widgets/config/image-source-parser.js +7 -8
- package/components/widgets/config/mask.d.ts +6 -1
- package/components/widgets/config/mask.js +24 -1
- package/components/widgets/config/parser-primitives.js +72 -0
- package/components/widgets/config/stack-tabs.d.ts +1 -1
- package/components/widgets/config/stack-tabs.js +2 -3
- package/components/widgets/config/strict-config-reader.d.ts +40 -0
- package/components/widgets/config/strict-config-reader.js +174 -0
- package/components/widgets/label-sets/effects.js +2 -0
- package/components/widgets/label-types/effects.d.ts +1 -0
- package/components/widgets/label-types/effects.js +1 -0
- package/components/widgets/navigation-descriptor-resolver.server.js +20 -8
- package/components/widgets/shared/bullet-list-vocabulary.d.ts +17 -1
- package/components/widgets/shared/bullet-list-vocabulary.js +19 -2
- package/components/widgets/shared/card-body-client.d.ts +16 -4
- package/components/widgets/shared/card-body-client.js +81 -24
- package/components/widgets/shared/card-vocabulary.d.ts +21 -4
- package/components/widgets/shared/card-vocabulary.js +28 -2
- package/components/widgets/shared/markdown-body-client.d.ts +2 -1
- package/components/widgets/shared/markdown-body-client.js +3 -1
- package/components/widgets/shared/markdown-render.js +8 -1
- package/components/widgets/signals/control-signal-capabilities.d.ts +0 -18
- package/components/widgets/signals/control-signal-capabilities.js +10 -22
- package/components/workspace/catalog-store.d.ts +4 -3
- package/components/workspace/catalog-store.js +6 -5
- package/gateway/dashboard-cards-route.js +1 -0
- package/gateway/internal-references.d.ts +6 -1
- package/gateway/internal-references.js +48 -23
- package/gateway/site-cms-write-validation.d.ts +9 -0
- package/gateway/site-cms-write-validation.js +78 -0
- package/gateway/site-proxy.js +19 -3
- package/helpers/renderable-block-serialization.js +1 -1
- package/next/config.d.mts +3 -0
- package/next/config.mjs +28 -1
- package/package.json +2 -2
- package/plugins/runtime/phi-slot-child-viewport-effects-observer.js +5 -1
- package/plugins/runtime-modules/accounting/presets.d.ts +9 -0
- package/plugins/runtime-modules/accounting/presets.js +37 -0
- package/plugins/runtime-modules/accounting/server.d.ts +1 -4
- package/plugins/runtime-modules/accounting/server.js +4 -7
- package/plugins/runtime-modules/app/presets.d.ts +18 -0
- package/plugins/runtime-modules/app/presets.js +67 -0
- package/plugins/runtime-modules/app/server.d.ts +1 -4
- package/plugins/runtime-modules/app/server.js +4 -7
- package/plugins/runtime-modules/asset/controller/runtime.js +2 -2
- package/plugins/runtime-modules/asset/services/collection.js +9 -1
- package/plugins/runtime-modules/asset/services/options.js +2 -2
- package/plugins/runtime-modules/builder/area-settings-answer.js +2 -1
- package/plugins/runtime-modules/builder/authoring-canvas.js +6 -6
- package/plugins/runtime-modules/builder/cards.js +3 -5
- package/plugins/runtime-modules/builder/clients/builder-region-overrides.js +3 -3
- package/plugins/runtime-modules/builder/clients/canvas-widget.js +15 -54
- package/plugins/runtime-modules/builder/clients/inspector-config-field.d.ts +4 -1
- package/plugins/runtime-modules/builder/clients/inspector-config-field.js +5 -34
- package/plugins/runtime-modules/builder/clients/inspector-link-target-field.js +1 -1
- package/plugins/runtime-modules/builder/clients/inspector-section-widget.js +8 -8
- package/plugins/runtime-modules/builder/clients/inspector-title.js +6 -6
- package/plugins/runtime-modules/builder/clients/layout-inspector.d.ts +1 -1
- package/plugins/runtime-modules/builder/clients/layout-inspector.js +11 -25
- package/plugins/runtime-modules/builder/clients/mode-switch.js +1 -1
- package/plugins/runtime-modules/builder/clients/pages-header.js +11 -11
- package/plugins/runtime-modules/builder/clients/pages-workspace.js +1 -1
- package/plugins/runtime-modules/builder/clients/region-visibility-fields.js +1 -1
- package/plugins/runtime-modules/builder/clients/runtime-module-authoring-boundary.js +1 -1
- package/plugins/runtime-modules/builder/clients/shells-workspace.js +15 -31
- package/plugins/runtime-modules/builder/clients/structure-canvas.js +1 -1
- package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.d.ts +26 -0
- package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.js +36 -0
- package/plugins/runtime-modules/builder/clients/widget-effects-editor.js +1 -1
- package/plugins/runtime-modules/builder/clients/widget-inspector.js +1 -0
- package/plugins/runtime-modules/builder/clients/workspace-scope-boundary.js +2 -2
- package/plugins/runtime-modules/builder/cms-instance-allocator.js +8 -28
- package/plugins/runtime-modules/builder/controller/client.d.ts +0 -15
- package/plugins/runtime-modules/builder/controller/definition.d.ts +0 -15
- package/plugins/runtime-modules/builder/controller/definition.js +0 -8
- package/plugins/runtime-modules/builder/controller/draft-command-controller.d.ts +1 -2
- package/plugins/runtime-modules/builder/controller/draft-command-controller.js +11 -30
- package/plugins/runtime-modules/builder/controller/draft-status-controller.js +15 -2
- package/plugins/runtime-modules/builder/controller/inspector-controller.d.ts +1 -2
- package/plugins/runtime-modules/builder/controller/inspector-controller.js +4 -7
- package/plugins/runtime-modules/builder/controller/page-controller.d.ts +1 -2
- package/plugins/runtime-modules/builder/controller/page-controller.js +16 -68
- package/plugins/runtime-modules/builder/controller/server-definition.d.ts +0 -15
- package/plugins/runtime-modules/builder/controller/signal-wiring-controller.d.ts +2 -5
- package/plugins/runtime-modules/builder/controller/signal-wiring-controller.js +6 -50
- package/plugins/runtime-modules/builder/controller/workspace-controller.d.ts +2 -3
- package/plugins/runtime-modules/builder/controller/workspace-controller.js +89 -153
- package/plugins/runtime-modules/builder/data-providers.d.ts +1 -0
- package/plugins/runtime-modules/builder/data-providers.js +1 -0
- package/plugins/runtime-modules/builder/definition.d.ts +1 -0
- package/plugins/runtime-modules/builder/developer-workspace-store.d.ts +64 -30
- package/plugins/runtime-modules/builder/developer-workspace-store.js +255 -61
- package/plugins/runtime-modules/builder/edit-scaffold-drawer.js +1 -1
- package/plugins/runtime-modules/builder/history.d.ts +3 -1
- package/plugins/runtime-modules/builder/options-providers.js +3 -2
- package/plugins/runtime-modules/builder/page-catalog-client.js +19 -7
- package/plugins/runtime-modules/builder/page-meta-form.js +1 -0
- package/plugins/runtime-modules/builder/page-references-provider.js +1 -1
- package/plugins/runtime-modules/builder/persistence.js +33 -69
- package/plugins/runtime-modules/builder/public-route-collisions.d.ts +2 -2
- package/plugins/runtime-modules/builder/public-route-collisions.js +6 -19
- package/plugins/runtime-modules/builder/render-root-node-preview.server.js +20 -3
- package/plugins/runtime-modules/builder/render-root-node-scaffold.js +3 -3
- package/plugins/runtime-modules/builder/runtime-module-selection.d.ts +2 -12
- package/plugins/runtime-modules/builder/runtime-module-selection.js +16 -42
- package/plugins/runtime-modules/builder/services/navigation-table.js +9 -15
- package/plugins/runtime-modules/builder/services/page-source-tree.js +8 -8
- package/plugins/runtime-modules/builder/services/runtime-modules-table.js +10 -10
- package/plugins/runtime-modules/builder/services/signal-routes-table.js +3 -3
- package/plugins/runtime-modules/builder/signal-route-selection.d.ts +1 -2
- package/plugins/runtime-modules/builder/signal-route-selection.js +2 -2
- package/plugins/runtime-modules/builder/signal-wiring-options.js +3 -2
- package/plugins/runtime-modules/builder/structure-dnd.js +8 -61
- package/plugins/runtime-modules/builder/trees/phi-default-builder-area-preset-tree.js +13 -10
- package/plugins/runtime-modules/builder/widgets/structure-region/built-in.js +12 -18
- package/plugins/runtime-modules/builder/workspace-catalog-actions.d.ts +55 -0
- package/plugins/runtime-modules/builder/workspace-catalog-actions.js +142 -0
- package/plugins/runtime-modules/client-manifests/common.js +1 -1
- package/plugins/runtime-modules/{runtime-calendar-adapters.js → core/calendar-adapters.js} +2 -2
- package/plugins/runtime-modules/{client-calendar-adapters/core.js → core/client-calendar-adapters.js} +1 -1
- package/plugins/runtime-modules/core/content-entries/table.js +1 -1
- package/plugins/runtime-modules/core/data-providers.d.ts +3 -0
- package/plugins/runtime-modules/core/data-providers.js +2 -1
- package/plugins/runtime-modules/core/definition.d.ts +3 -0
- package/plugins/runtime-modules/core/definition.js +1 -1
- package/plugins/runtime-modules/core/messaging/data-providers.d.ts +1 -0
- package/plugins/runtime-modules/core/messaging/data-providers.js +1 -0
- package/plugins/runtime-modules/core/messaging/thread-inbox-table.js +1 -1
- package/plugins/runtime-modules/core/server.js +1 -1
- package/plugins/runtime-modules/core/themes.d.ts +44 -0
- package/plugins/runtime-modules/core/themes.js +12 -0
- package/plugins/runtime-modules/core/widgets/card/collection-view-binding.js +25 -9
- package/plugins/runtime-modules/core/widgets/card/config.d.ts +296 -254
- package/plugins/runtime-modules/core/widgets/card/config.js +52 -3
- package/plugins/runtime-modules/core/widgets/card/editor.js +30 -3
- package/plugins/runtime-modules/core/widgets/card/server.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/card/server.js +31 -3
- package/plugins/runtime-modules/core/widgets/collection-view/asset-binding.js +7 -6
- package/plugins/runtime-modules/core/widgets/collection-view/config.js +9 -2
- package/plugins/runtime-modules/core/widgets/description/config.d.ts +1 -25
- package/plugins/runtime-modules/core/widgets/description/editor.js +4 -61
- package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +1 -25
- package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +1 -25
- package/plugins/runtime-modules/core/widgets/image/config.js +2 -2
- package/plugins/runtime-modules/core/widgets/markdown/config.d.ts +3 -1
- package/plugins/runtime-modules/core/widgets/markdown/config.js +14 -0
- package/plugins/runtime-modules/core/widgets/markdown/editor.js +2 -3
- package/plugins/runtime-modules/core/widgets/result/config.d.ts +4 -25
- package/plugins/runtime-modules/core/widgets/result/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/result/server.js +25 -19
- package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +1 -25
- package/plugins/runtime-modules/core/widgets/slot-upload/client.js +11 -2
- package/plugins/runtime-modules/core/widgets/table/client.js +8 -4
- package/plugins/runtime-modules/core/widgets/table/config.d.ts +3 -83
- package/plugins/runtime-modules/core/widgets/table/config.js +302 -452
- package/plugins/runtime-modules/core/widgets/tree/config.js +5 -2
- package/plugins/runtime-modules/dashboard/card-rows.d.ts +5 -0
- package/plugins/runtime-modules/dashboard/card-rows.js +59 -0
- package/plugins/runtime-modules/dashboard/clients/dashboard-card-view.js +4 -6
- package/plugins/runtime-modules/dashboard/services/collection.js +17 -7
- package/plugins/runtime-modules/groups/data-providers.d.ts +2 -0
- package/plugins/runtime-modules/groups/data-providers.js +3 -3
- package/plugins/runtime-modules/groups/definition.d.ts +2 -0
- package/plugins/runtime-modules/localization/data-providers.d.ts +3 -0
- package/plugins/runtime-modules/localization/data-providers.js +2 -0
- package/plugins/runtime-modules/localization/definition.d.ts +3 -0
- package/plugins/runtime-modules/localization/services/table.js +3 -7
- package/plugins/runtime-modules/observability/data-providers.d.ts +1 -0
- package/plugins/runtime-modules/observability/data-providers.js +1 -0
- package/plugins/runtime-modules/observability/definition.d.ts +1 -0
- package/plugins/runtime-modules/observability/module.d.ts +1 -0
- package/plugins/runtime-modules/observability/services/table.js +1 -1
- package/plugins/runtime-modules/phi-default-site-area-preset-tree.js +2 -105
- package/plugins/runtime-modules/public/presets.d.ts +115 -0
- package/plugins/runtime-modules/{area-base-presets.js → public/presets.js} +19 -119
- package/plugins/runtime-modules/public/server.d.ts +1 -4
- package/plugins/runtime-modules/public/server.js +4 -7
- package/plugins/runtime-modules/public/trees/phi-default-pub-error-page-tree.js +7 -8
- package/plugins/runtime-modules/public-base-page-references.d.ts +1 -1
- package/plugins/runtime-modules/public-base-page-references.js +1 -1
- package/plugins/runtime-modules/revisions/controller/client.js +11 -11
- package/plugins/runtime-modules/revisions/services/table.js +3 -3
- package/plugins/runtime-modules/theme/trees/phi-default-builder-theme-page-tree.js +22 -0
- package/plugins/runtime-modules/theme/widgets/brand-controls/client.d.ts +2 -1
- package/plugins/runtime-modules/theme/widgets/brand-controls/client.js +93 -58
- package/plugins/runtime-modules/theme/widgets/brand-controls/config.d.ts +2 -1
- package/plugins/runtime-modules/theme/widgets/brand-controls/config.js +23 -22
- package/plugins/runtime-modules/theme/widgets/brand-controls/plugin.js +1 -1
- package/plugins/runtime-modules/theme-descriptors.js +1 -1
- package/plugins/runtime-modules/user-management/data-providers.d.ts +2 -0
- package/plugins/runtime-modules/user-management/data-providers.js +1 -0
- package/plugins/runtime-modules/user-management/definition.d.ts +2 -0
- package/styles/control-shape.css +11 -11
- package/styles/controls.css +29 -3
- package/styles/layout.css +16 -7
- package/types/cms-config.js +142 -185
- package/types/cms-plugins.d.ts +4 -11
- package/types/core-widget-placements.d.ts +17 -3
- package/types/dashboard-cards.d.ts +9 -0
- package/types/media.d.ts +0 -3
- package/types/renderable-block.d.ts +6 -1
- package/types/table-widget.d.ts +9 -0
- package/types/table-widget.js +20 -0
- package/types.d.ts +1 -1
- package/widget-config.d.ts +2 -0
- package/widget-config.js +6 -0
- package/plugins/runtime-modules/area-base-presets.d.ts +0 -139
- /package/plugins/runtime-modules/{runtime-calendar-adapters.d.ts → core/calendar-adapters.d.ts} +0 -0
- /package/plugins/runtime-modules/{client-calendar-adapters/core.d.ts → core/client-calendar-adapters.d.ts} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cloneElement, isValidElement } from "react";
|
|
3
|
+
import { resolvePhiRenderFailureCode } from "../widgets/config/strict-config-reader";
|
|
3
4
|
import { readPhiCmsRegionPageScope, resolvePhiCmsRegionPageScope } from "../../helpers/region-page-scope";
|
|
4
5
|
import { isPhiCmsWidgetContentUnpublished } from "../../helpers/cms-content-binding";
|
|
5
6
|
import { comparePhiCmsInstanceIds } from "../../types/cms-instance-id";
|
|
@@ -435,7 +436,7 @@ function renderContentWidget(widget, context) {
|
|
|
435
436
|
}
|
|
436
437
|
catch (error) {
|
|
437
438
|
return renderCmsDiagnostic({
|
|
438
|
-
code:
|
|
439
|
+
code: resolvePhiRenderFailureCode(error),
|
|
439
440
|
kind: "widget",
|
|
440
441
|
type: widget.widgetType,
|
|
441
442
|
blockId: widget.id,
|
|
@@ -507,7 +508,7 @@ function withLayoutRenderKey(node, key) {
|
|
|
507
508
|
/** What a Widget that threw while rendering on the server reports in its place. */
|
|
508
509
|
export function buildPhiRenderFailureIssue(error, options) {
|
|
509
510
|
return {
|
|
510
|
-
code:
|
|
511
|
+
code: resolvePhiRenderFailureCode(error),
|
|
511
512
|
kind: options.kind,
|
|
512
513
|
type: options.typeKey ?? "unknown",
|
|
513
514
|
blockId: options.blockId,
|
|
@@ -703,7 +704,7 @@ function renderLayoutNode(node, context) {
|
|
|
703
704
|
}
|
|
704
705
|
catch (error) {
|
|
705
706
|
return renderCmsDiagnostic({
|
|
706
|
-
code:
|
|
707
|
+
code: resolvePhiRenderFailureCode(error),
|
|
707
708
|
kind: "layout",
|
|
708
709
|
type: node.widgetType,
|
|
709
710
|
blockId: node.id,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
2
|
import type { PhiBlockRuntime } from "../../types";
|
|
3
3
|
import type { PhiCmsSiteBridge } from "../../types/cms-plugins";
|
|
4
4
|
import type { loadPhiCmsRootRequest } from "../../server-helpers/cms-root";
|
|
5
5
|
type PhiCmsResolvedRootRequest = NonNullable<Awaited<ReturnType<typeof loadPhiCmsRootRequest>>["resolvedRequest"]>;
|
|
6
6
|
/**
|
|
7
|
-
* What a Page and each of its Region slots work out before they render: the
|
|
8
|
-
*
|
|
9
|
-
* Controllers for the Regions in question.
|
|
7
|
+
* What a Page and each of its Region slots work out before they render: the shared part above, and the
|
|
8
|
+
* Page's Controllers for the Regions in question.
|
|
10
9
|
*
|
|
11
10
|
* The Page and the slot used to carry this as two copies, four blocks apart, and the slot's trailed the
|
|
12
11
|
* Page's. One resolution, parameterised by the Regions it is for.
|
|
@@ -36,7 +35,7 @@ export declare function resolvePhiCmsPageRenderScope({ cmsBridge, resolvedReques
|
|
|
36
35
|
};
|
|
37
36
|
runtimeRegistry: import("../../types/cms-plugins").PhiCmsRuntimeRenderRegistry;
|
|
38
37
|
pageControllerSettings: import("../../types").PhiRuntimeControllerSetting[];
|
|
39
|
-
controllerConfigOverlays: {
|
|
38
|
+
controllerConfigOverlays: readonly {
|
|
40
39
|
address: `controller:${string}/${string}:${string}`;
|
|
41
40
|
config: Record<string, unknown>;
|
|
42
41
|
}[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cache } from "react";
|
|
2
3
|
import { PhiRuntimeControllerServerHost } from "../runtime/runtime-controller-server-host";
|
|
3
4
|
import { collectPhiRuntimeControllerConfigOverlays, materializePhiRuntimeControllerSettings, } from "../runtime/runtime-controller-materialization";
|
|
4
5
|
import { PhiRuntimeControllerConfigOverlays } from "../runtime/runtime-controller-config-overlays";
|
|
@@ -9,15 +10,17 @@ import { buildPhiRuntimeModuleAccessRegistry, filterPhiCmsRenderableTreeForViewe
|
|
|
9
10
|
import { resolvePhiCmsAreaRuntimeModuleScope, resolvePhiCmsTreeRuntimeRegistry, } from "./phi-cms-runtime-registry";
|
|
10
11
|
import { resolvePhiPageTour } from "../../server-helpers/page-tour";
|
|
11
12
|
import { PHI_PAGE_TOUR_CONFIG_KEY, PHI_PAGE_TOUR_CONTROLLER_FLAG, readPhiTourTargets, } from "../../types/tours";
|
|
12
|
-
|
|
13
|
-
* What a Page and
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
/*
|
|
14
|
+
* What a Page and every one of its Region slots share: the Area's Module scope, the Page's Tour, the tree
|
|
15
|
+
* filtered for this viewer, the registry of what that tree needs, and the Controller config the tree
|
|
16
|
+
* carries. None of it depends on the Region.
|
|
16
17
|
*
|
|
17
|
-
* The Page and
|
|
18
|
-
*
|
|
18
|
+
* The Page and its six slots render in parallel and each worked all of it out again -- up to seven
|
|
19
|
+
* filters of the same tree and seven registries per request (audit R9). The root request is memoized per
|
|
20
|
+
* request (`loadPhiCmsRootRequest`), so every slot holds the same object, and React's `cache` keyed by it
|
|
21
|
+
* and the bridge keeps this for exactly that request.
|
|
19
22
|
*/
|
|
20
|
-
|
|
23
|
+
const resolvePhiCmsPageRenderBase = cache(async (cmsBridge, resolvedRequest) => {
|
|
21
24
|
const runtimeModuleScope = await resolvePhiCmsAreaRuntimeModuleScope({
|
|
22
25
|
cmsBridge,
|
|
23
26
|
area: resolvedRequest.runtime.area,
|
|
@@ -47,20 +50,6 @@ export async function resolvePhiCmsPageRenderScope({ cmsBridge, resolvedRequest,
|
|
|
47
50
|
});
|
|
48
51
|
// What the Area runs for every Page: a Page setting for one of these configures it, it is not a second.
|
|
49
52
|
const enclosingSettings = runtimeModuleScope.moduleSet.areaControllerSettings;
|
|
50
|
-
const pageControllerSettings = materializePhiRuntimeControllerSettings({
|
|
51
|
-
tree: filteredPageTree,
|
|
52
|
-
ownerMountScope: "page",
|
|
53
|
-
widgetPluginsByType: runtimeModuleScope.widgetDefinitionsByType,
|
|
54
|
-
enclosingSettings,
|
|
55
|
-
activeControllerTypes: [...runtimeModuleScope.moduleSet.controllerDescriptorsByType.keys()],
|
|
56
|
-
regionTypes,
|
|
57
|
-
...(includeOverlays ? { includeOverlays: true } : {}),
|
|
58
|
-
});
|
|
59
|
-
const controllerDefinitionsByType = await resolvePhiRuntimeControllerDefinitions({
|
|
60
|
-
catalog: cmsBridge.runtimeModuleCatalog,
|
|
61
|
-
moduleSet: runtimeModuleScope.moduleSet,
|
|
62
|
-
settings: pageControllerSettings,
|
|
63
|
-
});
|
|
64
53
|
const controllerConfigOverlays = collectPhiRuntimeControllerConfigOverlays({
|
|
65
54
|
tree: filteredPageTree,
|
|
66
55
|
ownerMountScope: "page",
|
|
@@ -83,8 +72,40 @@ export async function resolvePhiCmsPageRenderScope({ cmsBridge, resolvedRequest,
|
|
|
83
72
|
runtimeModuleScope,
|
|
84
73
|
filteredPageTree,
|
|
85
74
|
runtimeRegistry,
|
|
75
|
+
enclosingSettings,
|
|
76
|
+
controllerConfigOverlays: controllerConfigOverlays,
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* What a Page and each of its Region slots work out before they render: the shared part above, and the
|
|
81
|
+
* Page's Controllers for the Regions in question.
|
|
82
|
+
*
|
|
83
|
+
* The Page and the slot used to carry this as two copies, four blocks apart, and the slot's trailed the
|
|
84
|
+
* Page's. One resolution, parameterised by the Regions it is for.
|
|
85
|
+
*/
|
|
86
|
+
export async function resolvePhiCmsPageRenderScope({ cmsBridge, resolvedRequest, regionTypes, includeOverlays = false, }) {
|
|
87
|
+
const base = await resolvePhiCmsPageRenderBase(cmsBridge, resolvedRequest);
|
|
88
|
+
const { runtimeModuleScope, filteredPageTree } = base;
|
|
89
|
+
const pageControllerSettings = materializePhiRuntimeControllerSettings({
|
|
90
|
+
tree: filteredPageTree,
|
|
91
|
+
ownerMountScope: "page",
|
|
92
|
+
widgetPluginsByType: runtimeModuleScope.widgetDefinitionsByType,
|
|
93
|
+
enclosingSettings: base.enclosingSettings,
|
|
94
|
+
activeControllerTypes: [...runtimeModuleScope.moduleSet.controllerDescriptorsByType.keys()],
|
|
95
|
+
regionTypes,
|
|
96
|
+
...(includeOverlays ? { includeOverlays: true } : {}),
|
|
97
|
+
});
|
|
98
|
+
const controllerDefinitionsByType = await resolvePhiRuntimeControllerDefinitions({
|
|
99
|
+
catalog: cmsBridge.runtimeModuleCatalog,
|
|
100
|
+
moduleSet: runtimeModuleScope.moduleSet,
|
|
101
|
+
settings: pageControllerSettings,
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
runtimeModuleScope,
|
|
105
|
+
filteredPageTree,
|
|
106
|
+
runtimeRegistry: base.runtimeRegistry,
|
|
86
107
|
pageControllerSettings,
|
|
87
|
-
controllerConfigOverlays,
|
|
108
|
+
controllerConfigOverlays: base.controllerConfigOverlays,
|
|
88
109
|
controllerDefinitionsByType,
|
|
89
110
|
};
|
|
90
111
|
}
|
|
@@ -13,6 +13,8 @@ function buildIssueTitle(issue) {
|
|
|
13
13
|
return `${formatKind(issue.kind)} visibility unresolved`;
|
|
14
14
|
if (issue.code === "missing-node")
|
|
15
15
|
return `${formatKind(issue.kind)} root missing`;
|
|
16
|
+
if (issue.code === "invalid-config")
|
|
17
|
+
return `${formatKind(issue.kind)} settings invalid`;
|
|
16
18
|
return `${formatKind(issue.kind)} not renderable`;
|
|
17
19
|
}
|
|
18
20
|
function buildIssueDescription(issue) {
|
|
@@ -24,9 +26,11 @@ function buildIssueDescription(issue) {
|
|
|
24
26
|
? "A Module its condition reads could not be asked this render."
|
|
25
27
|
: issue.code === "missing-node"
|
|
26
28
|
? "The stored tree names a node it does not contain."
|
|
27
|
-
: issue.
|
|
28
|
-
?
|
|
29
|
-
:
|
|
29
|
+
: issue.code === "invalid-config"
|
|
30
|
+
? "Correct the field in the Inspector; on the live page this block is left out until then."
|
|
31
|
+
: issue.moduleId
|
|
32
|
+
? `Module: ${issue.moduleId}.`
|
|
33
|
+
: "The required renderer is unavailable.";
|
|
30
34
|
return `${issue.type}. ${moduleDescription}${issue.detail ? ` ${issue.detail}` : ""}`;
|
|
31
35
|
}
|
|
32
36
|
function buildIssueKey(issue) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { Component } from "react";
|
|
4
4
|
import { PhiCmsRenderDiagnostic } from "./phi-cms-render-diagnostic";
|
|
5
|
+
import { resolvePhiRenderFailureCode } from "../widgets/config/strict-config-reader";
|
|
5
6
|
export class PhiCmsRenderErrorBoundary extends Component {
|
|
6
7
|
state = {
|
|
7
8
|
error: null,
|
|
@@ -20,7 +21,7 @@ export class PhiCmsRenderErrorBoundary extends Component {
|
|
|
20
21
|
render() {
|
|
21
22
|
if (this.state.error) {
|
|
22
23
|
return _jsx(PhiCmsRenderDiagnostic, { issue: {
|
|
23
|
-
code:
|
|
24
|
+
code: resolvePhiRenderFailureCode(this.state.error),
|
|
24
25
|
kind: this.props.kind,
|
|
25
26
|
type: this.props.typeKey ?? "unknown",
|
|
26
27
|
blockId: this.props.blockId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PhiIcon } from "../shell/phi-icon";
|
|
3
3
|
import { phiSurfaceDrawsChrome, resolvePhiSurfaceStyle } from "../../helpers/surface-style";
|
|
4
4
|
import { PHI_COLOR, PHI_RADIUS, PHI_SPACE } from "../../theme/antd-css-var-contract";
|
|
@@ -7,6 +7,21 @@ import { PhiBulletListFlag, resolvePhiBulletListLevel, resolvePhiBulletListStyle
|
|
|
7
7
|
import { hasPhiFlag } from "../../helpers/flags";
|
|
8
8
|
const PHI_BULLET_LIST_MARKER_SIZE = PHI_SPACE.xs;
|
|
9
9
|
const PHI_BULLET_LIST_ICON_SIZE = 14;
|
|
10
|
+
/*
|
|
11
|
+
* An entry's state stands in place of the level's marker: a tick for what is included, a dash for what is
|
|
12
|
+
* not. Neither is the list's colour: included is the Theme's success, excluded the tertiary text, so a
|
|
13
|
+
* plan's list reads the same whatever marker its neutral entries take.
|
|
14
|
+
*/
|
|
15
|
+
function renderStateMarker(state) {
|
|
16
|
+
switch (state) {
|
|
17
|
+
case "included":
|
|
18
|
+
return _jsx(PhiIcon, { name: "antd:check-outlined", size: PHI_BULLET_LIST_ICON_SIZE, style: { color: PHI_COLOR.success } });
|
|
19
|
+
case "excluded":
|
|
20
|
+
return _jsx(PhiIcon, { name: "antd:minus-outlined", size: PHI_BULLET_LIST_ICON_SIZE, style: { color: PHI_COLOR.textTertiary } });
|
|
21
|
+
default:
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
10
25
|
function renderMarker(marker, icon, number) {
|
|
11
26
|
switch (marker) {
|
|
12
27
|
case "none":
|
|
@@ -69,5 +84,19 @@ export function PhiBulletListControl({ items, listStyle = resolvePhiBulletListSt
|
|
|
69
84
|
...surface.style,
|
|
70
85
|
...(boxed ? { padding: `${PHI_SPACE.sm} ${PHI_SPACE.md}` } : {}),
|
|
71
86
|
...(divided && index > 0 ? { borderTop: `1px solid ${PHI_COLOR.borderSecondary}`, paddingTop: gap } : {}),
|
|
72
|
-
}, children: [
|
|
87
|
+
}, children: [(() => {
|
|
88
|
+
const stated = renderStateMarker(item.state);
|
|
89
|
+
/* An editor's marker is a button, so a list whose marker is `none` still offers one. */
|
|
90
|
+
const drawn = stated ?? renderMarker(marker === "none" && item.onMarkerClick ? "dot" : marker, listStyle.icon, start + index);
|
|
91
|
+
if (drawn == null)
|
|
92
|
+
return null;
|
|
93
|
+
const markerStyle = {
|
|
94
|
+
display: "inline-flex",
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "center",
|
|
97
|
+
flexShrink: 0,
|
|
98
|
+
height: markerLineHeight,
|
|
99
|
+
};
|
|
100
|
+
return item.onMarkerClick ? (_jsx("button", { type: "button", className: "phi-bullet-list__marker-button", "aria-label": `State: ${item.state ?? "neutral"}`, onClick: item.onMarkerClick, style: { ...markerStyle, padding: 0, border: 0, background: "none", cursor: "pointer", color: "inherit" }, children: drawn })) : (_jsx("span", { "aria-hidden": "true", style: markerStyle, children: drawn }));
|
|
101
|
+
})(), _jsxs("div", { style: { display: "grid", gap, flex: 1, minWidth: 0, ...(item.state === "excluded" ? { color: PHI_COLOR.textTertiary } : {}) }, children: [item.content, item.children?.length ? (_jsx(PhiBulletListControl, { items: item.children, listStyle: listStyle, depth: depth + 1, markerLineHeight: markerLineHeight })) : null] })] }, index))) }));
|
|
73
102
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
export type PhiRibbonControlProps = {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
/** The band's ground; absent, the Theme's primary. Its words are the light text on any ground. */
|
|
5
|
+
color?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Where the band stands: `corner` flush with the box's top and end edge, its top end corner the box's
|
|
8
|
+
* own; `edge` a small padding down the end edge. Either way it floats: nothing in the box moves for it.
|
|
9
|
+
*/
|
|
10
|
+
placement?: "corner" | "edge";
|
|
11
|
+
style?: CSSProperties;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* A band of words at the end edge of a box: "Popular", "New", "-20 %".
|
|
15
|
+
*
|
|
16
|
+
* Ant Design draws this as `Badge.Ribbon`, with a fold that hangs past the box's edge. Not that one: it
|
|
17
|
+
* wraps the box in an element of its own, and its fold needs the box not to clip -- a card clips, so its
|
|
18
|
+
* picture keeps its corners. This band stands inside the box and needs nothing from it but a position
|
|
19
|
+
* to stand against. It is drawn on the server as well, without hooks.
|
|
20
|
+
*
|
|
21
|
+
* It floats and takes no room, so boxes side by side in a row start their content on one line whether
|
|
22
|
+
* they carry a band or not. A band on a line of its own pushed its box's words down; squeezed into the
|
|
23
|
+
* box's top inset it was too thin to read. In the corner it stands over the inset and a little into the
|
|
24
|
+
* first line's end, which a long eyebrow in a narrow box can reach.
|
|
25
|
+
*
|
|
26
|
+
* It sits above what the box draws, the highlight's ring included, and takes no clicks, so a card that
|
|
27
|
+
* is a link stays one under its band.
|
|
28
|
+
*/
|
|
29
|
+
export declare function PhiRibbonControl({ children, color, placement, style }: PhiRibbonControlProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PHI_COLOR, PHI_FONT_SIZE, PHI_SPACE } from "../../theme/antd-css-var-contract";
|
|
3
|
+
/**
|
|
4
|
+
* A band of words at the end edge of a box: "Popular", "New", "-20 %".
|
|
5
|
+
*
|
|
6
|
+
* Ant Design draws this as `Badge.Ribbon`, with a fold that hangs past the box's edge. Not that one: it
|
|
7
|
+
* wraps the box in an element of its own, and its fold needs the box not to clip -- a card clips, so its
|
|
8
|
+
* picture keeps its corners. This band stands inside the box and needs nothing from it but a position
|
|
9
|
+
* to stand against. It is drawn on the server as well, without hooks.
|
|
10
|
+
*
|
|
11
|
+
* It floats and takes no room, so boxes side by side in a row start their content on one line whether
|
|
12
|
+
* they carry a band or not. A band on a line of its own pushed its box's words down; squeezed into the
|
|
13
|
+
* box's top inset it was too thin to read. In the corner it stands over the inset and a little into the
|
|
14
|
+
* first line's end, which a long eyebrow in a narrow box can reach.
|
|
15
|
+
*
|
|
16
|
+
* It sits above what the box draws, the highlight's ring included, and takes no clicks, so a card that
|
|
17
|
+
* is a link stays one under its band.
|
|
18
|
+
*/
|
|
19
|
+
export function PhiRibbonControl({ children, color, placement = "edge", style }) {
|
|
20
|
+
const radius = "var(--phi-control-radius-sm)";
|
|
21
|
+
const position = placement === "corner"
|
|
22
|
+
? {
|
|
23
|
+
top: 0,
|
|
24
|
+
paddingBlock: PHI_SPACE.xxs,
|
|
25
|
+
// The top end corner is the box's own, which clips it; only the corner inside the box is rounded.
|
|
26
|
+
borderEndStartRadius: radius,
|
|
27
|
+
}
|
|
28
|
+
: {
|
|
29
|
+
top: PHI_SPACE.sm,
|
|
30
|
+
paddingBlock: PHI_SPACE.xxs,
|
|
31
|
+
borderStartStartRadius: radius,
|
|
32
|
+
borderEndStartRadius: radius,
|
|
33
|
+
};
|
|
34
|
+
return (_jsx("span", { className: "phi-ribbon-control", style: {
|
|
35
|
+
position: "absolute",
|
|
36
|
+
insetInlineEnd: 0,
|
|
37
|
+
zIndex: 4,
|
|
38
|
+
maxWidth: "70%",
|
|
39
|
+
boxSizing: "border-box",
|
|
40
|
+
paddingInline: PHI_SPACE.sm,
|
|
41
|
+
background: color ?? PHI_COLOR.primary,
|
|
42
|
+
color: PHI_COLOR.textLightSolid,
|
|
43
|
+
fontSize: PHI_FONT_SIZE.sm,
|
|
44
|
+
fontWeight: 600,
|
|
45
|
+
lineHeight: 2,
|
|
46
|
+
whiteSpace: "nowrap",
|
|
47
|
+
overflow: "hidden",
|
|
48
|
+
textOverflow: "ellipsis",
|
|
49
|
+
pointerEvents: "none",
|
|
50
|
+
...position,
|
|
51
|
+
...style,
|
|
52
|
+
}, children: children }));
|
|
53
|
+
}
|
|
@@ -44,7 +44,10 @@ export type PhiTableControlColumn<TRow extends Record<string, unknown>> = {
|
|
|
44
44
|
export type PhiTableControlPagination = {
|
|
45
45
|
page: number;
|
|
46
46
|
pageSize: number;
|
|
47
|
+
/** The rows the whole query has. Absent, the Table pages without a count: back, this page, next. */
|
|
47
48
|
total?: number;
|
|
49
|
+
/** Without a count: whether a page follows this one. */
|
|
50
|
+
hasMore?: boolean;
|
|
48
51
|
pageSizeOptions?: readonly number[];
|
|
49
52
|
showSizeChanger?: boolean;
|
|
50
53
|
onChange: (page: number, pageSize: number) => void;
|
|
@@ -1022,7 +1022,19 @@ export function PhiTableControl({ rows, rowIdentityPath, columns, columnOrder, s
|
|
|
1022
1022
|
...{ [PHI_VISUAL_ANCHOR_PART_ATTRIBUTE]: "pagination" },
|
|
1023
1023
|
current: pagination.page,
|
|
1024
1024
|
pageSize: pagination.pageSize,
|
|
1025
|
-
|
|
1025
|
+
...(pagination.total === undefined
|
|
1026
|
+
? {
|
|
1027
|
+
/*
|
|
1028
|
+
* No count: a total that reaches exactly one row past this page when another follows, and
|
|
1029
|
+
* only the current page's number drawn -- page numbers beyond it would be a guess.
|
|
1030
|
+
*/
|
|
1031
|
+
total: pagination.page * pagination.pageSize + (pagination.hasMore ? 1 : 0),
|
|
1032
|
+
showLessItems: true,
|
|
1033
|
+
itemRender: (page, type, element) => type === "page" ? (page === pagination.page ? element : null)
|
|
1034
|
+
: type === "jump-prev" || type === "jump-next" ? null
|
|
1035
|
+
: element,
|
|
1036
|
+
}
|
|
1037
|
+
: { total: pagination.total }),
|
|
1026
1038
|
pageSizeOptions: pagination.pageSizeOptions?.map(String),
|
|
1027
1039
|
showSizeChanger: pagination.showSizeChanger,
|
|
1028
1040
|
onChange: pagination.onChange,
|
|
@@ -154,8 +154,8 @@ export function PhiTreeControl({ nodes, nodeIdentityPath, parentNodeIdentityPath
|
|
|
154
154
|
padding: token.paddingSM,
|
|
155
155
|
background: token.colorBgContainer,
|
|
156
156
|
border: `1px solid ${token.colorBorderSecondary}`,
|
|
157
|
-
// The frame is the surface; its corner is the Site's step,
|
|
158
|
-
//
|
|
159
|
-
borderRadius: "var(--phi-surface-radius
|
|
157
|
+
// The frame is the surface; its corner is the Site's step, declared by the Provider every Tree
|
|
158
|
+
// renders under (THEME.md, "Control shape").
|
|
159
|
+
borderRadius: "var(--phi-surface-radius)",
|
|
160
160
|
}, children: tree })) : tree;
|
|
161
161
|
}
|
|
@@ -31,11 +31,8 @@ placeholderRows = 1) {
|
|
|
31
31
|
* Control line, which on the one-row placeholder is exactly the capsule and on a taller one is the
|
|
32
32
|
* capsule held -- the same answer the field itself will give when it arrives, so the shape does not
|
|
33
33
|
* change under the reader at the moment the chunk lands.
|
|
34
|
-
*
|
|
35
|
-
* Here the fallback is the plain surface radius and not the large one: this is an ordinary `div`,
|
|
36
|
-
* not an Ant Design Control, so nothing has redefined `--ant-border-radius` on it.
|
|
37
34
|
*/
|
|
38
|
-
borderRadius: "var(--phi-control-radius-grown-md
|
|
35
|
+
borderRadius: "var(--phi-control-radius-grown-md)",
|
|
39
36
|
background: "var(--ant-color-fill-quaternary)",
|
|
40
37
|
} }));
|
|
41
38
|
return function PhiLazyFormFieldControl(props) {
|
|
@@ -3,9 +3,9 @@ import { useEffect, useMemo } from "react";
|
|
|
3
3
|
import { PHI_MEDIA_LIBRARY_DATA_PROVIDER_KEYS } from "../../constants/media-library-provider-keys";
|
|
4
4
|
import { usePhiCollectionProvider } from "../widgets/client/shared/phi-collection-provider";
|
|
5
5
|
import { usePhiMediaSpaceSelectionAllowed } from "./media-space-selection";
|
|
6
|
+
import { readPhiMediaAssetTiles, readPhiMediaFolders, readPhiMediaPagination, readPhiMediaSpace, readPhiMediaSpaces, } from "./phi-image-preview-data";
|
|
6
7
|
import { PHI_ASSET_CONTROLLER_STORE_KEY, } from "./asset-controller-signals";
|
|
7
8
|
import { setPhiImagePreviewError, setPhiImagePreviewLoading, setPhiImagePreviewResults, usePhiImagePreviewStore, } from "./phi-image-preview-store";
|
|
8
|
-
import { isPhiRecord } from "../../helpers/is-record";
|
|
9
9
|
export const PHI_ASSET_COLLECTION_DATA_SOURCE = {
|
|
10
10
|
providerKey: PHI_MEDIA_LIBRARY_DATA_PROVIDER_KEYS.collection,
|
|
11
11
|
resourceKey: "assets",
|
|
@@ -29,22 +29,12 @@ export function buildPhiAssetCollectionQuery(state) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
export function applyPhiAssetCollectionData(data, resolvedCollectionRequestKey) {
|
|
32
|
-
const folders = Array.isArray(data.meta?.folders)
|
|
33
|
-
? data.meta.folders.filter(isPhiRecord)
|
|
34
|
-
: [];
|
|
35
|
-
const pagination = isPhiRecord(data.meta?.pagination)
|
|
36
|
-
? data.meta.pagination
|
|
37
|
-
: null;
|
|
38
32
|
setPhiImagePreviewResults(PHI_ASSET_CONTROLLER_STORE_KEY, {
|
|
39
|
-
activeSpace:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
: [],
|
|
45
|
-
assets: data.items.filter(isPhiRecord),
|
|
46
|
-
folders,
|
|
47
|
-
pagination,
|
|
33
|
+
activeSpace: readPhiMediaSpace(data.meta?.activeSpace),
|
|
34
|
+
spaces: readPhiMediaSpaces(data.meta?.spaces),
|
|
35
|
+
assets: readPhiMediaAssetTiles(data.items),
|
|
36
|
+
folders: readPhiMediaFolders(data.meta?.folders),
|
|
37
|
+
pagination: readPhiMediaPagination(data.meta?.pagination),
|
|
48
38
|
resolvedCollectionRequestKey,
|
|
49
39
|
});
|
|
50
40
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isPhiFontSubsetKey } from "@phis/contracts/media";
|
|
2
|
+
import { requirePhiField, } from "../widgets/config/strict-config-reader";
|
|
3
|
+
/*
|
|
4
|
+
* A font's metrics, read as the contract states them (`@phis/contracts/media`).
|
|
5
|
+
*
|
|
6
|
+
* The server measures them once, at upload, and writes every field. Two readers took them on trust: the
|
|
7
|
+
* public reference projection checked nothing below `font`, and the font list of the Theme took a stored
|
|
8
|
+
* `meta.font` for metrics as soon as it had a unit grid -- a record missing its ascent would have set a
|
|
9
|
+
* fallback face with `NaN` overrides. Both read through this now, so a wrong record is an error naming
|
|
10
|
+
* the field. `coverage` is the one field allowed to be absent: a font uploaded before cuts existed has
|
|
11
|
+
* none and is delivered whole.
|
|
12
|
+
*/
|
|
13
|
+
const nullableNumber = (reader, key) => reader.number(key) ?? null;
|
|
14
|
+
const requiredNumber = (reader, key) => requirePhiField(reader, key, "a number", reader.number);
|
|
15
|
+
function readPhiFontCoverage(reader) {
|
|
16
|
+
const subsets = requirePhiField(reader, "subsets", "a list of subset keys", (key) => reader.value(key, "a list of subset keys", (value) => Array.isArray(value) && value.every(isPhiFontSubsetKey) ? value : undefined));
|
|
17
|
+
const restRanges = reader.value("restRanges", "a list of [start, end] code point ranges", (value) => Array.isArray(value) && value.every((entry) => Array.isArray(entry) && entry.length === 2 &&
|
|
18
|
+
Number.isInteger(entry[0]) && Number.isInteger(entry[1]) &&
|
|
19
|
+
entry[0] >= 0 && entry[0] <= entry[1] && entry[1] <= 0x10ffff)
|
|
20
|
+
? value
|
|
21
|
+
: undefined) ?? [];
|
|
22
|
+
return { subsets, restRanges };
|
|
23
|
+
}
|
|
24
|
+
export function readPhiFontMetricsFields(reader) {
|
|
25
|
+
const unitsPerEm = requiredNumber(reader, "unitsPerEm");
|
|
26
|
+
if (unitsPerEm <= 0)
|
|
27
|
+
reader.fail("unitsPerEm", "a positive number");
|
|
28
|
+
const coverage = reader.object("coverage", readPhiFontCoverage);
|
|
29
|
+
return {
|
|
30
|
+
format: requirePhiField(reader, "format", "a font container", (key) => reader.oneOf(key, ["sfnt", "woff", "woff2"])),
|
|
31
|
+
familyName: reader.string("familyName")?.trim() || null,
|
|
32
|
+
unitsPerEm,
|
|
33
|
+
ascent: requiredNumber(reader, "ascent"),
|
|
34
|
+
descent: requiredNumber(reader, "descent"),
|
|
35
|
+
lineGap: requiredNumber(reader, "lineGap"),
|
|
36
|
+
capHeight: nullableNumber(reader, "capHeight"),
|
|
37
|
+
xHeight: nullableNumber(reader, "xHeight"),
|
|
38
|
+
xWidthAvg: nullableNumber(reader, "xWidthAvg"),
|
|
39
|
+
xWidthAvgSource: reader.oneOf("xWidthAvgSource", ["glyphs", "os2"]) ?? null,
|
|
40
|
+
category: reader.oneOf("category", ["serif", "sans-serif", "monospace"]) ?? null,
|
|
41
|
+
...(coverage ? { coverage } : {}),
|
|
42
|
+
};
|
|
43
|
+
}
|