@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
|
@@ -3,7 +3,7 @@ import { cloneElement, isValidElement } from "react";
|
|
|
3
3
|
import { readPhiCmsRegionPageScope, resolvePhiCmsRegionPageScope } from "../../helpers/region-page-scope";
|
|
4
4
|
import { isPhiCmsWidgetContentUnpublished } from "../../helpers/cms-content-binding";
|
|
5
5
|
import { comparePhiCmsInstanceIds } from "../../types/cms-instance-id";
|
|
6
|
-
import { readPhiVisualAnchorOwner } from "../../types/
|
|
6
|
+
import { readPhiVisualAnchorOwner } from "../../types/visual-anchors";
|
|
7
7
|
import { hasPhiFlag } from "../../helpers/flags";
|
|
8
8
|
import { PhiCmsFlags } from "../../constants/phi-cms";
|
|
9
9
|
import { PhiFlexVerticalLayout } from "../layouts/phi-flex-vertical-layout";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Typography } from "antd";
|
|
4
4
|
import { usePhiConfig } from "../root/phi-config-provider";
|
|
5
|
-
import { PHI_VISUAL_ANCHOR_PART_ATTRIBUTE } from "../../types/
|
|
5
|
+
import { PHI_VISUAL_ANCHOR_PART_ATTRIBUTE } from "../../types/visual-anchors";
|
|
6
6
|
import { PhiDescriptionHint } from "./phi-description-tooltip-icon";
|
|
7
7
|
export function PhiCollectionHeaderControl({ title, description, filters, toolbar, }) {
|
|
8
8
|
const { token } = usePhiConfig();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { PHI_VISUAL_ANCHOR_PART_ATTRIBUTE } from "../../types/visual-anchors";
|
|
3
4
|
import { usePhiConfig } from "../root/phi-config-provider";
|
|
4
5
|
import { PhiCollectionHeaderControl } from "./phi-collection-header-control";
|
|
5
6
|
import { PhiCollectionLayoutControl } from "./phi-collection-layout-control";
|
|
@@ -8,7 +9,7 @@ import { PhiSkeletonControl } from "./phi-skeleton-control";
|
|
|
8
9
|
export function PhiCollectionViewControl({ title, description, filters, toolbar, panel, diagnostics, body, items, mode = "grid", gap, minColumnWidth, pagination, }) {
|
|
9
10
|
const { token } = usePhiConfig();
|
|
10
11
|
const resolvedGap = gap ?? token.paddingSM;
|
|
11
|
-
return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: token.paddingSM, width: "100%", minWidth: 0 }, children: [_jsx(PhiCollectionHeaderControl, { title: title, description: description, filters: filters, toolbar: toolbar }), panel, diagnostics, body ?? (_jsx(PhiCollectionLayoutControl, { mode: mode, gap: resolvedGap, minColumnWidth: minColumnWidth ?? 102, items: [...(items ?? [])] })), pagination ? (_jsx("div", { style: { display: "flex", justifyContent: "flex-end", width: "100%", minWidth: 0 }, children: _jsx(PhiPaginationControl, { page: pagination.page, pageSize: pagination.pageSize, total: pagination.total, simple: pagination.simple, showSizeChanger: pagination.showSizeChanger, pageSizeOptions: pagination.pageSizeOptions, size: pagination.size, onChange: (value) => pagination.onChange(value.page, value.pageSize) }) })) : null] }));
|
|
12
|
+
return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: token.paddingSM, width: "100%", minWidth: 0 }, children: [_jsx(PhiCollectionHeaderControl, { title: title, description: description, filters: filters, toolbar: toolbar }), panel, diagnostics, _jsx("div", { [PHI_VISUAL_ANCHOR_PART_ATTRIBUTE]: "items", style: { width: "100%", minWidth: 0 }, children: body ?? (_jsx(PhiCollectionLayoutControl, { mode: mode, gap: resolvedGap, minColumnWidth: minColumnWidth ?? 102, items: [...(items ?? [])] })) }), pagination ? (_jsx("div", { [PHI_VISUAL_ANCHOR_PART_ATTRIBUTE]: "pagination", style: { display: "flex", justifyContent: "flex-end", width: "100%", minWidth: 0 }, children: _jsx(PhiPaginationControl, { page: pagination.page, pageSize: pagination.pageSize, total: pagination.total, simple: pagination.simple, showSizeChanger: pagination.showSizeChanger, pageSizeOptions: pagination.pageSizeOptions, size: pagination.size, onChange: (value) => pagination.onChange(value.page, value.pageSize) }) })) : null] }));
|
|
12
13
|
}
|
|
13
14
|
export function PhiCollectionViewSkeletonControl({ mode = "grid", gap, minColumnWidth, active = true, count = 8, }) {
|
|
14
15
|
const { token } = usePhiConfig();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PhiDrawerControlProps } from "./phi-drawer-control";
|
|
2
|
-
export declare function PhiDrawerControlAdapter({ open, title, header, body, footer, closable, keyboard, mask, mountPolicy, placement, size, maxSize, resizable, push, zIndex, containerStyle, onDismiss, afterOpenChange, }: PhiDrawerControlProps): import("react").JSX.Element;
|
|
2
|
+
export declare function PhiDrawerControlAdapter({ open, title, header, body, footer, closable, keyboard, mask, mountPolicy, placement, size, maxSize, resizable, push, zIndex, containerStyle, onDismiss, afterOpenChange, panelRef, }: PhiDrawerControlProps): import("react").JSX.Element;
|
|
@@ -12,7 +12,7 @@ const subscribeHydration = () => () => undefined;
|
|
|
12
12
|
const PHI_DRAWER_HEADER_MIN_BLOCK_SIZE = `calc(var(--ant-control-height) + ${PHI_SPACE.xs} + ${PHI_SPACE.xs})`;
|
|
13
13
|
/** Where a title starts when the close button stands before it: past the button, not beneath it. */
|
|
14
14
|
const PHI_DRAWER_TITLE_AFTER_CLOSE = `calc(${PHI_SPACE.sm} + var(--ant-control-height) + ${PHI_SPACE.xs})`;
|
|
15
|
-
export function PhiDrawerControlAdapter({ open, title, header, body, footer, closable = true, keyboard = true, mask = PHI_OVERLAY_DEFAULT_MASK, mountPolicy = "remount", placement = "right", size, maxSize, resizable = false, push = false, zIndex, containerStyle, onDismiss, afterOpenChange, }) {
|
|
15
|
+
export function PhiDrawerControlAdapter({ open, title, header, body, footer, closable = true, keyboard = true, mask = PHI_OVERLAY_DEFAULT_MASK, mountPolicy = "remount", placement = "right", size, maxSize, resizable = false, push = false, zIndex, containerStyle, onDismiss, afterOpenChange, panelRef, }) {
|
|
16
16
|
const hydrated = useSyncExternalStore(subscribeHydration, () => true, () => false);
|
|
17
17
|
const resolvedMask = resolvePhiOverlayMaskPresentation(mask);
|
|
18
18
|
const closeAtInlineStart = placement === "right";
|
|
@@ -71,5 +71,5 @@ export function PhiDrawerControlAdapter({ open, title, header, body, footer, clo
|
|
|
71
71
|
background: "transparent",
|
|
72
72
|
},
|
|
73
73
|
footer: { flex: "0 0 auto", padding: 0, background: "transparent" },
|
|
74
|
-
}, onClose: (event) => onDismiss?.(resolvePhiOverlayDismissSource(event)), afterOpenChange: afterOpenChange, drawerRender: (node) => (_jsx("div", { style: { display: "flex", flexDirection: "column", blockSize: "100%", minBlockSize: 0 }, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: node })), children: _jsx("div", { "data-phi-drawer-body-content": "true", style: { display: "contents" }, children: body }) }));
|
|
74
|
+
}, onClose: (event) => onDismiss?.(resolvePhiOverlayDismissSource(event)), afterOpenChange: afterOpenChange, drawerRender: (node) => (_jsx("div", { ref: panelRef, style: { display: "flex", flexDirection: "column", blockSize: "100%", minBlockSize: 0 }, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: node })), children: _jsx("div", { "data-phi-drawer-body-content": "true", style: { display: "contents" }, children: body }) }));
|
|
75
75
|
}
|
|
@@ -32,6 +32,11 @@ export type PhiImageControlProps = {
|
|
|
32
32
|
loading?: "eager" | "lazy";
|
|
33
33
|
/** Opens the picture larger over the page when clicked. */
|
|
34
34
|
preview?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Scales the picture to the viewport over the page when clicked, with nothing around it; another click
|
|
37
|
+
* closes it. The plain counterpart of `preview`, which brings the lightbox's tools.
|
|
38
|
+
*/
|
|
39
|
+
zoom?: boolean;
|
|
35
40
|
/** The box around the picture: size, corners, mask. */
|
|
36
41
|
style?: CSSProperties;
|
|
37
42
|
/** Added to the picture's own style after the framing. */
|
|
@@ -49,4 +54,4 @@ export type PhiImageControlProps = {
|
|
|
49
54
|
*
|
|
50
55
|
* `preview` hands the picture to `PhiLightboxImageControl`, the one place the lightbox lives.
|
|
51
56
|
*/
|
|
52
|
-
export declare function PhiImageControl({ presentation, source, alt, title, width, height, blurDataUrl, optimizable, sizes, preload, loading, preview, style, imageStyle, }: PhiImageControlProps): import("react").JSX.Element | null;
|
|
57
|
+
export declare function PhiImageControl({ presentation, source, alt, title, width, height, blurDataUrl, optimizable, sizes, preload, loading, preview, zoom, style, imageStyle, }: PhiImageControlProps): import("react").JSX.Element | null;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import NextImage from "next/image";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { PhiLightboxImageControl } from "./phi-lightbox-image-control";
|
|
6
|
+
import { PhiZoomImageOverlay } from "./phi-zoom-image-overlay";
|
|
6
7
|
function toCssSize(value) {
|
|
7
8
|
if (typeof value === "number" && Number.isFinite(value))
|
|
8
9
|
return `${value}px`;
|
|
@@ -22,8 +23,9 @@ function toCssSize(value) {
|
|
|
22
23
|
*
|
|
23
24
|
* `preview` hands the picture to `PhiLightboxImageControl`, the one place the lightbox lives.
|
|
24
25
|
*/
|
|
25
|
-
export function PhiImageControl({ presentation, source, alt, title, width, height, blurDataUrl, optimizable = false, sizes, preload = false, loading, preview = false, style, imageStyle, }) {
|
|
26
|
+
export function PhiImageControl({ presentation, source, alt, title, width, height, blurDataUrl, optimizable = false, sizes, preload = false, loading, preview = false, zoom = false, style, imageStyle, }) {
|
|
26
27
|
const [loadedUrl, setLoadedUrl] = useState(null);
|
|
28
|
+
const [zoomed, setZoomed] = useState(false);
|
|
27
29
|
const url = presentation.url;
|
|
28
30
|
if (!url) {
|
|
29
31
|
return null;
|
|
@@ -40,8 +42,25 @@ export function PhiImageControl({ presentation, source, alt, title, width, heigh
|
|
|
40
42
|
lineHeight: 0,
|
|
41
43
|
overflow: presentation.simulatedCropStyle ? "hidden" : undefined,
|
|
42
44
|
...(loaded || blur ? {} : { backgroundColor: "var(--ant-color-fill-quaternary)" }),
|
|
45
|
+
...(zoom ? { cursor: "zoom-in" } : {}),
|
|
43
46
|
...style,
|
|
44
47
|
};
|
|
48
|
+
// The box is what is clicked: the picture itself may be `next/image`, which hands out no handler of ours.
|
|
49
|
+
const zoomTrigger = zoom
|
|
50
|
+
? {
|
|
51
|
+
role: "button",
|
|
52
|
+
tabIndex: 0,
|
|
53
|
+
"aria-label": alt || title,
|
|
54
|
+
onClick: () => setZoomed(true),
|
|
55
|
+
onKeyDown: (event) => {
|
|
56
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
57
|
+
return;
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
setZoomed(true);
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
: {};
|
|
63
|
+
const zoomOverlay = zoom ? (_jsx(PhiZoomImageOverlay, { open: zoomed, src: url, alt: alt, title: title, onClose: () => setZoomed(false) })) : null;
|
|
45
64
|
const pictureStyle = {
|
|
46
65
|
objectFit: presentation.fit,
|
|
47
66
|
objectPosition: presentation.objectPosition,
|
|
@@ -63,7 +82,7 @@ export function PhiImageControl({ presentation, source, alt, title, width, heigh
|
|
|
63
82
|
return (_jsx("div", { style: boxStyle, children: _jsx(PhiLightboxImageControl, { alt: alt, src: url, title: title, width: numericWidth, height: numericHeight, style: pictureStyle }) }));
|
|
64
83
|
}
|
|
65
84
|
if (source !== "url" && numericWidth != null && numericHeight != null) {
|
|
66
|
-
return (
|
|
85
|
+
return (_jsxs("div", { style: boxStyle, ...zoomTrigger, children: [_jsx(NextImage, { alt: alt, src: url, title: title, width: numericWidth, height: numericHeight, sizes: sizes?.trim() || undefined, unoptimized: !optimizable, placeholder: blur ? "blur" : undefined, blurDataURL: blur ?? undefined, preload: preload, loading: loading, onLoad: markLoaded, style: pictureStyle }), zoomOverlay] }));
|
|
67
86
|
}
|
|
68
|
-
return (
|
|
87
|
+
return (_jsxs("div", { style: boxStyle, ...zoomTrigger, children: [_jsx("img", { alt: alt, src: url, title: title, width: numericWidth, height: numericHeight, loading: loading ?? (preload ? "eager" : "lazy"), ref: noticeLoaded, onLoad: markLoaded, style: pictureStyle }), zoomOverlay] }));
|
|
69
88
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/*
|
|
4
|
+
* Ant Design's Image, behind `PhiLightboxImageControl`, which loads this file where a picture is drawn
|
|
5
|
+
* with its lightbox. The primitive brings its preview -- the overlay, the toolbar, zoom and rotation --
|
|
6
|
+
* whether or not a page shows one, so every page that draws a card or a picture would carry it.
|
|
7
|
+
*/
|
|
8
|
+
import { Image } from "antd";
|
|
9
|
+
export function PhiLightboxImageControlAdapter({ src, alt, title, width, height, style }) {
|
|
10
|
+
return _jsx(Image, { alt: alt, src: src, title: title, width: width, height: height, style: style, preview: true });
|
|
11
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
2
|
export type PhiLightboxImageControlProps = {
|
|
3
3
|
src: string;
|
|
4
4
|
alt: string;
|
|
@@ -12,5 +12,6 @@ export type PhiLightboxImageControlProps = {
|
|
|
12
12
|
*
|
|
13
13
|
* Only for that: an image that is just shown is an `<img>` or `next/image` in the Widget that places it.
|
|
14
14
|
* The lightbox is what needs a primitive -- the overlay, the zoom, the close -- and so it is a Control.
|
|
15
|
+
* Until the primitive has loaded, the picture stands there plainly, at the same size.
|
|
15
16
|
*/
|
|
16
|
-
export declare function PhiLightboxImageControl(
|
|
17
|
+
export declare function PhiLightboxImageControl(props: PhiLightboxImageControlProps): import("react").JSX.Element;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { lazy, Suspense } from "react";
|
|
4
|
+
const PhiLightboxImageControlAdapter = lazy(() => import("./phi-lightbox-image-control-adapter")
|
|
5
|
+
.then((module) => ({ default: module.PhiLightboxImageControlAdapter })));
|
|
4
6
|
/**
|
|
5
7
|
* An image that opens larger over the page when clicked.
|
|
6
8
|
*
|
|
7
9
|
* Only for that: an image that is just shown is an `<img>` or `next/image` in the Widget that places it.
|
|
8
10
|
* The lightbox is what needs a primitive -- the overlay, the zoom, the close -- and so it is a Control.
|
|
11
|
+
* Until the primitive has loaded, the picture stands there plainly, at the same size.
|
|
9
12
|
*/
|
|
10
|
-
export function PhiLightboxImageControl(
|
|
11
|
-
|
|
13
|
+
export function PhiLightboxImageControl(props) {
|
|
14
|
+
const { src, alt, title, width, height, style } = props;
|
|
15
|
+
return (_jsx(Suspense, { fallback: _jsx("img", { alt: alt, src: src, title: title, width: width, height: height, style: style }), children: _jsx(PhiLightboxImageControlAdapter, { ...props }) }));
|
|
12
16
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PhiModalControlProps } from "./phi-modal-control";
|
|
2
|
-
export declare function PhiModalControlAdapter({ open, title, header, body, footer, closable, keyboard, mask, mountPolicy, centered, controlSize, size, width, rootClassName, containerStyle, onDismiss, afterOpenChange, }: PhiModalControlProps): import("react").JSX.Element;
|
|
2
|
+
export declare function PhiModalControlAdapter({ open, title, header, body, footer, closable, keyboard, mask, mountPolicy, centered, controlSize, size, width, rootClassName, containerStyle, onDismiss, afterOpenChange, panelRef, }: PhiModalControlProps): import("react").JSX.Element;
|
|
@@ -56,7 +56,7 @@ const PHI_MODAL_TAB_STOP_SELECTOR = [
|
|
|
56
56
|
/** About a second: a Form that loads its descriptor late still gets the focus, a slower one does not. */
|
|
57
57
|
const PHI_MODAL_FIRST_FIELD_MAX_FRAMES = 60;
|
|
58
58
|
const PHI_MODAL_HEADER_MIN_BLOCK_SIZE = `calc(${PHI_CONTROL.md} + ${PHI_SPACE.xs} + ${PHI_SPACE.xs})`;
|
|
59
|
-
export function PhiModalControlAdapter({ open, title, header, body, footer, closable = true, keyboard = true, mask = PHI_OVERLAY_DEFAULT_MASK, mountPolicy = "remount", centered = false, controlSize, size, width, rootClassName, containerStyle, onDismiss, afterOpenChange, }) {
|
|
59
|
+
export function PhiModalControlAdapter({ open, title, header, body, footer, closable = true, keyboard = true, mask = PHI_OVERLAY_DEFAULT_MASK, mountPolicy = "remount", centered = false, controlSize, size, width, rootClassName, containerStyle, onDismiss, afterOpenChange, panelRef, }) {
|
|
60
60
|
const { token } = usePhiConfig();
|
|
61
61
|
const hydrated = useSyncExternalStore(subscribeHydration, () => true, () => false);
|
|
62
62
|
const mode = useSyncExternalStore(subscribeModalMode, readModalMode, readServerModalMode);
|
|
@@ -205,7 +205,10 @@ export function PhiModalControlAdapter({ open, title, header, body, footer, clos
|
|
|
205
205
|
padding: 0,
|
|
206
206
|
background: "transparent",
|
|
207
207
|
},
|
|
208
|
-
}, onCancel: (event) => onDismiss?.(resolvePhiOverlayDismissSource(event)), afterOpenChange: afterOpenChange, modalRender: (node) => (_jsxs("div", { ref:
|
|
208
|
+
}, onCancel: (event) => onDismiss?.(resolvePhiOverlayDismissSource(event)), afterOpenChange: afterOpenChange, modalRender: (node) => (_jsxs("div", { ref: (element) => {
|
|
209
|
+
dialogRef.current = element;
|
|
210
|
+
panelRef?.(element);
|
|
211
|
+
}, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: [node, _jsx("span", { tabIndex: 0, "data-phi-modal-focus-wrap": "true", style: { position: "fixed", inlineSize: 0, blockSize: 0, overflow: "hidden" }, onFocus: (event) => {
|
|
209
212
|
const dialog = dialogRef.current;
|
|
210
213
|
if (dialog == null)
|
|
211
214
|
return;
|
|
@@ -19,6 +19,11 @@ export type PhiOverlayControlCommonProps = {
|
|
|
19
19
|
containerStyle?: CSSProperties;
|
|
20
20
|
onDismiss?: (source: PhiOverlayCloseSource) => void;
|
|
21
21
|
afterOpenChange?: (open: boolean) => void;
|
|
22
|
+
/**
|
|
23
|
+
* The element the Overlay is drawn as, handed out while it is mounted -- what a Tour points at when it
|
|
24
|
+
* names the Overlay (design/TOURS.md, Visual-anchor registration). Never an Ant Design ref.
|
|
25
|
+
*/
|
|
26
|
+
panelRef?: (element: HTMLElement | null) => void;
|
|
22
27
|
};
|
|
23
28
|
export declare const PHI_OVERLAY_DEFAULT_MASK: {
|
|
24
29
|
readonly appearance: "normal";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { PhiPaginationControlProps } from "./phi-pagination-control";
|
|
2
|
+
export declare function PhiPaginationControlAdapter({ page, pageSize, total, disabled, readOnly, simple, showSizeChanger, pageSizeOptions, size, getPopupContainer, popupRootClassName, onPopupOpenChange, onChange, }: PhiPaginationControlProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/*
|
|
4
|
+
* Ant Design's Pagination, behind `PhiPaginationControl`, which loads this file where a list is drawn
|
|
5
|
+
* page by page. A Collection that shows everything at once -- a Dashboard's cards, a short Entry list --
|
|
6
|
+
* would otherwise carry the pager, its size changer and its Select all the same.
|
|
7
|
+
*/
|
|
8
|
+
import { Pagination } from "antd";
|
|
9
|
+
export function PhiPaginationControlAdapter({ page, pageSize, total, disabled = false, readOnly = false, simple, showSizeChanger, pageSizeOptions, size, getPopupContainer, popupRootClassName, onPopupOpenChange, onChange, }) {
|
|
10
|
+
return (_jsx(Pagination, { current: page, pageSize: pageSize, total: total, disabled: disabled || readOnly, simple: simple, size: size, pageSizeOptions: pageSizeOptions ? [...pageSizeOptions] : undefined, showSizeChanger: showSizeChanger ? {
|
|
11
|
+
getPopupContainer,
|
|
12
|
+
classNames: popupRootClassName ? { popup: { root: popupRootClassName } } : undefined,
|
|
13
|
+
onOpenChange: onPopupOpenChange,
|
|
14
|
+
} : false, onChange: (nextPage, nextPageSize) => onChange?.({ page: nextPage, pageSize: nextPageSize, total }) }));
|
|
15
|
+
}
|
|
@@ -22,4 +22,5 @@ export type PhiPaginationControlProps = PhiPaginationControlValue & {
|
|
|
22
22
|
onPopupOpenChange?: (open: boolean) => void;
|
|
23
23
|
onChange?: (value: PhiPaginationControlValue) => void;
|
|
24
24
|
};
|
|
25
|
-
|
|
25
|
+
/** The pager. Until the primitive has loaded, its row is held at the height it will take. */
|
|
26
|
+
export declare function PhiPaginationControl(props: PhiPaginationControlProps): import("react").JSX.Element;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
import { lazy, Suspense } from "react";
|
|
4
|
+
import { usePhiConfig } from "../root/phi-config-provider";
|
|
5
|
+
const PhiPaginationControlAdapter = lazy(() => import("./phi-pagination-control-adapter")
|
|
6
|
+
.then((module) => ({ default: module.PhiPaginationControlAdapter })));
|
|
7
|
+
/** The pager. Until the primitive has loaded, its row is held at the height it will take. */
|
|
8
|
+
export function PhiPaginationControl(props) {
|
|
9
|
+
const { token } = usePhiConfig();
|
|
10
|
+
const height = props.size === "small"
|
|
11
|
+
? token.controlHeightSM
|
|
12
|
+
: props.size === "large" ? token.controlHeightLG : token.controlHeight;
|
|
13
|
+
return (_jsx(Suspense, { fallback: _jsx("div", { style: { minHeight: height } }), children: _jsx(PhiPaginationControlAdapter, { ...props }) }));
|
|
10
14
|
}
|
|
@@ -122,6 +122,11 @@ export type PhiTableControlProps<TRow extends Record<string, unknown>> = {
|
|
|
122
122
|
bordered?: boolean;
|
|
123
123
|
striped?: boolean;
|
|
124
124
|
showHeader?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* The header row stays at the top while the rows scroll under it: under the Shell's Header on a page,
|
|
127
|
+
* at the top edge of a Modal's or Drawer's body. `styles/controls.css` places it.
|
|
128
|
+
*/
|
|
129
|
+
stickyHeader?: boolean;
|
|
125
130
|
footer?: PhiTableControlFooter;
|
|
126
131
|
summary?: PhiTableControlSummary;
|
|
127
132
|
size?: PhiControlSize;
|
|
@@ -141,4 +146,4 @@ export type PhiTableControlProps<TRow extends Record<string, unknown>> = {
|
|
|
141
146
|
onExternalDrop?: (event: DragEvent<HTMLDivElement>) => void;
|
|
142
147
|
};
|
|
143
148
|
export declare function readPhiTableControlValue(row: Record<string, unknown>, path: string): unknown;
|
|
144
|
-
export declare function PhiTableControl<TRow extends Record<string, unknown>>({ rows, rowIdentityPath, columns, columnOrder, sortingMode, sorts, onSortsChange, columnReordering, onColumnOrderChange, rowSelection, pagination, tree, rowReordering, editing, loading, bordered, striped, showHeader, footer, summary, size, emptyText, layout, rowStyle, onRowActivate, onExternalRowDragOver, onExternalRowDrop, onExternalDragOver, onExternalDrop, }: PhiTableControlProps<TRow>): import("react").JSX.Element;
|
|
149
|
+
export declare function PhiTableControl<TRow extends Record<string, unknown>>({ rows, rowIdentityPath, columns, columnOrder, sortingMode, sorts, onSortsChange, columnReordering, onColumnOrderChange, rowSelection, pagination, tree, rowReordering, editing, loading, bordered, striped, stickyHeader, showHeader, footer, summary, size, emptyText, layout, rowStyle, onRowActivate, onExternalRowDragOver, onExternalRowDrop, onExternalDragOver, onExternalDrop, }: PhiTableControlProps<TRow>): import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { usePhiShellStickyTop } from "../shell/use-phi-shell-sticky-top";
|
|
3
4
|
import { Button, Flex, Table } from "antd";
|
|
4
5
|
import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from "@dnd-kit/core";
|
|
5
6
|
import { SortableContext, sortableKeyboardCoordinates, useSortable, } from "@dnd-kit/sortable";
|
|
@@ -7,7 +8,7 @@ import { CSS } from "@dnd-kit/utilities";
|
|
|
7
8
|
import { flushSync } from "react-dom";
|
|
8
9
|
import { Children, cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
9
10
|
import { PHI_GREGORY_CALENDAR_ADAPTER_KEY } from "../../types/calendar-keys";
|
|
10
|
-
import { PHI_VISUAL_ANCHOR_PART_ATTRIBUTE } from "../../types/
|
|
11
|
+
import { PHI_VISUAL_ANCHOR_PART_ATTRIBUTE } from "../../types/visual-anchors";
|
|
11
12
|
import { PhiColorControl } from "./phi-color-control";
|
|
12
13
|
import { PhiCheckboxControl } from "./phi-checkbox-control";
|
|
13
14
|
import { PhiCheckboxGroupControl } from "./phi-checkbox-group-control";
|
|
@@ -354,7 +355,7 @@ function buildRowMove(rows, rowIdentityPath, parentRowIdentityPath, movedRowIden
|
|
|
354
355
|
afterRowIdentity: placement === "after" ? targetRowIdentity : null,
|
|
355
356
|
};
|
|
356
357
|
}
|
|
357
|
-
export function PhiTableControl({ rows, rowIdentityPath, columns, columnOrder, sortingMode, sorts, onSortsChange, columnReordering = false, onColumnOrderChange, rowSelection, pagination = false, tree, rowReordering, editing, loading = false, bordered, striped = false, showHeader, footer, summary, size, emptyText, layout, rowStyle, onRowActivate, onExternalRowDragOver, onExternalRowDrop, onExternalDragOver, onExternalDrop, }) {
|
|
358
|
+
export function PhiTableControl({ rows, rowIdentityPath, columns, columnOrder, sortingMode, sorts, onSortsChange, columnReordering = false, onColumnOrderChange, rowSelection, pagination = false, tree, rowReordering, editing, loading = false, bordered, striped = false, stickyHeader = false, showHeader, footer, summary, size, emptyText, layout, rowStyle, onRowActivate, onExternalRowDragOver, onExternalRowDrop, onExternalDragOver, onExternalDrop, }) {
|
|
358
359
|
const { token } = usePhiConfig();
|
|
359
360
|
const [editingRowIdentityState, setEditingRowIdentity] = useState(null);
|
|
360
361
|
const [rowEditPatch, setRowEditPatch] = useState({});
|
|
@@ -988,6 +989,8 @@ export function PhiTableControl({ rows, rowIdentityPath, columns, columnOrder, s
|
|
|
988
989
|
const hasClosingBlock = !loading &&
|
|
989
990
|
(Boolean(footer) || (summary != null && summary.placement !== "sticky-top"));
|
|
990
991
|
const frameRef = useRef(null);
|
|
992
|
+
// Where the Shell's Header ends, which is where a sticky header row stops (`styles/controls.css`).
|
|
993
|
+
usePhiShellStickyTop({ active: stickyHeader && showHeader !== false, elementRef: frameRef });
|
|
991
994
|
const [headerBox, setHeaderBox] = useState(null);
|
|
992
995
|
useEffect(() => {
|
|
993
996
|
const frame = frameRef.current;
|
|
@@ -1007,11 +1010,15 @@ export function PhiTableControl({ rows, rowIdentityPath, columns, columnOrder, s
|
|
|
1007
1010
|
observer.observe(frame);
|
|
1008
1011
|
return () => observer.disconnect();
|
|
1009
1012
|
}, [showHeader, loading]);
|
|
1010
|
-
const table = (_jsx(Table, { className: [
|
|
1013
|
+
const table = (_jsx(Table, { className: [
|
|
1014
|
+
"phi-table-control",
|
|
1015
|
+
hasClosingBlock ? "phi-table-control--closing-block" : null,
|
|
1016
|
+
stickyHeader && showHeader !== false ? "phi-table-control--sticky-header" : null,
|
|
1017
|
+
]
|
|
1011
1018
|
.filter(Boolean)
|
|
1012
1019
|
.join(" "), style: { "--phi-table-striped-row-background": token.colorFillAlter }, rowKey: (row) => loading
|
|
1013
1020
|
? `__phi_table_loading_${String(row[PHI_TABLE_LOADING_ROW])}`
|
|
1014
|
-
: String(readIdentity(row, rowIdentityPath)), columns: renderedColumns, dataSource: loading ? loadingRows : dataSource, bordered: bordered, showHeader: showHeader, tableLayout: layout.mode, size: size, rowClassName: (_row, index) => striped && index % 2 === 1 ? "phi-table-control__row--striped" : "", rowSelection: loading ? undefined : antdRowSelection, components: rowReordering?.enabled && !loading ? { body: { row: PhiTableSortableRow } } : undefined, scroll: layout.overflowX === "auto" ? { x: true } : undefined, pagination: pagination === false ? false : {
|
|
1021
|
+
: String(readIdentity(row, rowIdentityPath)), columns: renderedColumns, dataSource: loading ? loadingRows : dataSource, bordered: bordered, showHeader: showHeader, tableLayout: layout.mode, size: size, rowClassName: (_row, index) => striped && index % 2 === 1 ? "phi-table-control__row--striped" : "", rowSelection: loading ? undefined : antdRowSelection, components: rowReordering?.enabled && !loading ? { body: { row: PhiTableSortableRow } } : undefined, scroll: layout.overflowX === "auto" ? { x: true } : undefined, sticky: stickyHeader && showHeader !== false ? true : undefined, pagination: pagination === false ? false : {
|
|
1015
1022
|
...{ [PHI_VISUAL_ANCHOR_PART_ATTRIBUTE]: "pagination" },
|
|
1016
1023
|
current: pagination.page,
|
|
1017
1024
|
pageSize: pagination.pageSize,
|
|
@@ -1097,7 +1104,12 @@ export function PhiTableControl({ rows, rowIdentityPath, columns, columnOrder, s
|
|
|
1097
1104
|
insertionGapIndex,
|
|
1098
1105
|
insertionGapHeight: activeDragRowHeight,
|
|
1099
1106
|
}, children: table }) }) })) : table;
|
|
1100
|
-
|
|
1107
|
+
/*
|
|
1108
|
+
* Clipped, not hidden: `hidden` makes the frame a scroll container, and a sticky header row then sticks
|
|
1109
|
+
* to the frame's own top -- pushed down inside the Table by the Shell's Header height -- instead of to
|
|
1110
|
+
* the page. `clip` cuts off the same overflow and leaves the page the one that scrolls.
|
|
1111
|
+
*/
|
|
1112
|
+
const constrainedTable = (_jsxs("div", { ref: frameRef, style: { position: "relative", width: "100%", maxWidth: "100%", minWidth: 0, overflow: "clip" }, children: [renderedTable, headerBox ? (_jsx("div", { "aria-hidden": true, [PHI_VISUAL_ANCHOR_PART_ATTRIBUTE]: "header", style: { position: "absolute", left: 0, right: 0, top: headerBox.top, height: headerBox.height, pointerEvents: "none" } })) : null] }));
|
|
1101
1113
|
return onExternalDragOver || onExternalDrop ? (_jsx("div", { onDragOver: (event) => {
|
|
1102
1114
|
if (event.defaultPrevented) {
|
|
1103
1115
|
setExternalAppendActive(false);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/*
|
|
4
|
+
* Ant Design's Timeline, behind `PhiTimelineControl`, which loads this file where a Timeline is drawn.
|
|
5
|
+
*/
|
|
6
|
+
import { Timeline } from "antd";
|
|
7
|
+
import { PHI_COLOR } from "../../theme/antd-css-var-contract";
|
|
8
|
+
import { PhiIcon } from "../shell/phi-icon";
|
|
9
|
+
/*
|
|
10
|
+
* Ant Design colours four marks by name and takes anything else as a CSS colour. The Theme's own tokens
|
|
11
|
+
* go in as that colour, so a tone follows the Theme the way a text tone does.
|
|
12
|
+
*/
|
|
13
|
+
const PHI_TIMELINE_TONE_COLOR = {
|
|
14
|
+
secondary: PHI_COLOR.textTertiary,
|
|
15
|
+
success: PHI_COLOR.success,
|
|
16
|
+
warning: PHI_COLOR.warning,
|
|
17
|
+
danger: PHI_COLOR.error,
|
|
18
|
+
};
|
|
19
|
+
export function PhiTimelineControlAdapter({ items, placement = "start", ariaLabel, }) {
|
|
20
|
+
return (_jsx(Timeline, { "aria-label": ariaLabel, mode: placement, items: items.map((item) => ({
|
|
21
|
+
key: item.key,
|
|
22
|
+
title: item.title && item.time ? `${item.time} · ${item.title}` : item.title ?? item.time,
|
|
23
|
+
content: item.content,
|
|
24
|
+
icon: item.icon ? _jsx(PhiIcon, { name: item.icon, size: "inherit" }) : undefined,
|
|
25
|
+
color: item.tone ? PHI_TIMELINE_TONE_COLOR[item.tone] : undefined,
|
|
26
|
+
loading: item.pending,
|
|
27
|
+
})) }));
|
|
28
|
+
}
|
|
@@ -28,5 +28,7 @@ export type PhiTimelineControlProps = {
|
|
|
28
28
|
* a Timeline here is a record a Widget stores or a Module reads, so its entries are words and tones.
|
|
29
29
|
* The time stands in Ant Design's title column when the entry has no title of its own, and in front of
|
|
30
30
|
* the title otherwise -- one column, so that `alternate` still has a side to put it on.
|
|
31
|
+
*
|
|
32
|
+
* Until the primitive has loaded, the entries stand there as a plain list, in the same words.
|
|
31
33
|
*/
|
|
32
|
-
export declare function PhiTimelineControl(
|
|
34
|
+
export declare function PhiTimelineControl(props: PhiTimelineControlProps): import("react").JSX.Element;
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
* Ant Design colours four marks by name and takes anything else as a CSS colour. The Theme's own tokens
|
|
8
|
-
* go in as that colour, so a tone follows the Theme the way a text tone does.
|
|
9
|
-
*/
|
|
10
|
-
const PHI_TIMELINE_TONE_COLOR = {
|
|
11
|
-
secondary: PHI_COLOR.textTertiary,
|
|
12
|
-
success: PHI_COLOR.success,
|
|
13
|
-
warning: PHI_COLOR.warning,
|
|
14
|
-
danger: PHI_COLOR.error,
|
|
15
|
-
};
|
|
3
|
+
import { lazy, Suspense } from "react";
|
|
4
|
+
const PhiTimelineControlAdapter = lazy(() => import("./phi-timeline-control-adapter")
|
|
5
|
+
.then((module) => ({ default: module.PhiTimelineControlAdapter })));
|
|
16
6
|
/**
|
|
17
7
|
* What happened, in order: a ticket's history, the revisions of a Page, the stages of an order.
|
|
18
8
|
*
|
|
@@ -20,14 +10,10 @@ const PHI_TIMELINE_TONE_COLOR = {
|
|
|
20
10
|
* a Timeline here is a record a Widget stores or a Module reads, so its entries are words and tones.
|
|
21
11
|
* The time stands in Ant Design's title column when the entry has no title of its own, and in front of
|
|
22
12
|
* the title otherwise -- one column, so that `alternate` still has a side to put it on.
|
|
13
|
+
*
|
|
14
|
+
* Until the primitive has loaded, the entries stand there as a plain list, in the same words.
|
|
23
15
|
*/
|
|
24
|
-
export function PhiTimelineControl(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
title: item.title && item.time ? `${item.time} · ${item.title}` : item.title ?? item.time,
|
|
28
|
-
content: item.content,
|
|
29
|
-
icon: item.icon ? _jsx(PhiIcon, { name: item.icon, size: "inherit" }) : undefined,
|
|
30
|
-
color: item.tone ? PHI_TIMELINE_TONE_COLOR[item.tone] : undefined,
|
|
31
|
-
loading: item.pending,
|
|
32
|
-
})) }));
|
|
16
|
+
export function PhiTimelineControl(props) {
|
|
17
|
+
const fallback = (_jsx("ol", { "aria-label": props.ariaLabel, style: { listStyle: "none", margin: 0, padding: 0 }, children: props.items.map((item) => (_jsx("li", { children: [item.time, item.title, item.content].filter(Boolean).join(" · ") }, item.key))) }));
|
|
18
|
+
return (_jsx(Suspense, { fallback: fallback, children: _jsx(PhiTimelineControlAdapter, { ...props }) }));
|
|
33
19
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useMemo } from "react";
|
|
3
|
+
import { useEffect, useMemo } from "react";
|
|
4
4
|
import { Tour } from "antd";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
5
|
+
import { PhiCompactGroupControl } from "./phi-compact-group-control";
|
|
6
|
+
import { bringPhiTourTargetIntoView, resolvePhiTourScrollBehavior, resolvePhiTourScrollBlock, } from "./phi-tour-viewport";
|
|
8
7
|
/**
|
|
9
8
|
* A guided Tour's presentation, and the only place Ant Design `Tour` is used.
|
|
10
9
|
*
|
|
@@ -22,8 +21,27 @@ export function PhiTourControl({ open, current, steps, labels, mask = true, disa
|
|
|
22
21
|
// Ant Design types the getter as one that always finds its element; a target can leave mid-step.
|
|
23
22
|
target: (step.target ?? null),
|
|
24
23
|
placement: step.target ? step.placement : undefined,
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// Ant Design spaces the two buttons apart; joined, the seam between them is drawn once instead.
|
|
25
|
+
prevButtonProps: { children: labels.previous, style: { marginInlineStart: 0 } },
|
|
26
|
+
nextButtonProps: { children: index === steps.length - 1 ? labels.finish : labels.next, style: { marginInlineStart: 0 } },
|
|
27
27
|
})), [labels.finish, labels.next, labels.previous, steps]);
|
|
28
|
-
|
|
28
|
+
/*
|
|
29
|
+
* The shown step scrolls the way its Controller already brought it in (`phi-tour-viewport.ts`): Ant
|
|
30
|
+
* Design scrolls again whenever the target is not wholly inside the window, which a tall one never is,
|
|
31
|
+
* and the same alignment under the same scroll padding lands where the target already stands.
|
|
32
|
+
*/
|
|
33
|
+
const shownTarget = open ? steps[current]?.target?.() ?? null : null;
|
|
34
|
+
const shownSteps = shownTarget
|
|
35
|
+
? tourSteps.map((step, index) => index === current
|
|
36
|
+
? { ...step, scrollIntoViewOptions: { block: resolvePhiTourScrollBlock(shownTarget), inline: "nearest", behavior: resolvePhiTourScrollBehavior() } }
|
|
37
|
+
: step)
|
|
38
|
+
: tourSteps;
|
|
39
|
+
// A target under a sticky band is inside the window, so Ant Design leaves it there; this brings it out.
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (shownTarget)
|
|
42
|
+
bringPhiTourTargetIntoView(shownTarget, resolvePhiTourScrollBehavior());
|
|
43
|
+
}, [current, shownTarget]);
|
|
44
|
+
return (_jsx(Tour, { open: open && steps.length > 0, current: current, steps: shownSteps, mask: mask, disabledInteraction: disabledInteraction, keyboard: true,
|
|
45
|
+
// Previous and Next as one bar: two steps of one way through, not two separate commands.
|
|
46
|
+
actionsRender: (actions) => _jsx(PhiCompactGroupControl, { size: "small", children: actions }), scrollIntoViewOptions: { block: "center", behavior: resolvePhiTourScrollBehavior() }, onChange: onStepChange, onClose: onClose, onFinish: onFinish }));
|
|
29
47
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a Tour step's target is brought into view: below whatever stays stuck at the top of the window.
|
|
3
|
+
*
|
|
4
|
+
* Ant Design's Tour knows neither. It scrolls only when the target is not wholly inside the window, so a
|
|
5
|
+
* target taller than the window is scrolled on every step and every scroll event -- to the middle, its
|
|
6
|
+
* top under the Header -- and a target under a sticky Header counts as seen and is not scrolled at all.
|
|
7
|
+
* So the owning Controller sets the window's scroll padding to the cover before the step is presented
|
|
8
|
+
* (design/TOURS.md, Target readiness), `PhiTourControl` hands Ant Design the alignment that fits the
|
|
9
|
+
* target, and once the step stands it brings in a target Ant Design took for seen. Every scroll then
|
|
10
|
+
* aims at the same place, and the one Ant Design repeats on every scroll event moves nothing.
|
|
11
|
+
*
|
|
12
|
+
* Not while the previous step is still shown: Ant Design scrolls back to a shown target that leaves the
|
|
13
|
+
* window, so a scroll begun before the new step is presented is undone by the old one.
|
|
14
|
+
*
|
|
15
|
+
* The cover is found from the target outwards, not by searching the document: the Shell's Header bands
|
|
16
|
+
* and a Page's sticky band are siblings of something the target stands in, so the bands are found among
|
|
17
|
+
* the earlier siblings of the target's ancestors that are stuck, sit at the top, and stand over the target.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolvePhiTourScrollBehavior(): ScrollBehavior;
|
|
20
|
+
/**
|
|
21
|
+
* Centered where the target fits below the cover, top-aligned under it where it does not: a target
|
|
22
|
+
* taller than what is left of the window is read from its top.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolvePhiTourScrollBlock(target: HTMLElement, cover?: number): Extract<ScrollLogicalPosition, "center" | "start">;
|
|
25
|
+
/**
|
|
26
|
+
* Keeps the window's scroll padding at the cover over `target`, so every `scrollIntoView` -- Ant
|
|
27
|
+
* Design's included -- aligns below it. Returns the cover.
|
|
28
|
+
*/
|
|
29
|
+
export declare function holdPhiTourViewport(target: HTMLElement): number;
|
|
30
|
+
/**
|
|
31
|
+
* Brings `target` into the part of the window nothing covers. A target already wholly in that part --
|
|
32
|
+
* or, taller than it, already standing at its top -- is left where it is. Returns whether it scrolled.
|
|
33
|
+
*/
|
|
34
|
+
export declare function bringPhiTourTargetIntoView(target: HTMLElement, behavior: ScrollBehavior): boolean;
|
|
35
|
+
/** The window's scroll padding as it was before a Tour set it. */
|
|
36
|
+
export declare function releasePhiTourViewport(): void;
|