@red-hat-developer-hub/backstage-plugin-global-header 1.21.0 → 1.21.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-global-header
2
2
 
3
+ ## 1.21.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 4cabc3b: Fix help dropdown not closing when selecting Quick Start menu item.
8
+
9
+ ## 1.21.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 351d260: Fixed the css issue when drawer opens, fixed the validity check bug
14
+
3
15
  ## 1.21.0
4
16
 
5
17
  ### Minor Changes
@@ -7,16 +7,29 @@ import { useGlobalHeaderComponents } from '../extensions/GlobalHeaderContext.esm
7
7
 
8
8
  const GlobalHeader = () => {
9
9
  const components = useGlobalHeaderComponents();
10
- return /* @__PURE__ */ jsx(AppBar, { position: "sticky", component: "nav", id: "global-header", children: /* @__PURE__ */ jsx(
11
- Toolbar,
10
+ return /* @__PURE__ */ jsx(
11
+ AppBar,
12
12
  {
13
+ position: "sticky",
14
+ component: "nav",
15
+ id: "global-header",
13
16
  sx: {
14
- gap: 1,
15
- color: (theme) => theme.rhdh?.general?.appBarForegroundColor ?? theme.palette.text.primary
17
+ width: "auto",
18
+ marginRight: "var(--docked-drawer-width, 0px)",
19
+ transition: "margin-right 225ms cubic-bezier(0, 0, 0.2, 1)"
16
20
  },
17
- children: components.map((item, index) => /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Box, { sx: item.layout, children: /* @__PURE__ */ jsx(item.component, {}) }) }, `gh-component-${index}`))
21
+ children: /* @__PURE__ */ jsx(
22
+ Toolbar,
23
+ {
24
+ sx: {
25
+ gap: 1,
26
+ color: (theme) => theme.rhdh?.general?.appBarForegroundColor ?? theme.palette.text.primary
27
+ },
28
+ children: components.map((item, index) => /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Box, { sx: item.layout, children: /* @__PURE__ */ jsx(item.component, {}) }) }, `gh-component-${index}`))
29
+ }
30
+ )
18
31
  }
19
- ) });
32
+ );
20
33
  };
21
34
 
