@heliosgraphics/ui 2.0.0-alpha.77 → 2.0.0-alpha.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Clock/Clock.tsx +1 -1
- package/components/Icon/Icon.tsx +3 -3
- package/components/Loading/Loading.tsx +3 -3
- package/components/Menu/components/MenuCategory/MenuCategory.tsx +18 -8
- package/components/Pill/Pill.tsx +38 -36
- package/components/Separator/Separator.tsx +20 -25
- package/components/Spacer/Spacer.tsx +3 -3
- package/components/Text/Text.tsx +3 -3
- package/contexts/LayoutContext/LayoutContext.tsx +5 -2
- package/hooks/useChatScroll.tsx +2 -2
- package/package.json +10 -10
|
@@ -6,7 +6,7 @@ import type { FC } from "react"
|
|
|
6
6
|
import type { ClockProps } from "./Clock.types"
|
|
7
7
|
|
|
8
8
|
export const Clock: FC<ClockProps> = () => {
|
|
9
|
-
const [time, setTime] = useState(new Date())
|
|
9
|
+
const [time, setTime] = useState(() => new Date())
|
|
10
10
|
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
const timerId = globalThis.setInterval(() => {
|
package/components/Icon/Icon.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { getClasses } from "@heliosgraphics/utils/classnames"
|
|
2
2
|
import { icons } from "@heliosgraphics/icons"
|
|
3
3
|
import styles from "./Icon.module.css"
|
|
4
|
-
import type
|
|
4
|
+
import { memo, type FC } from "react"
|
|
5
5
|
import type { IconProps } from "./Icon.types"
|
|
6
6
|
|
|
7
|
-
export const Icon: FC<IconProps> = ({ icon, className, emphasis, size }) => {
|
|
7
|
+
export const Icon: FC<IconProps> = memo(({ icon, className, emphasis, size }) => {
|
|
8
8
|
const iconSizeStyle = {
|
|
9
9
|
height: size + "px",
|
|
10
10
|
minHeight: size + "px",
|
|
@@ -26,4 +26,4 @@ export const Icon: FC<IconProps> = ({ icon, className, emphasis, size }) => {
|
|
|
26
26
|
dangerouslySetInnerHTML={{ __html: icons[icon] || "" }}
|
|
27
27
|
/>
|
|
28
28
|
)
|
|
29
|
-
}
|
|
29
|
+
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getClasses } from "@heliosgraphics/utils/classnames"
|
|
2
2
|
import styles from "./Loading.module.css"
|
|
3
|
-
import type
|
|
3
|
+
import { memo, type FC } from "react"
|
|
4
4
|
import type { LoadingProps } from "./Loading.types"
|
|
5
5
|
|
|
6
|
-
export const Loading: FC<LoadingProps> = ({ className, size, emphasis }) => {
|
|
6
|
+
export const Loading: FC<LoadingProps> = memo(({ className, size, emphasis }) => {
|
|
7
7
|
const rSize = size / 2
|
|
8
8
|
const cSize = rSize + 2
|
|
9
9
|
const dashSize = size + cSize
|
|
@@ -40,4 +40,4 @@ export const Loading: FC<LoadingProps> = ({ className, size, emphasis }) => {
|
|
|
40
40
|
/>
|
|
41
41
|
</svg>
|
|
42
42
|
)
|
|
43
|
-
}
|
|
43
|
+
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useState, type FC } from "react"
|
|
4
4
|
import { Flex } from "../../../Flex"
|
|
5
5
|
import { Icon } from "../../../Icon"
|
|
6
6
|
import { Text } from "../../../Text"
|
|
@@ -8,9 +8,23 @@ import { getClasses } from "@heliosgraphics/utils"
|
|
|
8
8
|
import styles from "./MenuCategory.module.css"
|
|
9
9
|
import type { MenuCategoryProps } from "./MenuCategory.types"
|
|
10
10
|
|
|
11
|
-
export const MenuCategory: FC<MenuCategoryProps> = ({
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
export const MenuCategory: FC<MenuCategoryProps> = ({
|
|
12
|
+
category,
|
|
13
|
+
children,
|
|
14
|
+
isFolder,
|
|
15
|
+
isOpen: controlledIsOpen,
|
|
16
|
+
isInitiallyClosed,
|
|
17
|
+
}) => {
|
|
18
|
+
const [localIsOpen, setLocalIsOpen] = useState<boolean>(!isInitiallyClosed)
|
|
19
|
+
|
|
20
|
+
const isControlled: boolean = controlledIsOpen !== undefined
|
|
21
|
+
const isOpen: boolean = isControlled ? !!controlledIsOpen : localIsOpen
|
|
22
|
+
|
|
23
|
+
const onToggle = (): void => {
|
|
24
|
+
if (!isControlled) {
|
|
25
|
+
setLocalIsOpen((prev) => !prev)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
14
28
|
|
|
15
29
|
const menuCategoryClasses: string = getClasses(styles.menuCategory, {
|
|
16
30
|
[styles.menuCategoryFolder]: category,
|
|
@@ -28,10 +42,6 @@ export const MenuCategory: FC<MenuCategoryProps> = ({ category, children, isFold
|
|
|
28
42
|
|
|
29
43
|
const showHeader: boolean = Boolean(category || isFolder)
|
|
30
44
|
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
setOpen(!!isIncomingOpen)
|
|
33
|
-
}, [isIncomingOpen])
|
|
34
|
-
|
|
35
45
|
return (
|
|
36
46
|
<Flex isColumn={true} isXCentered={true} data-ui-component="Menu.Category" className={menuCategoryClasses}>
|
|
37
47
|
{showHeader && (
|
package/components/Pill/Pill.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { Flex } from "../Flex"
|
|
|
4
4
|
import { Text } from "../Text"
|
|
5
5
|
import { Icon } from "../Icon"
|
|
6
6
|
import styles from "./Pill.module.css"
|
|
7
|
-
import type
|
|
7
|
+
import { memo, type FC } from "react"
|
|
8
8
|
import type { PillProps } from "./Pill.types"
|
|
9
9
|
|
|
10
10
|
const PILL_ICON_SIZE: Record<string, number> = {
|
|
@@ -13,43 +13,45 @@ const PILL_ICON_SIZE: Record<string, number> = {
|
|
|
13
13
|
normal: 24,
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const Pill: FC<PillProps> = (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
export const Pill: FC<PillProps> = memo(
|
|
17
|
+
({
|
|
18
|
+
appearance = "light",
|
|
19
|
+
color = "gray",
|
|
20
|
+
className,
|
|
21
|
+
icon,
|
|
22
|
+
isLabelHidden,
|
|
23
|
+
isMono,
|
|
24
|
+
isRounded,
|
|
25
|
+
label,
|
|
26
|
+
onClick,
|
|
27
|
+
size = "normal",
|
|
28
|
+
}) => {
|
|
29
|
+
const pillColorClasses: Array<string> = getColorClasses(color, appearance)
|
|
30
|
+
const pillClasses = getClasses(styles.pill, "non-selectable break-word", ...pillColorClasses, className, {
|
|
31
|
+
[styles.pillRounded]: isRounded,
|
|
32
|
+
[`radius-md`]: !isRounded,
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
[styles.pillLight]: appearance === "light",
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
[styles.pillNormal]: !size || size === "normal",
|
|
37
|
+
[styles.pillSmall]: size === "small",
|
|
38
|
+
[styles.pillTiny]: size === "tiny",
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
[styles.pillIconOnly]: !!icon && isLabelHidden,
|
|
41
|
+
})
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const isSmall: boolean = size !== "normal"
|
|
44
|
+
const pillTextSize = isSmall ? "tiny" : "small"
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
46
|
+
return (
|
|
47
|
+
<Flex {...(onClick && { onClick })} className={pillClasses} isCentered={true} gap={2} data-ui-component="Pill">
|
|
48
|
+
{icon && <Icon size={PILL_ICON_SIZE[size] || 16} icon={icon} />}
|
|
49
|
+
{!isLabelHidden && (
|
|
50
|
+
<Text type={pillTextSize} whiteSpace="nowrap" {...(isMono && { fontFamily: "mono" })} fontWeight="medium">
|
|
51
|
+
{label}
|
|
52
|
+
</Text>
|
|
53
|
+
)}
|
|
54
|
+
</Flex>
|
|
55
|
+
)
|
|
56
|
+
},
|
|
57
|
+
)
|
|
@@ -3,32 +3,27 @@ import { VerticalSeparator } from "./components/VerticalSeparator"
|
|
|
3
3
|
import styles from "./Separator.module.css"
|
|
4
4
|
import { getClasses } from "@heliosgraphics/utils"
|
|
5
5
|
import type { SeparatorProps } from "./Separator.types"
|
|
6
|
-
import type
|
|
6
|
+
import { memo, type FC } from "react"
|
|
7
7
|
|
|
8
|
-
export const Separator: FC<SeparatorProps> = (
|
|
9
|
-
className,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}) => {
|
|
16
|
-
const separatorClasses: string = getClasses(className, {
|
|
17
|
-
[styles.separatorPrimary]: emphasis === "primary",
|
|
18
|
-
[styles.separatorSecondary]: emphasis === "secondary",
|
|
19
|
-
[styles.separatorTertiary]: emphasis === "tertiary",
|
|
20
|
-
})
|
|
8
|
+
export const Separator: FC<SeparatorProps> = memo(
|
|
9
|
+
({ className, emphasis = "primary", isVertical, height, lineStyle = "solid", width }) => {
|
|
10
|
+
const separatorClasses: string = getClasses(className, {
|
|
11
|
+
[styles.separatorPrimary]: emphasis === "primary",
|
|
12
|
+
[styles.separatorSecondary]: emphasis === "secondary",
|
|
13
|
+
[styles.separatorTertiary]: emphasis === "tertiary",
|
|
14
|
+
})
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
const separatorProps: SeparatorProps = {
|
|
17
|
+
className: separatorClasses,
|
|
18
|
+
emphasis,
|
|
19
|
+
...(isVertical !== undefined && { isVertical }),
|
|
20
|
+
...(height !== undefined && { height }),
|
|
21
|
+
lineStyle,
|
|
22
|
+
...(width !== undefined && { width }),
|
|
23
|
+
}
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
if (isVertical) return <VerticalSeparator {...separatorProps} />
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
}
|
|
27
|
+
return <HorizontalSeparator {...separatorProps} />
|
|
28
|
+
},
|
|
29
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { memo, type FC } from "react"
|
|
2
2
|
import type { SpacerProps } from "./Spacer.types"
|
|
3
3
|
|
|
4
|
-
export const Spacer: FC<SpacerProps> = ({ gap }) => {
|
|
4
|
+
export const Spacer: FC<SpacerProps> = memo(({ gap }) => {
|
|
5
5
|
return <div style={{ height: `${gap ?? 0}px` }} />
|
|
6
|
-
}
|
|
6
|
+
})
|
package/components/Text/Text.tsx
CHANGED
|
@@ -4,12 +4,12 @@ import { getTypographyUtility } from "./Text.utils"
|
|
|
4
4
|
import { P } from "./components/P"
|
|
5
5
|
import { Small } from "./components/Small"
|
|
6
6
|
import { Tiny } from "./components/Tiny"
|
|
7
|
-
import { type FC } from "react"
|
|
7
|
+
import { memo, type FC } from "react"
|
|
8
8
|
import styles from "./Text.module.css"
|
|
9
9
|
import type { TextProps } from "./Text.types"
|
|
10
10
|
import { Micro } from "./components/Micro"
|
|
11
11
|
|
|
12
|
-
export const Text: FC<TextProps> = (props) => {
|
|
12
|
+
export const Text: FC<TextProps> = memo((props) => {
|
|
13
13
|
const textClasses: string = getClasses(props.className, styles.text, {
|
|
14
14
|
[styles.textPrimary]: props.emphasis === "primary",
|
|
15
15
|
[styles.textSecondary]: props.emphasis === "secondary",
|
|
@@ -51,4 +51,4 @@ export const Text: FC<TextProps> = (props) => {
|
|
|
51
51
|
default:
|
|
52
52
|
return <Div {...baseTextProps} />
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
})
|
|
@@ -19,6 +19,7 @@ const LayoutProvider: FC<LayoutProviderProps> = ({ children, breakpoint = 960 })
|
|
|
19
19
|
const [hasMounted, setHasMounted] = useState<boolean>(false)
|
|
20
20
|
const asideRef = useRef<HTMLElement | null>(null)
|
|
21
21
|
const isMenuVisibleRef = useRef<boolean>(false)
|
|
22
|
+
const windowWidthRef = useRef<number>(0)
|
|
22
23
|
|
|
23
24
|
useEffect(() => {
|
|
24
25
|
isMenuVisibleRef.current = isMenuVisible
|
|
@@ -29,6 +30,7 @@ const LayoutProvider: FC<LayoutProviderProps> = ({ children, breakpoint = 960 })
|
|
|
29
30
|
|
|
30
31
|
setHasMounted(true)
|
|
31
32
|
setWindowWidth(initialWidth)
|
|
33
|
+
windowWidthRef.current = initialWidth
|
|
32
34
|
|
|
33
35
|
const initialMenuVisible = initialWidth >= breakpoint
|
|
34
36
|
|
|
@@ -37,10 +39,11 @@ const LayoutProvider: FC<LayoutProviderProps> = ({ children, breakpoint = 960 })
|
|
|
37
39
|
|
|
38
40
|
const handleResize = (): void => {
|
|
39
41
|
const newWidth: number = globalThis.innerWidth
|
|
40
|
-
const wasWideEnough: boolean =
|
|
42
|
+
const wasWideEnough: boolean = windowWidthRef.current >= breakpoint
|
|
41
43
|
const isNowWideEnough: boolean = newWidth >= breakpoint
|
|
42
44
|
|
|
43
45
|
setWindowWidth(newWidth)
|
|
46
|
+
windowWidthRef.current = newWidth
|
|
44
47
|
|
|
45
48
|
if (isNowWideEnough && !wasWideEnough) {
|
|
46
49
|
setIsMenuVisible(true)
|
|
@@ -71,7 +74,7 @@ const LayoutProvider: FC<LayoutProviderProps> = ({ children, breakpoint = 960 })
|
|
|
71
74
|
globalThis.removeEventListener("resize", handleResize)
|
|
72
75
|
globalThis.document.removeEventListener("mousedown", handleClickOutside)
|
|
73
76
|
}
|
|
74
|
-
}, [breakpoint
|
|
77
|
+
}, [breakpoint])
|
|
75
78
|
|
|
76
79
|
const isWideEnough: boolean = hasMounted ? windowWidth >= breakpoint : false
|
|
77
80
|
const shouldShowNavigation: boolean = isWideEnough || isMenuVisible
|
package/hooks/useChatScroll.tsx
CHANGED
|
@@ -19,11 +19,11 @@ export const useChatScroll = (
|
|
|
19
19
|
onResetManual: () => void
|
|
20
20
|
} => {
|
|
21
21
|
const [isManual, setManual] = useState<boolean>(false)
|
|
22
|
-
const [scrollPos, setScrollPos] = useState<ScrollPosition>({
|
|
22
|
+
const [scrollPos, setScrollPos] = useState<ScrollPosition>(() => ({
|
|
23
23
|
top: 0,
|
|
24
24
|
bottom: 0,
|
|
25
25
|
height: 0,
|
|
26
|
-
})
|
|
26
|
+
}))
|
|
27
27
|
const ref = useRef<HTMLDivElement>(null)
|
|
28
28
|
const wasAtBottom = useRef<boolean>(true)
|
|
29
29
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heliosgraphics/ui",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.78",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"author": "Chris Puska <chris@puska.org>",
|
|
@@ -37,23 +37,23 @@
|
|
|
37
37
|
"react-plock": "^3.6.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@testing-library/react": "^16.3.
|
|
40
|
+
"@testing-library/react": "^16.3.2",
|
|
41
41
|
"@types/node": "^25",
|
|
42
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.53.1",
|
|
43
43
|
"@vitejs/plugin-react": "^5.1.2",
|
|
44
|
-
"@vitest/coverage-v8": "^4.0.
|
|
44
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
45
45
|
"esbuild": "latest",
|
|
46
46
|
"esbuild-css-modules-plugin": "latest",
|
|
47
47
|
"eslint": "^9.39.2",
|
|
48
48
|
"eslint-config-prettier": "^10.1.8",
|
|
49
|
-
"eslint-plugin-prettier": "^5.5.
|
|
49
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
50
50
|
"glob": "latest",
|
|
51
|
-
"jsdom": "^27.
|
|
52
|
-
"next": "^16.1.
|
|
53
|
-
"prettier": "^3.
|
|
51
|
+
"jsdom": "^27.4.0",
|
|
52
|
+
"next": "^16.1.4",
|
|
53
|
+
"prettier": "^3.8.1",
|
|
54
54
|
"typescript": "^5.9.3",
|
|
55
|
-
"vite": "^7.3.
|
|
56
|
-
"vitest": "^4.0.
|
|
55
|
+
"vite": "^7.3.1",
|
|
56
|
+
"vitest": "^4.0.18"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@types/react": "^19",
|