@uxf/cms 13.0.2 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,7 +16,7 @@ It is not a general UI kit (`@uxf/ui`), a form library (`@uxf/form`), or a data
16
16
  yarn add @uxf/cms
17
17
  ```
18
18
 
19
- Peer dependencies: `@uxf/core`, `@uxf/core-react`, `@uxf/data-grid`, `@uxf/form`, `@uxf/router`, `@uxf/styles`, `@uxf/ui`, `@uxf/wysiwyg`, `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/utilities`, `@floating-ui/react`, `axios`, `axios-hooks`, `swr`, `react-hook-form`, `next` (>=15.0.4), `react` (^19.3.0), `react-dom` (^19.3.0).
19
+ Peer dependencies: `@uxf/core`, `@uxf/core-react`, `@uxf/data-grid`, `@uxf/form`, `@uxf/router`, `@uxf/styles`, `@uxf/ui`, `@uxf/wysiwyg`, `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/utilities`, `@floating-ui/react`, `axios`, `axios-hooks`, `swr`, `react-hook-form`, `next` (>=16.0.0), `react` (^19.3.0), `react-dom` (^19.3.0).
20
20
 
21
21
  Because it builds on `@uxf/ui`, `@uxf/form` and `@uxf/data-grid`, complete their setup as well (see [`@uxf/ui`](../ui/README.md) and [`@uxf/form`](../form/README.md)) — the `UiContextProvider`, the token layer, and the component CSS they require.
22
22
 
@@ -34,9 +34,11 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.Sidebar = void 0;
37
+ const use_media_query_1 = require("@uxf/core-react/hooks/use-media-query");
37
38
  const rem_1 = require("@uxf/styles/units/rem");
38
39
  const react_1 = __importStar(require("react"));
39
40
  const tw_screens_1 = require("../../ui/tw-tokens/tw-screens");
41
+ const use_visual_viewport_height_1 = require("../../utils/use-visual-viewport-height");
40
42
  const menu_1 = require("../menu");
41
43
  const mobile_bar_1 = require("../menu/mobile-bar");
42
44
  const user_menu_1 = require("../menu/ui/user-menu");
@@ -45,39 +47,29 @@ const uxfLogo = (react_1.default.createElement("svg", { height: "30", viewBox: "
45
47
  react_1.default.createElement("path", { clipRule: "evenodd", d: "M33.563 12.874a9.103 9.103 0 0 0 0-12.874L20.69 12.874l.107.105a9.103 9.103 0 0 0 12.766-.105Zm-20.69-6.437a9.103 9.103 0 0 1 .106 12.766l-.105.107L0 6.437a9.103 9.103 0 0 1 12.874 0ZM40 33.563 27.127 20.69l-.106.107a9.103 9.103 0 0 0 12.98 12.766Zm-20.69-6.437-.107-.105A9.103 9.103 0 0 0 6.437 40l12.874-12.874Z", fill: "#FFF", fillRule: "evenodd" }),
46
48
  react_1.default.createElement("path", { clipRule: "evenodd", d: "m84.325 7.295 5.133 8.675h.199l5.158-8.675h6.078l-7.768 12.727 7.942 12.727h-6.19l-5.22-8.687h-.199l-5.22 8.687h-6.165l7.967-12.727-7.818-12.727h6.103Zm-24.194 0v16.07c0 .97.214 1.832.64 2.586a4.58 4.58 0 0 0 1.809 1.777c.779.431 1.686.647 2.722.647 1.044 0 1.953-.216 2.728-.647a4.591 4.591 0 0 0 1.802-1.777c.427-.754.64-1.616.64-2.585V7.296h5.382v16.53c0 1.856-.441 3.48-1.324 4.872-.882 1.392-2.115 2.475-3.697 3.25-1.583.775-3.426 1.162-5.531 1.162-2.113 0-3.96-.387-5.543-1.162-1.583-.775-2.813-1.858-3.692-3.25-.878-1.392-1.317-3.016-1.317-4.872V7.296h5.381ZM170.25 13.41c2.411 0 4.311.51 5.698 1.529 1.388 1.019 2.198 2.407 2.43 4.164l-4.847.298a2.555 2.555 0 0 0-.534-1.125 2.942 2.942 0 0 0-1.075-.808c-.444-.203-.972-.304-1.585-.304-.821 0-1.512.172-2.076.515-.563.344-.845.802-.845 1.374 0 .456.182.84.547 1.156.364.315.99.567 1.877.758l3.455.696c1.856.381 3.24.994 4.151 1.84.912.845 1.367 1.955 1.367 3.33 0 1.252-.366 2.35-1.1 3.294-.733.945-1.736 1.68-3.007 2.206-1.272.526-2.737.79-4.394.79-2.527 0-4.539-.529-6.034-1.585-1.496-1.057-2.372-2.496-2.629-4.32l5.208-.273c.157.77.538 1.357 1.143 1.759.605.402 1.38.603 2.324.603.928 0 1.676-.18 2.244-.54.567-.361.855-.827.864-1.4-.009-.48-.212-.875-.609-1.186-.398-.31-1.011-.55-1.84-.715l-3.306-.659c-1.864-.372-3.25-1.019-4.157-1.938-.908-.92-1.361-2.093-1.361-3.518 0-1.226.333-2.283 1-3.17.667-.886 1.608-1.57 2.821-2.05 1.214-.48 2.637-.72 4.27-.72Zm-36.686.373a12.285 12.285 0 0 0-3.051-.373c-1.525 0-2.865.23-4.021.69-1.156.46-2.098 1.114-2.827 1.964-.73.849-1.219 1.854-1.467 3.014l4.897.397c.182-.63.555-1.153 1.119-1.572.563-.418 1.321-.627 2.274-.627.903 0 1.601.215 2.094.646.493.43.74 1.04.74 1.827v.075c0 .405-.153.712-.46.92-.307.206-.8.362-1.479.465-.68.104-1.574.214-2.685.33-.944.09-1.845.248-2.703.472a7.698 7.698 0 0 0-2.293.994 4.727 4.727 0 0 0-1.591 1.74c-.39.721-.584 1.612-.584 2.673 0 1.259.275 2.31.826 3.15a5.147 5.147 0 0 0 2.256 1.902c.953.427 2.038.64 3.257.64.944 0 1.777-.126 2.498-.38a5.55 5.55 0 0 0 1.852-1.055 5.31 5.31 0 0 0 1.23-1.573h.149v2.648h5.022V19.873c0-1.135-.22-2.11-.659-2.927a5.655 5.655 0 0 0-1.796-2.007 8.039 8.039 0 0 0-2.598-1.156Zm-13.424-2.05V7.294h-16.853v25.454h5.381V22.235h10.354v-4.438h-10.354v-6.065h11.472Zm32.603 1.677c1.326 0 2.482.29 3.468.87.986.58 1.753 1.407 2.3 2.48.546 1.073.82 2.35.82 3.834V32.75h-5.295V21.539c.008-1.169-.29-2.082-.895-2.74-.605-.66-1.437-.989-2.498-.989-.713 0-1.34.153-1.883.46a3.166 3.166 0 0 0-1.268 1.336c-.302.584-.458 1.286-.466 2.107V32.75h-5.295V13.659h5.047v3.368H147a5.358 5.358 0 0 1 2.126-2.641c.994-.65 2.2-.976 3.616-.976Zm-20.061 10.782c.286-.087.512-.184.678-.292v2.026c0 .671-.17 1.272-.51 1.802-.34.53-.808.951-1.404 1.262-.597.31-1.285.466-2.064.466-.812 0-1.481-.189-2.007-.566-.526-.377-.789-.925-.789-1.646 0-.497.128-.914.385-1.25.257-.335.617-.602 1.082-.801a6.547 6.547 0 0 1 1.628-.435l.969-.143a24.15 24.15 0 0 0 1.069-.186c.356-.071.677-.15.963-.237Z", fill: "#FFF", fillRule: "evenodd" })));
47
49
  const Sidebar = (props) => {
48
- var _a, _b, _c;
49
- const [deviceHeight, setDeviceHeight] = (0, react_1.useState)(0);
50
+ var _a, _b, _c, _d;
51
+ const deviceHeight = (_a = (0, use_visual_viewport_height_1.useVisualViewportHeight)()) !== null && _a !== void 0 ? _a : 0;
50
52
  const [isMenuOpen, setIsMenuOpen] = (0, react_1.useState)(false);
51
53
  const toggleMenu = () => setIsMenuOpen((prev) => !prev);
54
+ // The open menu covers the page below the md breakpoint, so the page must not scroll under it.
55
+ const isDesktop = (0, use_media_query_1.useMediaQuery)(`(min-width: ${tw_screens_1.twScreens.md})`);
56
+ const isPageLocked = isMenuOpen && !isDesktop;
52
57
  (0, react_1.useEffect)(() => {
53
- const handler = () => { var _a, _b; return setDeviceHeight((_b = (_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : window.innerHeight); };
54
- handler();
55
- window.addEventListener("resize", handler);
58
+ if (!isPageLocked) {
59
+ return;
60
+ }
61
+ // Restored rather than cleared, so a lock someone else holds survives the menu closing.
62
+ const previousOverflow = document.body.style.overflow;
63
+ document.body.style.overflow = "hidden";
56
64
  return () => {
57
- window.removeEventListener("resize", handler);
65
+ document.body.style.overflow = previousOverflow;
58
66
  };
59
- }, []);
60
- (0, react_1.useEffect)(() => {
61
- const handler = () => {
62
- if (!window.matchMedia(`(min-width: ${tw_screens_1.twScreens.md})`).matches && isMenuOpen) {
63
- document.body.style.overflow = "hidden";
64
- }
65
- else {
66
- document.body.style.overflow = "";
67
- }
68
- };
69
- handler();
70
- window.addEventListener("resize", handler);
71
- return () => {
72
- document.body.style.overflow = "";
73
- window.removeEventListener("resize", handler);
74
- };
75
- }, [isMenuOpen]);
76
- return ((_a = props.CustomSidebar) !== null && _a !== void 0 ? _a : (react_1.default.createElement("div", { className: "uxf-cms-sidebar", style: { "--drawer-width": (0, rem_1.rem)(styles_1.drawerWidth) } },
67
+ }, [isPageLocked]);
68
+ return ((_b = props.CustomSidebar) !== null && _b !== void 0 ? _b : (react_1.default.createElement("div", { className: "uxf-cms-sidebar", style: { "--drawer-width": (0, rem_1.rem)(styles_1.drawerWidth) } },
77
69
  react_1.default.createElement("div", { className: `uxf-cms-sidebar__content ${isMenuOpen ? "uxf-cms-sidebar__content--open" : "uxf-cms-sidebar__content--closed"}`, style: { "--device-height": (0, rem_1.rem)(deviceHeight) } },
78
- react_1.default.createElement("div", { className: "uxf-cms-sidebar__logo" }, (_b = props.Logo) !== null && _b !== void 0 ? _b : uxfLogo),
70
+ react_1.default.createElement("div", { className: "uxf-cms-sidebar__logo" }, (_c = props.Logo) !== null && _c !== void 0 ? _c : uxfLogo),
79
71
  props.menuConfiguration && props.menuConfiguration.length > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
80
- react_1.default.createElement("div", { className: `uxf-cms-sidebar__nav ${((_c = props.menuConfiguration.at(0)) === null || _c === void 0 ? void 0 : _c.type) === "super-section"
72
+ react_1.default.createElement("div", { className: `uxf-cms-sidebar__nav ${((_d = props.menuConfiguration.at(0)) === null || _d === void 0 ? void 0 : _d.type) === "super-section"
81
73
  ? "uxf-cms-sidebar__nav--super-section"
82
74
  : ""}` },
83
75
  react_1.default.createElement(menu_1.Menu, { menu: props.menuConfiguration })),
@@ -50,9 +50,12 @@ const MenuItem = (props) => {
50
50
  const firstVisibleChild = visibleChildren.at(0);
51
51
  const isInitiallyOpen = (isActive || hasActiveChildren) && props.item.children.length > 0;
52
52
  const [isSubmenuOpen, setIsSubmenuOpen] = (0, react_1.useState)(isInitiallyOpen);
53
- (0, react_1.useEffect)(() => {
53
+ // Follow the route during render instead of in an effect, which first rendered one commit with the old value.
54
+ const [previousIsInitiallyOpen, setPreviousIsInitiallyOpen] = (0, react_1.useState)(isInitiallyOpen);
55
+ if (isInitiallyOpen !== previousIsInitiallyOpen) {
56
+ setPreviousIsInitiallyOpen(isInitiallyOpen);
54
57
  setIsSubmenuOpen(isInitiallyOpen);
55
- }, [isInitiallyOpen]);
58
+ }
56
59
  const toggle = () => setIsSubmenuOpen((prev) => !prev);
57
60
  if (!props.item.isVisible(loggedUser) ||
58
61
  (props.item.children.length !== 0 && !props.item.hasVisibleChildren(loggedUser))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/cms",
3
- "version": "13.0.2",
3
+ "version": "14.0.0",
4
4
  "description": "UXF Cms",
5
5
  "author": "UXFans <dev@uxf.cz>",
6
6
  "homepage": "https://gitlab.com/uxf-npm/cms#readme",
@@ -29,18 +29,18 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@floating-ui/react": "^0.27.20",
32
- "@uxf/core": "13.0.0",
33
- "@uxf/core-react": "13.0.0",
34
- "@uxf/data-grid": "13.0.2",
35
- "@uxf/dnd": "13.0.2",
36
- "@uxf/form": "13.0.2",
37
- "@uxf/router": "13.0.0",
38
- "@uxf/styles": "13.0.0",
39
- "@uxf/ui": "13.0.2",
40
- "@uxf/wysiwyg": "13.0.2",
32
+ "@uxf/core": "14.0.0",
33
+ "@uxf/core-react": "14.0.0",
34
+ "@uxf/data-grid": "14.0.0",
35
+ "@uxf/dnd": "14.0.0",
36
+ "@uxf/form": "14.0.0",
37
+ "@uxf/router": "14.0.0",
38
+ "@uxf/styles": "14.0.0",
39
+ "@uxf/ui": "14.0.0",
40
+ "@uxf/wysiwyg": "14.0.0",
41
41
  "axios": "^1.20.0",
42
42
  "axios-hooks": "^5.1.1",
43
- "next": ">=15.0.4",
43
+ "next": ">=16.0.0",
44
44
  "react": "^19.3.0",
45
45
  "react-dom": "^19.3.0",
46
46
  "react-hook-form": "^7.89.0",
@@ -51,15 +51,15 @@
51
51
  "@types/node": "24",
52
52
  "@types/react": "19.3.0",
53
53
  "@types/react-dom": "19.3.0",
54
- "@uxf/core": "13.0.0",
55
- "@uxf/core-react": "13.0.0",
56
- "@uxf/data-grid": "13.0.2",
57
- "@uxf/dnd": "13.0.2",
58
- "@uxf/form": "13.0.2",
59
- "@uxf/router": "13.0.0",
60
- "@uxf/styles": "13.0.0",
61
- "@uxf/ui": "13.0.2",
62
- "@uxf/wysiwyg": "13.0.2",
54
+ "@uxf/core": "14.0.0",
55
+ "@uxf/core-react": "14.0.0",
56
+ "@uxf/data-grid": "14.0.0",
57
+ "@uxf/dnd": "14.0.0",
58
+ "@uxf/form": "14.0.0",
59
+ "@uxf/router": "14.0.0",
60
+ "@uxf/styles": "14.0.0",
61
+ "@uxf/ui": "14.0.0",
62
+ "@uxf/wysiwyg": "14.0.0",
63
63
  "axios": "^1.20.0",
64
64
  "axios-hooks": "^5.1.1",
65
65
  "next": "16.3.8",
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = require("@testing-library/react");
7
+ const translations_1 = require("@uxf/core-react/translations");
8
+ const create_default_t_1 = require("@uxf/core-react/translations/create-default-t");
9
+ const react_2 = __importDefault(require("react"));
10
+ const translations_2 = __importDefault(require("../translations"));
11
+ const content_header_1 = require("./content-header");
12
+ // The real icons need @uxf/ui's provider config. IconButton names the button through the icon's aria-label,
13
+ // so the stand-in keeps it.
14
+ jest.mock("@uxf/ui/icon", () => ({
15
+ Icon: (props) => react_2.default.createElement("svg", { "aria-label": props["aria-label"], role: "img" }),
16
+ }));
17
+ const cs = (0, create_default_t_1.createDefaultT)(JSON.parse(JSON.stringify(translations_2.default, (_key, value) => ((value === null || value === void 0 ? void 0 : value.cs) !== undefined ? value.cs : value))));
18
+ test("names the delete button", () => {
19
+ (0, react_1.render)(react_2.default.createElement(translations_1.TranslationsProvider, { value: cs },
20
+ react_2.default.createElement(content_header_1.ContentHeader, { ...{ id: "1", onRemove: jest.fn(), title: "Section" } })));
21
+ expect(react_1.screen.getByRole("button", { name: "Smazat sekci" })).toBeTruthy();
22
+ });
@@ -59,7 +59,7 @@ const ContentHeader = (props) => {
59
59
  return (react_1.default.createElement("div", { ...clickableProps },
60
60
  react_1.default.createElement("h3", { className: "uxf-typo-h6" }, props.title),
61
61
  react_1.default.createElement("div", { className: "flex items-center space-x-4" },
62
- react_1.default.createElement(icon_button_1.IconButton, { iconName: "delete", label: "d", onClick: removeHandler, size: "sm", variant: "secondary" }),
62
+ react_1.default.createElement(icon_button_1.IconButton, { iconName: "delete", label: t("uxf-cms-pages-content-builder:components.content-header.delete-section"), onClick: removeHandler, size: "sm", variant: "secondary" }),
63
63
  react_1.default.createElement(icon_1.Icon, { name: `${visibility ? "chevronUp" : "chevronDown"}`, size: 16 }))));
64
64
  };
65
65
  exports.ContentHeader = ContentHeader;
@@ -37,8 +37,8 @@ exports.DetailsVisibilityProvider = exports.useDetailsVisibilityControls = expor
37
37
  const noop_1 = require("@uxf/core/utils/noop");
38
38
  const global_context_1 = require("@uxf/core-react/global-context");
39
39
  const react_1 = __importStar(require("react"));
40
- const detailsVisibilityContext = (0, global_context_1.createGlobalContext)("cms/content-builder/details-visibility", [[], noop_1.noop, true, noop_1.noop]);
41
- const useDetailsVisibility = () => (0, react_1.useContext)(detailsVisibilityContext);
40
+ const DetailsVisibilityContext = (0, global_context_1.createGlobalContext)("cms/content-builder/details-visibility", [[], noop_1.noop, true, noop_1.noop]);
41
+ const useDetailsVisibility = () => (0, react_1.useContext)(DetailsVisibilityContext);
42
42
  const useDetailsVisibilityForSection = (sectionId) => {
43
43
  var _a;
44
44
  const [detailsVisibility, setDetailsVisibility, defaultVisibility] = useDetailsVisibility();
@@ -64,6 +64,6 @@ exports.useDetailsVisibilityControls = useDetailsVisibilityControls;
64
64
  const DetailsVisibilityProvider = (props) => {
65
65
  const [defaultVisibility, setDefaultVisibility] = (0, react_1.useState)(true);
66
66
  const [detailsVisibility, setDetailsVisibility] = (0, react_1.useState)([]);
67
- return (react_1.default.createElement(detailsVisibilityContext.Provider, { value: [detailsVisibility, setDetailsVisibility, defaultVisibility, setDefaultVisibility] }, props.children));
67
+ return (react_1.default.createElement(DetailsVisibilityContext, { value: [detailsVisibility, setDetailsVisibility, defaultVisibility, setDefaultVisibility] }, props.children));
68
68
  };
69
69
  exports.DetailsVisibilityProvider = DetailsVisibilityProvider;
@@ -53,10 +53,10 @@ const loader_1 = require("@uxf/ui/loader");
53
53
  const link_1 = __importDefault(require("next/link"));
54
54
  const router_2 = __importStar(require("next/router"));
55
55
  const react_1 = __importStar(require("react"));
56
- const url_1 = require("url");
57
56
  const swr_1 = require("../../api/swr");
58
57
  const api_1 = require("../../lib/api");
59
58
  const restricted_page_1 = require("../../security/restricted-page");
59
+ const history_pathname_1 = require("./history-pathname");
60
60
  // TODO use swr
61
61
  const { axiosRequest } = (0, api_1.createAxiosInstance)("");
62
62
  const dataGridLoader = (gridName, request) => {
@@ -81,7 +81,7 @@ function GridPageComponent(props) {
81
81
  // save filter to url
82
82
  const newQuery = { ...query, filter: encodedRequest };
83
83
  // TODO @vejvis - dodělat vlastní router a tuhle magii smazat!
84
- router_2.default.replace(`${(0, url_1.parse)(((_a = window.history.state) === null || _a === void 0 ? void 0 : _a.url) || "").pathname}?${(0, qs_1.stringify)(newQuery)}`, `${(0, url_1.parse)(((_b = window.history.state) === null || _b === void 0 ? void 0 : _b.as) || "").pathname}?${(0, qs_1.stringify)(newQuery)}`, { shallow: true });
84
+ router_2.default.replace(`${(0, history_pathname_1.historyPathname)((_a = window.history.state) === null || _a === void 0 ? void 0 : _a.url)}?${(0, qs_1.stringify)(newQuery)}`, `${(0, history_pathname_1.historyPathname)((_b = window.history.state) === null || _b === void 0 ? void 0 : _b.as)}?${(0, qs_1.stringify)(newQuery)}`, { shallow: true });
85
85
  return response;
86
86
  }, [query]);
87
87
  const { data, isLoading, error, reload } = (0, use_data_grid_fetching_1.useDataGridFetching)({
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The pathname of a URL kept in Next.js's `history.state` (`url` or `as`), resolved against the current page.
3
+ * Node's legacy `url.parse` used to do this: it is deprecated (DEP0169), dragged a `url` polyfill into the
4
+ * browser bundle, and for a missing URL returned `null`, which ended up in the address as "null?…".
5
+ */
6
+ export declare function historyPathname(url: string | undefined): string;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.historyPathname = historyPathname;
4
+ /**
5
+ * The pathname of a URL kept in Next.js's `history.state` (`url` or `as`), resolved against the current page.
6
+ * Node's legacy `url.parse` used to do this: it is deprecated (DEP0169), dragged a `url` polyfill into the
7
+ * browser bundle, and for a missing URL returned `null`, which ended up in the address as "null?…".
8
+ */
9
+ function historyPathname(url) {
10
+ return new URL(url !== null && url !== void 0 ? url : "", window.location.href).pathname;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const history_pathname_1 = require("./history-pathname");
4
+ test("takes the pathname of a history-state URL", () => {
5
+ expect((0, history_pathname_1.historyPathname)("/cms/grid/[entity]?entity=user&filter=abc")).toBe("/cms/grid/[entity]");
6
+ });
7
+ test("falls back to the current page when history state has no URL", () => {
8
+ window.history.replaceState(null, "", "/cms/grid/user?x=1");
9
+ expect((0, history_pathname_1.historyPathname)(undefined)).toBe("/cms/grid/user");
10
+ expect((0, history_pathname_1.historyPathname)("")).toBe("/cms/grid/user");
11
+ });
@@ -5,6 +5,9 @@ declare const _default: {
5
5
  "confirm-delete-section": {
6
6
  cs: string;
7
7
  };
8
+ "delete-section": {
9
+ cs: string;
10
+ };
8
11
  };
9
12
  header: {
10
13
  save: {
@@ -7,6 +7,9 @@ exports.default = {
7
7
  "confirm-delete-section": {
8
8
  cs: "Opravdu chcete smazat tuto sekci?",
9
9
  },
10
+ "delete-section": {
11
+ cs: "Smazat sekci",
12
+ },
10
13
  },
11
14
  header: {
12
15
  save: {
@@ -16,7 +16,7 @@ function ErrorContent(props) {
16
16
  if (props.error.code === "UNAUTHORIZED") {
17
17
  return (react_1.default.createElement(react_1.default.Fragment, null,
18
18
  react_1.default.createElement("div", null, t("uxf-cms-restricted-page:login-required")),
19
- react_1.default.createElement(button_1.Button, { href: `/admin/login?redirect=${window.location.href}` }, t("uxf-cms-restricted-page:login"))));
19
+ react_1.default.createElement(button_1.Button, { href: `/admin/login?${new URLSearchParams({ redirect: window.location.href })}` }, t("uxf-cms-restricted-page:login"))));
20
20
  }
21
21
  return react_1.default.createElement("div", null, t("uxf-cms-restricted-page:unknown-error"));
22
22
  }
@@ -69,7 +69,8 @@
69
69
  "uxf-cms-pages-content-builder": {
70
70
  "components": {
71
71
  "content-header": {
72
- "confirm-delete-section": "Opravdu chcete smazat tuto sekci?"
72
+ "confirm-delete-section": "Opravdu chcete smazat tuto sekci?",
73
+ "delete-section": "Smazat sekci"
73
74
  },
74
75
  "header": {
75
76
  "save": "Uložit"
@@ -31,6 +31,9 @@ declare const _default: {
31
31
  "confirm-delete-section": {
32
32
  cs: string;
33
33
  };
34
+ "delete-section": {
35
+ cs: string;
36
+ };
34
37
  };
35
38
  header: {
36
39
  save: {
@@ -2,27 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useViewportHeight = useViewportHeight;
4
4
  const react_1 = require("react");
5
- function getHeight() {
6
- var _a, _b;
7
- if (typeof window === "undefined") {
8
- return "100vh";
9
- }
10
- return (_b = (_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : "100vh";
11
- }
5
+ const use_visual_viewport_height_1 = require("./use-visual-viewport-height");
12
6
  function useViewportHeight(scrollLock) {
13
- const [height, setHeight] = (0, react_1.useState)(() => getHeight());
7
+ var _a;
14
8
  (0, react_1.useEffect)(() => {
15
- if (scrollLock) {
16
- document.body.classList.add("xl:overflow-hidden");
9
+ if (!scrollLock) {
10
+ return;
17
11
  }
18
- const handler = () => setHeight(getHeight());
19
- window.addEventListener("resize", handler);
20
- return () => {
21
- if (scrollLock) {
22
- document.body.classList.remove("xl:overflow-hidden");
23
- }
24
- window.removeEventListener("resize", handler);
25
- };
12
+ document.body.classList.add("xl:overflow-hidden");
13
+ return () => document.body.classList.remove("xl:overflow-hidden");
26
14
  }, [scrollLock]);
27
- return height;
15
+ return (_a = (0, use_visual_viewport_height_1.useVisualViewportHeight)()) !== null && _a !== void 0 ? _a : "100vh";
28
16
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_1 = require("@testing-library/react");
4
+ const use_viewport_height_1 = require("./use-viewport-height");
5
+ class FakeVisualViewport extends EventTarget {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.height = 700;
9
+ this.scale = 1;
10
+ }
11
+ }
12
+ let visualViewport;
13
+ beforeEach(() => {
14
+ visualViewport = new FakeVisualViewport();
15
+ Object.defineProperty(window, "visualViewport", { configurable: true, value: visualViewport });
16
+ });
17
+ afterEach(() => {
18
+ Object.defineProperty(window, "visualViewport", { configurable: true, value: undefined });
19
+ });
20
+ test("follows the visual viewport, which shrinks when the on-screen keyboard opens", () => {
21
+ const { result } = (0, react_1.renderHook)(() => (0, use_viewport_height_1.useViewportHeight)());
22
+ (0, react_1.act)(() => {
23
+ visualViewport.height = 400;
24
+ // iOS fires this on the visual viewport only; window gets no resize event.
25
+ visualViewport.dispatchEvent(new Event("resize"));
26
+ });
27
+ expect(result.current).toBe(400);
28
+ });
29
+ test("ignores pinch zoom, which shrinks the visual viewport by the zoom scale", () => {
30
+ const { result } = (0, react_1.renderHook)(() => (0, use_viewport_height_1.useViewportHeight)());
31
+ (0, react_1.act)(() => {
32
+ visualViewport.scale = 2;
33
+ visualViewport.height = 350;
34
+ visualViewport.dispatchEvent(new Event("resize"));
35
+ });
36
+ expect(result.current).toBe(700);
37
+ });
@@ -0,0 +1,2 @@
1
+ /** Height of the visual viewport in px, not counting pinch zoom; `undefined` on the server and while hydrating. */
2
+ export declare function useVisualViewportHeight(): number | undefined;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useVisualViewportHeight = useVisualViewportHeight;
4
+ const react_1 = require("react");
5
+ function subscribe(onStoreChange) {
6
+ var _a;
7
+ // The visual viewport has its own resize event: iOS fires it when the on-screen keyboard opens, and the window
8
+ // gets none.
9
+ const target = (_a = window.visualViewport) !== null && _a !== void 0 ? _a : window;
10
+ const controller = new AbortController();
11
+ target.addEventListener("resize", onStoreChange, { signal: controller.signal });
12
+ return () => controller.abort();
13
+ }
14
+ function getSnapshot() {
15
+ const viewport = window.visualViewport;
16
+ // Times the zoom scale: pinch zoom shrinks `height` by the scale, and the layout must not shrink with it. The
17
+ // on-screen keyboard shrinks it at scale 1, which is the change to follow.
18
+ return viewport ? viewport.height * viewport.scale : window.innerHeight;
19
+ }
20
+ /** Height of the visual viewport in px, not counting pinch zoom; `undefined` on the server and while hydrating. */
21
+ function useVisualViewportHeight() {
22
+ return (0, react_1.useSyncExternalStore)(subscribe, getSnapshot, () => undefined);
23
+ }