22
35
  export { GlobalHeader };
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalHeader.esm.js","sources":["../../../src/alpha/components/GlobalHeader.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ErrorBoundary } from '@backstage/core-components';\n\nimport AppBar from '@mui/material/AppBar';\nimport Box from '@mui/material/Box';\nimport Toolbar from '@mui/material/Toolbar';\n\nimport { useGlobalHeaderComponents } from '../extensions/GlobalHeaderContext';\n\n/**\n * Global header bar. Reads toolbar items from GlobalHeaderContext\n * and renders them in a sticky AppBar.\n *\n * @alpha\n */\nexport const GlobalHeader = () => {\n const components = useGlobalHeaderComponents();\n\n return (\n <AppBar position=\"sticky\" component=\"nav\" id=\"global-header\">\n <Toolbar\n sx={{\n gap: 1,\n color: theme =>\n (theme as any).rhdh?.general?.appBarForegroundColor ??\n theme.palette.text.primary,\n }}\n >\n {components.map((item, index) => (\n <ErrorBoundary key={`gh-component-${index}`}>\n <Box sx={item.layout}>\n <item.component />\n </Box>\n </ErrorBoundary>\n ))}\n </Toolbar>\n </AppBar>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA8BO,MAAM,eAAe,MAAM;AAChC,EAAA,MAAM,aAAa,yBAA0B,EAAA;AAE7C,EAAA,2BACG,MAAO,EAAA,EAAA,QAAA,EAAS,UAAS,SAAU,EAAA,KAAA,EAAM,IAAG,eAC3C,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,EAAI,EAAA;AAAA,QACF,GAAK,EAAA,CAAA;AAAA,QACL,KAAA,EAAO,WACJ,KAAc,CAAA,IAAA,EAAM,SAAS,qBAC9B,IAAA,KAAA,CAAM,QAAQ,IAAK,CAAA;AAAA,OACvB;AAAA,MAEC,QAAA,EAAA,UAAA,CAAW,IAAI,CAAC,IAAA,EAAM,0BACpB,GAAA,CAAA,aAAA,EAAA,EACC,8BAAC,GAAI,EAAA,EAAA,EAAA,EAAI,KAAK,MACZ,EAAA,QAAA,kBAAA,GAAA,CAAC,KAAK,SAAL,EAAA,EAAe,GAClB,CAHkB,EAAA,EAAA,CAAA,aAAA,EAAgB,KAAK,CAAA,CAIzC,CACD;AAAA;AAAA,GAEL,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"GlobalHeader.esm.js","sources":["../../../src/alpha/components/GlobalHeader.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ErrorBoundary } from '@backstage/core-components';\n\nimport AppBar from '@mui/material/AppBar';\nimport Box from '@mui/material/Box';\nimport Toolbar from '@mui/material/Toolbar';\n\nimport { useGlobalHeaderComponents } from '../extensions/GlobalHeaderContext';\n\n/**\n * Global header bar. Reads toolbar items from GlobalHeaderContext\n * and renders them in a sticky AppBar.\n *\n * @alpha\n */\nexport const GlobalHeader = () => {\n const components = useGlobalHeaderComponents();\n\n return (\n <AppBar\n position=\"sticky\"\n component=\"nav\"\n id=\"global-header\"\n sx={{\n width: 'auto',\n marginRight: 'var(--docked-drawer-width, 0px)',\n transition: 'margin-right 225ms cubic-bezier(0, 0, 0.2, 1)',\n }}\n >\n <Toolbar\n sx={{\n gap: 1,\n color: theme =>\n (theme as any).rhdh?.general?.appBarForegroundColor ??\n theme.palette.text.primary,\n }}\n >\n {components.map((item, index) => (\n <ErrorBoundary key={`gh-component-${index}`}>\n <Box sx={item.layout}>\n <item.component />\n </Box>\n </ErrorBoundary>\n ))}\n </Toolbar>\n </AppBar>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA8BO,MAAM,eAAe,MAAM;AAChC,EAAA,MAAM,aAAa,yBAA0B,EAAA;AAE7C,EACE,uBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,QAAA;AAAA,MACT,SAAU,EAAA,KAAA;AAAA,MACV,EAAG,EAAA,eAAA;AAAA,MACH,EAAI,EAAA;AAAA,QACF,KAAO,EAAA,MAAA;AAAA,QACP,WAAa,EAAA,iCAAA;AAAA,QACb,UAAY,EAAA;AAAA,OACd;AAAA,MAEA,QAAA,kBAAA,GAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,EAAI,EAAA;AAAA,YACF,GAAK,EAAA,CAAA;AAAA,YACL,KAAA,EAAO,WACJ,KAAc,CAAA,IAAA,EAAM,SAAS,qBAC9B,IAAA,KAAA,CAAM,QAAQ,IAAK,CAAA;AAAA,WACvB;AAAA,UAEC,QAAA,EAAA,UAAA,CAAW,IAAI,CAAC,IAAA,EAAM,0BACpB,GAAA,CAAA,aAAA,EAAA,EACC,8BAAC,GAAI,EAAA,EAAA,EAAA,EAAI,KAAK,MACZ,EAAA,QAAA,kBAAA,GAAA,CAAC,KAAK,SAAL,EAAA,EAAe,GAClB,CAHkB,EAAA,EAAA,CAAA,aAAA,EAAgB,KAAK,CAAA,CAIzC,CACD;AAAA;AAAA;AACH;AAAA,GACF;AAEJ;;;;"}
@@ -23,13 +23,14 @@ const GlobalHeaderDropdown = ({
23
23
  const entries = useMemo(() => buildDropdownEntries(menuItems), [menuItems]);
24
24
  const menuListRef = useRef(null);
25
25
  const [hasVisibleItems, setHasVisibleItems] = useState(true);
26
+ const isOpen = Boolean(anchorEl);
26
27
  useLayoutEffect(() => {
27
- if (!trackValidity || !menuListRef.current) return;
28
+ if (!trackValidity || !isOpen || !menuListRef.current) return;
28
29
  const found = menuListRef.current.querySelector('[role="menuitem"]') !== null;
29
30
  if (found !== hasVisibleItems) {
30
31
  setHasVisibleItems(found);
31
32
  }
32
- }, [trackValidity, hasVisibleItems]);
33
+ }, [trackValidity, hasVisibleItems, isOpen]);
33
34
  if (menuItems.length === 0 && !emptyState) return null;
34
35
  const showEmpty = entries.length === 0 || trackValidity && !hasVisibleItems;
35
36
  return /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalHeaderDropdown.esm.js","sources":["../../../src/alpha/components/GlobalHeaderDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type Button from '@mui/material/Button';\n\nimport { useGlobalHeaderMenuItems } from '../extensions/GlobalHeaderContext';\nimport { buildDropdownEntries } from '../utils/menuItemGrouping';\nimport { useDropdownManager } from '../../hooks';\nimport { HeaderDropdownComponent } from '../../components/HeaderDropdownComponent/HeaderDropdownComponent';\nimport { GlobalHeaderDropdownContent } from './GlobalHeaderDropdownContent';\n\n/**\n * Props for {@link GlobalHeaderDropdown}.\n *\n * @alpha\n */\nexport interface GlobalHeaderDropdownProps {\n /** Extension target name that items are collected from (e.g. `'help'`, `'create'`). */\n target: string;\n /** Content rendered inside the trigger button. */\n buttonContent: ReactNode;\n /** MUI Button props forwarded to the trigger. */\n buttonProps?: ComponentProps<typeof Button>;\n /** Render an `IconButton` instead of a regular `Button`. */\n isIconButton?: boolean;\n /** Tooltip shown on hover of the trigger button. */\n tooltip?: string;\n /** Rendered when no menu items are contributed (or all render empty when `trackValidity` is on). */\n emptyState?: ReactNode;\n /**\n * When `true`, the dropdown checks the rendered MenuList for visible\n * `[role=\"menuitem\"]` elements after each render. If none are found,\n * the `emptyState` is shown instead.\n */\n trackValidity?: boolean;\n}\n\n/**\n * High-level dropdown building block for the global header.\n *\n * Collects menu items from a named extension `target`, groups them\n * by section, sorts by priority, and renders them inside a\n * `HeaderDropdownComponent`.\n *\n * @alpha\n */\nexport const GlobalHeaderDropdown = ({\n target,\n buttonContent,\n buttonProps,\n isIconButton,\n tooltip,\n emptyState,\n trackValidity = false,\n}: GlobalHeaderDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n const menuItems = useGlobalHeaderMenuItems(target);\n const entries = useMemo(() => buildDropdownEntries(menuItems), [menuItems]);\n\n const menuListRef = useRef<HTMLUListElement>(null);\n const [hasVisibleItems, setHasVisibleItems] = useState(true);\n\n useLayoutEffect(() => {\n if (!trackValidity || !menuListRef.current) return;\n const found =\n menuListRef.current.querySelector('[role=\"menuitem\"]') !== null;\n if (found !== hasVisibleItems) {\n setHasVisibleItems(found);\n }\n }, [trackValidity, hasVisibleItems]);\n\n if (menuItems.length === 0 && !emptyState) return null;\n\n const showEmpty = entries.length === 0 || (trackValidity && !hasVisibleItems);\n\n return (\n <HeaderDropdownComponent\n buttonContent={buttonContent}\n buttonProps={buttonProps}\n isIconButton={isIconButton}\n tooltip={tooltip}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n menuListRef={trackValidity ? menuListRef : undefined}\n >\n {showEmpty ? (\n emptyState\n ) : (\n <GlobalHeaderDropdownContent\n entries={entries}\n target={target}\n handleClose={handleClose}\n />\n )}\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AA6DO,MAAM,uBAAuB,CAAC;AAAA,EACnC,MAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAgB,GAAA;AAClB,CAAiC,KAAA;AAC/B,EAAA,MAAM,EAAE,QAAA,EAAU,UAAY,EAAA,WAAA,KAAgB,kBAAmB,EAAA;AACjE,EAAM,MAAA,SAAA,GAAY,yBAAyB,MAAM,CAAA;AACjD,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM,oBAAA,CAAqB,SAAS,CAAG,EAAA,CAAC,SAAS,CAAC,CAAA;AAE1E,EAAM,MAAA,WAAA,GAAc,OAAyB,IAAI,CAAA;AACjD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3D,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,CAAC,aAAA,IAAiB,CAAC,WAAA,CAAY,OAAS,EAAA;AAC5C,IAAA,MAAM,KACJ,GAAA,WAAA,CAAY,OAAQ,CAAA,aAAA,CAAc,mBAAmB,CAAM,KAAA,IAAA;AAC7D,IAAA,IAAI,UAAU,eAAiB,EAAA;AAC7B,MAAA,kBAAA,CAAmB,KAAK,CAAA;AAAA;AAC1B,GACC,EAAA,CAAC,aAAe,EAAA,eAAe,CAAC,CAAA;AAEnC,EAAA,IAAI,SAAU,CAAA,MAAA,KAAW,CAAK,IAAA,CAAC,YAAmB,OAAA,IAAA;AAElD,EAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,MAAW,KAAA,CAAA,IAAM,iBAAiB,CAAC,eAAA;AAE7D,EACE,uBAAA,GAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,aAAA;AAAA,MACA,WAAA;AAAA,MACA,YAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAQ,EAAA,UAAA;AAAA,MACR,OAAS,EAAA,WAAA;AAAA,MACT,QAAA;AAAA,MACA,WAAA,EAAa,gBAAgB,WAAc,GAAA,KAAA,CAAA;AAAA,MAE1C,sBACC,UAEA,mBAAA,GAAA;AAAA,QAAC,2BAAA;AAAA,QAAA;AAAA,UACC,OAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA;AAAA;AACF;AAAA,GAEJ;AAEJ;;;;"}
1
+ {"version":3,"file":"GlobalHeaderDropdown.esm.js","sources":["../../../src/alpha/components/GlobalHeaderDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type Button from '@mui/material/Button';\n\nimport { useGlobalHeaderMenuItems } from '../extensions/GlobalHeaderContext';\nimport { buildDropdownEntries } from '../utils/menuItemGrouping';\nimport { useDropdownManager } from '../../hooks';\nimport { HeaderDropdownComponent } from '../../components/HeaderDropdownComponent/HeaderDropdownComponent';\nimport { GlobalHeaderDropdownContent } from './GlobalHeaderDropdownContent';\n\n/**\n * Props for {@link GlobalHeaderDropdown}.\n *\n * @alpha\n */\nexport interface GlobalHeaderDropdownProps {\n /** Extension target name that items are collected from (e.g. `'help'`, `'create'`). */\n target: string;\n /** Content rendered inside the trigger button. */\n buttonContent: ReactNode;\n /** MUI Button props forwarded to the trigger. */\n buttonProps?: ComponentProps<typeof Button>;\n /** Render an `IconButton` instead of a regular `Button`. */\n isIconButton?: boolean;\n /** Tooltip shown on hover of the trigger button. */\n tooltip?: string;\n /** Rendered when no menu items are contributed (or all render empty when `trackValidity` is on). */\n emptyState?: ReactNode;\n /**\n * When `true`, the dropdown checks the rendered MenuList for visible\n * `[role=\"menuitem\"]` elements after each render. If none are found,\n * the `emptyState` is shown instead.\n */\n trackValidity?: boolean;\n}\n\n/**\n * High-level dropdown building block for the global header.\n *\n * Collects menu items from a named extension `target`, groups them\n * by section, sorts by priority, and renders them inside a\n * `HeaderDropdownComponent`.\n *\n * @alpha\n */\nexport const GlobalHeaderDropdown = ({\n target,\n buttonContent,\n buttonProps,\n isIconButton,\n tooltip,\n emptyState,\n trackValidity = false,\n}: GlobalHeaderDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n const menuItems = useGlobalHeaderMenuItems(target);\n const entries = useMemo(() => buildDropdownEntries(menuItems), [menuItems]);\n\n const menuListRef = useRef<HTMLUListElement>(null);\n const [hasVisibleItems, setHasVisibleItems] = useState(true);\n const isOpen = Boolean(anchorEl);\n\n useLayoutEffect(() => {\n if (!trackValidity || !isOpen || !menuListRef.current) return;\n const found =\n menuListRef.current.querySelector('[role=\"menuitem\"]') !== null;\n if (found !== hasVisibleItems) {\n setHasVisibleItems(found);\n }\n }, [trackValidity, hasVisibleItems, isOpen]);\n\n if (menuItems.length === 0 && !emptyState) return null;\n\n const showEmpty = entries.length === 0 || (trackValidity && !hasVisibleItems);\n\n return (\n <HeaderDropdownComponent\n buttonContent={buttonContent}\n buttonProps={buttonProps}\n isIconButton={isIconButton}\n tooltip={tooltip}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n menuListRef={trackValidity ? menuListRef : undefined}\n >\n {showEmpty ? (\n emptyState\n ) : (\n <GlobalHeaderDropdownContent\n entries={entries}\n target={target}\n handleClose={handleClose}\n />\n )}\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AA6DO,MAAM,uBAAuB,CAAC;AAAA,EACnC,MAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAgB,GAAA;AAClB,CAAiC,KAAA;AAC/B,EAAA,MAAM,EAAE,QAAA,EAAU,UAAY,EAAA,WAAA,KAAgB,kBAAmB,EAAA;AACjE,EAAM,MAAA,SAAA,GAAY,yBAAyB,MAAM,CAAA;AACjD,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM,oBAAA,CAAqB,SAAS,CAAG,EAAA,CAAC,SAAS,CAAC,CAAA;AAE1E,EAAM,MAAA,WAAA,GAAc,OAAyB,IAAI,CAAA;AACjD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,IAAI,CAAA;AAC3D,EAAM,MAAA,MAAA,GAAS,QAAQ,QAAQ,CAAA;AAE/B,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,CAAC,aAAiB,IAAA,CAAC,MAAU,IAAA,CAAC,YAAY,OAAS,EAAA;AACvD,IAAA,MAAM,KACJ,GAAA,WAAA,CAAY,OAAQ,CAAA,aAAA,CAAc,mBAAmB,CAAM,KAAA,IAAA;AAC7D,IAAA,IAAI,UAAU,eAAiB,EAAA;AAC7B,MAAA,kBAAA,CAAmB,KAAK,CAAA;AAAA;AAC1B,GACC,EAAA,CAAC,aAAe,EAAA,eAAA,EAAiB,MAAM,CAAC,CAAA;AAE3C,EAAA,IAAI,SAAU,CAAA,MAAA,KAAW,CAAK,IAAA,CAAC,YAAmB,OAAA,IAAA;AAElD,EAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,MAAW,KAAA,CAAA,IAAM,iBAAiB,CAAC,eAAA;AAE7D,EACE,uBAAA,GAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,aAAA;AAAA,MACA,WAAA;AAAA,MACA,YAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAQ,EAAA,UAAA;AAAA,MACR,OAAS,EAAA,WAAA;AAAA,MACT,QAAA;AAAA,MACA,WAAA,EAAa,gBAAgB,WAAc,GAAA,KAAA,CAAA;AAAA,MAE1C,sBACC,UAEA,mBAAA,GAAA;AAAA,QAAC,2BAAA;AAAA,QAAA;AAAA,UACC,OAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA;AAAA;AACF;AAAA,GAEJ;AAEJ;;;;"}
@@ -1,5 +1,4 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { Fragment } from 'react';
3
2
  import { Link } from '@backstage/core-components';
4
3
  import MenuItem from '@mui/material/MenuItem';
5
4
  import { MenuItemLink } from '../../components/MenuItemLink/MenuItemLink.esm.js';
@@ -20,8 +19,7 @@ const GlobalHeaderMenuItem = ({
20
19
  disableTouchRipple: true,
21
20
  onClick,
22
21
  sx: { py: 0.5, color: "inherit", textDecoration: "none" },
23
- component: to ? Link : Fragment,
24
- to,
22
+ ...to ? { component: Link, to } : {},
25
23
  children: /* @__PURE__ */ jsx(
26
24
  MenuItemLink,
27
25
  {
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalHeaderMenuItem.esm.js","sources":["../../../src/alpha/components/GlobalHeaderMenuItem.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\n\nimport { Link } from '@backstage/core-components';\n\nimport MenuItem from '@mui/material/MenuItem';\n\nimport { MenuItemLink } from '../../components/MenuItemLink/MenuItemLink';\n\n/**\n * Props for {@link GlobalHeaderMenuItem}.\n *\n * @alpha\n */\nexport interface GlobalHeaderMenuItemProps {\n /** Navigation URL. When absent the item renders as a plain action button. */\n to?: string;\n /** Display title. */\n title?: string;\n /** Translation key for the title. */\n titleKey?: string;\n /** Secondary text rendered below the title. */\n subTitle?: string;\n /** Translation key for the secondary text. */\n subTitleKey?: string;\n /** Icon identifier passed to `HeaderIcon`. */\n icon?: string;\n /** Tooltip shown on hover. */\n tooltip?: string;\n /** Called when the item is clicked (typically the dropdown's `handleClose`). */\n onClick?: () => void;\n}\n\n/**\n * A complete, self-contained menu item for use inside header dropdowns.\n *\n * Renders a MUI `MenuItem` with optional `Link` navigation and the\n * standard `MenuItemLink` content (icon, title, subtitle, external\n * link indicator). Consumers only need this one component — no manual\n * `MenuItem` or `Link` wrapping required.\n *\n * @example\n * ```tsx\n * const MyHelpItem = ({ handleClose }) => (\n * <GlobalHeaderMenuItem\n * to=\"https://docs.example.com\"\n * title=\"Documentation\"\n * icon=\"menu_book\"\n * onClick={handleClose}\n * />\n * );\n * ```\n *\n * @alpha\n */\nexport const GlobalHeaderMenuItem = ({\n to,\n title,\n titleKey,\n subTitle,\n subTitleKey,\n icon,\n tooltip,\n onClick,\n}: GlobalHeaderMenuItemProps) => (\n <MenuItem\n disableRipple\n disableTouchRipple\n onClick={onClick}\n sx={{ py: 0.5, color: 'inherit', textDecoration: 'none' }}\n component={to ? Link : Fragment}\n to={to}\n >\n <MenuItemLink\n to={to ?? ''}\n title={title}\n titleKey={titleKey}\n subTitle={subTitle}\n subTitleKey={subTitleKey}\n icon={icon}\n tooltip={tooltip}\n />\n </MenuItem>\n);\n"],"names":[],"mappings":";;;;;;AAsEO,MAAM,uBAAuB,CAAC;AAAA,EACnC,EAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CACE,qBAAA,GAAA;AAAA,EAAC,QAAA;AAAA,EAAA;AAAA,IACC,aAAa,EAAA,IAAA;AAAA,IACb,kBAAkB,EAAA,IAAA;AAAA,IAClB,OAAA;AAAA,IACA,IAAI,EAAE,EAAA,EAAI,KAAK,KAAO,EAAA,SAAA,EAAW,gBAAgB,MAAO,EAAA;AAAA,IACxD,SAAA,EAAW,KAAK,IAAO,GAAA,QAAA;AAAA,IACvB,EAAA;AAAA,IAEA,QAAA,kBAAA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,IAAI,EAAM,IAAA,EAAA;AAAA,QACV,KAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA;AAAA;AACF;AACF;;;;"}
1
+ {"version":3,"file":"GlobalHeaderMenuItem.esm.js","sources":["../../../src/alpha/components/GlobalHeaderMenuItem.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Link } from '@backstage/core-components';\n\nimport MenuItem from '@mui/material/MenuItem';\n\nimport { MenuItemLink } from '../../components/MenuItemLink/MenuItemLink';\n\n/**\n * Props for {@link GlobalHeaderMenuItem}.\n *\n * @alpha\n */\nexport interface GlobalHeaderMenuItemProps {\n /** Navigation URL. When absent the item renders as a plain action button. */\n to?: string;\n /** Display title. */\n title?: string;\n /** Translation key for the title. */\n titleKey?: string;\n /** Secondary text rendered below the title. */\n subTitle?: string;\n /** Translation key for the secondary text. */\n subTitleKey?: string;\n /** Icon identifier passed to `HeaderIcon`. */\n icon?: string;\n /** Tooltip shown on hover. */\n tooltip?: string;\n /** Called when the item is clicked (typically the dropdown's `handleClose`). */\n onClick?: () => void;\n}\n\n/**\n * A complete, self-contained menu item for use inside header dropdowns.\n *\n * Renders a MUI `MenuItem` with optional `Link` navigation and the\n * standard `MenuItemLink` content (icon, title, subtitle, external\n * link indicator). Consumers only need this one component — no manual\n * `MenuItem` or `Link` wrapping required.\n *\n * @example\n * ```tsx\n * const MyHelpItem = ({ handleClose }) => (\n * <GlobalHeaderMenuItem\n * to=\"https://docs.example.com\"\n * title=\"Documentation\"\n * icon=\"menu_book\"\n * onClick={handleClose}\n * />\n * );\n * ```\n *\n * @alpha\n */\nexport const GlobalHeaderMenuItem = ({\n to,\n title,\n titleKey,\n subTitle,\n subTitleKey,\n icon,\n tooltip,\n onClick,\n}: GlobalHeaderMenuItemProps) => (\n <MenuItem\n disableRipple\n disableTouchRipple\n onClick={onClick}\n sx={{ py: 0.5, color: 'inherit', textDecoration: 'none' }}\n {...(to ? { component: Link, to } : {})}\n >\n <MenuItemLink\n to={to ?? ''}\n title={title}\n titleKey={titleKey}\n subTitle={subTitle}\n subTitleKey={subTitleKey}\n icon={icon}\n tooltip={tooltip}\n />\n </MenuItem>\n);\n"],"names":[],"mappings":";;;;;AAoEO,MAAM,uBAAuB,CAAC;AAAA,EACnC,EAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CACE,qBAAA,GAAA;AAAA,EAAC,QAAA;AAAA,EAAA;AAAA,IACC,aAAa,EAAA,IAAA;AAAA,IACb,kBAAkB,EAAA,IAAA;AAAA,IAClB,OAAA;AAAA,IACA,IAAI,EAAE,EAAA,EAAI,KAAK,KAAO,EAAA,SAAA,EAAW,gBAAgB,MAAO,EAAA;AAAA,IACvD,GAAI,EAAK,GAAA,EAAE,WAAW,IAAM,EAAA,EAAA,KAAO,EAAC;AAAA,IAErC,QAAA,kBAAA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,IAAI,EAAM,IAAA,EAAA;AAAA,QACV,KAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA;AAAA;AACF;AACF;;;;"}
@@ -55,15 +55,18 @@ const HelpDropdown = ({ layout }) => {
55
55
  const componentId = `${mp.config?.props?.title || "helpItem"}-${mp.config?.priority || 0}-${index}`;
56
56
  return {
57
57
  componentId,
58
- Component: () => /* @__PURE__ */ jsx(
59
- ValidityTracker,
60
- {
61
- Component: mp.Component,
62
- props: mp.config?.props || {},
63
- componentId,
64
- onValidityChange: updateComponentValidity
65
- }
66
- ),
58
+ Component: (props) => {
59
+ const onClick = "onClick" in props ? props.onClick : void 0;
60
+ return /* @__PURE__ */ jsx(
61
+ ValidityTracker,
62
+ {
63
+ Component: mp.Component,
64
+ props: { ...mp.config?.props || {}, onClick },
65
+ componentId,
66
+ onValidityChange: updateComponentValidity
67
+ }
68
+ );
69
+ },
67
70
  icon: mp.config?.props?.icon,
68
71
  label: mp.config?.props?.title,
69
72
  link: mp.config?.props?.link,
@@ -1 +1 @@
1
- {"version":3,"file":"HelpDropdown.esm.js","sources":["../../../src/components/HeaderDropdownComponent/HelpDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport type { ComponentType, CSSProperties } from 'react';\nimport { HeaderDropdownComponent } from './HeaderDropdownComponent';\nimport { useDropdownManager } from '../../hooks';\nimport HelpOutlineIcon from '@mui/icons-material/HelpOutline';\nimport { useHelpDropdownMountPoints } from '../../hooks/useHelpDropdownMountPoints';\nimport { MenuSection } from './MenuSection';\nimport { DropdownEmptyState } from './DropdownEmptyState';\nimport SupportAgentIcon from '@mui/icons-material/SupportAgent';\nimport { useValidComponentTracker } from '../../hooks/useValidComponentTracker';\nimport { useTranslation } from '../../hooks/useTranslation';\n\n/**\n * @public\n */\nexport interface HelpDropdownProps {\n layout?: CSSProperties;\n}\n\nconst ValidityTracker = ({\n Component,\n props,\n componentId,\n onValidityChange,\n}: {\n Component: ComponentType<any>;\n props: any;\n componentId: string;\n onValidityChange: (componentId: string, isValid: boolean) => void;\n}) => {\n const contentRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const checkContent = () => {\n if (!contentRef.current) return;\n\n const element = contentRef.current;\n const hasText = (element.textContent?.trim().length ?? 0) > 0;\n const hasChildren = element.children.length > 0;\n const hasChildNodes = element.childNodes.length > 0;\n\n // A component is valid if it renders ANY content at all\n const componentIsValid = hasText || hasChildren || hasChildNodes;\n\n onValidityChange(componentId, componentIsValid);\n };\n\n // Check after component has had time to render (longer timeout for lazy components)\n const timer1 = setTimeout(checkContent, 500);\n const timer2 = setTimeout(checkContent, 1500); // Double check later\n\n return () => {\n clearTimeout(timer1);\n clearTimeout(timer2);\n };\n }, [componentId, onValidityChange]);\n\n try {\n return (\n <div ref={contentRef}>\n <Component {...props} />\n </div>\n );\n } catch (error) {\n onValidityChange(componentId, false);\n return null;\n }\n};\n\nexport const HelpDropdown = ({ layout }: HelpDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n const helpDropdownMountPoints = useHelpDropdownMountPoints();\n const { t } = useTranslation();\n\n const { shouldShowEmpty, updateComponentValidity } = useValidComponentTracker(\n helpDropdownMountPoints?.length ?? 0,\n );\n\n // Create all mount point items with validity tracking\n const allMenuItems = useMemo(() => {\n return (helpDropdownMountPoints ?? [])\n .map((mp, index) => {\n const componentId = `${mp.config?.props?.title || 'helpItem'}-${\n mp.config?.priority || 0\n }-${index}`;\n\n return {\n componentId,\n Component: () => (\n <ValidityTracker\n Component={mp.Component}\n props={mp.config?.props || {}}\n componentId={componentId}\n onValidityChange={updateComponentValidity}\n />\n ),\n icon: mp.config?.props?.icon,\n label: mp.config?.props?.title,\n link: mp.config?.props?.link,\n tooltip: mp.config?.props?.tooltip,\n style: mp.config?.style,\n priority: mp.config?.priority ?? 0,\n };\n })\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n }, [helpDropdownMountPoints, updateComponentValidity]);\n\n const menuItems = allMenuItems;\n\n return (\n <HeaderDropdownComponent\n isIconButton\n tooltip={t('help.tooltip')}\n buttonContent={<HelpOutlineIcon />}\n buttonProps={{\n color: 'inherit',\n sx: layout,\n }}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n >\n {!shouldShowEmpty ? (\n <MenuSection hideDivider items={menuItems} handleClose={handleClose} />\n ) : (\n <DropdownEmptyState\n title={t('help.noSupportLinks')}\n subTitle={t('help.noSupportLinksSubtitle')}\n icon={\n <SupportAgentIcon sx={{ fontSize: 64, color: 'text.disabled' }} />\n }\n />\n )}\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HelpDropdown.esm.js","sources":["../../../src/components/HeaderDropdownComponent/HelpDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport type { ComponentType, CSSProperties } from 'react';\nimport type { MenuItemProps } from '@mui/material/MenuItem';\nimport { HeaderDropdownComponent } from './HeaderDropdownComponent';\nimport { useDropdownManager } from '../../hooks';\nimport HelpOutlineIcon from '@mui/icons-material/HelpOutline';\nimport { useHelpDropdownMountPoints } from '../../hooks/useHelpDropdownMountPoints';\nimport { MenuSection } from './MenuSection';\nimport { DropdownEmptyState } from './DropdownEmptyState';\nimport SupportAgentIcon from '@mui/icons-material/SupportAgent';\nimport { useValidComponentTracker } from '../../hooks/useValidComponentTracker';\nimport { useTranslation } from '../../hooks/useTranslation';\nimport type { MenuItemLinkProps } from '../MenuItemLink/MenuItemLink';\n\n/**\n * @public\n */\nexport interface HelpDropdownProps {\n layout?: CSSProperties;\n}\n\nconst ValidityTracker = ({\n Component,\n props,\n componentId,\n onValidityChange,\n}: {\n Component: ComponentType<any>;\n props: any;\n componentId: string;\n onValidityChange: (componentId: string, isValid: boolean) => void;\n}) => {\n const contentRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const checkContent = () => {\n if (!contentRef.current) return;\n\n const element = contentRef.current;\n const hasText = (element.textContent?.trim().length ?? 0) > 0;\n const hasChildren = element.children.length > 0;\n const hasChildNodes = element.childNodes.length > 0;\n\n // A component is valid if it renders ANY content at all\n const componentIsValid = hasText || hasChildren || hasChildNodes;\n\n onValidityChange(componentId, componentIsValid);\n };\n\n // Check after component has had time to render (longer timeout for lazy components)\n const timer1 = setTimeout(checkContent, 500);\n const timer2 = setTimeout(checkContent, 1500); // Double check later\n\n return () => {\n clearTimeout(timer1);\n clearTimeout(timer2);\n };\n }, [componentId, onValidityChange]);\n\n try {\n return (\n <div ref={contentRef}>\n <Component {...props} />\n </div>\n );\n } catch (error) {\n onValidityChange(componentId, false);\n return null;\n }\n};\n\nexport const HelpDropdown = ({ layout }: HelpDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n const helpDropdownMountPoints = useHelpDropdownMountPoints();\n const { t } = useTranslation();\n\n const { shouldShowEmpty, updateComponentValidity } = useValidComponentTracker(\n helpDropdownMountPoints?.length ?? 0,\n );\n\n // Create all mount point items with validity tracking\n const allMenuItems = useMemo(() => {\n return (helpDropdownMountPoints ?? [])\n .map((mp, index) => {\n const componentId = `${mp.config?.props?.title || 'helpItem'}-${\n mp.config?.priority || 0\n }-${index}`;\n\n return {\n componentId,\n Component: (props: MenuItemLinkProps | MenuItemProps | {}) => {\n const onClick = 'onClick' in props ? props.onClick : undefined;\n return (\n <ValidityTracker\n Component={mp.Component}\n props={{ ...(mp.config?.props || {}), onClick }}\n componentId={componentId}\n onValidityChange={updateComponentValidity}\n />\n );\n },\n icon: mp.config?.props?.icon,\n label: mp.config?.props?.title,\n link: mp.config?.props?.link,\n tooltip: mp.config?.props?.tooltip,\n style: mp.config?.style,\n priority: mp.config?.priority ?? 0,\n };\n })\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n }, [helpDropdownMountPoints, updateComponentValidity]);\n\n const menuItems = allMenuItems;\n\n return (\n <HeaderDropdownComponent\n isIconButton\n tooltip={t('help.tooltip')}\n buttonContent={<HelpOutlineIcon />}\n buttonProps={{\n color: 'inherit',\n sx: layout,\n }}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n >\n {!shouldShowEmpty ? (\n <MenuSection hideDivider items={menuItems} handleClose={handleClose} />\n ) : (\n <DropdownEmptyState\n title={t('help.noSupportLinks')}\n subTitle={t('help.noSupportLinksSubtitle')}\n icon={\n <SupportAgentIcon sx={{ fontSize: 64, color: 'text.disabled' }} />\n }\n />\n )}\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/backstage-plugin-global-header",
3
- "version": "1.21.0",
3
+ "version": "1.21.2",
4
4
  "main": "./dist/index.esm.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {