Skip to content

Commit

Permalink
fix: decrease bundle size and remove extra deps
Browse files Browse the repository at this point in the history
add injectUniqueKeyframe function + tests
  • Loading branch information
moh3n9595 committed Jan 4, 2023
1 parent 48bfb10 commit 332d916
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 195 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
## Installation

```
yarn add react-beacon-hint
yarn add @floating-ui/react framer-motion react-beacon-hint
```

or

```
npm i react-beacon-hint
npm i @floating-ui/react framer-motion react-beacon-hint
```

## Inspiration
Expand All @@ -43,4 +43,4 @@ All developers who wish to contribute through code or issues, take a look at the

## License

This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/moh3n9595/react-beacon-hint/blob/master/LICENSE) file for details
This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/moh3n9595/react-beacon-hint/blob/master/LICENSE) file for details.
1 change: 1 addition & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {flip, FloatingTree, limitShift, offset, shift} from '@floating-ui/react';
import {useEffect, useState} from 'react';
import {FillBeacon, Floating, OutlineBeacon, Popover} from 'react-beacon-hint';
import 'react-beacon-hint/lib/style.css';
import './App.scss';

function App() {
Expand Down
1 change: 0 additions & 1 deletion example/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom/client';

import '@styles';
import App from './App';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
Expand Down
5 changes: 1 addition & 4 deletions example/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import {defineConfig} from 'vite';
export default defineConfig({
plugins: [react()],
resolve: {
alias: [
{find: 'react-beacon-hint', replacement: path.resolve(__dirname, '..')},
{find: '@styles', replacement: path.resolve(__dirname, '../lib/style.css')},
],
alias: [{find: 'react-beacon-hint', replacement: path.resolve(__dirname, '..')}],
},
});
25 changes: 12 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
"example"
],
"scripts": {
"postinstall": "husky install",
"prepack": "pinst --disable",
"postpack": "pinst --enable",
"install:husky": "husky install",
"build": "vite build",
"dev": "concurrently --kill-others -n Component,Test,Example \"vite build --watch\" \"yarn test:watch\" \"yarn workspace example dev\"",
"test:watch": "vitest",
Expand All @@ -28,6 +26,10 @@
".": {
"import": "./lib/react-beacon-hint.es.js",
"require": "./lib/react-beacon-hint.umd.js"
},
"./lib/style.css": {
"import": "./lib/style.css",
"require": "./lib/style.css"
}
},
"keywords": [
Expand Down Expand Up @@ -59,11 +61,12 @@
"devDependencies": {
"@commitlint/cli": "^17.3.0",
"@commitlint/config-conventional": "^17.3.0",
"@floating-ui/react": "^0.15.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/jsdom": "^20.0.1",
"@types/react": "^18.0.26",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"@vitejs/plugin-react": "^3.0.0",
Expand All @@ -76,9 +79,9 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-unused-imports": "^2.0.0",
"framer-motion": "8.0.2",
"husky": "^8.0.2",
"jsdom": "^20.0.3",
"pinst": "^3.0.0",
"prettier": "^2.8.1",
"react": "^18.2.0",
"sass": "^1.57.1",
Expand All @@ -91,15 +94,11 @@
"vitest": "^0.26.2"
},
"peerDependencies": {
"react": "^18.2.0"
"@floating-ui/react": ">=0.15",
"framer-motion": ">=6.5",
"react": ">=16.8"
},
"dependencies": {
"@floating-ui/react": "^0.15.1",
"color-alpha": "^1.1.3",
"framer-motion": "^8.0.2",
"styled-components": "^5.3.6"
},
"resolutions": {
"styled-components": "^5"
"color-alpha": "^1.1.3"
}
}
2 changes: 1 addition & 1 deletion src/arrow/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Arrow from '.';
import {Arrow} from '.';
import {render, screen} from '../test/utils';
import {ArrowProps} from '../@types';

Expand Down
3 changes: 2 additions & 1 deletion src/arrow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ const Arrow = forwardRef<HTMLSpanElement, ArrowProps>(({size = 12, className = '
});

Arrow.displayName = 'Arrow';
export default memo(Arrow);
const MemoizedArrow = memo(Arrow);
export {MemoizedArrow as Arrow};
27 changes: 16 additions & 11 deletions src/beacons/fill/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import colorAlpha from 'color-alpha';
import {memo} from 'react';
import styled, {keyframes} from 'styled-components';
import {memo, useLayoutEffect, useState} from 'react';
import {BeaconProps} from '../../@types';
import styles from './index.module.scss';
import defaultStyles from '../index.module.scss';
import {injectUniqueKeyframe} from '../../utils/cssInjector';

const styleEl = document.createElement('style');
document.head.appendChild(styleEl);

const FillBeacon = ({size = 18, color = 'rgb(255, 0, 68)', className = '', style = {}}: BeaconProps) => {
const animation = keyframes`
0% {
const [animation, setAnimation] = useState('none');

useLayoutEffect(() => {
const {animationName} = injectUniqueKeyframe(
`0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 ${colorAlpha(color, 0.7)};
}
Expand All @@ -18,13 +24,12 @@ const FillBeacon = ({size = 18, color = 'rgb(255, 0, 68)', className = '', style
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}
`;
}`,
color,
);

const Pulse = styled.span`
animation-name: ${animation};
border-radius: ${size}px;
`;
setAnimation(animationName);
}, [color]);

