Skip to content

Commit d6d92e0

Browse files
authored
Merge pull request #93 from builder-group/92-create-basic-widget-grid-library
Create basic Widget Grid library
2 parents 6ce496b + b8a3569 commit d6d92e0

File tree

113 files changed

+6910
-797
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+6910
-797
lines changed

.vscode/settings.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
// File nesting in explorer
2424
"explorer.fileNesting.enabled": true,
2525
"explorer.fileNesting.patterns": {
26-
"*.ts": "${capture}.js, ${capture}.test.ts",
27-
"*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts, ${capture}.test.js",
28-
"*.jsx": "${capture}.js",
29-
"*.tsx": "${capture}.ts, ${capture}.stories.tsx",
26+
"*.ts": "${capture}.js, ${capture}.test.ts, ${capture}.md",
27+
"*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts, ${capture}.test.js, ${capture}.md",
28+
"*.jsx": "${capture}.js, ${capture}.md",
29+
"*.tsx": "${capture}.ts, ${capture}.stories.tsx, ${capture}.md",
3030
".npmrc": ".nvmrc, .yarnrc.yml",
3131
".gitignore": ".eslintignore, .prettierignore, .dockerignore",
3232
"README.md": "CONTRIBUTING.md, CODE_OF_CONDUCT.md",

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ A collection of open source libraries maintained by [builder.group](https://buil
3333
| [validatenv](https://github.com/builder-group/community/blob/develop/packages/validatenv) | Type-safe, straightforward, and lightweight library for validating environment variables using existing validation libraries like Zod, Valibot, and Yup. | [`validatenv`](https://www.npmjs.com/package/validatenv) |
3434
| [validation-adapter](https://github.com/builder-group/community/blob/develop/packages/validation-adapter) | Universal validation adapter that integrates various validation libraries like Zod, Valibot, and Yup | [`validation-adapter`](https://www.npmjs.com/package/validation-adapter) |
3535
| [validation-adapters](https://github.com/builder-group/community/blob/develop/packages/validation-adapters) | Pre-made validation adapters for the validation-adapter library, including adapters for Zod and Valibot | [`validation-adapters`](https://www.npmjs.com/package/validation-adapters) |
36+
| [widget-grid](https://github.com/builder-group/community/blob/develop/packages/widget-grid) | Framework agnostic library for creating and manipulating widget grids | [`widget-grid`](https://www.npmjs.com/package/widget-grid) |
3637
| [xml-tokenizer](https://github.com/builder-group/community/blob/develop/packages/xml-tokenizer) | Straightforward and typesafe XML tokenizer that streams tokens through a callback mechanism | [`xml-tokenizer`](https://www.npmjs.com/package/xml-tokenizer) |
3738

3839
### 📚 Examples
@@ -109,3 +110,9 @@ createState({
109110
We currently use the "wrapper pattern" because it ensures better TypeScript type inference. Each wrapper function modifies the state's type in a specific sequence, which is harder to achieve reliably with a feature array.
110111

111112
We're [actively exploring solutions](https://github.com/builder-group/community/blob/develop/packages/feature-state/src/_experimental) to support both patterns, combining the type safety of the wrapper pattern with the simplicity of declarative APIs. Contributions and ideas are always welcome :)
113+
114+
### Why do feature-based libraries use Objects instead of Classes?
115+
116+
This [Medium post](https://medium.com/@markmiro/thoughts-on-choosing-between-plain-js-objects-and-classes-6422af8aaad5) explains the key differences well.
117+
118+
In short, we use objects because they are more flexible and allow for the kind of extensibility we need. Achieving this level of extensibility with classes isn't feasible for our use case, so using objects was the better choice.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9+
10+
## Expanding the ESLint configuration
11+
12+
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13+
14+
- Configure the top-level `parserOptions` property like this:
15+
16+
```js
17+
export default tseslint.config({
18+
languageOptions: {
19+
// other options...
20+
parserOptions: {
21+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
22+
tsconfigRootDir: import.meta.dirname
23+
}
24+
}
25+
});
26+
```
27+
28+
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
29+
- Optionally add `...tseslint.configs.stylisticTypeChecked`
30+
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
31+
32+
```js
33+
// eslint.config.js
34+
import react from 'eslint-plugin-react';
35+
36+
export default tseslint.config({
37+
// Set the react version
38+
settings: { react: { version: '18.3' } },
39+
plugins: {
40+
// Add the react plugin
41+
react
42+
},
43+
rules: {
44+
// other rules...
45+
// Enable its recommended rules
46+
...react.configs.recommended.rules,
47+
...react.configs['jsx-runtime'].rules
48+
}
49+
});
50+
```
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import js from '@eslint/js';
2+
import reactHooks from 'eslint-plugin-react-hooks';
3+
import reactRefresh from 'eslint-plugin-react-refresh';
4+
import globals from 'globals';
5+
import tseslint from 'typescript-eslint';
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist'] },
9+
{
10+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11+
files: ['**/*.{ts,tsx}'],
12+
languageOptions: {
13+
ecmaVersion: 2020,
14+
globals: globals.browser
15+
},
16+
plugins: {
17+
'react-hooks': reactHooks,
18+
'react-refresh': reactRefresh
19+
},
20+
rules: {
21+
...reactHooks.configs.recommended.rules,
22+
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }]
23+
}
24+
}
25+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + React + TS</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "basic",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"build": "tsc -b && vite build",
8+
"dev": "vite",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"feature-react": "workspace:*",
14+
"feature-state": "workspace:*",
15+
"react": "^18.3.1",
16+
"react-dom": "^18.3.1",
17+
"widget-grid": "workspace:*"
18+
},
19+
"devDependencies": {
20+
"@eslint/js": "^9.17.0",
21+
"@types/react": "^18.3.18",
22+
"@types/react-dom": "^18.3.5",
23+
"@vitejs/plugin-react": "^4.3.4",
24+
"eslint": "^9.17.0",
25+
"eslint-plugin-react-hooks": "^5.0.0",
26+
"eslint-plugin-react-refresh": "^0.4.16",
27+
"globals": "^15.14.0",
28+
"typescript": "~5.6.2",
29+
"typescript-eslint": "^8.18.2",
30+
"vite": "^6.0.5"
31+
}
32+
}
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { withGlobalBind } from 'feature-react/state';
2+
import React, { useState } from 'react';
3+
import { WidgetGrid } from './components';
4+
import './index.css';
5+
import { TWidgetGridPresetKey, widgetGridPresets } from './widget-grid';
6+
7+
const App: React.FC = () => {
8+
const [currentWidgetGridPresetKey, setWidgetGridPresetKey] =
9+
useState<TWidgetGridPresetKey>('playground');
10+
11+
const preset = React.useMemo(
12+
() => withGlobalBind('__widgetGrid', widgetGridPresets[currentWidgetGridPresetKey]),
13+
[currentWidgetGridPresetKey]
14+
);
15+
16+
return (
17+
<div style={{ width: '100%', height: '100vh', backgroundColor: 'blue', padding: '48px' }}>
18+
<div style={{ marginBottom: '20px' }}>
19+
<select
20+
value={currentWidgetGridPresetKey}
21+
onChange={(e) => setWidgetGridPresetKey(e.target.value as TWidgetGridPresetKey)}
22+
style={{ marginRight: '10px' }}
23+
>
24+
<option value="playground">Playground</option>
25+
<option value="performance">Performance Test</option>
26+
</select>
27+
28+
{preset.actions.map((action, index) => (
29+
<button
30+
key={index}
31+
onClick={() => action.action(preset.grid as any)}
32+
style={{ marginRight: '10px' }}
33+
>
34+
{action.label}
35+
</button>
36+
))}
37+
</div>
38+
39+
<WidgetGrid
40+
widgetGrid={preset.grid as any}
41+
renderItem={(item) => {
42+
return (
43+
<div
44+
style={{
45+
backgroundColor: 'red',
46+
width: '100%',
47+
height: '100%',
48+
display: 'flex',
49+
justifyContent: 'center',
50+
alignItems: 'center',
51+
border: '1px solid black'
52+
}}
53+
>
54+
{item.id}
55+
</div>
56+
);
57+
}}
58+
/>
59+
</div>
60+
);
61+
};
62+
63+
export default App;

0 commit comments

Comments
 (0)