Skip to content

Commit 1af9f21

Browse files
Memoized icons (#46)
* Memoized icons * Remove unused imports * More memoized icons * More memoized icons * More memoized icons * PR comments
1 parent 66af8ce commit 1af9f21

File tree

12 files changed

+247
-68
lines changed

12 files changed

+247
-68
lines changed

components/AdminMessages.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AdminMessageLevel, AdminMessagesProps } from "@/submodules/react-components/types/admin-messages";
22
import { CurrentPage } from "@/submodules/react-components/hooks/web-socket/constants";
3-
import { IconAlertCircle, IconInfoSquare, IconPoint, IconX } from "@tabler/icons-react";
43
import { useMemo } from "react";
4+
import { MemoIconAlertCircle, MemoIconInfoSquare, MemoIconPoint, MemoIconX } from "./kern-icons/icons";
55

66
export default function AdminMessages(props: AdminMessagesProps) {
77
const isOnLabelingPage = useMemo(() => props.currentPage == CurrentPage.LABELING, [props.currentPage]);
@@ -18,13 +18,13 @@ export default function AdminMessages(props: AdminMessagesProps) {
1818
<div key={activeMessage.id} className={`pointer-events-auto items-center justify-between gap-x-6 py-2.5 mt-2 border px-6 sm:rounded-xl sm:py-3 sm:pr-3.5 sm:pl-4 ${activeMessage.borderColor} ${activeMessage.backgroundColor} ${activeMessage.visible ? 'flex' : 'hidden'}`}
1919
style={{ maxWidth: props.maxWidth ?? 'calc(100vw - 200px)' }}>
2020
<div className={`text-sm leading-6 flex flex-row items-center w-full ${activeMessage.textColor}`}>
21-
{activeMessage.level == AdminMessageLevel.INFO && <IconInfoSquare className="text-blue-700" size={24} />}
22-
{activeMessage.level == AdminMessageLevel.WARNING && <IconAlertCircle className="text-yellow-700" size={24} />}
23-
<strong className="font-semibold uppercase">{activeMessage.level}</strong><IconPoint className="mx-2" size={16} />
21+
{activeMessage.level == AdminMessageLevel.INFO && <MemoIconInfoSquare className="text-blue-700" size={24} />}
22+
{activeMessage.level == AdminMessageLevel.WARNING && <MemoIconAlertCircle className="text-yellow-700" size={24} />}
23+
<strong className="font-semibold uppercase">{activeMessage.level}</strong><MemoIconPoint className="mx-2" size={16} />
2424
<strong className="font-semibold">{activeMessage.text}</strong>
25-
{activeMessage.displayDate && <><IconPoint className="mx-2" size={16} /><div>Scheduled for {activeMessage.displayDate}</div></>}
25+
{activeMessage.displayDate && <><MemoIconPoint className="mx-2" size={16} /><div>Scheduled for {activeMessage.displayDate}</div></>}
2626
<button type="button" className="-my-1.5 ml-auto mr-0 flex-none p-1.5" onClick={() => closeMessage(activeMessage.id)}>
27-
<IconX className={`${activeMessage.textColor} cursor-pointer`} size={20} strokeWidth={1.5} />
27+
<MemoIconX className={`${activeMessage.textColor} cursor-pointer`} size={20} strokeWidth={1.5} />
2828
</button>
2929
</div>
3030
</div >))

components/InfoButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { combineClassNames } from "@/submodules/javascript-functions/general";
22
import { useDefaults } from "@/submodules/react-components/hooks/useDefaults";
3-
import { IconInfoCircle } from "@tabler/icons-react";
43
import { Dispatch, Fragment, SetStateAction, useEffect, useRef, useState } from "react";
54
import useOnClickOutside from "@/submodules/react-components/hooks/useHooks/useOnClickOutside";
65
import { Transition } from "@headlessui/react";
76
import { INFO_BUTTON_DEFAULT_VALUES, InfoButtonConfig, InfoButtonProps } from "../types/infoButton";
7+
import { MemoIconInfoCircle } from "./kern-icons/icons";
88

99

