xmlui 0.10.25 → 0.10.26
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/dist/lib/{index-CCEPGw_x.mjs → index-DHXWMb-6.mjs} +5798 -5755
- package/dist/lib/{initMock-DFcCR7ey.mjs → initMock-TxnkId6_.mjs} +1 -1
- package/dist/lib/language-server-web-worker.mjs +1 -1
- package/dist/lib/language-server.mjs +1 -1
- package/dist/lib/{metadata-utils-Dx-2qZBh.mjs → metadata-utils-DXUdlyja.mjs} +6 -6
- package/dist/lib/{server-common--BHVvP1o.mjs → server-common-CtpN0Z4h.mjs} +1 -1
- package/dist/lib/xmlui.mjs +1 -1
- package/dist/metadata/{collectedComponentMetadata-mwkNkxN_.mjs → collectedComponentMetadata-BgHIc2Iu.mjs} +12381 -12338
- package/dist/metadata/{initMock-BVxHA6wu.mjs → initMock-B3UDa-rw.mjs} +1 -1
- package/dist/metadata/xmlui-metadata.mjs +1 -1
- package/dist/metadata/xmlui-metadata.umd.js +3 -3
- package/dist/scripts/package.json +1 -1
- package/dist/scripts/src/components/App/App.spec.js +100 -0
- package/dist/scripts/src/components/App/AppNative.js +13 -2
- package/dist/scripts/src/components/AppHeader/AppHeader.js +1 -6
- package/dist/scripts/src/components/AppHeader/AppHeaderNative.js +6 -7
- package/dist/scripts/src/components/Heading/Heading.js +45 -5
- package/dist/scripts/src/components/Heading/Heading.spec.js +82 -0
- package/dist/scripts/src/components-core/rendering/valueExtractor.js +9 -1
- package/dist/scripts/src/components-core/utils/extractParam.js +2 -1
- package/dist/standalone/xmlui-standalone.umd.js +32 -32
- package/package.json +1 -1
|
@@ -217,3 +217,103 @@ fixtures_1.test.describe("Event Handling", () => {
|
|
|
217
217
|
yield fixtures_1.expect.poll(testStateDriver.testState).toEqual(testData);
|
|
218
218
|
}));
|
|
219
219
|
});
|
|
220
|
+
// =============================================================================
|
|
221
|
+
// Drawer HANDLING TESTS
|
|
222
|
+
// =============================================================================
|
|
223
|
+
fixtures_1.test.describe("Drawer Handling", () => {
|
|
224
|
+
(0, fixtures_1.test)("Drawer displayed if NavPanel has no 'when'", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
225
|
+
// Set small viewport to trigger drawer mode
|
|
226
|
+
yield page.setViewportSize({ width: 400, height: 600 });
|
|
227
|
+
yield initTestBed(`
|
|
228
|
+
<App layout="condensed">
|
|
229
|
+
<AppHeader testId="appHeader"/>
|
|
230
|
+
<NavPanel>
|
|
231
|
+
<NavGroup label="Pages">
|
|
232
|
+
<NavLink label="Page 1" to="/page1"/>
|
|
233
|
+
<NavLink label="Page 2" to="/page2"/>
|
|
234
|
+
</NavGroup>
|
|
235
|
+
</NavPanel>
|
|
236
|
+
</App>
|
|
237
|
+
`);
|
|
238
|
+
// Open drawer by clicking hamburger button
|
|
239
|
+
const appHeader = page.getByTestId("appHeader");
|
|
240
|
+
const hamburgerButton = appHeader.locator('[data-part-id="hamburger"]').first();
|
|
241
|
+
yield (0, fixtures_1.expect)(hamburgerButton).toBeVisible();
|
|
242
|
+
}));
|
|
243
|
+
(0, fixtures_1.test)("Drawer displayed if NavPanel has when='true'", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
244
|
+
// Set small viewport to trigger drawer mode
|
|
245
|
+
yield page.setViewportSize({ width: 400, height: 600 });
|
|
246
|
+
yield initTestBed(`
|
|
247
|
+
<App layout="condensed">
|
|
248
|
+
<AppHeader testId="appHeader"/>
|
|
249
|
+
<NavPanel when="true">
|
|
250
|
+
<NavGroup label="Pages">
|
|
251
|
+
<NavLink label="Page 1" to="/page1"/>
|
|
252
|
+
<NavLink label="Page 2" to="/page2"/>
|
|
253
|
+
</NavGroup>
|
|
254
|
+
</NavPanel>
|
|
255
|
+
</App>
|
|
256
|
+
`);
|
|
257
|
+
// Open drawer by clicking hamburger button
|
|
258
|
+
const appHeader = page.getByTestId("appHeader");
|
|
259
|
+
const hamburgerButton = appHeader.locator('[data-part-id="hamburger"]').first();
|
|
260
|
+
yield (0, fixtures_1.expect)(hamburgerButton).toBeVisible();
|
|
261
|
+
}));
|
|
262
|
+
(0, fixtures_1.test)("Drawer displayed if NavPanel has when='{true}'", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
263
|
+
// Set small viewport to trigger drawer mode
|
|
264
|
+
yield page.setViewportSize({ width: 400, height: 600 });
|
|
265
|
+
yield initTestBed(`
|
|
266
|
+
<App layout="condensed">
|
|
267
|
+
<AppHeader testId="appHeader"/>
|
|
268
|
+
<NavPanel when="{true}">
|
|
269
|
+
<NavGroup label="Pages">
|
|
270
|
+
<NavLink label="Page 1" to="/page1"/>
|
|
271
|
+
<NavLink label="Page 2" to="/page2"/>
|
|
272
|
+
</NavGroup>
|
|
273
|
+
</NavPanel>
|
|
274
|
+
</App>
|
|
275
|
+
`);
|
|
276
|
+
// Open drawer by clicking hamburger button
|
|
277
|
+
const appHeader = page.getByTestId("appHeader");
|
|
278
|
+
const hamburgerButton = appHeader.locator('[data-part-id="hamburger"]').first();
|
|
279
|
+
yield (0, fixtures_1.expect)(hamburgerButton).toBeVisible();
|
|
280
|
+
}));
|
|
281
|
+
(0, fixtures_1.test)("Drawer not displayed if NavPanel has when='false'", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
282
|
+
// Set small viewport to trigger drawer mode
|
|
283
|
+
yield page.setViewportSize({ width: 400, height: 600 });
|
|
284
|
+
yield initTestBed(`
|
|
285
|
+
<App layout="condensed">
|
|
286
|
+
<AppHeader testId="appHeader"/>
|
|
287
|
+
<NavPanel when="false">
|
|
288
|
+
<NavGroup label="Pages">
|
|
289
|
+
<NavLink label="Page 1" to="/page1"/>
|
|
290
|
+
<NavLink label="Page 2" to="/page2"/>
|
|
291
|
+
</NavGroup>
|
|
292
|
+
</NavPanel>
|
|
293
|
+
</App>
|
|
294
|
+
`);
|
|
295
|
+
// Open drawer by clicking hamburger button
|
|
296
|
+
const appHeader = page.getByTestId("appHeader");
|
|
297
|
+
const hamburgerButton = appHeader.locator('[data-part-id="hamburger"]').first();
|
|
298
|
+
yield (0, fixtures_1.expect)(hamburgerButton).not.toBeVisible();
|
|
299
|
+
}));
|
|
300
|
+
(0, fixtures_1.test)("Drawer not displayed if NavPanel has when='{false}'", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
301
|
+
// Set small viewport to trigger drawer mode
|
|
302
|
+
yield page.setViewportSize({ width: 400, height: 600 });
|
|
303
|
+
yield initTestBed(`
|
|
304
|
+
<App layout="condensed">
|
|
305
|
+
<AppHeader testId="appHeader"/>
|
|
306
|
+
<NavPanel when="{false}">
|
|
307
|
+
<NavGroup label="Pages">
|
|
308
|
+
<NavLink label="Page 1" to="/page1"/>
|
|
309
|
+
<NavLink label="Page 2" to="/page2"/>
|
|
310
|
+
</NavGroup>
|
|
311
|
+
</NavPanel>
|
|
312
|
+
</App>
|
|
313
|
+
`);
|
|
314
|
+
// Open drawer by clicking hamburger button
|
|
315
|
+
const appHeader = page.getByTestId("appHeader");
|
|
316
|
+
const hamburgerButton = appHeader.locator('[data-part-id="hamburger"]').first();
|
|
317
|
+
yield (0, fixtures_1.expect)(hamburgerButton).not.toBeVisible();
|
|
318
|
+
}));
|
|
319
|
+
});
|
|
@@ -34,6 +34,7 @@ const AppLayoutContext_1 = require("./AppLayoutContext");
|
|
|
34
34
|
const SearchContext_1 = require("./SearchContext");
|
|
35
35
|
const LinkInfoContext_1 = require("./LinkInfoContext");
|
|
36
36
|
const constants_1 = require("../../components-core/constants");
|
|
37
|
+
const extractParam_1 = require("../../components-core/utils/extractParam");
|
|
37
38
|
exports.defaultProps = {
|
|
38
39
|
scrollWholePage: true,
|
|
39
40
|
noScrollbarGutters: false,
|
|
@@ -50,9 +51,19 @@ function App(_a) {
|
|
|
50
51
|
const mounted = (0, react_1.useRef)(false);
|
|
51
52
|
const layoutWithDefaultValue = layout || getThemeVar("layout-App") || "condensed-sticky";
|
|
52
53
|
const safeLayout = layoutWithDefaultValue === null || layoutWithDefaultValue === void 0 ? void 0 : layoutWithDefaultValue.trim().replace(/[\u2013\u2014\u2011]/g, "-"); //It replaces all – (–) and — (—) and non-breaking hyphen '‑' symbols with simple dashes (-).
|
|
53
|
-
const
|
|
54
|
+
const appContext = (0, AppContext_1.useAppContext)();
|
|
55
|
+
const { setLoggedInUser, mediaSize, forceRefreshAnchorScroll, appGlobals } = appContext;
|
|
54
56
|
const hasRegisteredHeader = header !== undefined;
|
|
55
|
-
|
|
57
|
+
// --- Check if NavPanel's "when" condition allows it to be rendered
|
|
58
|
+
// --- This ensures the drawer and hamburger menu are hidden when NavPanel.when evaluates to false
|
|
59
|
+
const navPanelShouldRender = (0, react_1.useMemo)(() => {
|
|
60
|
+
if (!navPanelDef)
|
|
61
|
+
return false;
|
|
62
|
+
// Use shouldKeep to evaluate the NavPanel's when condition
|
|
63
|
+
// Pass empty state {} and appContext since we're evaluating at the App level
|
|
64
|
+
return (0, extractParam_1.shouldKeep)(navPanelDef.when, {}, appContext);
|
|
65
|
+
}, [navPanelDef, appContext]);
|
|
66
|
+
const hasRegisteredNavPanel = navPanelDef !== undefined && navPanelShouldRender;
|
|
56
67
|
(0, react_1.useEffect)(() => {
|
|
57
68
|
setLoggedInUser(loggedInUser);
|
|
58
69
|
}, [loggedInUser, setLoggedInUser]);
|
|
@@ -34,11 +34,6 @@ exports.AppHeaderMd = (0, metadata_helpers_1.createMetadata)({
|
|
|
34
34
|
valueType: "boolean",
|
|
35
35
|
defaultValue: AppHeaderNative_1.defaultProps.showLogo,
|
|
36
36
|
},
|
|
37
|
-
showNavPanelIf: {
|
|
38
|
-
description: "Determines if the navigation panel should be displayed",
|
|
39
|
-
valueType: "boolean",
|
|
40
|
-
defaultValue: AppHeaderNative_1.defaultProps.showNavPanelIf,
|
|
41
|
-
},
|
|
42
37
|
},
|
|
43
38
|
themeVars: (0, themeVars_1.parseScssVar)(AppHeader_module_scss_1.default.themeVars),
|
|
44
39
|
themeVarDescriptions: {
|
|
@@ -53,7 +48,7 @@ exports.appHeaderComponentRenderer = (0, renderers_1.createComponentRenderer)(CO
|
|
|
53
48
|
// --- Convert the plain (text) logo template into component definition
|
|
54
49
|
const logoTemplate = node.props.logoTemplate || ((_a = node.slots) === null || _a === void 0 ? void 0 : _a.logoSlot);
|
|
55
50
|
const titleTemplate = node.props.titleTemplate || ((_b = node.slots) === null || _b === void 0 ? void 0 : _b.titleSlot);
|
|
56
|
-
return ((0, jsx_runtime_1.jsx)(AppHeaderNative_1.AppContextAwareAppHeader, { profileMenu: renderChild(extractValue(node.props.profileMenuTemplate, true)), title: extractValue(node.props.title), showLogo: extractValue.asOptionalBoolean(node.props.showLogo),
|
|
51
|
+
return ((0, jsx_runtime_1.jsx)(AppHeaderNative_1.AppContextAwareAppHeader, { profileMenu: renderChild(extractValue(node.props.profileMenuTemplate, true)), title: extractValue(node.props.title), showLogo: extractValue.asOptionalBoolean(node.props.showLogo), titleContent: titleTemplate && ((0, jsx_runtime_1.jsx)(SlotItem_1.SlotItem, { node: titleTemplate, renderChild: renderChild, slotProps: { title: extractValue(node.props.title) } })), logoContent: renderChild(logoTemplate, {
|
|
57
52
|
type: "Stack",
|
|
58
53
|
orientation: "horizontal",
|
|
59
54
|
}), className: (0, classnames_1.default)(layoutContext === null || layoutContext === void 0 ? void 0 : layoutContext.themeClassName, className), renderChild: renderChild, children: renderChild(node.children, {
|
|
@@ -33,7 +33,6 @@ const hooks_1 = require("../../components-core/utils/hooks");
|
|
|
33
33
|
const PART_HAMBURGER = "hamburger";
|
|
34
34
|
exports.defaultProps = {
|
|
35
35
|
showLogo: true,
|
|
36
|
-
showNavPanelIf: true,
|
|
37
36
|
};
|
|
38
37
|
function useLogoUrl() {
|
|
39
38
|
const { logo, logoLight, logoDark } = (0, AppLayoutContext_1.useAppLayoutContext)() || {};
|
|
@@ -47,27 +46,27 @@ function useLogoUrl() {
|
|
|
47
46
|
return toneLogoUrl || baseLogoUrl;
|
|
48
47
|
}
|
|
49
48
|
const AppHeader = (_a) => {
|
|
50
|
-
var { children, profileMenu, style = constants_1.EMPTY_OBJECT, logoContent, className, canRestrictContentWidth, navPanelVisible = true, toggleDrawer, showLogo = exports.defaultProps.showLogo,
|
|
49
|
+
var { children, profileMenu, style = constants_1.EMPTY_OBJECT, logoContent, className, canRestrictContentWidth, navPanelVisible = true, toggleDrawer, showLogo = exports.defaultProps.showLogo, hasRegisteredNavPanel, title, titleContent, registerSubNavPanelSlot } = _a, rest = __rest(_a, ["children", "profileMenu", "style", "logoContent", "className", "canRestrictContentWidth", "navPanelVisible", "toggleDrawer", "showLogo", "hasRegisteredNavPanel", "title", "titleContent", "registerSubNavPanelSlot"]);
|
|
51
50
|
const { mediaSize } = (0, AppContext_1.useAppContext)();
|
|
52
51
|
const logoUrl = useLogoUrl();
|
|
53
52
|
const subNavPanelSlot = (0, react_1.useRef)(null);
|
|
54
|
-
const effectiveNavPanelVisible = navPanelVisible
|
|
53
|
+
const effectiveNavPanelVisible = navPanelVisible;
|
|
55
54
|
const safeLogoTitle = mediaSize.sizeIndex < 2 ? null : !titleContent && title ? ((0, jsx_runtime_1.jsx)(NavLinkNative_1.NavLink, { to: "/", displayActive: false, style: { paddingLeft: 0 }, children: title })) : (titleContent);
|
|
56
55
|
(0, hooks_1.useIsomorphicLayoutEffect)(() => {
|
|
57
56
|
registerSubNavPanelSlot === null || registerSubNavPanelSlot === void 0 ? void 0 : registerSubNavPanelSlot(subNavPanelSlot.current);
|
|
58
57
|
}, []);
|
|
59
58
|
return ((0, jsx_runtime_1.jsx)("div", Object.assign({}, rest, { className: (0, classnames_1.default)(AppHeader_module_scss_1.default.header, className), style: style, role: "banner", children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(AppHeader_module_scss_1.default.headerInner, {
|
|
60
59
|
[AppHeader_module_scss_1.default.full]: !canRestrictContentWidth,
|
|
61
|
-
}), children: [hasRegisteredNavPanel &&
|
|
60
|
+
}), children: [hasRegisteredNavPanel && ((0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { "data-part-id": PART_HAMBURGER, onClick: toggleDrawer, icon: (0, jsx_runtime_1.jsx)(IconNative_1.Icon, { name: "hamburger" }), variant: "ghost", className: AppHeader_module_scss_1.default.drawerToggle, style: { color: "inherit", flexShrink: 0 } })), (0, jsx_runtime_1.jsx)("div", { className: AppHeader_module_scss_1.default.logoAndTitle, children: (showLogo || !effectiveNavPanelVisible) &&
|
|
62
61
|
(logoContent ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: AppHeader_module_scss_1.default.customLogoContainer, children: logoContent }), safeLogoTitle] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!!logoUrl && ((0, jsx_runtime_1.jsx)("div", { className: AppHeader_module_scss_1.default.logoContainer, children: (0, jsx_runtime_1.jsx)(NavLinkNative_1.NavLink, { to: "/", displayActive: false, className: AppHeader_module_scss_1.default.logoLink, children: (0, jsx_runtime_1.jsx)(LogoNative_1.Logo, {}) }) })), safeLogoTitle] }))) }), (0, jsx_runtime_1.jsx)("div", { ref: subNavPanelSlot, className: AppHeader_module_scss_1.default.subNavPanelSlot }), (0, jsx_runtime_1.jsx)("div", { className: AppHeader_module_scss_1.default.childrenWrapper, children: children }), profileMenu && (0, jsx_runtime_1.jsx)("div", { className: AppHeader_module_scss_1.default.rightItems, children: profileMenu })] }) })));
|
|
63
62
|
};
|
|
64
63
|
exports.AppHeader = AppHeader;
|
|
65
|
-
function AppContextAwareAppHeader({ children, logoContent, profileMenu, style, className, title, titleContent, showLogo = true,
|
|
64
|
+
function AppContextAwareAppHeader({ children, logoContent, profileMenu, style, className, title, titleContent, showLogo = true, renderChild, }) {
|
|
66
65
|
const appLayoutContext = (0, AppLayoutContext_1.useAppLayoutContext)();
|
|
67
66
|
const { navPanelVisible, toggleDrawer, layout, hasRegisteredNavPanel, navPanelDef, logoContentDef, registerSubNavPanelSlot, } = appLayoutContext || {};
|
|
68
67
|
// console.log("APP LAYOUT CONTEXT", appLayoutContext);
|
|
69
68
|
const displayLogo = layout !== "vertical" && layout !== "vertical-sticky" && showLogo;
|
|
70
69
|
const canRestrictContentWidth = layout !== "vertical-full-header";
|
|
71
|
-
const effectiveNavPanelVisible = navPanelVisible
|
|
72
|
-
return ((0, jsx_runtime_1.jsxs)(exports.AppHeader, { hasRegisteredNavPanel: hasRegisteredNavPanel, navPanelVisible: effectiveNavPanelVisible, toggleDrawer: toggleDrawer, canRestrictContentWidth: canRestrictContentWidth, showLogo: displayLogo,
|
|
70
|
+
const effectiveNavPanelVisible = navPanelVisible;
|
|
71
|
+
return ((0, jsx_runtime_1.jsxs)(exports.AppHeader, { hasRegisteredNavPanel: hasRegisteredNavPanel, navPanelVisible: effectiveNavPanelVisible, toggleDrawer: toggleDrawer, canRestrictContentWidth: canRestrictContentWidth, showLogo: displayLogo, logoContent: logoContent || renderChild(logoContentDef), profileMenu: profileMenu, style: style, className: className, title: title, titleContent: titleContent, registerSubNavPanelSlot: registerSubNavPanelSlot, children: [(layout === null || layout === void 0 ? void 0 : layout.startsWith("condensed")) && effectiveNavPanelVisible && ((0, jsx_runtime_1.jsx)("div", { style: { minWidth: 0 }, children: renderChild(navPanelDef) })), children] }));
|
|
73
72
|
}
|
|
@@ -23,6 +23,37 @@ const HeadingNative_1 = require("./HeadingNative");
|
|
|
23
23
|
const extractParam_1 = require("../../components-core/utils/extractParam");
|
|
24
24
|
const metadata_helpers_1 = require("../metadata-helpers");
|
|
25
25
|
const COMP = "Heading";
|
|
26
|
+
/**
|
|
27
|
+
* Normalizes the level value to a valid HeadingLevel (h1-h6).
|
|
28
|
+
* Accepts: 1-6, "1"-"6", "h1"-"h6", "H1"-"H6"
|
|
29
|
+
* Returns "h1" for any invalid value.
|
|
30
|
+
*/
|
|
31
|
+
function normalizeHeadingLevel(value) {
|
|
32
|
+
if (value === null || value === undefined) {
|
|
33
|
+
return "h1";
|
|
34
|
+
}
|
|
35
|
+
// Handle numeric values (1-6)
|
|
36
|
+
if (typeof value === "number") {
|
|
37
|
+
if (value >= 1 && value <= 6) {
|
|
38
|
+
return `h${value}`;
|
|
39
|
+
}
|
|
40
|
+
return "h1";
|
|
41
|
+
}
|
|
42
|
+
// Handle string values
|
|
43
|
+
if (typeof value === "string") {
|
|
44
|
+
const trimmed = value.trim().toLowerCase();
|
|
45
|
+
// Handle "h1"-"h6" (case insensitive)
|
|
46
|
+
if (/^h[1-6]$/.test(trimmed)) {
|
|
47
|
+
return trimmed;
|
|
48
|
+
}
|
|
49
|
+
// Handle "1"-"6"
|
|
50
|
+
if (/^[1-6]$/.test(trimmed)) {
|
|
51
|
+
return `h${trimmed}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Default fallback
|
|
55
|
+
return "h1";
|
|
56
|
+
}
|
|
26
57
|
const VALUE_DESC = (0, metadata_helpers_1.d)(`This property determines the text displayed in the heading. \`${COMP}\` also accepts nested ` +
|
|
27
58
|
`text instead of specifying the \`value\`. If both \`value\` and a nested text are used, ` +
|
|
28
59
|
`the \`value\` will be displayed.`);
|
|
@@ -68,8 +99,14 @@ exports.HeadingMd = (0, metadata_helpers_1.createMetadata)({
|
|
|
68
99
|
props: {
|
|
69
100
|
value: VALUE_DESC,
|
|
70
101
|
level: {
|
|
71
|
-
description: "This property sets the visual significance (level) of the heading."
|
|
72
|
-
|
|
102
|
+
description: "This property sets the visual significance (level) of the heading. " +
|
|
103
|
+
"Accepts multiple formats: `h1`-`h6`, `H1`-`H6`, or `1`-`6`." +
|
|
104
|
+
"Invalid values default to `h1`.",
|
|
105
|
+
availableValues: [
|
|
106
|
+
"h1", "h2", "h3", "h4", "h5", "h6",
|
|
107
|
+
"H1", "H2", "H3", "H4", "H5", "H6",
|
|
108
|
+
"1", "2", "3", "4", "5", "6",
|
|
109
|
+
],
|
|
73
110
|
defaultValue: HeadingNative_1.defaultProps.level,
|
|
74
111
|
},
|
|
75
112
|
maxLines: MAX_LINES_DESC,
|
|
@@ -278,11 +315,14 @@ exports.H6Md = (0, metadata_helpers_1.createMetadata)({
|
|
|
278
315
|
},
|
|
279
316
|
});
|
|
280
317
|
function renderHeading({ node, extractValue, className, level, renderChild, registerComponentApi, }) {
|
|
281
|
-
var _a, _b
|
|
282
|
-
const
|
|
318
|
+
var _a, _b;
|
|
319
|
+
const _c = node.props, { maxLines, preserveLinebreaks, ellipses, showAnchor } = _c, restProps = __rest(_c, ["maxLines", "preserveLinebreaks", "ellipses", "showAnchor"]);
|
|
283
320
|
delete restProps.level; // Remove level from restProps as it is handled separately
|
|
284
321
|
const showAnchorValue = extractValue.asOptionalBoolean((_a = node.props) === null || _a === void 0 ? void 0 : _a.showAnchor);
|
|
285
|
-
|
|
322
|
+
// Extract and normalize the level value
|
|
323
|
+
const extractedLevel = extractValue(level);
|
|
324
|
+
const normalizedLevel = normalizeHeadingLevel(extractedLevel);
|
|
325
|
+
return ((0, jsx_runtime_1.jsx)(HeadingNative_1.Heading, Object.assign({ uid: node.uid, level: normalizedLevel, maxLines: extractValue.asOptionalNumber(maxLines), preserveLinebreaks: extractValue.asOptionalBoolean(preserveLinebreaks, false), ellipses: extractValue.asOptionalBoolean(ellipses, true), showAnchor: showAnchorValue, className: className, omitFromToc: extractValue.asOptionalBoolean((_b = node.props) === null || _b === void 0 ? void 0 : _b.omitFromToc), registerComponentApi: registerComponentApi }, (0, extractParam_1.resolveAndCleanProps)(restProps, extractValue), { children: extractValue.asDisplayText(node.props.value) || renderChild(node.children) })));
|
|
286
326
|
}
|
|
287
327
|
exports.headingComponentRenderer = (0, renderers_1.createComponentRenderer)(COMP, exports.HeadingMd, ({ node, extractValue, className, renderChild, registerComponentApi }) => {
|
|
288
328
|
return renderHeading({
|
|
@@ -336,6 +336,88 @@ fixtures_1.test.describe("Basic Functionality", () => {
|
|
|
336
336
|
const driver = yield createHeadingDriver();
|
|
337
337
|
yield (0, fixtures_1.expect)(driver.component).toHaveText("Child content text");
|
|
338
338
|
}));
|
|
339
|
+
fixtures_1.test.describe("level property accepts numeric values", () => {
|
|
340
|
+
[1, 2, 3, 4, 5, 6].forEach((level) => {
|
|
341
|
+
(0, fixtures_1.test)(`level="{${level}}" renders as h${level}`, (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createHeadingDriver }) {
|
|
342
|
+
yield initTestBed(`<Heading level="{${level}}">Numeric Level ${level}</Heading>`);
|
|
343
|
+
const driver = yield createHeadingDriver();
|
|
344
|
+
yield (0, fixtures_1.expect)(driver.component).toBeVisible();
|
|
345
|
+
const tagName = yield driver.getComponentTagName();
|
|
346
|
+
(0, fixtures_1.expect)(tagName.toLowerCase()).toBe(`h${level}`);
|
|
347
|
+
yield (0, fixtures_1.expect)(driver.component).toHaveText(`Numeric Level ${level}`);
|
|
348
|
+
}));
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
fixtures_1.test.describe("level property accepts string numeric values", () => {
|
|
352
|
+
["1", "2", "3", "4", "5", "6"].forEach((level) => {
|
|
353
|
+
(0, fixtures_1.test)(`level="${level}" renders as h${level}`, (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createHeadingDriver }) {
|
|
354
|
+
yield initTestBed(`<Heading level="${level}">String Level ${level}</Heading>`);
|
|
355
|
+
const driver = yield createHeadingDriver();
|
|
356
|
+
yield (0, fixtures_1.expect)(driver.component).toBeVisible();
|
|
357
|
+
const tagName = yield driver.getComponentTagName();
|
|
358
|
+
(0, fixtures_1.expect)(tagName.toLowerCase()).toBe(`h${level}`);
|
|
359
|
+
yield (0, fixtures_1.expect)(driver.component).toHaveText(`String Level ${level}`);
|
|
360
|
+
}));
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
fixtures_1.test.describe("level property accepts uppercase H format", () => {
|
|
364
|
+
["H1", "H2", "H3", "H4", "H5", "H6"].forEach((level) => {
|
|
365
|
+
(0, fixtures_1.test)(`level="${level}" renders as ${level.toLowerCase()}`, (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createHeadingDriver }) {
|
|
366
|
+
yield initTestBed(`<Heading level="${level}">Uppercase Level ${level}</Heading>`);
|
|
367
|
+
const driver = yield createHeadingDriver();
|
|
368
|
+
yield (0, fixtures_1.expect)(driver.component).toBeVisible();
|
|
369
|
+
const tagName = yield driver.getComponentTagName();
|
|
370
|
+
(0, fixtures_1.expect)(tagName.toLowerCase()).toBe(level.toLowerCase());
|
|
371
|
+
yield (0, fixtures_1.expect)(driver.component).toHaveText(`Uppercase Level ${level}`);
|
|
372
|
+
}));
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
fixtures_1.test.describe("level property handles invalid values", () => {
|
|
376
|
+
[
|
|
377
|
+
{ value: '"invalid"', label: "invalid string" },
|
|
378
|
+
{ value: '"{0}"', label: "zero" },
|
|
379
|
+
{ value: '"{7}"', label: "out of range number (7)" },
|
|
380
|
+
{ value: '"{-1}"', label: "negative number" },
|
|
381
|
+
{ value: '"{999}"', label: "large number" },
|
|
382
|
+
{ value: '"h7"', label: "invalid h-format (h7)" },
|
|
383
|
+
{ value: '"h0"', label: "invalid h-format (h0)" },
|
|
384
|
+
{ value: '"7"', label: "out of range string (7)" },
|
|
385
|
+
{ value: '"{null}"', label: "null" },
|
|
386
|
+
{ value: '"{undefined}"', label: "undefined" },
|
|
387
|
+
{ value: '"{{}}"', label: "empty object" },
|
|
388
|
+
{ value: '"{[]}"', label: "empty array" },
|
|
389
|
+
].forEach(({ value, label }) => {
|
|
390
|
+
(0, fixtures_1.test)(`level=${value} (${label}) defaults to h1`, (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createHeadingDriver }) {
|
|
391
|
+
yield initTestBed(`<Heading level=${value}>Invalid Level Fallback</Heading>`);
|
|
392
|
+
const driver = yield createHeadingDriver();
|
|
393
|
+
yield (0, fixtures_1.expect)(driver.component).toBeVisible();
|
|
394
|
+
const tagName = yield driver.getComponentTagName();
|
|
395
|
+
(0, fixtures_1.expect)(tagName.toLowerCase()).toBe("h1");
|
|
396
|
+
yield (0, fixtures_1.expect)(driver.component).toHaveText("Invalid Level Fallback");
|
|
397
|
+
}));
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
(0, fixtures_1.test)("level property with mixed case string formats", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createHeadingDriver }) {
|
|
401
|
+
const testCases = [
|
|
402
|
+
{ input: "H3", expected: "h3" },
|
|
403
|
+
{ input: "h3", expected: "h3" },
|
|
404
|
+
{ input: "h3", expected: "h3" },
|
|
405
|
+
];
|
|
406
|
+
for (const { input, expected } of testCases) {
|
|
407
|
+
yield initTestBed(`<Heading level="${input}">Mixed Case ${input}</Heading>`);
|
|
408
|
+
const driver = yield createHeadingDriver();
|
|
409
|
+
yield (0, fixtures_1.expect)(driver.component).toBeVisible();
|
|
410
|
+
const tagName = yield driver.getComponentTagName();
|
|
411
|
+
(0, fixtures_1.expect)(tagName.toLowerCase()).toBe(expected);
|
|
412
|
+
}
|
|
413
|
+
}));
|
|
414
|
+
(0, fixtures_1.test)("level property handles whitespace in string values", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createHeadingDriver }) {
|
|
415
|
+
yield initTestBed(`<Heading level=" h2 ">Whitespace Level</Heading>`);
|
|
416
|
+
const driver = yield createHeadingDriver();
|
|
417
|
+
yield (0, fixtures_1.expect)(driver.component).toBeVisible();
|
|
418
|
+
const tagName = yield driver.getComponentTagName();
|
|
419
|
+
(0, fixtures_1.expect)(tagName.toLowerCase()).toBe("h2");
|
|
420
|
+
}));
|
|
339
421
|
});
|
|
340
422
|
// =============================================================================
|
|
341
423
|
// ACCESSIBILITY TESTS (REQUIRED)
|
|
@@ -43,6 +43,14 @@ function collectParams(expression) {
|
|
|
43
43
|
function asOptionalBoolean(value, defValue) {
|
|
44
44
|
if (value === undefined || value === null)
|
|
45
45
|
return defValue;
|
|
46
|
+
// Empty array returns false
|
|
47
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// Empty object returns false
|
|
51
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
46
54
|
if (typeof value === "number") {
|
|
47
55
|
return value !== 0;
|
|
48
56
|
}
|
|
@@ -64,7 +72,7 @@ function asOptionalBoolean(value, defValue) {
|
|
|
64
72
|
if (typeof value === "boolean") {
|
|
65
73
|
return value;
|
|
66
74
|
}
|
|
67
|
-
|
|
75
|
+
return true;
|
|
68
76
|
}
|
|
69
77
|
// This function represents the extractor function we pass to extractValue
|
|
70
78
|
function createValueExtractor(state, appContext, referenceTrackedApi, memoedVarsRef) {
|
|
@@ -15,6 +15,7 @@ const ParameterParser_1 = require("../script-runner/ParameterParser");
|
|
|
15
15
|
const eval_tree_sync_1 = require("../script-runner/eval-tree-sync");
|
|
16
16
|
const LruCache_1 = require("../utils/LruCache");
|
|
17
17
|
const descriptorHelper_1 = require("../descriptorHelper");
|
|
18
|
+
const valueExtractor_1 = require("../rendering/valueExtractor");
|
|
18
19
|
/**
|
|
19
20
|
* Extract the value of the specified parameter from the given view container state
|
|
20
21
|
* @param state The state of the view container
|
|
@@ -159,7 +160,7 @@ function shouldKeep(when, componentState, appContext) {
|
|
|
159
160
|
if (when === undefined) {
|
|
160
161
|
return true;
|
|
161
162
|
}
|
|
162
|
-
return extractParam(componentState, when, appContext, true);
|
|
163
|
+
return (0, valueExtractor_1.asOptionalBoolean)(extractParam(componentState, when, appContext, true));
|
|
163
164
|
}
|
|
164
165
|
/**
|
|
165
166
|
* Resolves props that can either be regular properties or URL resources.
|