return (
<span
Expand All @@ -33,7 +38,7 @@ const FillBeacon = ({size = 18, color = 'rgb(255, 0, 68)', className = '', style
data-testid='fill-beacon'
>
<button type='button' style={{width: size, height: size}}>
<Pulse className='pulse' style={{backgroundColor: color}} />
<span className='pulse' style={{backgroundColor: color, animationName: animation, borderRadius: size}} />
</button>
</span>
);
Expand Down
2 changes: 1 addition & 1 deletion src/floating/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import {AnimatePresence, motion} from 'framer-motion';
import {forwardRef, Fragment, memo, useImperativeHandle, useLayoutEffect, useMemo, useState} from 'react';
import {FloatingProps} from '../@types';
import Arrow from '../arrow';
import {Arrow} from '../arrow';

export interface FloatingRef {
update: () => void;
Expand Down
4 changes: 4 additions & 0 deletions src/test/setup.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
import '@testing-library/jest-dom';

import {JSDOM} from 'jsdom';
const dom = new JSDOM();
global.document = dom.window.document;
35 changes: 35 additions & 0 deletions src/utils/cssInjector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const styleEl = document.createElement('style');
styleEl.setAttribute('data-testid', 'injectUniqueKeyframe');
document.head.appendChild(styleEl);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const styleSheet = styleEl.sheet!;

export const injectUniqueKeyframe = (keyframe: string, name: string) => {
// eslint-disable-next-line no-useless-escape
const escapedName = name.replace(/[\(|\)|\,|\ |\#|\%]/g, '');
const animationName = `animation-${escapedName}`;
const keyframes = `
@keyframes ${animationName} {
${keyframe}
}`;

styleSheet?.insertRule(keyframes, styleSheet?.cssRules?.length);
const uniqueRules: string[] = [];
const uniqueIndexes: number[] = [];
for (let index = 0; index < styleSheet?.cssRules?.length; index++) {
if (
typeof styleSheet?.cssRules[index]?.cssText === 'string' &&
!uniqueRules.includes(styleSheet?.cssRules[index]?.cssText)
) {
uniqueRules.push(styleSheet?.cssRules[index]?.cssText);
uniqueIndexes.push(index);
}
}
for (let index = 0; index < styleSheet?.cssRules?.length; index++) {
if (!uniqueIndexes.includes(index)) {
styleSheet?.deleteRule(index);
}
}

return {animationName, rulesLength: styleSheet?.cssRules?.length};
};
28 changes: 28 additions & 0 deletions src/utils/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {injectUniqueKeyframe} from './cssInjector';

describe('injectUniqueKeyframe', () => {
it('should set keyframes', () => {
const firstRule = 'first-test';
const secondRule = 'second-rule';
const keyframe = `0% {
transform: scale(0.5);
box-shadow: 0 0 0 0 red;
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}`;

const {rulesLength: firstAnimationNameRulesLength} = injectUniqueKeyframe(keyframe, firstRule);
expect(firstAnimationNameRulesLength).toBe(1);

const {rulesLength: secondAnimationNameRulesLength} = injectUniqueKeyframe(keyframe, secondRule);
expect(secondAnimationNameRulesLength).toBe(2);

const {rulesLength: thirdAnimationNameRulesLength} = injectUniqueKeyframe(keyframe, secondRule);
expect(thirdAnimationNameRulesLength).toBe(2);

const {rulesLength: fourthAnimationNameRulesLength} = injectUniqueKeyframe(keyframe, firstRule);
expect(fourthAnimationNameRulesLength).toBe(2);
});
});
3 changes: 3 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export default defineConfig({
globals: {
react: 'React',
'react-dom': 'ReactDom',
'styled-components': 'styled',
'@floating-ui/react': 'FloatingUIReactDOM',
'framer-motion': 'Motion',
},
},
},
Expand Down
Loading

0 comments on commit 332d916

Please sign in to comment.