Skip to content

Commit

Permalink
feat: react component
Browse files Browse the repository at this point in the history
  • Loading branch information
Mordech committed Sep 23, 2023
1 parent 4744bf2 commit ef3bf0f
Show file tree
Hide file tree
Showing 26 changed files with 872 additions and 53 deletions.
3 changes: 3 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tabWidth: 2
semi: true
singleQuote: true
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,30 @@
],
"dependencies": {
"@lit-labs/observers": "^2.0.0",
"lit": "^2.7.6"
"lit": "^2.7.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@mordech/dynamic-grid-core": "workspace:*",
"@mordech/vite-lit-loader": "^0.29.1",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"@vitejs/plugin-react": "^4.0.3",
"classnames": "^2.3.2",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-simple-import-sort": "^10.0.0",
"husky": "^8.0.3",
"lerna": "^7.3.0",
"prettier": "^3.0.3",
"react-merge-refs": "^2.0.2",
"sass": "^1.64.1",
"ts-lit-plugin": "^1.2.1",
"typescript": "^5.1.6",
Expand Down
8 changes: 4 additions & 4 deletions packages/dynamic-grid-core/lib/calcColumns.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
interface CalcColumnParams {
minWidth: number;
elementWidth: number;
gap?: number;
dividedBy?: number;
maxColumns?: number;
scrollHint?: number;
gap: number | undefined;
dividedBy: number | undefined;
maxColumns: number | undefined;
scrollHint: number | undefined;
}

const divideColumns = (columns: number, divideBy: number) =>
Expand Down
4 changes: 2 additions & 2 deletions packages/dynamic-grid-core/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from "./calcColumns";
export * from "./utils";
export * from './calcColumns';
export * from './utils';
2 changes: 1 addition & 1 deletion packages/dynamic-grid-core/lib/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./unit-converter";
export * from './unit-converter';
16 changes: 8 additions & 8 deletions packages/dynamic-grid-core/lib/utils/unit-converter.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
export function getUnit(value: number | string) {
if (typeof value === "number") return "px";
const unit = value.replace(/[\d.]/g, "");
return unit === "" ? "px" : unit;
if (typeof value === 'number') return 'px';
const unit = value.replace(/[\d.]/g, '');
return unit === '' ? 'px' : unit;
}

export function convertUnit(value: number | string, toUnit: "px" | "rem") {
export function convertUnit(value: number | string, toUnit: 'px' | 'rem') {
const rem = parseFloat(
getComputedStyle(document.documentElement).fontSize || "16",
getComputedStyle(document.documentElement).fontSize || '16',
);

if (typeof value === "number") return value;
if (typeof value === 'number') return value;

const unit = getUnit(value);

const number = parseFloat(value);

if (unit === toUnit) return number;
if (unit === "px" && toUnit === "rem") return number / rem;
if (unit === "rem" && toUnit === "px") return number * rem;
if (unit === 'px' && toUnit === 'rem') return number / rem;
if (unit === 'rem' && toUnit === 'px') return number * rem;
throw new Error(`Cannot convert ${unit} to ${toUnit}, use px or rem`);
}
5 changes: 5 additions & 0 deletions packages/dynamic-grid-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"private": true,
"description": "A dynamic grid component",
"main": "./dist/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/Mordech/dynamic-grid.git",
"homepage": "https://github.com/Mordech/dynamic-grid/tree/main/packages/dynamic-grid-core#readme"
},
"scripts": {
"build-js": "tsc",
"build-css": "sass ./lib:./css",
Expand Down
19 changes: 19 additions & 0 deletions packages/dynamic-grid-react/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
"../../.eslintrc.json",
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
};
24 changes: 24 additions & 0 deletions packages/dynamic-grid-react/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
1 change: 1 addition & 0 deletions packages/dynamic-grid-react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# dynamic-grid-react
12 changes: 12 additions & 0 deletions packages/dynamic-grid-react/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/lib/main.tsx"></script>
</body>
</html>
30 changes: 30 additions & 0 deletions packages/dynamic-grid-react/lib/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DynamicGrid } from '.';

