@phis/ui 0.3.0 → 0.4.1
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 +1 -1
- package/components/controls/phi-collection-header-control.js +1 -1
- package/components/controls/phi-collection-view-control.js +2 -1
- package/components/controls/phi-drawer-control-adapter.d.ts +1 -1
- package/components/controls/phi-drawer-control-adapter.js +2 -2
- package/components/controls/phi-image-control.d.ts +6 -1
- package/components/controls/phi-image-control.js +23 -4
- package/components/controls/phi-lightbox-image-control-adapter.d.ts +2 -0
- package/components/controls/phi-lightbox-image-control-adapter.js +11 -0
- package/components/controls/phi-lightbox-image-control.d.ts +3 -2
- package/components/controls/phi-lightbox-image-control.js +7 -3
- package/components/controls/phi-modal-control-adapter.d.ts +1 -1
- package/components/controls/phi-modal-control-adapter.js +5 -2
- package/components/controls/phi-overlay-control-contract.d.ts +5 -0
- package/components/controls/phi-pagination-control-adapter.d.ts +2 -0
- package/components/controls/phi-pagination-control-adapter.js +15 -0
- package/components/controls/phi-pagination-control.d.ts +2 -1
- package/components/controls/phi-pagination-control.js +11 -7
- package/components/controls/phi-table-control.d.ts +6 -1
- package/components/controls/phi-table-control.js +17 -5
- package/components/controls/phi-timeline-control-adapter.d.ts +2 -0
- package/components/controls/phi-timeline-control-adapter.js +28 -0
- package/components/controls/phi-timeline-control.d.ts +3 -1
- package/components/controls/phi-timeline-control.js +8 -22
- package/components/controls/phi-tour-control.js +25 -7
- package/components/controls/phi-tour-viewport.d.ts +36 -0
- package/components/controls/phi-tour-viewport.js +86 -0
- package/components/controls/phi-zoom-image-overlay.d.ts +17 -0
- package/components/controls/phi-zoom-image-overlay.js +58 -0
- package/components/layouts/layout-definitions.d.ts +2 -20
- package/components/layouts/layout-definitions.js +13 -2
- package/components/layouts/plugins/carousel-layout-plugin.js +2 -1
- package/components/media/aspect-ratios.d.ts +14 -0
- package/components/media/aspect-ratios.js +13 -0
- package/components/motion/phi-sequence-run.d.ts +27 -0
- package/components/motion/phi-sequence-run.js +87 -0
- package/components/motion/phi-sequence-viewport.d.ts +16 -0
- package/components/motion/phi-sequence-viewport.js +97 -34
- package/components/overlays/phi-overlay-container-client.js +5 -2
- package/components/runtime/runtime-visual-anchors.d.ts +13 -2
- package/components/runtime/runtime-visual-anchors.js +49 -3
- package/components/shell/use-phi-shell-sticky-top.d.ts +5 -0
- package/components/shell/use-phi-shell-sticky-top.js +78 -0
- package/components/widgets/config/image-variant-options.d.ts +3 -5
- package/components/widgets/config/image-variant-options.js +11 -11
- package/components/widgets/config/sequence-settings.d.ts +75 -0
- package/components/widgets/config/sequence-settings.js +173 -0
- package/components/widgets/helpers/semantic-html-translation.d.ts +3 -1
- package/components/widgets/helpers/semantic-html-translation.js +8 -3
- package/components/widgets/label-sets/content-entries.d.ts +9 -0
- package/components/widgets/label-sets/content-entries.js +17 -0
- package/components/widgets/label-types/gallery.d.ts +2 -10
- package/components/widgets/label-types/sequence.d.ts +18 -0
- package/components/widgets/label-types/sequence.js +1 -0
- package/components/widgets/navigation-descriptor-resolver.server.js +6 -1
- package/components/widgets/shared/markdown-render.js +15 -5
- package/helpers/cms-layout-defaults.js +9 -2
- package/helpers/cms-region-keys.d.ts +1 -1
- package/helpers/motion.d.ts +7 -0
- package/helpers/motion.js +7 -0
- package/helpers/text-source.d.ts +19 -0
- package/helpers/text-source.js +20 -0
- package/next/config.mjs +1 -1
- package/package.json +1 -1
- package/plugins/runtime-modules/asset/data-providers.d.ts +4 -0
- package/plugins/runtime-modules/asset/data-providers.js +1 -0
- package/plugins/runtime-modules/asset/definition.d.ts +4 -0
- package/plugins/runtime-modules/asset/presets.d.ts +53 -1
- package/plugins/runtime-modules/asset/presets.js +16 -12
- package/plugins/runtime-modules/asset/tour.d.ts +44 -0
- package/plugins/runtime-modules/asset/tour.js +53 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-confirm-page-tree.js +3 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-login-page-tree.js +2 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-registration-page-tree.js +3 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-reset-password-page-tree.js +3 -0
- package/plugins/runtime-modules/builder/clients/inspector-config-field.js +42 -18
- package/plugins/runtime-modules/builder/clients/inspector-image-field.js +2 -2
- package/plugins/runtime-modules/builder/clients/widget-inspector.js +9 -0
- package/plugins/runtime-modules/builder/clients/workspace-scope-boundary.js +10 -0
- package/plugins/runtime-modules/builder/controller/workspace-controller.js +18 -3
- package/plugins/runtime-modules/builder/plugin-meta-labels.js +8 -0
- package/plugins/runtime-modules/builder/presets.js +5 -3
- package/plugins/runtime-modules/builder/tour.d.ts +316 -0
- package/plugins/runtime-modules/builder/tour.js +337 -0
- package/plugins/runtime-modules/builder/trees/phi-builder-inspector-area-overlay-tree.server.js +8 -1
- package/plugins/runtime-modules/builder/trees/phi-default-builder-area-preset-tree.js +4 -0
- package/plugins/runtime-modules/builder/widgets/structure-region/built-in.js +3 -2
- package/plugins/runtime-modules/core/widgets/card/server.js +4 -2
- package/plugins/runtime-modules/core/widgets/collection-view/client.js +10 -0
- package/plugins/runtime-modules/core/widgets/description/config.d.ts +28 -1
- package/plugins/runtime-modules/core/widgets/description/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/description/server.js +10 -12
- package/plugins/runtime-modules/core/widgets/entry-detail/config.d.ts +2 -0
- package/plugins/runtime-modules/core/widgets/entry-detail/config.js +8 -1
- package/plugins/runtime-modules/core/widgets/entry-header/config.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/entry-header/config.js +8 -1
- package/plugins/runtime-modules/core/widgets/entry-list/client.d.ts +4 -1
- package/plugins/runtime-modules/core/widgets/entry-list/client.js +3 -2
- package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +392 -93
- package/plugins/runtime-modules/core/widgets/entry-list/config.js +21 -3
- package/plugins/runtime-modules/core/widgets/entry-list/server.js +4 -2
- package/plugins/runtime-modules/core/widgets/gallery/authoring.js +62 -10
- package/plugins/runtime-modules/core/widgets/gallery/client.d.ts +6 -1
- package/plugins/runtime-modules/core/widgets/gallery/client.js +7 -79
- package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +337 -144
- package/plugins/runtime-modules/core/widgets/gallery/config.js +52 -113
- package/plugins/runtime-modules/core/widgets/gallery/defaults.d.ts +15 -0
- package/plugins/runtime-modules/core/widgets/gallery/defaults.js +20 -0
- package/plugins/runtime-modules/core/widgets/html/server.js +1 -1
- package/plugins/runtime-modules/core/widgets/image/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/image/config.d.ts +29 -4
- package/plugins/runtime-modules/core/widgets/image/config.js +19 -2
- package/plugins/runtime-modules/core/widgets/image/editor.js +1 -1
- package/plugins/runtime-modules/core/widgets/markdown-toc/server.js +7 -2
- package/plugins/runtime-modules/core/widgets/quick-links/config.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/quick-links/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/quick-links/plugin.js +4 -2
- package/plugins/runtime-modules/core/widgets/quick-links/server.d.ts +5 -1
- package/plugins/runtime-modules/core/widgets/quick-links/server.js +4 -2
- package/plugins/runtime-modules/core/widgets/result/config.d.ts +25 -1
- package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +28 -1
- package/plugins/runtime-modules/core/widgets/simple-text/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/simple-text/plugin.js +1 -1
- package/plugins/runtime-modules/core/widgets/simple-text/server.d.ts +4 -1
- package/plugins/runtime-modules/core/widgets/simple-text/server.js +3 -3
- package/plugins/runtime-modules/core/widgets/table/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/table/config.d.ts +80 -3
- package/plugins/runtime-modules/core/widgets/table/config.js +3 -0
- package/plugins/runtime-modules/core/widgets/tour-button/client.js +1 -1
- package/plugins/runtime-modules/phi-default-site-area-preset-tree.js +12 -4
- package/plugins/runtime-modules/public/trees/phi-default-pub-contact-page-tree.js +2 -0
- package/plugins/runtime-modules/public/trees/phi-default-pub-unsubscribe-page-tree.js +3 -0
- package/plugins/runtime-modules/public/trees/phi-default-pub-welcome-page-tree.js +2 -1
- package/plugins/runtime-modules/revisions/presets.d.ts +53 -2
- package/plugins/runtime-modules/revisions/presets.js +16 -12
- package/plugins/runtime-modules/revisions/tour.d.ts +43 -0
- package/plugins/runtime-modules/revisions/tour.js +51 -0
- package/plugins/runtime-modules/revisions/trees/phi-default-builder-revisions-page-tree.js +4 -0
- package/plugins/runtime-modules/theme/presets.d.ts +36 -4
- package/plugins/runtime-modules/theme/tour.d.ts +45 -11
- package/plugins/runtime-modules/theme/tour.js +39 -8
- package/plugins/runtime-modules/tour/controller/address.js +2 -2
- package/plugins/runtime-modules/tour/controller/client.js +43 -2
- package/plugins/runtime-modules/tour/controller/definition.js +2 -1
- package/server-helpers/cms-request.js +1 -0
- package/server-helpers/page-tour.d.ts +10 -3
- package/server-helpers/page-tour.js +25 -12
- package/server-helpers/translate.d.ts +9 -0
- package/server-helpers/translate.js +14 -0
- package/styles/controls.css +15 -1
- package/styles/root.css +20 -19
- package/types/cms-config.d.ts +3 -1
- package/types/cms-config.js +3 -3
- package/types/cms-plugins.d.ts +31 -4
- package/types/core-widget-placements.d.ts +5 -0
- package/types/table-widget.d.ts +2 -0
- package/types/tour-controller.d.ts +10 -0
- package/types/tour-controller.js +13 -0
- package/types/tours.d.ts +27 -25
- package/types/tours.js +9 -23
- package/types/visual-anchors.d.ts +15 -0
- package/types/visual-anchors.js +12 -0
- package/types.d.ts +2 -0
- package/types.js +4 -1
|
@@ -1,34 +1,68 @@
|
|
|
1
|
+
import type { PhiCmsInstanceId } from "../../../types/cms-instance-id";
|
|
2
|
+
import type { PhiTourStepSignal } from "../../../types/tours";
|
|
1
3
|
/**
|
|
2
4
|
* The Theme workspace's Tour (TODOS.md, "A Tour for the Theme workspace").
|
|
3
5
|
*
|
|
4
|
-
* What the workspace does not say out loud is its first step:
|
|
5
|
-
*
|
|
6
|
-
* rest is the order a person meets the workspace in.
|
|
6
|
+
* What the workspace does not say out loud is its first step: the selector picks what a draft starts
|
|
7
|
+
* from. A Module's Theme is a base to start from, never edited through it, and installing a package
|
|
8
|
+
* that ships a look changes nothing for the Site. The rest is the order a person meets the workspace in.
|
|
7
9
|
*/
|
|
8
10
|
export declare const PHI_THEME_WORKSPACE_TOUR: {
|
|
9
11
|
readonly id: "@phis/ui/modules/theme/workspace";
|
|
10
12
|
readonly version: 1;
|
|
11
13
|
readonly steps: readonly [{
|
|
12
14
|
readonly key: "theme-choice";
|
|
13
|
-
readonly target: `cms:${
|
|
14
|
-
readonly title: "
|
|
15
|
-
readonly description: "The Site's published theme, its draft, or a theme a Module brings.
|
|
15
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
16
|
+
readonly title: "What your draft starts from";
|
|
17
|
+
readonly description: "The Site's published theme, its draft, or a theme a Module brings. Picking one makes it the base of your theme draft; the Module's theme itself stays as it is.";
|
|
16
18
|
readonly placement: "bottom";
|
|
17
19
|
}, {
|
|
18
20
|
readonly key: "theme-parts";
|
|
19
|
-
readonly target: `cms:${
|
|
20
|
-
readonly title: "
|
|
21
|
-
readonly description: "
|
|
21
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
22
|
+
readonly title: "Four parts of the theme";
|
|
23
|
+
readonly description: "Colour, style, background and brand: each opens its own controls on the left, with the preview beside them.";
|
|
22
24
|
readonly placement: "bottom";
|
|
25
|
+
}, {
|
|
26
|
+
readonly key: string;
|
|
27
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
28
|
+
readonly title: string;
|
|
29
|
+
readonly description: string;
|
|
30
|
+
readonly placement: "right";
|
|
31
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
32
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
33
|
+
}, {
|
|
34
|
+
readonly key: string;
|
|
35
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
36
|
+
readonly title: string;
|
|
37
|
+
readonly description: string;
|
|
38
|
+
readonly placement: "right";
|
|
39
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
40
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
41
|
+
}, {
|
|
42
|
+
readonly key: string;
|
|
43
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
44
|
+
readonly title: string;
|
|
45
|
+
readonly description: string;
|
|
46
|
+
readonly placement: "right";
|
|
47
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
48
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
49
|
+
}, {
|
|
50
|
+
readonly key: string;
|
|
51
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
52
|
+
readonly title: string;
|
|
53
|
+
readonly description: string;
|
|
54
|
+
readonly placement: "right";
|
|
55
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
56
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
23
57
|
}, {
|
|
24
58
|
readonly key: "preview-mode";
|
|
25
|
-
readonly target: `cms:${
|
|
59
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
26
60
|
readonly title: "Light and dark";
|
|
27
61
|
readonly description: "See the theme in either mode. This switches the preview, not the Site.";
|
|
28
62
|
readonly placement: "bottom";
|
|
29
63
|
}, {
|
|
30
64
|
readonly key: "draft-status";
|
|
31
|
-
readonly target: `cms:${
|
|
65
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
32
66
|
readonly title: "Where your changes stand";
|
|
33
67
|
readonly description: "What you change here is a draft. The Site keeps its published theme until the draft is published.";
|
|
34
68
|
readonly placement: "bottom";
|
|
@@ -1,11 +1,38 @@
|
|
|
1
|
+
import { PHI_CMS_SEQUENTIAL_LAYOUT_SLOTS } from "../../../constants/cms-layout-types";
|
|
1
2
|
import { PHI_THEME_RUNTIME_MODULE_ID } from "./ids";
|
|
2
|
-
import { PHI_THEME_PAGE_WIDGET_IDS } from "./page-ids";
|
|
3
|
+
import { PHI_THEME_PAGE_LAYOUT_IDS, PHI_THEME_PAGE_WIDGET_IDS } from "./page-ids";
|
|
4
|
+
/** Turns the workspace's Stack to one of its four panels, as the Segmented above it does. */
|
|
5
|
+
function showPanel(slot) {
|
|
6
|
+
return {
|
|
7
|
+
receiver: `cms:${PHI_THEME_PAGE_LAYOUT_IDS.layoutBrandStack}`,
|
|
8
|
+
channel: "activeSlotKey",
|
|
9
|
+
action: "change",
|
|
10
|
+
valueType: "string",
|
|
11
|
+
value: PHI_CMS_SEQUENTIAL_LAYOUT_SLOTS[slot].key,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One panel of the workspace, pointed at by its controls. The step turns the Stack to the panel and back
|
|
16
|
+
* to Color when it is left, the panel the workspace opens with; from one panel step to the next both
|
|
17
|
+
* arrive together, so the Stack simply moves on.
|
|
18
|
+
*/
|
|
19
|
+
function panelStep(key, slot, controls, title, description) {
|
|
20
|
+
return {
|
|
21
|
+
key,
|
|
22
|
+
target: `cms:${controls}`,
|
|
23
|
+
title,
|
|
24
|
+
description,
|
|
25
|
+
placement: "right",
|
|
26
|
+
prepare: [showPanel(slot)],
|
|
27
|
+
release: [showPanel(0)],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
3
30
|
/**
|
|
4
31
|
* The Theme workspace's Tour (TODOS.md, "A Tour for the Theme workspace").
|
|
5
32
|
*
|
|
6
|
-
* What the workspace does not say out loud is its first step:
|
|
7
|
-
*
|
|
8
|
-
* rest is the order a person meets the workspace in.
|
|
33
|
+
* What the workspace does not say out loud is its first step: the selector picks what a draft starts
|
|
34
|
+
* from. A Module's Theme is a base to start from, never edited through it, and installing a package
|
|
35
|
+
* that ships a look changes nothing for the Site. The rest is the order a person meets the workspace in.
|
|
9
36
|
*/
|
|
10
37
|
export const PHI_THEME_WORKSPACE_TOUR = {
|
|
11
38
|
id: `${PHI_THEME_RUNTIME_MODULE_ID}/workspace`,
|
|
@@ -14,17 +41,21 @@ export const PHI_THEME_WORKSPACE_TOUR = {
|
|
|
14
41
|
{
|
|
15
42
|
key: "theme-choice",
|
|
16
43
|
target: `cms:${PHI_THEME_PAGE_WIDGET_IDS.widgetBrandContextSelect}`,
|
|
17
|
-
title: "
|
|
18
|
-
description: "The Site's published theme, its draft, or a theme a Module brings.
|
|
44
|
+
title: "What your draft starts from",
|
|
45
|
+
description: "The Site's published theme, its draft, or a theme a Module brings. Picking one makes it the base of your theme draft; the Module's theme itself stays as it is.",
|
|
19
46
|
placement: "bottom",
|
|
20
47
|
},
|
|
21
48
|
{
|
|
22
49
|
key: "theme-parts",
|
|
23
50
|
target: `cms:${PHI_THEME_PAGE_WIDGET_IDS.widgetThemeStackSegmented}`,
|
|
24
|
-
title: "
|
|
25
|
-
description: "
|
|
51
|
+
title: "Four parts of the theme",
|
|
52
|
+
description: "Colour, style, background and brand: each opens its own controls on the left, with the preview beside them.",
|
|
26
53
|
placement: "bottom",
|
|
27
54
|
},
|
|
55
|
+
panelStep("color", 0, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandThemeControls, "Colour from a few seeds", "A palette is picked whole, or each colour is set on its own. Every colour is a seed: Primary, Info, Success, Warning, Error, Link, the text and the background each grow into the shades for hover, borders and backgrounds, and Custom grows into ten steps of its own."),
|
|
56
|
+
panelStep("style", 1, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandStyleControls, "Buttons and corners", "A shape sets the corners at once -- square, subtle, rounded or pill -- for buttons and fields alike. Below it the details: the buttons' shadows, the corner radius in three sizes, how tall controls are, and the fonts and their size."),
|
|
57
|
+
panelStep("background", 2, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandBackgroundControls, "Behind everything", "The root background is one layer behind the whole Site: a colour, a gradient or an image, still or in parallax, with an overlay of colour, pattern or noise on top. The chrome overlay is a second ground the header, the sider and the footer share, and the chrome shadow sets how they cast onto the Page. Each is set for light and dark."),
|
|
58
|
+
panelStep("brand", 3, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandIdentityControls, "The Site's own marks", "The logo, one per mode, and where a click on it leads; the wordmark, the Site's name in type; and the two short lines the Brand shows beside them."),
|
|
28
59
|
{
|
|
29
60
|
key: "preview-mode",
|
|
30
61
|
target: `cms:${PHI_THEME_PAGE_WIDGET_IDS.widgetBrandPreviewModeSwitch}`,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { PHI_TOUR_CONTROLLER_KEY, PHI_TOUR_CONTROLLER_PLUGIN_KEY } from "../../../../types/
|
|
2
|
-
// The Controller's address is the foundation's (`types/
|
|
1
|
+
import { PHI_TOUR_CONTROLLER_KEY, PHI_TOUR_CONTROLLER_PLUGIN_KEY } from "../../../../types/tour-controller";
|
|
2
|
+
// The Controller's address is the foundation's (`types/tour-controller.ts`): the Tour button, which is Core's, asks it.
|
|
3
3
|
export const PHI_TOUR_CONTROLLER_TYPE = `${PHI_TOUR_CONTROLLER_PLUGIN_KEY}/${PHI_TOUR_CONTROLLER_KEY}`;
|
|
@@ -3,16 +3,19 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { PHI_SIGNAL_VALUE_SCHEMAS } from "../../../../types/signals";
|
|
5
5
|
import { PhiTourControl } from "../../../../components/controls/phi-tour-control";
|
|
6
|
+
import { holdPhiTourViewport, releasePhiTourViewport } from "../../../../components/controls/phi-tour-viewport";
|
|
6
7
|
import { createPhiRuntimeControllerClient } from "../../../../components/runtime/runtime-controller-client-factory";
|
|
7
8
|
import { usePhiSignalDispatcher, usePhiSignalListener } from "../../../../components/runtime/runtime-signal-bus";
|
|
8
9
|
import { usePhiSignalRuntimePartition } from "../../../../components/runtime/runtime-signal-partition";
|
|
9
|
-
import { readPhiVisualAnchor, waitForPhiVisualAnchor } from "../../../../components/runtime/runtime-visual-anchors";
|
|
10
|
+
import { readPhiVisualAnchor, waitForPhiVisualAnchor, waitForPhiVisualAnchorToSettle, } from "../../../../components/runtime/runtime-visual-anchors";
|
|
10
11
|
import { fetchPhiUserState, writePhiUserState } from "../../../../components/runtime/user-state-client";
|
|
11
12
|
import { PHI_TOUR_PROGRESS_USER_STATE_KEY } from "../ids";
|
|
12
13
|
import { PHI_TOUR_RUNTIME_CONTROLLER_DEFINITION } from "./definition";
|
|
13
14
|
import { readPhiTourProgress, recordPhiTourProgress, shouldOfferPhiTour, } from "./progress";
|
|
14
15
|
/** How long a step waits for its target before its `ifMissing` decides. */
|
|
15
16
|
const TARGET_WAIT_MS = 4000;
|
|
17
|
+
/** How long a found target may keep moving before it is pointed at where it stands. */
|
|
18
|
+
const TARGET_SETTLE_MS = 1000;
|
|
16
19
|
const PROGRESS_DESCRIPTOR = {
|
|
17
20
|
key: PHI_TOUR_PROGRESS_USER_STATE_KEY,
|
|
18
21
|
shape: "value",
|
|
@@ -115,6 +118,31 @@ function PhiTourControllerView({ address, config }) {
|
|
|
115
118
|
* never pointed at anything but its own address in this partition.
|
|
116
119
|
*/
|
|
117
120
|
const step = run ? run.tour.steps[run.index] ?? null : null;
|
|
121
|
+
const send = useCallback((signals) => {
|
|
122
|
+
for (const signal of signals ?? []) {
|
|
123
|
+
dispatchSignal({
|
|
124
|
+
scope: "area",
|
|
125
|
+
channel: signal.channel,
|
|
126
|
+
action: signal.action,
|
|
127
|
+
value: signal.value ?? null,
|
|
128
|
+
valueType: signal.valueType,
|
|
129
|
+
...(signal.valueSchema ? { valueSchema: signal.valueSchema } : {}),
|
|
130
|
+
sender: address,
|
|
131
|
+
receiver: signal.receiver,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}, [address, dispatchSignal]);
|
|
135
|
+
/*
|
|
136
|
+
* The step asked for gets its `prepare` before its target is waited for, and its `release` the moment it
|
|
137
|
+
* is no longer the one asked for -- the next step, a step passed over, the Tour closed or finished, the
|
|
138
|
+
* Page left. One effect per step, so every prepare is answered by exactly one release.
|
|
139
|
+
*/
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!step)
|
|
142
|
+
return undefined;
|
|
143
|
+
send(step.prepare);
|
|
144
|
+
return () => send(step.release);
|
|
145
|
+
}, [send, step]);
|
|
118
146
|
// A step centered on purpose has nothing to wait for.
|
|
119
147
|
const presented = run && step?.target == null ? run.index : run?.presented ?? null;
|
|
120
148
|
useEffect(() => {
|
|
@@ -122,10 +150,16 @@ function PhiTourControllerView({ address, config }) {
|
|
|
122
150
|
return undefined;
|
|
123
151
|
const abort = new AbortController();
|
|
124
152
|
void waitForPhiVisualAnchor(partition, step.target, { timeoutMs: TARGET_WAIT_MS, signal: abort.signal })
|
|
125
|
-
.then((element) => {
|
|
153
|
+
.then(async (element) => {
|
|
126
154
|
if (abort.signal.aborted)
|
|
127
155
|
return;
|
|
128
156
|
if (element) {
|
|
157
|
+
// Pointed at once it stands still: a target a `prepare` just opened is often still moving in.
|
|
158
|
+
await waitForPhiVisualAnchorToSettle(element, { timeoutMs: TARGET_SETTLE_MS, signal: abort.signal });
|
|
159
|
+
if (abort.signal.aborted)
|
|
160
|
+
return;
|
|
161
|
+
// Scrolled to below the sticky bands, once the step is presented (`phi-tour-viewport.ts`).
|
|
162
|
+
holdPhiTourViewport(element);
|
|
129
163
|
setRun({ ...run, presented: run.index });
|
|
130
164
|
return;
|
|
131
165
|
}
|
|
@@ -136,6 +170,13 @@ function PhiTourControllerView({ address, config }) {
|
|
|
136
170
|
});
|
|
137
171
|
return () => abort.abort();
|
|
138
172
|
}, [partition, run, step]);
|
|
173
|
+
// The window's scroll padding is the Tour's only while a Tour runs.
|
|
174
|
+
const running = run != null;
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (!running)
|
|
177
|
+
return undefined;
|
|
178
|
+
return releasePhiTourViewport;
|
|
179
|
+
}, [running]);
|
|
139
180
|
const steps = useMemo(() => (run?.tour.steps ?? []).map((definition) => ({
|
|
140
181
|
key: definition.key,
|
|
141
182
|
title: definition.title,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PHI_SIGNAL_VALUE_SCHEMAS } from "../../../../types/signals";
|
|
2
|
-
import {
|
|
2
|
+
import { PHI_TOUR_CONTROLLER_KEY, PHI_TOUR_CONTROLLER_PLUGIN_KEY } from "../../../../types/tour-controller";
|
|
3
|
+
import { PHI_PAGE_TOUR_CONFIG_KEY, PHI_PAGE_TOUR_CONTROLLER_FLAG, readPhiResolvedPageTour, } from "../../../../types/tours";
|
|
3
4
|
/**
|
|
4
5
|
* Runs the Tour of whichever Page is shown (design/TOURS.md).
|
|
5
6
|
*
|
|
@@ -320,6 +320,7 @@ export async function resolvePhiCmsRequest({ siteKey, locale, area, path, cookie
|
|
|
320
320
|
pageTour: routeTour
|
|
321
321
|
? {
|
|
322
322
|
definition: routeTour,
|
|
323
|
+
ownerModuleId: routeBinding.descriptor.ownerModuleId,
|
|
323
324
|
sourceLocale: catalog.sourceLocaleByModuleId.get(routeBinding.descriptor.ownerModuleId),
|
|
324
325
|
}
|
|
325
326
|
: null,
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
+
import type { PhiRuntimeModuleId } from "../types/cms-module-descriptors";
|
|
2
3
|
import type { PhiResolvedPageTour, PhiTourDefinition } from "../types/tours";
|
|
3
4
|
/**
|
|
4
|
-
* A Page's Tour in the viewer's language: every step's words translated
|
|
5
|
-
*
|
|
5
|
+
* A Page's Tour in the viewer's language: every step's words translated, and the step buttons from Core's
|
|
6
|
+
* label set. Addresses, keys and step signals are not words and pass through.
|
|
7
|
+
*
|
|
8
|
+
* Where the words are kept depends on who wrote them. A built-in Tour's text is this package's, the same
|
|
9
|
+
* on every Site, so it is translated once in the global set. A third-party Module's Tour is translated per
|
|
10
|
+
* Site from the language that Module writes in, where the Site's own corrections apply. Either way the
|
|
11
|
+
* Tour's id is the context, so a translator sees which Tour a sentence belongs to.
|
|
6
12
|
*/
|
|
7
|
-
export declare function resolvePhiPageTour({ definition, sourceLocale, locale, }: {
|
|
13
|
+
export declare function resolvePhiPageTour({ definition, ownerModuleId, sourceLocale, locale, }: {
|
|
8
14
|
definition: PhiTourDefinition;
|
|
15
|
+
ownerModuleId: PhiRuntimeModuleId;
|
|
9
16
|
sourceLocale?: string;
|
|
10
17
|
locale: string;
|
|
11
18
|
}): Promise<PhiResolvedPageTour>;
|
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
import { getPhiTourWidgetLabels } from "../components/widgets/label-sets/tour";
|
|
3
|
+
import { PHI_SHARED_PACKAGE_NAME } from "../constants/package";
|
|
3
4
|
import { readPhiServerApiCredentials } from "../helpers/phis-server-credentials";
|
|
4
|
-
import {
|
|
5
|
+
import { trBulkForLocale, trGlobalBulkForLocale } from "./translate";
|
|
6
|
+
/** A Tour this package ships, whose words are the same on every Site. */
|
|
7
|
+
function isPhiBuiltInTour(ownerModuleId) {
|
|
8
|
+
return ownerModuleId.startsWith(`${PHI_SHARED_PACKAGE_NAME}/`);
|
|
9
|
+
}
|
|
5
10
|
/**
|
|
6
|
-
* A Page's Tour in the viewer's language: every step's words translated
|
|
7
|
-
*
|
|
11
|
+
* A Page's Tour in the viewer's language: every step's words translated, and the step buttons from Core's
|
|
12
|
+
* label set. Addresses, keys and step signals are not words and pass through.
|
|
13
|
+
*
|
|
14
|
+
* Where the words are kept depends on who wrote them. A built-in Tour's text is this package's, the same
|
|
15
|
+
* on every Site, so it is translated once in the global set. A third-party Module's Tour is translated per
|
|
16
|
+
* Site from the language that Module writes in, where the Site's own corrections apply. Either way the
|
|
17
|
+
* Tour's id is the context, so a translator sees which Tour a sentence belongs to.
|
|
8
18
|
*/
|
|
9
|
-
export async function resolvePhiPageTour({ definition, sourceLocale, locale, }) {
|
|
10
|
-
const
|
|
19
|
+
export async function resolvePhiPageTour({ definition, ownerModuleId, sourceLocale, locale, }) {
|
|
20
|
+
const texts = definition.steps.flatMap((step) => [step.title, step.description ?? ""]);
|
|
21
|
+
const translate = isPhiBuiltInTour(ownerModuleId)
|
|
22
|
+
? trGlobalBulkForLocale(locale, texts, definition.id)
|
|
23
|
+
: trBulkForLocale(locale, texts, definition.id, "text", sourceLocale);
|
|
11
24
|
const credentials = readPhiServerApiCredentials();
|
|
12
|
-
const [labels,
|
|
25
|
+
const [labels, translated] = await Promise.all([
|
|
13
26
|
getPhiTourWidgetLabels({ apiBaseUrl: credentials.apiBaseUrl, internalToken: credentials.internalToken, locale }),
|
|
14
|
-
|
|
15
|
-
...step,
|
|
16
|
-
title: await translate(step.title),
|
|
17
|
-
...(step.description ? { description: await translate(step.description) } : {}),
|
|
18
|
-
}))),
|
|
27
|
+
translate,
|
|
19
28
|
]);
|
|
20
29
|
return {
|
|
21
30
|
id: definition.id,
|
|
22
31
|
version: definition.version,
|
|
23
|
-
steps,
|
|
32
|
+
steps: definition.steps.map((step, index) => ({
|
|
33
|
+
...step,
|
|
34
|
+
title: translated[index * 2] ?? step.title,
|
|
35
|
+
...(step.description ? { description: translated[index * 2 + 1] ?? step.description } : {}),
|
|
36
|
+
})),
|
|
24
37
|
labels: { next: labels.next, previous: labels.previous, finish: labels.finish },
|
|
25
38
|
};
|
|
26
39
|
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
import { type PhiTranslationParams } from "../helpers/translation-format";
|
|
3
3
|
import { PHI_TR_CTX_WEB_UI_LABEL, type PhiTranslationFormat } from "../gateway/tr";
|
|
4
|
+
import { type PhiTextSource } from "../helpers/text-source";
|
|
4
5
|
export { PHI_TR_CTX_WEB_UI_LABEL };
|
|
5
6
|
export type { PhiTranslationParams } from "../helpers/translation-format";
|
|
6
7
|
export declare function tr(msg: string, params?: PhiTranslationParams, ctx?: string | number, format?: PhiTranslationFormat): Promise<string>;
|
|
7
8
|
export declare function trGlobal(msg: string, params?: PhiTranslationParams, ctx?: string | number, format?: PhiTranslationFormat): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* A text Widget's own words in the render's locale, from the store their source names.
|
|
11
|
+
*
|
|
12
|
+
* `textSource: "preset"` is a Preset's sentence and the platform's, so the global store answers it;
|
|
13
|
+
* anything else an author wrote and the Site's store does (`helpers/text-source.ts`). The locale is the
|
|
14
|
+
* render's where there is one: a static render has no request to read it from.
|
|
15
|
+
*/
|
|
16
|
+
export declare function trWidgetText(locale: string | undefined, msg: string, textSource: PhiTextSource | undefined): Promise<string>;
|
|
8
17
|
export declare function trForLocale(localeInput: string, msg: string, params?: PhiTranslationParams, ctx?: string | number, format?: PhiTranslationFormat,
|
|
9
18
|
/** The language `msg` is written in, when it is not the Site's own -- a Module's text. */
|
|
10
19
|
sourceLocale?: string): Promise<string>;
|
|
@@ -6,6 +6,7 @@ import { PHI_TR_CTX_WEB_UI_LABEL, trBulk as requestInternalTranslationBulk, tr a
|
|
|
6
6
|
import { getPhiRequestRuntime } from "./request-runtime";
|
|
7
7
|
import { resolvePhiRequestLocale } from "./request-locale";
|
|
8
8
|
import { readPhiServerApiCredentials } from "../helpers/phis-server-credentials";
|
|
9
|
+
import { PHI_TEXT_SOURCE_PRESET } from "../helpers/text-source";
|
|
9
10
|
export { PHI_TR_CTX_WEB_UI_LABEL };
|
|
10
11
|
function buildTranslatorOptions(locale, sourceLocale) {
|
|
11
12
|
const requestRuntime = getPhiRequestRuntime();
|
|
@@ -46,6 +47,19 @@ export async function trGlobal(msg, params = 0, ctx = 0, format = "text") {
|
|
|
46
47
|
const locale = await resolvePhiRequestLocale();
|
|
47
48
|
return trGlobalForLocale(locale, msg, params, ctx, format);
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* A text Widget's own words in the render's locale, from the store their source names.
|
|
52
|
+
*
|
|
53
|
+
* `textSource: "preset"` is a Preset's sentence and the platform's, so the global store answers it;
|
|
54
|
+
* anything else an author wrote and the Site's store does (`helpers/text-source.ts`). The locale is the
|
|
55
|
+
* render's where there is one: a static render has no request to read it from.
|
|
56
|
+
*/
|
|
57
|
+
export async function trWidgetText(locale, msg, textSource) {
|
|
58
|
+
if (textSource === PHI_TEXT_SOURCE_PRESET) {
|
|
59
|
+
return locale ? trGlobalForLocale(locale, msg) : trGlobal(msg);
|
|
60
|
+
}
|
|
61
|
+
return locale ? trForLocale(locale, msg) : tr(msg);
|
|
62
|
+
}
|
|
49
63
|
/**
|
|
50
64
|
* Trimmed, one per message and in order: an empty message stays in its place, and `trBulk` answers it
|
|
51
65
|
* with an empty text, so every answer lines up with the message it belongs to.
|
package/styles/controls.css
CHANGED
|
@@ -492,10 +492,24 @@ h5.phi-typography, .phi-typography h5 {
|
|
|
492
492
|
* as a Table closed with one instead of with a footer. Clipping the Table is what both cases want, which
|
|
493
493
|
* is why the rule names neither.
|
|
494
494
|
*/
|
|
495
|
+
/*
|
|
496
|
+
* A sticky header row sticks under the Shell's Header, which publishes where it ends right now
|
|
497
|
+
* (`components/shell/use-phi-shell-sticky-top.ts`), and at the top edge of an Overlay's body,
|
|
498
|
+
* which scrolls on its own. Ant Design writes the offset inline, so the position is stated over it.
|
|
499
|
+
*/
|
|
500
|
+
.phi-table-control.phi-table-control--sticky-header [class~="ant-table-sticky-holder"] {
|
|
501
|
+
top: var(--phi-table-sticky-top, var(--phi-shell-sticky-top, 0px)) !important;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
:is([data-phi-modal-body-content], [data-phi-drawer-body-content]) {
|
|
505
|
+
--phi-table-sticky-top: 0px;
|
|
506
|
+
}
|
|
507
|
+
|
|
495
508
|
.phi-table-control.phi-table-control--closing-block [class~="ant-table"] {
|
|
496
509
|
border-end-start-radius: var(--phi-surface-radius, var(--ant-border-radius-lg));
|
|
497
510
|
border-end-end-radius: var(--phi-surface-radius, var(--ant-border-radius-lg));
|
|
498
|
-
|
|
511
|
+
/* `clip`, not `hidden`, so the corners are cut without making this the sticky header's scroller. */
|
|
512
|
+
overflow: clip;
|
|
499
513
|
}
|
|
500
514
|
|
|
501
515
|
/*
|
package/styles/root.css
CHANGED
|
@@ -114,29 +114,30 @@ samp {
|
|
|
114
114
|
animation-timing-function: var(--phi-effects-animation-easing, ease-out);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
:where([data-phi-renderable-block="true"][data-phi-effects-transition="composite"][data-phi-effects-trigger="on_visible"]) {
|
|
118
|
-
animation-composition: var(--phi-effects-animation-composition, replace);
|
|
119
|
-
animation-delay: var(--phi-effects-animation-delay, 0ms);
|
|
120
|
-
animation-duration: var(--phi-effects-animation-duration, 1000ms);
|
|
121
|
-
animation-name: var(--phi-effects-animation-name);
|
|
122
|
-
animation-play-state: paused;
|
|
123
|
-
animation-timing-function: var(--phi-effects-animation-easing, ease-out);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
:where([data-phi-renderable-block="true"][data-phi-effects-transition="composite"][data-phi-effects-trigger="on_visible"][data-phi-effects-state="running"]) {
|
|
127
|
-
animation-play-state: running;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
117
|
/*
|
|
131
|
-
* On ready, the whole rule inside the query that asks whether anything can release it.
|
|
118
|
+
* On visible and on ready, the whole rule inside the query that asks whether anything can release it.
|
|
132
119
|
*
|
|
133
|
-
* The animation is held at its first frame until the
|
|
134
|
-
* content the server streams in a segment of its own can land,
|
|
135
|
-
* behind an entrance that has not started. Only scripting sets the
|
|
136
|
-
* is none the Block would stand at that first frame for good, which
|
|
137
|
-
* without scripting there is no animation at all and the Block is
|
|
120
|
+
* The animation is held at its first frame -- until the Block is scrolled into view, or until the page
|
|
121
|
+
* has finished arriving, so a Widget whose content the server streams in a segment of its own can land,
|
|
122
|
+
* and everything below it can settle, behind an entrance that has not started. Only scripting sets the
|
|
123
|
+
* state that releases it; where there is none the Block would stand at that first frame for good, which
|
|
124
|
+
* for a fade in means invisible. So without scripting there is no animation at all and the Block is
|
|
125
|
+
* simply there.
|
|
138
126
|
*/
|
|
139
127
|
@media (scripting: enabled) {
|
|
128
|
+
:where([data-phi-renderable-block="true"][data-phi-effects-transition="composite"][data-phi-effects-trigger="on_visible"]) {
|
|
129
|
+
animation-composition: var(--phi-effects-animation-composition, replace);
|
|
130
|
+
animation-delay: var(--phi-effects-animation-delay, 0ms);
|
|
131
|
+
animation-duration: var(--phi-effects-animation-duration, 1000ms);
|
|
132
|
+
animation-name: var(--phi-effects-animation-name);
|
|
133
|
+
animation-play-state: paused;
|
|
134
|
+
animation-timing-function: var(--phi-effects-animation-easing, ease-out);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
:where([data-phi-renderable-block="true"][data-phi-effects-transition="composite"][data-phi-effects-trigger="on_visible"][data-phi-effects-state="running"]) {
|
|
138
|
+
animation-play-state: running;
|
|
139
|
+
}
|
|
140
|
+
|
|
140
141
|
:where([data-phi-renderable-block="true"][data-phi-effects-transition="composite"][data-phi-effects-trigger="on_ready"]) {
|
|
141
142
|
animation-composition: var(--phi-effects-animation-composition, replace);
|
|
142
143
|
animation-delay: var(--phi-effects-animation-delay, 0ms);
|
package/types/cms-config.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type PhiCssLength } from "./length";
|
|
|
6
6
|
import type { PhiResponsiveValue } from "./responsive";
|
|
7
7
|
import type { PhiRenderableBlockBase, PhiRenderableBlockAnchor, PhiRenderableBlockResponsiveSize } from "./renderable-block";
|
|
8
8
|
import type { PhiBaseLayoutSlotStates } from "../components/layouts/phi-layout-contract";
|
|
9
|
+
import { type PhiSpacingScaleKey } from "../components/widgets/config/spacing-options";
|
|
9
10
|
export type PhiCmsPluginConfigBase = Record<string, unknown>;
|
|
10
11
|
export type PhiCmsRenderableBlockConfigBase = PhiCmsPluginConfigBase & PhiRenderableBlockBase;
|
|
11
12
|
export type PhiCmsLayerBase = PhiCmsRenderableBlockConfigBase & {
|
|
@@ -120,7 +121,8 @@ export type PhiCmsCarouselLayoutConfig = PhiCmsLayerBase & {
|
|
|
120
121
|
transition?: PhiSequenceTransition;
|
|
121
122
|
transitionDurationMs?: number;
|
|
122
123
|
transitionEasing?: PhiMotionEasing;
|
|
123
|
-
|
|
124
|
+
/** A step of the spacing scale between the slots of a window. */
|
|
125
|
+
slotGap?: PhiSpacingScaleKey;
|
|
124
126
|
/** Which of its own controls the Carousel draws. Pager Widgets work regardless of this. */
|
|
125
127
|
controls?: "none" | "arrows" | "dots" | "both";
|
|
126
128
|
loop?: boolean;
|
package/types/cms-config.js
CHANGED
|
@@ -9,6 +9,7 @@ import { applyPhiLayoutDefaults } from "../helpers/cms-layout-defaults";
|
|
|
9
9
|
import { resolvePhiLayoutDefaults } from "../helpers/cms-layout-defaults";
|
|
10
10
|
import { normalizeRenderableBlockAnchor } from "../helpers/renderable-block-anchor";
|
|
11
11
|
import { isPhiRecord } from "../helpers/is-record";
|
|
12
|
+
import { PHI_SPACING_SCALE_KEYS } from "../components/widgets/config/spacing-options";
|
|
12
13
|
import { PHI_GRID_COLUMN_COUNTS, isPhiGridColumnCount } from "../constants/grid-columns";
|
|
13
14
|
function readInitialSlotStates(value) {
|
|
14
15
|
if (Array.isArray(value)) {
|
|
@@ -334,6 +335,7 @@ export function parsePhiCmsCarouselLayoutConfig(config) {
|
|
|
334
335
|
const loop = readCarouselFlag(config.loop, "loop");
|
|
335
336
|
const autoplayMs = readCarouselCount(config.autoplayMs, "autoplayMs", 0);
|
|
336
337
|
const lookahead = readCarouselCount(config.lookahead, "lookahead", 0);
|
|
338
|
+
const slotGap = readCarouselMember(config.slotGap, PHI_SPACING_SCALE_KEYS, "slotGap");
|
|
337
339
|
return applyPhiLayoutDefaults({
|
|
338
340
|
...readRenderableBlockConfig(config),
|
|
339
341
|
labelEnd: readPhiLayoutLabelEnd(config.labelEnd),
|
|
@@ -342,15 +344,13 @@ export function parsePhiCmsCarouselLayoutConfig(config) {
|
|
|
342
344
|
...(visibleSlots === undefined ? {} : { visibleSlots }),
|
|
343
345
|
...(windowAnchor === undefined ? {} : { windowAnchor }),
|
|
344
346
|
...(transition === undefined ? {} : { transition }),
|
|
345
|
-
// Absent means "whatever the theme does", which is why nothing is written here rather than a
|
|
346
|
-
// number this parser invented.
|
|
347
347
|
...(config.transitionDurationMs === undefined || config.transitionDurationMs === null ? {} : {
|
|
348
348
|
transitionDurationMs: clampPhiSequenceTransitionMs(config.transitionDurationMs),
|
|
349
349
|
}),
|
|
350
350
|
...(config.transitionEasing === undefined ? {} : {
|
|
351
351
|
transitionEasing: readPhiMotionEasing(config.transitionEasing, undefined),
|
|
352
352
|
}),
|
|
353
|
-
slotGap:
|
|
353
|
+
...(slotGap === undefined ? {} : { slotGap }),
|
|
354
354
|
...(controls === undefined ? {} : { controls }),
|
|
355
355
|
...(loop === undefined ? {} : { loop }),
|
|
356
356
|
// Zero is how "does not move on its own" is written, so it is the one number below the floor
|
package/types/cms-plugins.d.ts
CHANGED
|
@@ -93,7 +93,12 @@ export type PhiCmsConfigFieldChoicePresentation = "select" | "segmented" | "tabs
|
|
|
93
93
|
*/
|
|
94
94
|
export type PhiCmsConfigFieldCollectionPresentation = "inline" | "overlay" | "select";
|
|
95
95
|
export type PhiCmsConfigFieldChoiceMode = "single" | "multiple";
|
|
96
|
-
|
|
96
|
+
/**
|
|
97
|
+
* What a `choice` stores. A text or a list of texts is the rule; `number` is a closed list of numbers --
|
|
98
|
+
* a key that is a number everywhere else, in the parser, the URL and the contracts, as the Image's
|
|
99
|
+
* Variant is -- and is stored as that number rather than spelled as a text the reader has to convert.
|
|
100
|
+
*/
|
|
101
|
+
export type PhiCmsConfigFieldChoiceValueType = "string" | "string[]" | "number";
|
|
97
102
|
export type PhiCmsConfigFieldChoiceCreateBehavior = "none" | "accept-custom" | "create-record";
|
|
98
103
|
export type PhiCmsConfigFieldColorMode = "single" | "gradient" | "both";
|
|
99
104
|
export type PhiCmsConfigFieldValueStorage = "field" | "self";
|
|
@@ -135,6 +140,12 @@ export type PhiCmsConfigField = (PhiCmsConfigFieldBase & {
|
|
|
135
140
|
}) | (PhiCmsConfigFieldBase & {
|
|
136
141
|
type: "data-provider";
|
|
137
142
|
providerKind?: PhiRuntimeDataProviderKind;
|
|
143
|
+
/**
|
|
144
|
+
* The one record Provider this binding names, for a Widget that can only read one: a Gallery
|
|
145
|
+
* reads a Folder, an entry header an entry. The Inspector then offers no choice of Provider -- a list
|
|
146
|
+
* that holds a single right answer and several wrong ones -- and asks only for its parameters.
|
|
147
|
+
*/
|
|
148
|
+
providerKey?: PhiRuntimeDataProviderKey;
|
|
138
149
|
}) | (PhiCmsConfigFieldBase & {
|
|
139
150
|
type: "calendar-adapter";
|
|
140
151
|
}) | (PhiCmsConfigFieldBase & {
|
|
@@ -235,10 +246,25 @@ export type PhiCmsConfigField = (PhiCmsConfigFieldBase & {
|
|
|
235
246
|
*/
|
|
236
247
|
presentation?: "slider";
|
|
237
248
|
suffix?: string;
|
|
249
|
+
}) | (PhiCmsConfigFieldBase & {
|
|
250
|
+
type: "choice";
|
|
251
|
+
valueType: "number";
|
|
252
|
+
options: PhiControlOption<number>[];
|
|
253
|
+
emptyOption?: PhiControlOption;
|
|
254
|
+
emptyValue?: null | undefined;
|
|
255
|
+
placeholder?: string;
|
|
256
|
+
mode?: never;
|
|
257
|
+
presentation?: never;
|
|
258
|
+
optionsProvider?: never;
|
|
259
|
+
allowCustom?: never;
|
|
260
|
+
createBehavior?: never;
|
|
261
|
+
filter?: never;
|
|
262
|
+
patchOnChange?: never;
|
|
263
|
+
optionPresets?: never;
|
|
238
264
|
}) | (PhiCmsConfigFieldBase & {
|
|
239
265
|
type: "choice";
|
|
240
266
|
mode?: PhiCmsConfigFieldChoiceMode;
|
|
241
|
-
valueType?: PhiCmsConfigFieldChoiceValueType
|
|
267
|
+
valueType?: Exclude<PhiCmsConfigFieldChoiceValueType, "number">;
|
|
242
268
|
presentation?: PhiCmsConfigFieldChoicePresentation;
|
|
243
269
|
options?: PhiControlOption[];
|
|
244
270
|
optionsProvider?: PhiControlOptionsProviderConfig;
|
|
@@ -635,11 +661,12 @@ export type PhiResolvedCmsRequest = {
|
|
|
635
661
|
runtime: PhiBlockRuntime;
|
|
636
662
|
serverCapabilities: import("./server-capabilities").PhiCapabilitySnapshot | null;
|
|
637
663
|
/**
|
|
638
|
-
* The Tour the Page's route carries, untranslated, with the
|
|
639
|
-
* Translated only where the Area has a Controller to hand it to (types/tours.ts).
|
|
664
|
+
* The Tour the Page's route carries, untranslated, with the Module that owns it and the language that
|
|
665
|
+
* Module writes in. Translated only where the Area has a Controller to hand it to (types/tours.ts).
|
|
640
666
|
*/
|
|
641
667
|
pageTour?: {
|
|
642
668
|
definition: import("./tours").PhiTourDefinition;
|
|
669
|
+
ownerModuleId: PhiRuntimeModuleId;
|
|
643
670
|
sourceLocale?: string;
|
|
644
671
|
} | null;
|
|
645
672
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PhiBulletListEntry, PhiBulletListStyle } from "../components/widgets/shared/bullet-list-vocabulary";
|
|
2
2
|
import type { PhiRenderableBlockBase } from "./renderable-block";
|
|
3
|
+
import type { PhiTextSource } from "../helpers/text-source";
|
|
3
4
|
import type { PhiRuntimeConditionExpression } from "./runtime-condition";
|
|
4
5
|
import type { PhiSignalRoute, PhiSignalValue } from "./signals";
|
|
5
6
|
import type { PhiCssLength } from "./length";
|
|
@@ -71,6 +72,8 @@ export type PhiSimpleTextWidgetPlacement = PhiWidgetPlacementBase & {
|
|
|
71
72
|
tone?: PhiTextTone;
|
|
72
73
|
marks?: PhiSimpleTextMark[];
|
|
73
74
|
disabled?: boolean;
|
|
75
|
+
/** `"preset"` while the words are a Preset's (`helpers/text-source.ts`). */
|
|
76
|
+
textSource?: PhiTextSource;
|
|
74
77
|
};
|
|
75
78
|
export type PhiDescriptionWidgetPlacement = PhiWidgetPlacementBase & {
|
|
76
79
|
eyebrow?: string;
|
|
@@ -81,6 +84,8 @@ export type PhiDescriptionWidgetPlacement = PhiWidgetPlacementBase & {
|
|
|
81
84
|
asideList?: PhiBulletListStyle;
|
|
82
85
|
footer?: string;
|
|
83
86
|
tone?: PhiTextTone;
|
|
87
|
+
/** `"preset"` while the words are a Preset's (`helpers/text-source.ts`). */
|
|
88
|
+
textSource?: PhiTextSource;
|
|
84
89
|
};
|
|
85
90
|
export type PhiButtonWidgetPlacement = PhiWidgetPlacementBase & PhiControlPlacement & PhiControlBadgeConfig & {
|
|
86
91
|
action?: PhiCommonControlActionKey;
|
package/types/table-widget.d.ts
CHANGED
|
@@ -306,6 +306,8 @@ export type PhiTableWidgetPresentation = PhiControlPresentationConfig & {
|
|
|
306
306
|
borders?: boolean;
|
|
307
307
|
/** The header row; shown unless this says `false`. */
|
|
308
308
|
header?: boolean;
|
|
309
|
+
/** Whether the header row stays at the top while the rows scroll under it; on unless this says `false`. */
|
|
310
|
+
stickyHeader?: boolean;
|
|
309
311
|
footer?: PhiTableFooterConfig;
|
|
310
312
|
summary?: PhiTableSummaryConfig;
|
|
311
313
|
row?: {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a Tour is asked for: the Tour Controller of the Area, which the Tour Module mounts.
|
|
3
|
+
*
|
|
4
|
+
* Here, in the foundation, rather than in that Module: the Tour button is Core's, so any Area -- and any
|
|
5
|
+
* Module's own Page -- can place it without depending on the Tour Module. With the Module off nobody
|
|
6
|
+
* answers at this address, and the button, never told that a Tour is there, stays hidden.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PHI_TOUR_CONTROLLER_PLUGIN_KEY = "@phis/ui/modules/tour/controller";
|
|
9
|
+
export declare const PHI_TOUR_CONTROLLER_KEY = "default";
|
|
10
|
+
export declare const PHI_TOUR_CONTROLLER_ADDRESS: `controller:${string}/${string}:${string}`;
|