@phis/ui 0.4.3 → 0.4.4
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/controls/phi-anchor-nav-control.js +4 -1
- package/components/controls/phi-background-control.js +21 -6
- package/components/controls/phi-bullet-list-control.d.ts +7 -2
- package/components/controls/phi-bullet-list-control.js +4 -3
- package/components/controls/phi-color-control.js +4 -2
- package/components/controls/phi-drawer-control-adapter.js +3 -2
- package/components/controls/phi-inline-text-editor.js +7 -1
- package/components/controls/phi-length-control.js +1 -1
- package/components/controls/phi-ribbon-control.d.ts +13 -4
- package/components/controls/phi-ribbon-control.js +10 -6
- package/components/controls/phi-ribbon-wrap-control.d.ts +26 -0
- package/components/controls/phi-ribbon-wrap-control.js +25 -0
- package/components/controls/phi-select-control.js +5 -2
- package/components/controls/phi-series-chart-control.d.ts +48 -0
- package/components/controls/phi-series-chart-control.js +82 -0
- package/components/controls/phi-text-control.js +57 -3
- package/components/controls/phi-tree-control.js +1 -1
- package/components/controls/phi-truncated-hover-text.d.ts +15 -0
- package/components/controls/phi-truncated-hover-text.js +25 -0
- package/components/forms/link-target-form-control.d.ts +1 -1
- package/components/forms/link-target-form-control.js +2 -45
- package/components/forms/phi-form-widget-frame.js +4 -2
- package/components/layouts/clients/phi-three-column-layout-client.js +10 -1
- package/components/navigation/phi-link.js +6 -1
- package/components/regions/clients/cms-region-container-client.js +6 -1
- package/components/regions/phi-cms-region-container.js +3 -0
- package/components/regions/phi-cms-region-shell.d.ts +12 -1
- package/components/regions/phi-cms-region-shell.js +81 -19
- package/components/root/phi-config-provider.d.ts +13 -0
- package/components/root/phi-config-provider.js +12 -1
- package/components/root/phi-root-background.d.ts +7 -0
- package/components/root/phi-root-background.js +20 -1
- package/components/root/phi-root-theme-resolver.js +3 -0
- package/components/root/phi-shell-chrome-overlay.d.ts +12 -1
- package/components/root/phi-shell-chrome-overlay.js +19 -3
- package/components/shell/phi-antd-icon.d.ts +1 -0
- package/components/shell/phi-antd-icon.js +3 -0
- package/components/shell/use-phi-shell-sticky-top.js +61 -16
- package/components/surface/phi-surface-tone.d.ts +13 -0
- package/components/surface/phi-surface-tone.js +21 -0
- package/components/widgets/client/bullet-list-entries-editor.js +7 -1
- package/components/widgets/client/html-editor.js +1 -1
- package/components/widgets/client/shared/use-page-reference-options.d.ts +17 -0
- package/components/widgets/client/shared/use-page-reference-options.js +57 -0
- package/components/widgets/config/background.d.ts +32 -1
- package/components/widgets/config/background.js +41 -2
- package/components/widgets/label-sets/background.js +2 -0
- package/components/widgets/label-types/background.d.ts +1 -0
- package/components/widgets/label-types/background.js +1 -0
- package/components/widgets/shared/bullet-list-vocabulary.d.ts +10 -0
- package/components/widgets/shared/bullet-list-vocabulary.js +5 -2
- package/components/widgets/shared/card-body-client.d.ts +5 -3
- package/components/widgets/shared/card-body-client.js +49 -6
- package/components/widgets/shared/card-vocabulary.d.ts +12 -2
- package/components/widgets/shared/card-vocabulary.js +7 -0
- package/components/widgets/shared/markdown-body-client.js +39 -10
- package/helpers/cms-container-chrome.js +6 -1
- package/helpers/locale.d.ts +8 -0
- package/helpers/locale.js +18 -0
- package/helpers/shell-region-style.js +2 -1
- package/helpers/surface-style.d.ts +12 -1
- package/helpers/surface-style.js +28 -2
- package/module-dashboard-cards.d.ts +1 -1
- package/module-dashboard-cards.js +1 -1
- package/package.json +1 -1
- package/plugins/runtime-modules/area-definitions.d.ts +0 -42
- package/plugins/runtime-modules/area-definitions.js +3 -8
- package/plugins/runtime-modules/builder/clients/inspector-config-field.js +20 -1
- package/plugins/runtime-modules/builder/clients/layout-scaffold-overlays.js +10 -5
- package/plugins/runtime-modules/builder/edit-scaffold-drawer.js +3 -2
- package/plugins/runtime-modules/builder/render-root-node-scaffold.js +25 -15
- 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 +15 -4
- package/plugins/runtime-modules/client-authoring-module.d.ts +8 -1
- package/plugins/runtime-modules/client-authoring-module.js +13 -3
- package/plugins/runtime-modules/core/widgets/brand/client.d.ts +12 -3
- package/plugins/runtime-modules/core/widgets/brand/client.js +3 -11
- package/plugins/runtime-modules/core/widgets/brand/home.d.ts +15 -0
- package/plugins/runtime-modules/core/widgets/brand/home.js +18 -0
- package/plugins/runtime-modules/core/widgets/brand/plugin.js +3 -2
- package/plugins/runtime-modules/core/widgets/brand/server.d.ts +2 -2
- package/plugins/runtime-modules/core/widgets/brand/server.js +2 -2
- package/plugins/runtime-modules/core/widgets/card/config.d.ts +6 -1
- package/plugins/runtime-modules/core/widgets/card/config.js +19 -3
- package/plugins/runtime-modules/core/widgets/card/editor.js +13 -3
- package/plugins/runtime-modules/core/widgets/card/server.js +1 -0
- package/plugins/runtime-modules/core/widgets/description/client.js +3 -3
- package/plugins/runtime-modules/core/widgets/description/config.d.ts +1 -0
- package/plugins/runtime-modules/core/widgets/description/editor.js +3 -2
- package/plugins/runtime-modules/core/widgets/description/server.js +3 -2
- package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +1 -0
- package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +1 -0
- package/plugins/runtime-modules/core/widgets/header-navigation/client.js +2 -2
- package/plugins/runtime-modules/core/widgets/html/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/markdown/config.d.ts +320 -2
- package/plugins/runtime-modules/core/widgets/markdown/config.js +18 -4
- package/plugins/runtime-modules/core/widgets/markdown/editor.js +9 -1
- package/plugins/runtime-modules/core/widgets/markdown-toc/client.js +6 -1
- package/plugins/runtime-modules/core/widgets/markdown-toc/config.d.ts +14 -0
- package/plugins/runtime-modules/core/widgets/markdown-toc/config.js +14 -2
- package/plugins/runtime-modules/core/widgets/quick-links/authoring.js +7 -2
- package/plugins/runtime-modules/core/widgets/quick-links/client.js +2 -2
- package/plugins/runtime-modules/core/widgets/quick-links/items.d.ts +0 -2
- package/plugins/runtime-modules/core/widgets/quick-links/items.js +0 -15
- package/plugins/runtime-modules/core/widgets/result/config.d.ts +1 -0
- package/plugins/runtime-modules/core/widgets/sidebar-navigation/authoring.js +1 -1
- package/plugins/runtime-modules/core/widgets/sidebar-navigation/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/simple-text/client.js +8 -3
- package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +1 -0
- package/plugins/runtime-modules/core/widgets/simple-text/editor.js +2 -2
- package/plugins/runtime-modules/core/widgets/table/config.d.ts +3 -0
- package/plugins/runtime-modules/dashboard/card-rows.d.ts +3 -1
- package/plugins/runtime-modules/dashboard/card-rows.js +30 -2
- package/plugins/runtime-modules/dashboard/clients/dashboard-card-view.js +29 -7
- package/plugins/runtime-modules/dashboard/trees/phi-default-builder-dashboard-page-tree.js +5 -40
- package/plugins/runtime-modules/theme/widgets/brand-controls/client.js +19 -15
- package/plugins/runtime-modules/theme/widgets/brand-controls/config.js +5 -9
- package/server-helpers/cms-link-targets.js +6 -0
- package/styles/controls.css +64 -2
- package/styles/layout.css +45 -2
- package/styles/shell.css +73 -0
- package/theme/phi-antd-token-resolver.js +20 -1
- package/theme/phi-theme-tokens.d.ts +1 -1
- package/theme/phi-theme-tokens.js +1 -0
- package/theme/phi-theme.d.ts +5 -0
- package/theme/phi-theme.js +21 -0
- package/theme/phi-tokens.d.ts +16 -15
- package/theme/phi-tokens.js +16 -15
- package/types/cms-plugins.d.ts +2 -0
- package/types/dashboard-cards.d.ts +39 -4
- package/types/dashboard-cards.js +6 -0
- package/types/site-theme.d.ts +10 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode, type Ref } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A hover text that says what an ellipsis cut off, and only then.
|
|
4
|
+
*
|
|
5
|
+
* Around one element that cuts its own text short (`text-overflow: ellipsis`): pointed at, the element is
|
|
6
|
+
* measured, and the whole text shows in the house tooltip when it did not fit. An element whose text fits
|
|
7
|
+
* shows nothing -- a tooltip repeating the words that stand right there is noise. The child is the element
|
|
8
|
+
* itself, not a component, so the measuring reaches the box that cuts.
|
|
9
|
+
*/
|
|
10
|
+
export declare function PhiTruncatedHoverText({ title, children, }: {
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
children: ReactElement<{
|
|
13
|
+
ref?: Ref<HTMLElement>;
|
|
14
|
+
}>;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cloneElement, lazy, Suspense, useState } from "react";
|
|
4
|
+
/* The same Tooltip `PhiHoverText` loads, and loaded the same way: only where one is drawn. */
|
|
5
|
+
const PhiLazyTooltip = lazy(() => import("antd/es/tooltip"));
|
|
6
|
+
/** Whether an element shows less than its text: cut off at its end by an ellipsis, or by its height. */
|
|
7
|
+
function isPhiElementTruncated(element) {
|
|
8
|
+
return element != null
|
|
9
|
+
&& (element.scrollWidth > element.clientWidth + 1 || element.scrollHeight > element.clientHeight + 1);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A hover text that says what an ellipsis cut off, and only then.
|
|
13
|
+
*
|
|
14
|
+
* Around one element that cuts its own text short (`text-overflow: ellipsis`): pointed at, the element is
|
|
15
|
+
* measured, and the whole text shows in the house tooltip when it did not fit. An element whose text fits
|
|
16
|
+
* shows nothing -- a tooltip repeating the words that stand right there is noise. The child is the element
|
|
17
|
+
* itself, not a component, so the measuring reaches the box that cuts.
|
|
18
|
+
*/
|
|
19
|
+
export function PhiTruncatedHoverText({ title, children, }) {
|
|
20
|
+
// A callback ref held as state: the element is read when it is pointed at, never while rendering.
|
|
21
|
+
const [element, setElement] = useState(null);
|
|
22
|
+
const [open, setOpen] = useState(false);
|
|
23
|
+
const target = cloneElement(children, { ref: setElement });
|
|
24
|
+
return (_jsx(Suspense, { fallback: children, children: _jsx(PhiLazyTooltip, { title: title, open: open, onOpenChange: (next) => setOpen(next && isPhiElementTruncated(element)), children: target }) }));
|
|
25
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ComponentType } from "react";
|
|
2
2
|
import type { PhiFormFieldProviderProps } from "./form-provider-registry";
|
|
3
3
|
/**
|
|
4
4
|
* The `link-target` field: one link, to a Page of an Area or to an address elsewhere (`FORMS.md`).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
4
3
|
import { isPhiCmsAreaKey } from "../../constants/cms-areas";
|
|
5
4
|
import { PhiLinkTargetControl } from "../widgets/client/shared/phi-link-target-control";
|
|
5
|
+
import { usePhiPageReferenceOptions } from "../widgets/client/shared/use-page-reference-options";
|
|
6
6
|
import { PHI_FORM_LINK_TARGET_LABEL_KEYS } from "./form-provider-contract";
|
|
7
7
|
const DEFAULT_LABELS = {
|
|
8
8
|
none: "None",
|
|
@@ -13,32 +13,6 @@ const DEFAULT_LABELS = {
|
|
|
13
13
|
newTab: "Open in a new tab",
|
|
14
14
|
pagesUnavailable: "The Pages could not be loaded.",
|
|
15
15
|
};
|
|
16
|
-
/*
|
|
17
|
-
* One request per Area for as long as the page lives: the create and the edit dialog offer the same
|
|
18
|
-
* Pages, and a list that changed meanwhile is a Page somebody published while this one was being written.
|
|
19
|
-
* A failed request is forgotten, so the next dialog asks again.
|
|
20
|
-
*/
|
|
21
|
-
const pageOptionsByArea = new Map();
|
|
22
|
-
function loadPageOptions(area) {
|
|
23
|
-
const cached = pageOptionsByArea.get(area);
|
|
24
|
-
if (cached)
|
|
25
|
-
return cached;
|
|
26
|
-
const request = (async () => {
|
|
27
|
-
const response = await fetch(`/api/site/page-references?area=${encodeURIComponent(area)}`, {
|
|
28
|
-
cache: "no-store",
|
|
29
|
-
credentials: "same-origin",
|
|
30
|
-
headers: { accept: "application/json" },
|
|
31
|
-
});
|
|
32
|
-
const payload = (await response.json().catch(() => null));
|
|
33
|
-
if (!response.ok || !Array.isArray(payload?.options)) {
|
|
34
|
-
throw new Error(`Page references for "${area}" answered ${response.status}.`);
|
|
35
|
-
}
|
|
36
|
-
return payload.options;
|
|
37
|
-
})();
|
|
38
|
-
pageOptionsByArea.set(area, request);
|
|
39
|
-
request.catch(() => pageOptionsByArea.delete(area));
|
|
40
|
-
return request;
|
|
41
|
-
}
|
|
42
16
|
/**
|
|
43
17
|
* The `link-target` field: one link, to a Page of an Area or to an address elsewhere (`FORMS.md`).
|
|
44
18
|
*
|
|
@@ -48,24 +22,7 @@ function loadPageOptions(area) {
|
|
|
48
22
|
*/
|
|
49
23
|
export const PhiLinkTargetFormControl = ({ field, value, labels, disabled, readOnly, onChange, }) => {
|
|
50
24
|
const area = isPhiCmsAreaKey(field.config?.area) ? field.config.area : "public";
|
|
51
|
-
const
|
|
52
|
-
const [failed, setFailed] = useState(false);
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
let current = true;
|
|
55
|
-
loadPageOptions(area).then((next) => {
|
|
56
|
-
if (current) {
|
|
57
|
-
setOptions(next);
|
|
58
|
-
setFailed(false);
|
|
59
|
-
}
|
|
60
|
-
}, (error) => {
|
|
61
|
-
console.warn("[phi-form] Page references could not be loaded.", { area, error });
|
|
62
|
-
if (current)
|
|
63
|
-
setFailed(true);
|
|
64
|
-
});
|
|
65
|
-
return () => {
|
|
66
|
-
current = false;
|
|
67
|
-
};
|
|
68
|
-
}, [area]);
|
|
25
|
+
const { options, failed } = usePhiPageReferenceOptions(area, "phi-form");
|
|
69
26
|
const read = (key, fallback) => labels?.[key]?.trim() || fallback;
|
|
70
27
|
const controlLabels = {
|
|
71
28
|
none: read(PHI_FORM_LINK_TARGET_LABEL_KEYS.none, DEFAULT_LABELS.none),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, Fragment, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
4
|
-
import { PHI_COLOR, PHI_SPACE } from "../../theme/antd-css-var-contract";
|
|
4
|
+
import { PHI_FONT_SIZE, PHI_COLOR, PHI_SPACE } from "../../theme/antd-css-var-contract";
|
|
5
5
|
import { PHI_THEME_BORDER_WIDTH } from "../../helpers/border-widget-style";
|
|
6
6
|
import { normalizePhiCssSize, PHI_LAYOUT_SURFACE_RADIUS, PHI_SLOT_INLINE_PLACEMENT_MARGIN_STYLE, } from "../layouts/phi-layout-contract";
|
|
7
7
|
import { PhiButtonControl } from "../controls/phi-button-control";
|
|
@@ -109,7 +109,9 @@ export function PhiFormWidgetFrame({ submit, card, maxFormWidth, links, layout,
|
|
|
109
109
|
* Widget rather than beside it: a Widget in the next slot stands in the Layout's box, not on the
|
|
110
110
|
* form's grid, and no percentage of the outer width lands on that column once the grid has gaps.
|
|
111
111
|
*/
|
|
112
|
-
const linksRow = links && links.length > 0 ? (_jsx("div", { className: "phi-form-descriptor-actions", children: _jsx("div", { className: "phi-form-cell phi-form-cell--control",
|
|
112
|
+
const linksRow = links && links.length > 0 ? (_jsx("div", { className: "phi-form-descriptor-actions", children: _jsx("div", { className: "phi-form-cell phi-form-cell--control",
|
|
113
|
+
// The ways out are asides to the form, taken now and then, so they write small (`sm`).
|
|
114
|
+
style: { display: "flex", flexWrap: "wrap", alignItems: "center", gap: PHI_SPACE.sm, fontSize: PHI_FONT_SIZE.sm }, children: links.map((link, index) => (_jsxs(Fragment, { children: [index > 0 ? _jsx("span", { "aria-hidden": true, style: { color: PHI_COLOR.textTertiary }, children: "|" }) : null, _jsx(PhiLink, { href: link.href, children: link.label })] }, link.key))) }) })) : null;
|
|
113
115
|
/*
|
|
114
116
|
* The ways out come first, then the button.
|
|
115
117
|
*
|
|
@@ -75,6 +75,8 @@ function renderColumn(isAuthoringRender, key, child, width, flex, anchor, slotRo
|
|
|
75
75
|
width: "100%",
|
|
76
76
|
} })) : null] }, key));
|
|
77
77
|
}
|
|
78
|
+
/** How much faster the middle slot grows than each balanced side. */
|
|
79
|
+
const PHI_THREE_COLUMN_MIDDLE_GROW = 2;
|
|
78
80
|
export function PhiThreeColumnLayout({ blockId, slots, balancedSides = true, gap = PHI_THREE_COLUMN_LAYOUT_DEFAULTS.gap, wrap = PHI_THREE_COLUMN_LAYOUT_DEFAULTS.wrap, align, justify, leftWidth, middleWidth, rightWidth, editSlotAnchor = "center", editSlotAction, editRenderInsertControl, renderMode = "live", ...layoutProps }) {
|
|
79
81
|
const isAuthoringRender = isPhiLayoutAuthoringRender({ editSlotAction, renderMode });
|
|
80
82
|
const { style, layoutKind = "threecol", padding, paddingTop, paddingRight, paddingBottom, paddingLeft, surface, labelEnd, size, minSize, maxSize, collapsedSizeHint, } = layoutProps;
|
|
@@ -83,7 +85,14 @@ export function PhiThreeColumnLayout({ blockId, slots, balancedSides = true, gap
|
|
|
83
85
|
const resolvedMiddleWidth = normalizePhiCssSize(middleWidth);
|
|
84
86
|
const resolvedRightWidth = normalizePhiCssSize(rightWidth);
|
|
85
87
|
const leftFlex = resolvedLeftWidth ? `0 0 ${resolvedLeftWidth}` : balancedSides ? "1 1 0" : "0 1 auto";
|
|
86
|
-
|
|
88
|
+
/*
|
|
89
|
+
* The middle is the main thing and takes the larger share: with balanced sides it grows twice as fast as
|
|
90
|
+
* each side, so the sides stay equal to each other and the middle stays centred; without, it takes what
|
|
91
|
+
* the sides' content leaves.
|
|
92
|
+
*/
|
|
93
|
+
const middleFlex = resolvedMiddleWidth
|
|
94
|
+
? `0 0 ${resolvedMiddleWidth}`
|
|
95
|
+
: `${PHI_THREE_COLUMN_MIDDLE_GROW} 1 0`;
|
|
87
96
|
const rightFlex = resolvedRightWidth ? `0 0 ${resolvedRightWidth}` : balancedSides ? "1 1 0" : "0 1 auto";
|
|
88
97
|
const showInsertButton = resolvedRenderMode === "editor";
|
|
89
98
|
const { style: resolvedLayoutStyle, ground, hasExplicitLayoutBackground, } = resolvePhiBaseLayoutChrome({
|
|
@@ -10,10 +10,15 @@ export function PhiLink({ href, children, external, newTab, prefetch, className,
|
|
|
10
10
|
const [active, setActive] = useState(false);
|
|
11
11
|
const useAnchor = external ?? isPhiExternalHref(href);
|
|
12
12
|
const linkStyle = useMemo(() => ({
|
|
13
|
-
color: active ? token.colorLinkActive : hovered ? token.colorLinkHover : token.colorLink,
|
|
14
13
|
textDecoration: "none",
|
|
15
14
|
cursor: "pointer",
|
|
16
15
|
...style,
|
|
16
|
+
/*
|
|
17
|
+
* A colour the caller states is the link at rest -- a Header's text colour, a list's inherited one --
|
|
18
|
+
* and never more: pointed at and pressed, a link answers in the Theme's link colours whatever it
|
|
19
|
+
* rests in. Spread after `style`, a stated colour had silenced the hover of every link that set one.
|
|
20
|
+
*/
|
|
21
|
+
color: active ? token.colorLinkActive : hovered ? token.colorLinkHover : style?.color ?? token.colorLink,
|
|
17
22
|
}), [active, hovered, style, token.colorLink, token.colorLinkActive, token.colorLinkHover]);
|
|
18
23
|
const interactionProps = {
|
|
19
24
|
onMouseEnter: () => setHovered(true),
|
|
@@ -17,7 +17,8 @@ import { PhiEffectsReadyTrigger } from "../../../plugins/runtime/phi-effects-rea
|
|
|
17
17
|
import { PhiSlotChildEffectsVisibilityObserver } from "../../../plugins/runtime/phi-slot-child-effects-visibility-observer";
|
|
18
18
|
import { PhiSlotChildViewportEffectsObserver } from "../../../plugins/runtime/phi-slot-child-viewport-effects-observer";
|
|
19
19
|
import { PhiFlexControl } from "../../controls/phi-flex-control";
|
|
20
|
-
import { resolvePhiCmsRegionShell } from "../phi-cms-region-shell";
|
|
20
|
+
import { phiCmsRegionSiderSticks, resolvePhiCmsRegionShell, } from "../phi-cms-region-shell";
|
|
21
|
+
import { usePhiShellStickyTop } from "../../shell/use-phi-shell-sticky-top";
|
|
21
22
|
import { usePhiVisualAnchor } from "../../runtime/runtime-visual-anchors";
|
|
22
23
|
import { usePhiPathname } from "../../runtime/use-phi-pathname";
|
|
23
24
|
import { stripLocaleAndAreaFromPathname } from "../../../helpers/locale";
|
|
@@ -100,6 +101,10 @@ export function PhiCmsRegionContainerClient({ children, className, regionKey, co
|
|
|
100
101
|
elementRef,
|
|
101
102
|
placeholderRef,
|
|
102
103
|
});
|
|
104
|
+
usePhiShellStickyTop({
|
|
105
|
+
active: !previewMode && inScope && phiCmsRegionSiderSticks(regionKey, initialConfig),
|
|
106
|
+
elementRef,
|
|
107
|
+
});
|
|
103
108
|
/*
|
|
104
109
|
* Off this Page, the Region leaves a hidden marker rather than nothing: `header_top` still has to tell
|
|
105
110
|
* the Shell it holds no room, and it finds the Shell from here.
|
|
@@ -3,6 +3,7 @@ import { isPhiCmsPageOwnedRegion } from "../../helpers/cms-region-keys";
|
|
|
3
3
|
import { hasPhiFlag } from "../../helpers/flags";
|
|
4
4
|
import { PhiCmsFlags } from "../../constants/phi-cms";
|
|
5
5
|
import { PhiCmsRegionStatic } from "./phi-cms-region-static";
|
|
6
|
+
import { phiCmsRegionSiderSticks } from "./phi-cms-region-shell";
|
|
6
7
|
import { resolveRenderableBlockEffectsAttributes, resolveRenderableBlockViewportEffects, } from "../../helpers/renderable-block-effects";
|
|
7
8
|
import { PhiRuntimeModuleRenderClientHost } from "../runtime/runtime-module-render-client-manifest";
|
|
8
9
|
import { PhiRuntimeRenderClientType } from "../../constants/runtime-render-client-types";
|
|
@@ -21,6 +22,8 @@ export function PhiCmsRegionContainer({ children, className, regionKey, config,
|
|
|
21
22
|
const requiresClientEnhancement = signalParticipant ||
|
|
22
23
|
pageScoped ||
|
|
23
24
|
(!previewMode && readPhiCmsRegionReveal(regionKey, config) !== "always") ||
|
|
25
|
+
// A stuck Sider stands under the Header as measured, and only the browser can measure it.
|
|
26
|
+
(!previewMode && phiCmsRegionSiderSticks(regionKey, config)) ||
|
|
24
27
|
hasPhiFlag(config?.flags, PhiCmsFlags.Collapsible) ||
|
|
25
28
|
requiresEffectsObserver ||
|
|
26
29
|
resolvePhiBackgroundMotion(config?.surface?.background) != null;
|
|
@@ -3,7 +3,7 @@ import type { CSSProperties } from "react";
|
|
|
3
3
|
import { type PhiRenderableBlockEffectsAttributes } from "../../helpers/renderable-block-effects";
|
|
4
4
|
import { resolvePhiShellRegionChrome } from "../../helpers/shell-region-style";
|
|
5
5
|
import type { PhiBlockRuntime, PhiCmsRegionConfig, PhiCmsRegionKey, PhiRenderableBlock } from "../../types";
|
|
6
|
-
import type
|
|
6
|
+
import { type PhiSurfaceGround } from "../../helpers/surface-style";
|
|
7
7
|
import type { PhiCmsRegionReveal } from "../../types/cms-presets";
|
|
8
8
|
import { type PhiCmsBackgroundWidgetConfig } from "../widgets/config/background";
|
|
9
9
|
/**
|
|
@@ -92,6 +92,17 @@ export type PhiCmsRegionShell = {
|
|
|
92
92
|
/** The content wrapper's style, which is where Region padding lives (LAYOUTING.md "Regions"). */
|
|
93
93
|
contentStyle: CSSProperties;
|
|
94
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* Whether a Region is a Sider that sticks under the Header, and so needs the Header's measured bottom.
|
|
97
|
+
*
|
|
98
|
+
* Two kinds of Sider stick, and only one of them under the Header. A `FullHeight` Sider is a column of the
|
|
99
|
+
* Shell from the viewport's top to its bottom -- an Admin or Builder navigation beside the Header, not
|
|
100
|
+
* below it -- and stands at its configured `offsetTop`. A `Sticky` Sider without it stands in the page
|
|
101
|
+
* below the Header -- a contents beside a text -- and sticks under the line the Shell publishes as
|
|
102
|
+
* `--phi-shell-sticky-top` (`usePhiShellStickyTop`), with its offset added. The Region renderer runs that
|
|
103
|
+
* measurement for such a Sider, which is why this is asked before the Region renders.
|
|
104
|
+
*/
|
|
105
|
+
export declare function phiCmsRegionSiderSticks(regionKey: PhiCmsRegionKey, config: Pick<PhiCmsRegionConfig, "flags"> | null | undefined): boolean;
|
|
95
106
|
/**
|
|
96
107
|
* The Region's shell, or null where the Region renders nothing: hidden, or collapsed in a preview.
|
|
97
108
|
* `header_bottom` is exempt from the preview collapse because the Page, not the Area, owns its content.
|
|
@@ -6,11 +6,12 @@ import { resolveRenderableBlockEffectsAttributes, resolveRenderableBlockEffectsS
|
|
|
6
6
|
import { resolvePhiShellRegionChrome, resolvePhiShellRegionGroundStyle, resolvePhiShellRegionTypography, resolvePhiShellRegionZIndex, resolvePhiShellSiderCollapsedWidth, resolvePhiShellSiderWidth, } from "../../helpers/shell-region-style";
|
|
7
7
|
import { PhiCmsFlags } from "../../constants/phi-cms";
|
|
8
8
|
import { resolvePhiCmsBorderSource } from "../../types/cms-border-source";
|
|
9
|
+
import { PHI_SURFACE_TONE_GROUND, phiSurfaceTakesToneGround, } from "../../helpers/surface-style";
|
|
9
10
|
import { resolvePhiRenderableBlockGeometry } from "../../types/renderable-block-geometry";
|
|
10
11
|
import { createPhiSignalAddress } from "../../types/signals";
|
|
11
12
|
import { readPhiCmsRegionReveal } from "../../helpers/region-page-scope";
|
|
12
13
|
import { resolvePhiPaddingStyle } from "../layouts/phi-layout-contract";
|
|
13
|
-
import { phiRegionUsesShellChromeOverlay } from "../root/phi-shell-chrome-overlay";
|
|
14
|
+
import { PHI_SHELL_STICKY_TOP_PROPERTY, phiRegionUsesShellChromeOverlay } from "../root/phi-shell-chrome-overlay";
|
|
14
15
|
import { normalizePhiBackgroundWidgetConfig, phiBackgroundWidgetConfigPaintsGround, resolvePhiBackgroundGroundFilter, resolvePhiBackgroundMotion, resolvePhiBackgroundMotionHostStyle, resolvePhiBackgroundPane, resolvePhiBackgroundWidgetStyle, } from "../widgets/config/background";
|
|
15
16
|
/*
|
|
16
17
|
* The longhands every Region that paints the Shell Chrome Overlay (SHELL.md) carries, read from the
|
|
@@ -45,6 +46,25 @@ function resolvePhiCmsRegionShellFamily(regionKey) {
|
|
|
45
46
|
}
|
|
46
47
|
return "other";
|
|
47
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether a Region is a Sider that sticks under the Header, and so needs the Header's measured bottom.
|
|
51
|
+
*
|
|
52
|
+
* Two kinds of Sider stick, and only one of them under the Header. A `FullHeight` Sider is a column of the
|
|
53
|
+
* Shell from the viewport's top to its bottom -- an Admin or Builder navigation beside the Header, not
|
|
54
|
+
* below it -- and stands at its configured `offsetTop`. A `Sticky` Sider without it stands in the page
|
|
55
|
+
* below the Header -- a contents beside a text -- and sticks under the line the Shell publishes as
|
|
56
|
+
* `--phi-shell-sticky-top` (`usePhiShellStickyTop`), with its offset added. The Region renderer runs that
|
|
57
|
+
* measurement for such a Sider, which is why this is asked before the Region renders.
|
|
58
|
+
*/
|
|
59
|
+
export function phiCmsRegionSiderSticks(regionKey, config) {
|
|
60
|
+
return resolvePhiCmsRegionShellFamily(regionKey) === "sider"
|
|
61
|
+
&& hasPhiFlag(config?.flags, PhiCmsFlags.Sticky)
|
|
62
|
+
&& !hasPhiFlag(config?.flags, PhiCmsFlags.FullHeight);
|
|
63
|
+
}
|
|
64
|
+
/** The line a stuck Sider stands at: under the Header as measured, plus its own offset. */
|
|
65
|
+
function resolvePhiCmsRegionSiderStuckTop(topCss) {
|
|
66
|
+
return `calc(var(${PHI_SHELL_STICKY_TOP_PROPERTY}, 0px) + ${topCss})`;
|
|
67
|
+
}
|
|
48
68
|
/*
|
|
49
69
|
* A Region's edge, from its Surface.
|
|
50
70
|
*
|
|
@@ -123,15 +143,24 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
123
143
|
* `scroll-up` band ever publishes it (SHELL.md "Region visibility per Page"), so for every other Shell
|
|
124
144
|
* it is unset and the offset is the one configured.
|
|
125
145
|
*/
|
|
146
|
+
/*
|
|
147
|
+
* A full-height Sider is a Shell column from the viewport's top and stands at its own offset; a sticky
|
|
148
|
+
* one stands under the Header as it is measured right now (`phiCmsRegionSiderSticks`) and is at most as
|
|
149
|
+
* tall as what is left of the viewport below that line.
|
|
150
|
+
*/
|
|
151
|
+
const siderUnderHeader = isSider && sticky && !fullHeight;
|
|
126
152
|
const stuckTop = !stuck
|
|
127
153
|
? undefined
|
|
128
154
|
: isHeader && regionKey !== "header_top"
|
|
129
155
|
? `calc(${topCss} + var(--phi-shell-header-top-stack, 0px))`
|
|
130
|
-
:
|
|
156
|
+
: siderUnderHeader
|
|
157
|
+
? resolvePhiCmsRegionSiderStuckTop(topCss)
|
|
158
|
+
: top;
|
|
131
159
|
const blockSize = geometry.block.size?.css;
|
|
132
160
|
const fullHeightSize = fullHeight && !blockSize
|
|
133
161
|
? `calc(100dvh - ${topCss})`
|
|
134
162
|
: blockSize;
|
|
163
|
+
const underHeaderMaxSize = siderUnderHeader ? `calc(100dvh - ${resolvePhiCmsRegionSiderStuckTop(topCss)})` : undefined;
|
|
135
164
|
const zIndex = config.zIndex ?? resolvePhiShellRegionZIndex(regionKey, hasPhiFlag(config.flags, PhiCmsFlags.FullHeight));
|
|
136
165
|
/*
|
|
137
166
|
* A Background config that paints nothing is not an authored ground. The Builder writes one onto every
|
|
@@ -143,12 +172,31 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
143
172
|
? normalizePhiBackgroundWidgetConfig(surface.background)
|
|
144
173
|
: null;
|
|
145
174
|
const backgroundConfig = phiBackgroundWidgetConfigPaintsGround(surfaceBackground) ? surfaceBackground : null;
|
|
175
|
+
/*
|
|
176
|
+
* A tone turns the ground as well, by the rule every Surface follows (LAYOUTING.md "Surface tone"):
|
|
177
|
+
* where the Background paints nothing, the Region takes its tone's container ground, which resolves
|
|
178
|
+
* under the tone class the root element carries. That is a ground of the Region's own, so the Shell's
|
|
179
|
+
* -- the Theme's record, the Chrome Overlay, a pane frosting either -- does not show beneath it.
|
|
180
|
+
*/
|
|
181
|
+
const toneGround = phiSurfaceTakesToneGround(surface?.tone, backgroundConfig != null);
|
|
182
|
+
/*
|
|
183
|
+
* The Theme's Overlay as the ground (`base.kind: "theme"`). Without a tone a Chrome Region takes it the
|
|
184
|
+
* way a Region without a Background does -- the `data-phi-shell-chrome` marker, so that where the Shell
|
|
185
|
+
* draws its panes the pane behind shows through instead of a second frosting -- but over any ground the
|
|
186
|
+
* Shell record sets. Every other Region, and a toned one, paints it itself, which under a tone's class
|
|
187
|
+
* is the Overlay of the tone's mode.
|
|
188
|
+
*/
|
|
189
|
+
const themeGround = backgroundConfig?.base.kind === "theme";
|
|
190
|
+
const themeGroundIsShellChrome = themeGround
|
|
191
|
+
&& resolvePhiSurfaceToneClassName(surface?.tone) == null
|
|
192
|
+
&& phiRegionUsesShellChromeOverlay({ regionKey, backgroundConfig, grounds: [] });
|
|
146
193
|
/*
|
|
147
194
|
* A pane on a Region without a ground of its own frosts the Shell's ground for this Region -- the
|
|
148
195
|
* Theme's record, or the family's fallback -- which is what glass on a bare Header has always meant.
|
|
149
|
-
* A Region that paints its own ground carries its pane inside that Background, as every Surface does
|
|
196
|
+
* A Region that paints its own ground carries its pane inside that Background, as every Surface does;
|
|
197
|
+
* the tone's ground is one, so its pane stays on the box under that ground, as on a toned Layout.
|
|
150
198
|
*/
|
|
151
|
-
const shellPane = backgroundConfig == null ? resolvePhiBackgroundPane(surfaceBackground) : null;
|
|
199
|
+
const shellPane = backgroundConfig == null && !toneGround ? resolvePhiBackgroundPane(surfaceBackground) : null;
|
|
152
200
|
const backgroundMoves = animatesBackground &&
|
|
153
201
|
backgroundConfig != null &&
|
|
154
202
|
resolvePhiBackgroundMotion(backgroundConfig) != null;
|
|
@@ -160,11 +208,18 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
160
208
|
motion: null,
|
|
161
209
|
}
|
|
162
210
|
: null;
|
|
163
|
-
const backgroundStyle =
|
|
211
|
+
const backgroundStyle = themeGroundIsShellChrome
|
|
164
212
|
? null
|
|
165
|
-
:
|
|
166
|
-
?
|
|
167
|
-
|
|
213
|
+
: toneGround
|
|
214
|
+
? {
|
|
215
|
+
...(surfaceBackground ? resolvePhiBackgroundWidgetStyle(surfaceBackground) : {}),
|
|
216
|
+
backgroundColor: PHI_SURFACE_TONE_GROUND,
|
|
217
|
+
}
|
|
218
|
+
: backgroundConfig == null || ground != null
|
|
219
|
+
? null
|
|
220
|
+
: backgroundMoves
|
|
221
|
+
? resolvePhiBackgroundMotionHostStyle(backgroundConfig)
|
|
222
|
+
: resolvePhiBackgroundWidgetStyle(backgroundConfig);
|
|
168
223
|
const chromeInput = {
|
|
169
224
|
shadow: surface?.shadow ?? undefined,
|
|
170
225
|
effect: shellPane ?? undefined,
|
|
@@ -184,12 +239,14 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
184
239
|
* the stored one: the Builder persists an empty Background record for every Region an author has ever
|
|
185
240
|
* opened, and the raw value is never null for those.
|
|
186
241
|
*/
|
|
187
|
-
const usesShellChromeOverlay =
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
242
|
+
const usesShellChromeOverlay = themeGround
|
|
243
|
+
? themeGroundIsShellChrome
|
|
244
|
+
: !toneGround && phiRegionUsesShellChromeOverlay({
|
|
245
|
+
regionKey,
|
|
246
|
+
backgroundConfig,
|
|
247
|
+
pane: shellPane,
|
|
248
|
+
grounds: [chrome.light.background, chrome.dark.background],
|
|
249
|
+
});
|
|
193
250
|
/*
|
|
194
251
|
* The ground. Published, it is the pair of custom properties `shell.css` paints from, because it may
|
|
195
252
|
* be a colour or a gradient and only CSS can tell which without guessing; nothing inline may name a
|
|
@@ -203,13 +260,18 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
203
260
|
* drop one of those from an element whose `background` shorthand is still set.
|
|
204
261
|
*/
|
|
205
262
|
const liveChrome = paint.kind === "live" ? chrome[paint.mode] : null;
|
|
263
|
+
/*
|
|
264
|
+
* A toned Region publishes no Shell ground: `shell.css` would paint a gradient one beneath its own. Nor
|
|
265
|
+
* does one whose ground is the Theme's: the Overlay stands where the Shell record's ground would.
|
|
266
|
+
*/
|
|
267
|
+
const withoutShellGround = toneGround || themeGround;
|
|
206
268
|
const modeStyle = liveChrome
|
|
207
269
|
? {}
|
|
208
270
|
: {
|
|
209
|
-
...(chrome.light.background == null
|
|
271
|
+
...(chrome.light.background == null || withoutShellGround
|
|
210
272
|
? {}
|
|
211
273
|
: { "--phi-region-background-light": String(chrome.light.background) }),
|
|
212
|
-
...(chrome.dark.background == null
|
|
274
|
+
...(chrome.dark.background == null || withoutShellGround
|
|
213
275
|
? {}
|
|
214
276
|
: { "--phi-region-background-dark": String(chrome.dark.background) }),
|
|
215
277
|
"--phi-region-color-light": String(chrome.light.color),
|
|
@@ -219,7 +281,7 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
219
281
|
const effectStyle = liveChrome || paintedChrome.effectStyle?.backgroundColor == null
|
|
220
282
|
? paintedChrome.effectStyle
|
|
221
283
|
: { ...paintedChrome.effectStyle, backgroundColor: "var(--phi-region-background)" };
|
|
222
|
-
const groundStyle = liveChrome && backgroundStyle == null
|
|
284
|
+
const groundStyle = liveChrome && backgroundStyle == null && !themeGround
|
|
223
285
|
? resolvePhiShellRegionGroundStyle(liveChrome.background)
|
|
224
286
|
: {};
|
|
225
287
|
const typography = resolvePhiShellRegionTypography(regionKey, shellTheme, {
|
|
@@ -258,11 +320,11 @@ export function resolvePhiCmsRegionShell({ regionKey, config, shellTheme, paint,
|
|
|
258
320
|
maxWidth: geometry.inline.max?.css ?? siderWidth,
|
|
259
321
|
height: fullHeightSize,
|
|
260
322
|
minHeight: geometry.block.min?.css ?? (fullHeight ? fullHeightSize : undefined),
|
|
261
|
-
maxHeight: geometry.block.max?.css,
|
|
323
|
+
maxHeight: geometry.block.max?.css ?? underHeaderMaxSize,
|
|
262
324
|
alignSelf: fullHeight ? "stretch" : "start",
|
|
263
325
|
flex: fullHeight ? "1 1 auto" : undefined,
|
|
264
326
|
overflowX: "visible",
|
|
265
|
-
overflowY: fullHeight ? "auto" : "visible",
|
|
327
|
+
overflowY: fullHeight || siderUnderHeader ? "auto" : "visible",
|
|
266
328
|
}
|
|
267
329
|
: {
|
|
268
330
|
width: geometry.inline.size?.css ?? "100%",
|
|
@@ -30,6 +30,11 @@ export type PhiConfig = {
|
|
|
30
30
|
* the reader rather than quietly working until the day the Theme is computed by something else.
|
|
31
31
|
*/
|
|
32
32
|
token: PhiThemeTokens;
|
|
33
|
+
/**
|
|
34
|
+
* The page's Theme where `token` is a Surface tone's (`PhiNestedModeConfigProvider`): set only inside
|
|
35
|
+
* a tone scope, so outside one the page's Theme is `token` itself. Read through `usePhiPageModeToken`.
|
|
36
|
+
*/
|
|
37
|
+
pageToken?: PhiThemeTokens;
|
|
33
38
|
};
|
|
34
39
|
export type PhiFontCatalogueFamily = {
|
|
35
40
|
family: string;
|
|
@@ -49,6 +54,14 @@ export declare function PhiConfigProvider({ children, locale, fonts, fontFamilie
|
|
|
49
54
|
controlShape: PhiControlShape;
|
|
50
55
|
}): import("react").JSX.Element;
|
|
51
56
|
export declare function usePhiConfig(): PhiConfig;
|
|
57
|
+
/**
|
|
58
|
+
* The Theme of the page's own mode, wherever this is asked -- inside a Surface tone too.
|
|
59
|
+
*
|
|
60
|
+
* What draws the page's tools rather than its content takes its colours from here: the Builder's scaffolds
|
|
61
|
+
* mark Layouts and Widgets in the editor's mode, and a Region turned inverse leaves them as they were
|
|
62
|
+
* instead of turning them with the content they stand around.
|
|
63
|
+
*/
|
|
64
|
+
export declare function usePhiPageModeToken(): PhiThemeTokens;
|
|
52
65
|
/** The locale the root adapter configures Ant Design with, for whoever hands it on. */
|
|
53
66
|
export type PhiConfigLocale = ConfigProviderProps["locale"];
|
|
54
67
|
/**
|
|
@@ -70,6 +70,17 @@ export function usePhiConfig() {
|
|
|
70
70
|
}
|
|
71
71
|
return config;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* The Theme of the page's own mode, wherever this is asked -- inside a Surface tone too.
|
|
75
|
+
*
|
|
76
|
+
* What draws the page's tools rather than its content takes its colours from here: the Builder's scaffolds
|
|
77
|
+
* mark Layouts and Widgets in the editor's mode, and a Region turned inverse leaves them as they were
|
|
78
|
+
* instead of turning them with the content they stand around.
|
|
79
|
+
*/
|
|
80
|
+
export function usePhiPageModeToken() {
|
|
81
|
+
const config = usePhiConfig();
|
|
82
|
+
return config.pageToken ?? config.token;
|
|
83
|
+
}
|
|
73
84
|
/**
|
|
74
85
|
* The page's config in another mode: Ant Design's Theme for `mode` and the house config with that mode's
|
|
75
86
|
* colours and tokens.
|
|
@@ -89,6 +100,6 @@ export function PhiNestedModeConfigProvider({ mode, theme, cssVarKey, locale, cu
|
|
|
89
100
|
function PhiNestedModeConfigValue({ mode, customColors, children, }) {
|
|
90
101
|
const outer = usePhiConfig();
|
|
91
102
|
const { token } = antdTheme.useToken();
|
|
92
|
-
const value = useMemo(() => ({ ...outer, mode, customColors, token }), [customColors, mode, outer, token]);
|
|
103
|
+
const value = useMemo(() => ({ ...outer, mode, customColors, token, pageToken: outer.pageToken ?? outer.token }), [customColors, mode, outer, token]);
|
|
93
104
|
return _jsx(PhiConfigContext.Provider, { value: value, children: children });
|
|
94
105
|
}
|
|
@@ -53,6 +53,13 @@ export declare const PHI_ROOT_BACKGROUND_IMAGE_SOURCE_KINDS: readonly PhiBackgro
|
|
|
53
53
|
* simply resolves away.
|
|
54
54
|
*/
|
|
55
55
|
export declare const PHI_ROOT_BACKGROUND_FILTERS: readonly PhiBackgroundFilter[];
|
|
56
|
+
/**
|
|
57
|
+
* The Base kinds the Theme Root Background offers and honours: every one but `theme`.
|
|
58
|
+
*
|
|
59
|
+
* `theme` is the Chrome Overlay standing in for a box's ground, and the Root Background is no box on the
|
|
60
|
+
* page but the ground beneath all of them. A stored value outside the offer resolves to `none`.
|
|
61
|
+
*/
|
|
62
|
+
export declare const PHI_ROOT_BACKGROUND_BASE_KINDS: readonly PhiCmsBackgroundWidgetConfig["base"]["kind"][];
|
|
56
63
|
/**
|
|
57
64
|
* What the ground paints, without the geometry of the layer that paints it.
|
|
58
65
|
*
|
|
@@ -59,8 +59,27 @@ export const PHI_ROOT_BACKGROUND_FILTERS = [];
|
|
|
59
59
|
function withoutPhiRootBackgroundFilter(config) {
|
|
60
60
|
return config ? { ...normalizePhiBackgroundWidgetConfig(config), filter: null } : null;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* The Base kinds the Theme Root Background offers and honours: every one but `theme`.
|
|
64
|
+
*
|
|
65
|
+
* `theme` is the Chrome Overlay standing in for a box's ground, and the Root Background is no box on the
|
|
66
|
+
* page but the ground beneath all of them. A stored value outside the offer resolves to `none`.
|
|
67
|
+
*/
|
|
68
|
+
export const PHI_ROOT_BACKGROUND_BASE_KINDS = [
|
|
69
|
+
"none",
|
|
70
|
+
"color",
|
|
71
|
+
"gradient",
|
|
72
|
+
"image",
|
|
73
|
+
];
|
|
62
74
|
function readPhiRootBackgroundConfig(root, mode) {
|
|
63
|
-
|
|
75
|
+
const configured = (mode === "dark" ? root?.background?.dark : root?.background?.light) ?? null;
|
|
76
|
+
if (configured == null) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const normalized = normalizePhiBackgroundWidgetConfig(configured);
|
|
80
|
+
return PHI_ROOT_BACKGROUND_BASE_KINDS.includes(normalized.base.kind)
|
|
81
|
+
? configured
|
|
82
|
+
: { ...normalized, base: { kind: "none" } };
|
|
64
83
|
}
|
|
65
84
|
/**
|
|
66
85
|
* What the ground paints, without the geometry of the layer that paints it.
|
|
@@ -53,6 +53,9 @@ export function resolvePhiRootTheme({ siteTheme, mode, fonts, presets, }) {
|
|
|
53
53
|
const resolvedShellHeaderMainBackground = resolvePhiShellRegionBackground(siteTheme?.shell, mode, { family: "header", region: "main" }) ??
|
|
54
54
|
(mode === "dark" ? PHI_DEFAULT_DARK_NAV_BACKGROUND : undefined);
|
|
55
55
|
const sharedComponentDefaults = buildPhiComponentTokens({
|
|
56
|
+
...(typeof effectiveThemeTokens.fontSizeSM === "number" ? { fontSizeSM: effectiveThemeTokens.fontSizeSM } : {}),
|
|
57
|
+
...(typeof effectiveThemeTokens.fontSize === "number" ? { fontSize: effectiveThemeTokens.fontSize } : {}),
|
|
58
|
+
...(typeof effectiveThemeTokens.lineHeight === "number" ? { lineHeight: effectiveThemeTokens.lineHeight } : {}),
|
|
56
59
|
layout: {
|
|
57
60
|
...(resolvedShellSiderBackground ? { siderBg: resolvedShellSiderBackground } : {}),
|
|
58
61
|
...(resolvedShellHeaderMainBackground ? { headerBg: resolvedShellHeaderMainBackground } : {}),
|
|
@@ -58,13 +58,18 @@ export declare const PHI_SHELL_CHROME_OVERLAY_IMAGE_SOURCE_KINDS: readonly PhiBa
|
|
|
58
58
|
export declare const PHI_SHELL_CHROME_OVERLAY_MOTION_MODES: readonly PhiBackgroundMotionMode[];
|
|
59
59
|
export type PhiShellChromeOverlayVariables = Record<`--phi-shell-chrome-${string}`, string>;
|
|
60
60
|
/**
|
|
61
|
-
* Whether this Region paints the shared overlay, which it does
|
|
61
|
+
* Whether this Region paints the shared overlay, which it does while it authored nothing itself -- or
|
|
62
|
+
* while what it authored is the overlay.
|
|
62
63
|
*
|
|
63
64
|
* A Region that authored its own chrome paints over the Theme, and that is how an Area keeps a look of
|
|
64
65
|
* its own. Authored means every carrier, not just one: the Region Surface's Background, the ground the
|
|
65
66
|
* Shell record sets, and a glass pane the Region asks for over that ground. Reading only the
|
|
66
67
|
* first let the Builder's Sider take the Site's overlay on top of the container ground it paints on
|
|
67
68
|
* purpose, which is what this exists to prevent.
|
|
69
|
+
*
|
|
70
|
+
* A Background whose Base is `theme` states the overlay, so a Chrome Region takes it whatever the Shell
|
|
71
|
+
* record says. The caller asks this only for a Region without a tone: a toned one wants the overlay of
|
|
72
|
+
* its tone's mode, which it paints itself (`PHI_BACKGROUND_THEME_STYLE`).
|
|
68
73
|
*/
|
|
69
74
|
export declare function phiRegionUsesShellChromeOverlay({ regionKey, backgroundConfig, pane, grounds, }: {
|
|
70
75
|
regionKey: string;
|
|
@@ -125,6 +130,12 @@ export declare function resolvePhiShellChromePaneStickyTop(bands: readonly PhiSh
|
|
|
125
130
|
*/
|
|
126
131
|
export declare const PHI_SHELL_HEADER_TOP_EXTENT_PROPERTY = "--phi-shell-header-top-extent";
|
|
127
132
|
export declare const PHI_SHELL_HEADER_TOP_STACK_PROPERTY = "--phi-shell-header-top-stack";
|
|
133
|
+
/**
|
|
134
|
+
* The Header's measured bottom: the lowest bottom of every Header band stuck right now, written on the
|
|
135
|
+
* Shell by `usePhiShellStickyTop` (components/shell/use-phi-shell-sticky-top.ts). A sticky Table header
|
|
136
|
+
* and a stuck Sider stand under it; unset, it reads `0px`.
|
|
137
|
+
*/
|
|
138
|
+
export declare const PHI_SHELL_STICKY_TOP_PROPERTY = "--phi-shell-sticky-top";
|
|
128
139
|
/**
|
|
129
140
|
* How `header_top` behaves where the browser decides it, as far as the Header pane is concerned.
|
|
130
141
|
*/
|
|
@@ -76,17 +76,27 @@ const PHI_SHELL_CHROME_OVERLAY_REGION_KEYS = [
|
|
|
76
76
|
"footer_bottom",
|
|
77
77
|
];
|
|
78
78
|
/**
|
|
79
|
-
* Whether this Region paints the shared overlay, which it does
|
|
79
|
+
* Whether this Region paints the shared overlay, which it does while it authored nothing itself -- or
|
|
80
|
+
* while what it authored is the overlay.
|
|
80
81
|
*
|
|
81
82
|
* A Region that authored its own chrome paints over the Theme, and that is how an Area keeps a look of
|
|
82
83
|
* its own. Authored means every carrier, not just one: the Region Surface's Background, the ground the
|
|
83
84
|
* Shell record sets, and a glass pane the Region asks for over that ground. Reading only the
|
|
84
85
|
* first let the Builder's Sider take the Site's overlay on top of the container ground it paints on
|
|
85
86
|
* purpose, which is what this exists to prevent.
|
|
87
|
+
*
|
|
88
|
+
* A Background whose Base is `theme` states the overlay, so a Chrome Region takes it whatever the Shell
|
|
89
|
+
* record says. The caller asks this only for a Region without a tone: a toned one wants the overlay of
|
|
90
|
+
* its tone's mode, which it paints itself (`PHI_BACKGROUND_THEME_STYLE`).
|
|
86
91
|
*/
|
|
87
92
|
export function phiRegionUsesShellChromeOverlay({ regionKey, backgroundConfig, pane, grounds, }) {
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
if (!PHI_SHELL_CHROME_OVERLAY_REGION_KEYS.includes(regionKey)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
if (backgroundConfig != null && normalizePhiBackgroundWidgetConfig(backgroundConfig).base.kind === "theme") {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return (backgroundConfig == null &&
|
|
90
100
|
pane == null &&
|
|
91
101
|
grounds.every((ground) => ground == null));
|
|
92
102
|
}
|
|
@@ -223,6 +233,12 @@ export function resolvePhiShellChromePaneStickyTop(bands) {
|
|
|
223
233
|
*/
|
|
224
234
|
export const PHI_SHELL_HEADER_TOP_EXTENT_PROPERTY = "--phi-shell-header-top-extent";
|
|
225
235
|
export const PHI_SHELL_HEADER_TOP_STACK_PROPERTY = "--phi-shell-header-top-stack";
|
|
236
|
+
/**
|
|
237
|
+
* The Header's measured bottom: the lowest bottom of every Header band stuck right now, written on the
|
|
238
|
+
* Shell by `usePhiShellStickyTop` (components/shell/use-phi-shell-sticky-top.ts). A sticky Table header
|
|
239
|
+
* and a stuck Sider stand under it; unset, it reads `0px`.
|
|
240
|
+
*/
|
|
241
|
+
export const PHI_SHELL_STICKY_TOP_PROPERTY = "--phi-shell-sticky-top";
|
|
226
242
|
/**
|
|
227
243
|
* Where the Header pane sticks when `header_top` may come and go.
|
|
228
244
|
*
|
|
@@ -17,6 +17,7 @@ declare const PHI_ANTD_ICON_LOADERS: {
|
|
|
17
17
|
readonly CalendarOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CalendarOutlined")>;
|
|
18
18
|
readonly CheckOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CheckOutlined")>;
|
|
19
19
|
readonly CloseOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CloseOutlined")>;
|
|
20
|
+
readonly CloudDownloadOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CloudDownloadOutlined")>;
|
|
20
21
|
readonly CloudUploadOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CloudUploadOutlined")>;
|
|
21
22
|
readonly ClusterOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/ClusterOutlined")>;
|
|
22
23
|
readonly CodeOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CodeOutlined")>;
|