Skip to content

Commit

Permalink
Brought latest changes from Blue Web
Browse files Browse the repository at this point in the history
`SidebarMenuItem` is now deprecated, because you can do the same with `MenuItem` now.
  • Loading branch information
lgk-bsw committed Oct 14, 2024
1 parent d7f659f commit 0150689
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 58 deletions.
2 changes: 1 addition & 1 deletion dist/style.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Blue React v9.11.0 (https://bruegmann.github.io/blue-react)
* Blue React v9.12.0 (https://bruegmann.github.io/blue-react)
* Licensed under GNU General Public License v3.0 (https://github.com/bruegmann/blue-react/blob/master/LICENSE).
*/

Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "blue-react",
"version": "9.11.0",
"version": "9.12.0",
"description": "Blue React Components",
"license": "LGPL-3.0-or-later",
"main": "index.js",
Expand Down Expand Up @@ -32,7 +32,7 @@
},
"dependencies": {
"@popperjs/core": "^2.11.5",
"blue-web": "^1.1.0",
"blue-web": "^1.2.0",
"bootstrap": "~5.3.3",
"clsx": "^1.1.1"
},
Expand Down
14 changes: 9 additions & 5 deletions src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,15 @@ export default class Layout extends Component<LayoutProps, LayoutState> {

this.defaultMatch = ["home"]

const expandSidebar = props.hideSidebarMenu
? false
: props.expandSidebar !== undefined
? props.expandSidebar
: localStorage.getItem("blueLayoutShrinkSidebar") === null

this.state = {
sidebarIn: props.sidebarIn || false,
expandSidebar: props.hideSidebarMenu
? false
: props.expandSidebar !== undefined
? props.expandSidebar
: localStorage.getItem("blueLayoutShrinkSidebar") === null,
expandSidebar,
match: null,
history: [],
hash: window.location.hash,
Expand All @@ -160,6 +162,8 @@ export default class Layout extends Component<LayoutProps, LayoutState> {
this.toggleExpandSidebar = this.toggleExpandSidebar.bind(this)

this.eventListeners = []

if (this.props.onChangeExpandSidebar) this.props.onChangeExpandSidebar(expandSidebar)
}

onHashChange() {
Expand Down
53 changes: 44 additions & 9 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import clsx from "clsx"
import React, { CSSProperties, createElement, useEffect, useState } from "react"
import React, { CSSProperties, createElement, useEffect, useRef, useState } from "react"
import Outside from "./Outside"
import Chevron from "./Chevron"

function findParentWithClass(element: HTMLElement | null, className: string) {
while (element && !element.classList.contains(className)) {
element = element.parentElement
}
return element
}

export interface MenuItemProps {
/**
* Sets `to` prop, e.g. when you use the `NavLink` component from React Router.
Expand Down Expand Up @@ -107,6 +114,13 @@ export interface MenuItemProps {
*/
supportOutside?: boolean

/**
* Overrides default class list to be ignored on click outside.
* Hint: If you want this menu item to stay open when others will open, set:
* `outsideIgnoreClasses={["blue-menu-item-wrapper"]}`.
*/
outsideIgnoreClasses?: string[]

/**
* By default, MenuItem is a `"button"`. If you set a `href`, it's a `"a"`.
* If you want to have it another type, you can pass a component reference with this prop (e.g. `Link`).
Expand Down Expand Up @@ -179,9 +193,13 @@ export interface MenuItemProps {
* Link, button or custom component for Sidebar, Actions or ActionMenu
*/
export default function MenuItem(props: MenuItemProps) {
const id = `blue-menu-item-wrapper-${Math.random().toString(36).substring(7)}`

const [showDropdown, setShowDropdown] = useState<boolean>(false)
const [active, setActive] = useState<boolean>(false)

const menuRef = useRef<HTMLDivElement>(null)

const checkActive = () => {
setActive(
(props.href && window.location.hash.indexOf(props.href) > -1) ||
Expand Down Expand Up @@ -210,13 +228,20 @@ export default function MenuItem(props: MenuItemProps) {
}

const onClickOutside = ({ target }: MouseEvent) => {
// Don't trigger when clicking on MenuItem
if (
!(target as HTMLElement | null)?.classList.contains("blue-menu-item-dropdown-toggle") &&
!(target as HTMLElement | null)?.classList.contains("blue-menu-item-label")
) {
setShowDropdown(false)
const ignoreClasses = props.outsideIgnoreClasses || [id]

if (ignoreClasses && target) {
for (let i = 0; i < ignoreClasses.length; i++) {
if (
(target as HTMLElement | null)?.classList.contains(ignoreClasses[i]) ||
findParentWithClass(target as HTMLElement, ignoreClasses[i])
) {
return
}
}
}

setShowDropdown(false)
}

useEffect(() => {
Expand All @@ -236,6 +261,14 @@ export default function MenuItem(props: MenuItemProps) {
}
}, [props.onShowDropdown, showDropdown])

useEffect(() => {
if (menuRef && menuRef.current) {
const el = menuRef.current
const rect = el.getBoundingClientRect()
el.style.setProperty("--offset-top", Math.round(rect.top) + "px")
}
}, [menuRef, showDropdown])

const className =
"blue-menu-item btn" +
(props.isActive ? " active" : "") +
Expand Down Expand Up @@ -264,7 +297,7 @@ export default function MenuItem(props: MenuItemProps) {
}

return (
<>
<div className={`blue-menu-item-wrapper ${id}`}>
{createElement(
props.elementType || (props.href ? "a" : "button"),
{
Expand Down Expand Up @@ -340,6 +373,7 @@ export default function MenuItem(props: MenuItemProps) {
{showDropdown &&
(props.supportOutside ? (
<Outside
wrapperRef={menuRef}
className={clsx("blue-menu-item-dropdown", props.dropdownClassName)}
onClickOutside={onClickOutside}
style={props.dropdownStyle}
Expand All @@ -348,12 +382,13 @@ export default function MenuItem(props: MenuItemProps) {
</Outside>
) : (
<div
ref={menuRef}
className={clsx("blue-menu-item-dropdown", props.dropdownClassName)}
style={props.dropdownStyle}
>
{props.children}
</div>
))}
</>
</div>
)
}
11 changes: 6 additions & 5 deletions src/components/Outside.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { CSSProperties, MouseEventHandler, MutableRefObject, useEffect, useRef } from "react"
import React, { CSSProperties, MouseEventHandler, MutableRefObject, RefObject, useEffect, useRef } from "react"

/**
* Hook that alerts clicks outside of the passed ref
Expand Down Expand Up @@ -28,17 +28,18 @@ export interface OutsideProps {
onClickOutside?: (event: MouseEvent) => void
onClick?: MouseEventHandler<HTMLDivElement> | undefined
style?: CSSProperties
wrapperRef?: RefObject<HTMLDivElement>
}

/**
* Component that fires an event if you click outside of it
*/
export default function Outside({ children, className, onClickOutside, onClick, style }: OutsideProps) {
const wrapperRef = useRef(null)
useOutside(wrapperRef, onClickOutside)
export default function Outside({ children, className, onClickOutside, onClick, style, wrapperRef }: OutsideProps) {
const ref = useRef(null)
useOutside(wrapperRef || ref, onClickOutside)

return (
<div ref={wrapperRef} className={className} style={style} onClick={onClick}>
<div ref={wrapperRef || ref} className={className} style={style} onClick={onClick}>
{children}
</div>
)
Expand Down
13 changes: 2 additions & 11 deletions src/components/SidebarMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,8 @@ export interface SidebarMenuItemProps extends MenuItemProps {
outerClass?: string
}

function getOffset(el: HTMLElement) {
const rect = el.getBoundingClientRect()
return {
left: Math.round(rect.left + window.scrollX),
top: Math.round(rect.top + window.scrollY)
}
}

/**
* @deprecated `MenuItem` now has all the features of `SidebarMenuItem`. Use `MenuItem` instead.
* Extends `MenuItem` with following features:
* * Shows provided label as tooltip if sidebar is closed.
* * Children will be displayed on the right side of the parent item.
Expand Down Expand Up @@ -43,8 +36,7 @@ export default function SidebarMenuItem({ outerClass = "", children, onClick, ..

useEffect(() => {
if (menuRef && menuRef.current) {
const offset = getOffset(menuRef.current)
setOffsetTop(offset.top)
setOffsetTop(menuRef.current.getBoundingClientRect().top)
}
}, [menuRef, open])

Expand All @@ -69,7 +61,6 @@ export default function SidebarMenuItem({ outerClass = "", children, onClick, ..
"ms-1",
"rounded",
"w-bla-sidebar-width",
"blue-menu-item-dropdown",
"blue-menu-item-dropdown-from-start"
].join(" ")}
style={{
Expand Down
21 changes: 7 additions & 14 deletions src/docs/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import {
StickiesFill,
Rss,
RssFill,
Eye,
BoxArrowUpRight
Eye
} from "react-bootstrap-icons"

import { ComponentPage } from "./pages/ComponentPage"
Expand All @@ -33,7 +32,6 @@ import LicenseReportPage from "./pages/LicenseReportPage"
import { useEffect } from "react"
import DemoApp from "./components/DemoApp"
import SidebarMenu from "../components/SidebarMenu"
import SidebarMenuItem from "../components/SidebarMenuItem"

function App() {
const onHashChange = () => {
Expand Down Expand Up @@ -127,14 +125,9 @@ function App() {
menuClass="overflow-visible"
bottomContent={
<>
<SidebarMenuItem
to="/demo#intro"
elementType={Link}
icon={<Eye />}
label="Demo App"
/>
<MenuItem to="/demo#intro" elementType={Link} icon={<Eye />} label="Demo App" />

<SidebarMenuItem
<MenuItem
href="https://github.com/bruegmann/blue-react"
icon={<CodeSquare />}
label="Code on GitHub"
Expand All @@ -144,30 +137,30 @@ function App() {
</>
}
>
<SidebarMenuItem
<MenuItem
icon={<House />}
iconForActive={<HouseFill />}
label="Start"
elementType={NavLink}
exact
to="/"
/>
<SidebarMenuItem
<MenuItem
icon={<Rss />}
iconForActive={<RssFill />}
label="Blog"
elementType={NavLink}
to="/blog"
/>

<SidebarMenuItem
<MenuItem
icon={<Puzzle />}
iconForActive={<PuzzleFill />}
label="React Components"
elementType={NavLink}
to="/component"
/>
<SidebarMenuItem
<MenuItem
icon={<Stickies />}
iconForActive={<StickiesFill />}
label="Recipes"
Expand Down
2 changes: 1 addition & 1 deletion src/docs/data/docs.json

Large diffs are not rendered by default.

Loading

0 comments on commit 0150689

Please sign in to comment.