function App() {
return (
<>
<DynamicGrid minColumnWidth="200px">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
<div>17</div>
<div>18</div>
</DynamicGrid>
</>
);
}

export default App;
105 changes: 105 additions & 0 deletions packages/dynamic-grid-react/lib/components/dynamic-grid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {
CSSProperties,
forwardRef,
useCallback,
useLayoutEffect,
useRef,
useState,
} from 'react';
import { mergeRefs } from 'react-merge-refs';
import { calcColumns, convertUnit } from '@mordech/dynamic-grid-core/lib';
import classnames from 'classnames';

import styles from '@mordech/dynamic-grid-core/lib/core.module.scss';

interface ScrollProps {
hint?: number;
hideScrollbar?: boolean;
rows?: number;
scrollSnapAlign?: 'start' | 'center' | 'end' | 'none';
}

type DynamicGridProps = {
minColumnWidth: string;
gridType?: 'auto-fill' | 'auto-fit';
gap?: string;
maxColumns?: number;
dividedBy?: number;
scrollOptions?: ScrollProps;
isScroll?: boolean;
} & React.HTMLAttributes<HTMLDivElement>;

export const DynamicGrid = forwardRef(
(
{
children,
minColumnWidth,
gridType = 'auto-fill',
gap,
maxColumns,
isScroll,
scrollOptions,
dividedBy,
...rest
}: DynamicGridProps,
ref,
) => {
const [columns, setColumns] = useState<number>(NaN);

const gridRef = useRef<HTMLDivElement>(null);

const mergedRef = mergeRefs([gridRef, ref]);

const getColumns = useCallback(
() =>
calcColumns({
minWidth: convertUnit(minColumnWidth, 'px'),
elementWidth: gridRef.current?.clientWidth || 0,
gap: gap ? convertUnit(gap, 'px') : undefined,
dividedBy,
maxColumns,
scrollHint: scrollOptions?.hint,
}),
[minColumnWidth, gap, maxColumns, dividedBy, scrollOptions?.hint],
);

useLayoutEffect(() => {
const handleResize = () => {
if (maxColumns || dividedBy || isScroll || scrollOptions) {
setColumns(getColumns);
}
};

const resizeObserver = new ResizeObserver(handleResize);

resizeObserver.observe(gridRef.current!);

return () => {
resizeObserver.disconnect();
};
}, [dividedBy, getColumns, isScroll, maxColumns, scrollOptions]);

const styleMap = {
'--dg-repeat-count': columns || gridType,
'--dg-min-width': minColumnWidth,
'--dg-gap': gap,
'--dg-scroll-hint': scrollOptions?.hint,
'--dg-scroll-snap-align': scrollOptions?.scrollSnapAlign,
'--dg-scroll-rows': scrollOptions?.rows,
} as CSSProperties;

return (
<div
ref={mergedRef}
className={classnames(styles.grid, {
[styles.isScroll]: isScroll || scrollOptions,
[styles.isScrollbarHidden]: scrollOptions?.hideScrollbar,
})}
style={styleMap}
{...rest}
>
{children}
</div>
);
},
);
1 change: 1 addition & 0 deletions packages/dynamic-grid-react/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './dynamic-grid';
1 change: 1 addition & 0 deletions packages/dynamic-grid-react/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components';
10 changes: 10 additions & 0 deletions packages/dynamic-grid-react/lib/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';

import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
1 change: 1 addition & 0 deletions packages/dynamic-grid-react/lib/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
29 changes: 29 additions & 0 deletions packages/dynamic-grid-react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@mordech/dynamic-grid-react",
"private": true,
"license": "MIT",
"version": "0.0.0",
"type": "module",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/Mordech/dynamic-grid.git",
"homepage": "https://github.com/Mordech/dynamic-grid/tree/main/packages/dynamic-grid-react#readme"
},
"files": [
"dist"
],
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint ./lib --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"vite": "^4.4.7"
}
}
26 changes: 26 additions & 0 deletions packages/dynamic-grid-react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["lib"],
"references": [{ "path": "./tsconfig.node.json" }]
}
10 changes: 10 additions & 0 deletions packages/dynamic-grid-react/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}
Loading

0 comments on commit ef3bf0f

Please sign in to comment.