1010
function generateAndCheckConfig(props: InfoButtonProps, setOpen: Dispatch<SetStateAction<boolean>>): InfoButtonConfig {
@@ -45,7 +45,7 @@ export function InfoButton(_props: InfoButtonProps) {
4545
if (!config) return null;
4646
return (
4747
<div className={combineClassNames("relative w-fit p-1", config.cursorClass)} onClick={props.access == 'click' ? config.showInfo : undefined} onMouseEnter={props.access == 'hover' ? config.showInfo : undefined} onMouseLeave={props.access == 'hover' ? config.hideInfo : undefined}>
48-
<IconInfoCircle size={config.size} className={props.infoButtonColorClass} />
48+
<MemoIconInfoCircle size={config.size} className={props.infoButtonColorClass} />
4949
{props.display == "absoluteDiv" ? <RenderDiv
5050
positionClass={config.positionClass + " " + props.addClasses}
5151
content={props.content}
@@ -76,7 +76,7 @@ function RenderDiv({ positionClass, open, content, access, onMouseEnter, onMouse
7676
{typeof content == "string" ?
7777
<div className="flex items-center gap-x-2">
7878
<div className="flex-shrink-0">
79-
<IconInfoCircle className="h-5 w-5 text-blue-400" aria-hidden="true" />
79+
<MemoIconInfoCircle className="h-5 w-5 text-blue-400" aria-hidden="true" />
8080
</div>
8181
<p className="text-sm text-blue-700 w-max max-w-sm">{content}</p>
8282
</div> : content}

components/InputWithClearIcon.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { IconX } from "@tabler/icons-react";
1+
import { useCallback } from "react";
2+
import { MemoIconX } from "./kern-icons/icons";
3+
import useRefFor from "../hooks/useRefFor";
24

35
export type InputWithClearIconProps = {
46
value: string;
@@ -8,14 +10,19 @@ export type InputWithClearIconProps = {
810
}
911

1012
export default function InputWithClearIcon(props: InputWithClearIconProps) {
13+
const clearInputRef = useRefFor(props.onChange)
14+
const clearInput = useCallback(() => {
15+
clearInputRef.current('');
16+
}, [props.onChange]);
17+
1118
return (<div className={`relative ${props.classNames}`}>
1219
<input id={props.id} type="text" placeholder="Search"
1320
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
1421
value={props.value}
1522
onChange={(event) => props.onChange(event.target.value)}
1623
/>
1724
{props.value && (
18-
<IconX className='absolute right-2 top-1/2 transform -translate-y-1/2 cursor-pointer text-gray-500' onClick={() => props.onChange("")} />
25+
<MemoIconX className='absolute right-2 top-1/2 transform -translate-y-1/2 cursor-pointer text-gray-500' onClick={clearInput} />
1926
)}
2027
</div>)
2128
}

components/KernDropdown.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import { KernDropdownProps } from '../types/dropdown';
44
import { combineClassNames } from '../../javascript-functions/general';
55
import { SELECT_ALL, checkDropdownProps, getActiveNegateGroupColor, getDropdownDisplayText, prepareDropdownOptionsToArray, reduceColorProperty, setOptionsWithSearchBar } from '../helpers/dropdown-helper';
66
import { Tooltip } from '@nextui-org/react';
7-
import { IconChevronDown, IconDotsVertical, IconExternalLink } from '@tabler/icons-react';
8-
import { IconTrashXFilled } from '@tabler/icons-react';
97
import useOnClickOutside from '../hooks/useHooks/useOnClickOutside';
108
import { useDefaults } from '../hooks/useDefaults';
119
import SVGIcon from './SVGIcon';
1210
import { CSSProperties } from 'react';
1311
import useRefFor from '../hooks/useRefFor';
12+
import { MemoIconChevronDown, MemoIconDotsVertical, MemoIconExternalLink, MemoIconTrashXFilled } from './kern-icons/icons';
1413

1514
const DEFAULTS = { fontSizeClass: 'text-xs' };
1615

@@ -197,14 +196,14 @@ export default function KernDropdown(props: KernDropdownProps) {
197196
className="h-9 w-full text-sm border-gray-300 rounded-md placeholder-italic border text-gray-900 pr-8 pl-4 truncate placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-300 focus:ring-offset-2 focus:ring-offset-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
198197
disabled={isDisabled && !props.ignoreDisabledForSearch}
199198
placeholder="Type to search..." />
200-
<IconChevronDown
199+
<MemoIconChevronDown
201200
className={`h-5 w-5 absolute right-0 mr-3 -mt-7 ${isDisabled && !props.ignoreDisabledForSearch ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
202201
aria-hidden="true"
203202
/>
204203
</div> : <>
205204
{props.hasButtonDots ? (<Menu.Button onClick={toggleDropdown} className="group relative inline-flex h-8 w-8 items-center justify-center rounded-full">
206205
<span className="flex h-full w-full items-center justify-center rounded-full">
207-
<IconDotsVertical
206+
<MemoIconDotsVertical
208207
size={24}
209208
strokeWidth={2}
210209
className='text-gray-700 font-bold' />
@@ -219,7 +218,7 @@ export default function KernDropdown(props: KernDropdownProps) {
219218
<span style={{ color: '#4e46e5' }}>{getDropdownDisplayText(props.options, "NOT_NEGATED")}</span>
220219
<span style={{ color: '#ef4444' }}>{getDropdownDisplayText(props.options, "NEGATED")}</span>
221220
</label>}
222-
<IconChevronDown
221+
<MemoIconChevronDown
223222
className="-mr-1 ml-2 h-5 w-5"
224223
aria-hidden="true"
225224
/>
@@ -271,8 +270,8 @@ export default function KernDropdown(props: KernDropdownProps) {
271270
{props.iconsArray && props.iconsArray[index] && <span className='mx-2 text-gray-700'>
272271
<SVGIcon icon={props.iconsArray[index]} size={16} strokeWidth={2} useFillForIcons={props.useFillForIcons && props.useFillForIcons[index]} /></span>}
273272
<span className='truncate'>{option}</span>
274-
{props.onClickDelete && <div className="ml-auto flex items-center cursor-pointer hover:bg-gray-200" onClick={(e) => { e.stopPropagation(); props.onClickDelete(option) }}><IconTrashXFilled size={20} /></div>}
275-
{props.optionsHaveLink && <a href={props.linkList[index]} target="_blank" className="h-4 w-4 mr-2 ml-auto flex items-center cursor-pointer"><IconExternalLink size={16} /></a>}
273+
{props.onClickDelete && <div className="ml-auto flex items-center cursor-pointer hover:bg-gray-200" onClick={(e) => { e.stopPropagation(); props.onClickDelete(option) }}><MemoIconTrashXFilled size={20} /></div>}
274+
{props.optionsHaveLink && <a href={props.linkList[index]} target="_blank" className="h-4 w-4 mr-2 ml-auto flex items-center cursor-pointer"><MemoIconExternalLink size={16} /></a>}
276275
{props.dropdownAdd && props.dropdownAdd[index]}
277276
</label>
278277
</Tooltip>

components/SVGIcon.tsx

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IconBolt, IconChevronDown, IconCode, IconDotsVertical, IconEdit, IconExternalLink, IconFileInfo, IconFilePencil, IconLoader, IconPlayerPlayFilled, IconShieldCheckFilled, IconShieldFilled, IconSquare, IconSquareCheck, IconTrash } from '@tabler/icons-react';
1+
import { MemoIconBolt, MemoIconChevronDown, MemoIconCode, MemoIconDotsVertical, MemoIconEdit, MemoIconExternalLink, MemoIconFileInfo, MemoIconFilePencil, MemoIconLoader, MemoIconPlayerPlayFilled, MemoIconShieldCheckFilled, MemoIconShieldFilled, MemoIconSquare, MemoIconSquareCheck, MemoIconTrash } from './kern-icons/icons';
22

33
export const SUPPORTED_ICONS = ['IconCode', 'IconBolt', 'IconSquareCheck', 'IconSquare', 'IconPlayerPlayFilled', 'IconTrash', 'IconExternalLink',
44
'IconLoader', 'IconFilePencil', 'IconFileInfo', 'IconEdit', 'IconShieldFilled', 'IconShieldCheckFilled'
@@ -14,36 +14,36 @@ type SVGIconProps = {
1414
export default function SVGIcon(props: SVGIconProps) {
1515
switch (props.icon) {
1616
case 'IconCode':
17-
return <IconCode size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
17+
return <MemoIconCode size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
1818
case 'IconBolt':
19-
return <IconBolt size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
19+
return <MemoIconBolt size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
2020
case 'IconSquareCheck':
21-
return <IconSquareCheck size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
21+
return <MemoIconSquareCheck size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
2222
case 'IconSquare':
23-
return <IconSquare size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
23+
return <MemoIconSquare size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
2424
case 'IconPlayerPlayFilled':
25-
return <IconPlayerPlayFilled size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
25+
return <MemoIconPlayerPlayFilled size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
2626
case 'IconTrash':
27-
return <IconTrash size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
27+
return <MemoIconTrash size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
2828
case 'IconExternalLink':
29-
return <IconExternalLink size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
29+
return <MemoIconExternalLink size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
3030
case 'IconChevronDown':
31-
return <IconChevronDown size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
31+
return <MemoIconChevronDown size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
3232
case 'IconDotsVertical':
33-
return <IconDotsVertical size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
33+
return <MemoIconDotsVertical size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
3434
case 'IconLoader':
35-
return <IconLoader size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
35+
return <MemoIconLoader size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
3636
case 'IconFilePencil':
37-
return <IconFilePencil size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
37+
return <MemoIconFilePencil size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
3838
case 'IconFileInfo':
39-
return <IconFileInfo size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
39+
return <MemoIconFileInfo size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
4040
case 'IconEdit':
41-
return <IconEdit size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
41+
return <MemoIconEdit size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
4242
case 'IconShieldFilled':
43-
return <IconShieldFilled size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
43+
return <MemoIconShieldFilled size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
4444
case 'IconShieldCheckFilled':
45-
return <IconShieldCheckFilled size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
46-
default: return <IconLoader size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
45+
return <MemoIconShieldCheckFilled size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
46+
default: return <MemoIconLoader size={props.size} strokeWidth={props.strokeWidth} className={`${props.useFillForIcons ? 'fill-gray-800' : ''}`} />
4747
}
4848

4949
}

components/kern-button/IconButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { combineClassNames } from "@/submodules/javascript-functions/general";
22
import { Tooltip } from '@nextui-org/react'
3-
import { IconCheck } from "@tabler/icons-react";
43
import { useState } from "react";
4+
import { MemoIconCheck } from "../kern-icons/icons";
55

66
interface IconButtonProps {
77
icon: (props: any) => any;
@@ -59,7 +59,7 @@ function InnerButton(props: IconButtonProps) {
5959
disabled={props.disabled}
6060
>
6161
{confirmed ? (
62-
<IconCheck
62+
<MemoIconCheck
6363
className={combineClassNames(
6464
`text-green-500 group-hover:text-green-600`,
6565
props.size == 'small' ? (

components/kern-button/KernButton.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { combineClassNames } from "@/submodules/javascript-functions/general";
2-
import { IconLoader2 } from "@tabler/icons-react";
32
import { Tooltip } from '@nextui-org/react'
43
import React, { useCallback, useMemo, useState } from "react";
5-
import { IconCheck } from "@tabler/icons-react";
4+
import { MemoIconCheck, MemoIconLoader2 } from "../kern-icons/icons";
65

76
interface KernButtonProps {
87
text?: string;
@@ -76,7 +75,7 @@ export default function KernButton(props: KernButtonProps) {
7675
const children = <Tooltip className={"flex gap-x-2 items-center " + (props.disabled ? "cursor-not-allowed" : "")} color="invert" content={props.tooltip} placement={props.tooltipPlacement || "bottom"} >
7776
{
7877
props.loading ? (
79-
<IconLoader2 className={combineClassNames(
78+
<MemoIconLoader2 className={combineClassNames(
8079
props.iconColor === "white" ? (
8180
`animate-spin text-white group-hover:text-white`
8281
) : (
@@ -86,7 +85,7 @@ export default function KernButton(props: KernButtonProps) {
8685
} />
8786
) : props.icon ? (
8887
confirm ? (
89-
<IconCheck className={combineClassNames(`text-green-500 group-hover:text-green-600`,
88+
<MemoIconCheck className={combineClassNames(`text-green-500 group-hover:text-green-600`,
9089
iconSize)} />
9190
) : (
9291
<props.icon className={combineClassNames(

0 commit comments

Comments
 (0)