@wazobiatech/wazui 0.0.1
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.dockerignore +9 -0
- package/.env.sample +22 -0
- package/.husky/pre-commit +7 -0
- package/.prettierignore +5 -0
- package/.prettierrc +9 -0
- package/.storybook/main.ts +41 -0
- package/.storybook/preview-head.html +3 -0
- package/.storybook/preview.ts +53 -0
- package/Dockerfile +58 -0
- package/Dockerfile.dev +11 -0
- package/README.md +130 -0
- package/__mocks__/fileMock.ts +1 -0
- package/__mocks__/svgMock.ts +1 -0
- package/babel.config.js +46 -0
- package/bitbucket-pipelines.yml +70 -0
- package/components.json +21 -0
- package/e2e/example.spec.ts +18 -0
- package/eslint.config.mjs +37 -0
- package/index.html +13 -0
- package/jest.config.ts +79 -0
- package/jest.setup.tsx +276 -0
- package/lint-staged.config.js +45 -0
- package/package.json +167 -0
- package/playwright.config.ts +79 -0
- package/plop-templates/Component.tsx.hbs +13 -0
- package/plop-templates/ComponentStories.tsx.hbs +24 -0
- package/plop-templates/ComponentTests.tsx.hbs +15 -0
- package/plop-templates/ComponentTypes.ts.hbs +1 -0
- package/plopfile.js +35 -0
- package/setupTests.ts +1 -0
- package/src/assets/dashboard/book.svg +6 -0
- package/src/assets/dashboard/edit.svg +5 -0
- package/src/assets/dashboard/emerald.svg +9 -0
- package/src/assets/dashboard/eye.svg +4 -0
- package/src/assets/dashboard/gold.svg +9 -0
- package/src/assets/dashboard/percentage-square.svg +6 -0
- package/src/assets/dashboard/sapphire.svg +9 -0
- package/src/assets/dashboard/send-2.svg +4 -0
- package/src/assets/desktop.svg +7 -0
- package/src/assets/fonts/UniversalFeature/FeatureJungle-Light.otf +0 -0
- package/src/assets/fonts/UniversalFeature/FeatureJungle-Light.woff +0 -0
- package/src/assets/fonts/UniversalFeature/FeatureJungle-Light.woff2 +0 -0
- package/src/assets/fonts/UniversalFeature/FeatureJungle-Regular.otf +0 -0
- package/src/assets/fonts/UniversalFeature/FeatureJungle-Regular.woff +0 -0
- package/src/assets/fonts/UniversalFeature/FeatureJungle-Regular.woff2 +0 -0
- package/src/assets/fonts/UniversalJungle/UniversalJungle-420.otf +0 -0
- package/src/assets/fonts/UniversalJungle/UniversalJungle-420.woff +0 -0
- package/src/assets/fonts/UniversalJungle/UniversalJungle-420.woff2 +0 -0
- package/src/assets/fonts/UniversalJungle/UniversalJungle-515.otf +0 -0
- package/src/assets/fonts/UniversalJungle/UniversalJungle-515.woff +0 -0
- package/src/assets/fonts/UniversalJungle/UniversalJungle-515.woff2 +0 -0
- package/src/assets/instagram.svg +9 -0
- package/src/assets/mobile.svg +4 -0
- package/src/assets/no-data-image.svg +41 -0
- package/src/assets/no-image-icon.svg +84 -0
- package/src/assets/pexels.svg +9 -0
- package/src/assets/react.svg +1 -0
- package/src/assets/sounds/draft.mp3 +0 -0
- package/src/assets/sounds/error.mp3 +0 -0
- package/src/assets/sounds/publish.mp3 +0 -0
- package/src/assets/tablet.svg +4 -0
- package/src/assets/unsplash.svg +3 -0
- package/src/assets/upload-image.svg +43 -0
- package/src/assets/user.svg +4 -0
- package/src/components/shadcn/index.ts +31 -0
- package/src/config/env.ts +15 -0
- package/src/contexts/ThemeContext.tsx +11 -0
- package/src/data/users.json +6014 -0
- package/src/decorators/ActionModalDecorator.tsx +10 -0
- package/src/decorators/ApolloDecorator.tsx +19 -0
- package/src/decorators/DolosApolloDecorator.tsx +31 -0
- package/src/decorators/JestDecorators.tsx +34 -0
- package/src/decorators/ReactQueryDecorator.tsx +13 -0
- package/src/decorators/RouterDecorator.tsx +5 -0
- package/src/decorators/UnsafePropsDecorator.tsx +0 -0
- package/src/env.ts +99 -0
- package/src/hooks/use-autogrow.ts +28 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/useAuthors.ts +78 -0
- package/src/hooks/useDebounce.ts +18 -0
- package/src/hooks/useMercuryProjectToken.ts +112 -0
- package/src/hooks/useProjectToken.ts +21 -0
- package/src/hooks/useTheme.ts +12 -0
- package/src/index.css +397 -0
- package/src/index.ts +59 -0
- package/src/mocks/env.ts +12 -0
- package/src/providers/QueryProvider/index.tsx +10 -0
- package/src/providers/ThemeProvider/index.tsx +52 -0
- package/src/types/category.types.ts +13 -0
- package/src/types/image.types.ts +44 -0
- package/src/types/post.types.ts +121 -0
- package/src/types/theme.types.ts +10 -0
- package/src/types/users.types.ts +5 -0
- package/src/utils/apolloClient.ts +160 -0
- package/src/utils/articleMetadata.ts +92 -0
- package/src/utils/audio.ts +10 -0
- package/src/utils/imageProcessing.ts +399 -0
- package/src/utils/images.ts +279 -0
- package/src/utils/mercury.ts +0 -0
- package/src/utils/utils.ts +638 -0
- package/src/utils/videos.ts +29 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +30 -0
- package/tsconfig.json +32 -0
- package/tsconfig.node.json +24 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vite.config.ts +50 -0
package/jest.setup.tsx
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import TimeAgo from 'javascript-time-ago';
|
|
4
|
+
import { TextEncoder as NodeTextEncoder, TextDecoder as NodeTextDecoder } from 'util';
|
|
5
|
+
|
|
6
|
+
import en from 'javascript-time-ago/locale/en';
|
|
7
|
+
import ru from 'javascript-time-ago/locale/ru';
|
|
8
|
+
|
|
9
|
+
// Simple polyfill for TextEncoder/TextDecodr with proper typing
|
|
10
|
+
if (typeof global.TextEncoder === 'undefined') {
|
|
11
|
+
global.TextEncoder = NodeTextEncoder as unknown as typeof TextEncoder;
|
|
12
|
+
global.TextDecoder = NodeTextDecoder as unknown as typeof TextDecoder;
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(global, 'importMeta', {
|
|
15
|
+
value: {
|
|
16
|
+
env: {},
|
|
17
|
+
url: 'file:///test',
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Mock ResizeObserver IMMEDIATELY
|
|
22
|
+
class MockResizeObserver {
|
|
23
|
+
callback: ResizeObserverCallback;
|
|
24
|
+
|
|
25
|
+
constructor(callback: ResizeObserverCallback) {
|
|
26
|
+
this.callback = callback;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
observe = jest.fn();
|
|
30
|
+
disconnect = jest.fn();
|
|
31
|
+
unobserve = jest.fn();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Set up ResizeObserver mock on global objects
|
|
35
|
+
Object.defineProperty(global, 'ResizeObserver', {
|
|
36
|
+
writable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
value: MockResizeObserver,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
Object.defineProperty(window, 'ResizeObserver', {
|
|
42
|
+
writable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
value: MockResizeObserver,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Mock IntersectionObserver
|
|
48
|
+
class MockIntersectionObserver {
|
|
49
|
+
callback: IntersectionObserverCallback;
|
|
50
|
+
|
|
51
|
+
constructor(callback: IntersectionObserverCallback) {
|
|
52
|
+
this.callback = callback;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
observe = jest.fn();
|
|
56
|
+
disconnect = jest.fn();
|
|
57
|
+
unobserve = jest.fn();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Object.defineProperty(global, 'IntersectionObserver', {
|
|
61
|
+
writable: true,
|
|
62
|
+
configurable: true,
|
|
63
|
+
value: MockIntersectionObserver,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
Object.defineProperty(window, 'IntersectionObserver', {
|
|
67
|
+
writable: true,
|
|
68
|
+
configurable: true,
|
|
69
|
+
value: MockIntersectionObserver,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Mock window.matchMedia
|
|
73
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
74
|
+
writable: true,
|
|
75
|
+
value: jest.fn().mockImplementation(query => ({
|
|
76
|
+
matches: false,
|
|
77
|
+
media: query,
|
|
78
|
+
onchange: null,
|
|
79
|
+
addListener: jest.fn(),
|
|
80
|
+
removeListener: jest.fn(),
|
|
81
|
+
addEventListener: jest.fn(),
|
|
82
|
+
removeEventListener: jest.fn(),
|
|
83
|
+
dispatchEvent: jest.fn(),
|
|
84
|
+
})),
|
|
85
|
+
});
|
|
86
|
+
TimeAgo.addDefaultLocale(en);
|
|
87
|
+
TimeAgo.addLocale(ru);
|
|
88
|
+
jest.mock('@/utils/images', () => ({
|
|
89
|
+
cn: jest.fn((...classes) => classes.filter(Boolean).join(' ')),
|
|
90
|
+
getImageWithDimensions: jest.fn((url, width, height) => {
|
|
91
|
+
if (width && height) {
|
|
92
|
+
return { url: `${url}?w=${width}&h=${height}`, srcset: `${url}?w=${width}&h=${height}` };
|
|
93
|
+
}
|
|
94
|
+
if (width) {
|
|
95
|
+
return {
|
|
96
|
+
url: `${url}?w=${width}`,
|
|
97
|
+
srcset: `${url}?w=${width}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { url, srcset: url };
|
|
101
|
+
}),
|
|
102
|
+
getImageTransformationsUrl: jest.fn(({ url }) => {
|
|
103
|
+
if (!url) {
|
|
104
|
+
console.warn('getImageTransformationsUrl: No URL provided');
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
return url;
|
|
108
|
+
}),
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
jest.mock('@/utils/apolloClient', () => ({
|
|
112
|
+
createApolloClient: jest.fn(() => ({
|
|
113
|
+
query: jest.fn(),
|
|
114
|
+
mutate: jest.fn(),
|
|
115
|
+
subscribe: jest.fn(),
|
|
116
|
+
cache: {
|
|
117
|
+
readQuery: jest.fn(),
|
|
118
|
+
writeQuery: jest.fn(),
|
|
119
|
+
},
|
|
120
|
+
})),
|
|
121
|
+
createApolloUploadClient: jest.fn(() => ({
|
|
122
|
+
query: jest.fn(),
|
|
123
|
+
mutate: jest.fn(),
|
|
124
|
+
subscribe: jest.fn(),
|
|
125
|
+
cache: {
|
|
126
|
+
readQuery: jest.fn(),
|
|
127
|
+
writeQuery: jest.fn(),
|
|
128
|
+
},
|
|
129
|
+
})),
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
// Mock Apollo Client Provider if needed
|
|
133
|
+
jest.mock('@apollo/client', () => ({
|
|
134
|
+
...jest.requireActual('@apollo/client'),
|
|
135
|
+
// ApolloProvider: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
|
136
|
+
useQuery: jest.fn(() => ({
|
|
137
|
+
data: null,
|
|
138
|
+
loading: false,
|
|
139
|
+
error: null,
|
|
140
|
+
})),
|
|
141
|
+
useMutation: jest.fn(() => [jest.fn(), { data: null, loading: false, error: null }]),
|
|
142
|
+
}));
|
|
143
|
+
|
|
144
|
+
jest.mock('quill', () => {
|
|
145
|
+
// Mock Quill constructor
|
|
146
|
+
const MockQuill = function (
|
|
147
|
+
this: {
|
|
148
|
+
selector: string;
|
|
149
|
+
options: any;
|
|
150
|
+
root: any;
|
|
151
|
+
container: any;
|
|
152
|
+
getContents: any;
|
|
153
|
+
setContents: jest.Mock<any, any, any>;
|
|
154
|
+
getText: any;
|
|
155
|
+
getLength: any;
|
|
156
|
+
insertText: jest.Mock<any, any, any>;
|
|
157
|
+
deleteText: jest.Mock<any, any, any>;
|
|
158
|
+
formatText: jest.Mock<any, any, any>;
|
|
159
|
+
getSelection: any;
|
|
160
|
+
setSelection: jest.Mock<any, any, any>;
|
|
161
|
+
focus: jest.Mock<any, any, any>;
|
|
162
|
+
blur: jest.Mock<any, any, any>;
|
|
163
|
+
enable: jest.Mock<any, any, any>;
|
|
164
|
+
disable: jest.Mock<any, any, any>;
|
|
165
|
+
on: jest.Mock<any, any, any>;
|
|
166
|
+
off: jest.Mock<any, any, any>;
|
|
167
|
+
once: jest.Mock<any, any, any>;
|
|
168
|
+
emit: jest.Mock<any, any, any>;
|
|
169
|
+
__esModule: true;
|
|
170
|
+
default: {
|
|
171
|
+
(selector: string, options: any): any;
|
|
172
|
+
// Add static methods that Quill might have
|
|
173
|
+
register: jest.Mock<any, any, any>;
|
|
174
|
+
find: jest.Mock<any, any, any>;
|
|
175
|
+
import: jest.Mock<any, any, any>;
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
selector: string,
|
|
179
|
+
options: any
|
|
180
|
+
) {
|
|
181
|
+
// Store the selector and options
|
|
182
|
+
this.selector = selector;
|
|
183
|
+
this.options = options;
|
|
184
|
+
this.root = null;
|
|
185
|
+
this.container = null;
|
|
186
|
+
|
|
187
|
+
// Mock methods that Quill instances typically have
|
|
188
|
+
this.getContents = jest.fn(() => ({ ops: [] }));
|
|
189
|
+
this.setContents = jest.fn();
|
|
190
|
+
this.getText = jest.fn(() => '');
|
|
191
|
+
this.getLength = jest.fn(() => 0);
|
|
192
|
+
this.insertText = jest.fn();
|
|
193
|
+
this.deleteText = jest.fn();
|
|
194
|
+
this.formatText = jest.fn();
|
|
195
|
+
this.getSelection = jest.fn(() => null);
|
|
196
|
+
this.setSelection = jest.fn();
|
|
197
|
+
this.focus = jest.fn();
|
|
198
|
+
this.blur = jest.fn();
|
|
199
|
+
this.enable = jest.fn();
|
|
200
|
+
this.disable = jest.fn();
|
|
201
|
+
this.on = jest.fn();
|
|
202
|
+
this.off = jest.fn();
|
|
203
|
+
this.once = jest.fn();
|
|
204
|
+
this.emit = jest.fn();
|
|
205
|
+
|
|
206
|
+
// Create mock DOM elements without accessing document directly
|
|
207
|
+
const mockElement = {
|
|
208
|
+
id: selector?.replace?.('#', ''),
|
|
209
|
+
innerHTML: '',
|
|
210
|
+
textContent: '',
|
|
211
|
+
addEventListener: jest.fn(),
|
|
212
|
+
removeEventListener: jest.fn(),
|
|
213
|
+
appendChild: jest.fn(),
|
|
214
|
+
removeChild: jest.fn(),
|
|
215
|
+
querySelector: jest.fn(),
|
|
216
|
+
querySelectorAll: jest.fn(() => []),
|
|
217
|
+
classList: {
|
|
218
|
+
add: jest.fn(),
|
|
219
|
+
remove: jest.fn(),
|
|
220
|
+
contains: jest.fn(() => false),
|
|
221
|
+
toggle: jest.fn(),
|
|
222
|
+
},
|
|
223
|
+
style: {},
|
|
224
|
+
setAttribute: jest.fn(),
|
|
225
|
+
getAttribute: jest.fn(),
|
|
226
|
+
removeAttribute: jest.fn(),
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
this.root = mockElement;
|
|
230
|
+
this.container = mockElement;
|
|
231
|
+
|
|
232
|
+
return this;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Add static methods that Quill might have
|
|
236
|
+
MockQuill.register = jest.fn();
|
|
237
|
+
MockQuill.find = jest.fn();
|
|
238
|
+
MockQuill.import = jest.fn();
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
__esModule: true,
|
|
242
|
+
default: MockQuill,
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
jest.mock('react-responsive-masonry', () => {
|
|
247
|
+
return {
|
|
248
|
+
__esModule: true,
|
|
249
|
+
default: ({
|
|
250
|
+
children,
|
|
251
|
+
columnsCount,
|
|
252
|
+
gutter,
|
|
253
|
+
}: {
|
|
254
|
+
children: React.ReactNode;
|
|
255
|
+
columnsCount: number;
|
|
256
|
+
gutter: string | number;
|
|
257
|
+
}) => (
|
|
258
|
+
<div
|
|
259
|
+
data-testid='mock-masonry'
|
|
260
|
+
className='mock-masonry-grid'
|
|
261
|
+
style={{
|
|
262
|
+
display: 'grid',
|
|
263
|
+
gridTemplateColumns: `repeat(${columnsCount}, 1fr)`,
|
|
264
|
+
gap: gutter,
|
|
265
|
+
}}
|
|
266
|
+
>
|
|
267
|
+
{children}
|
|
268
|
+
</div>
|
|
269
|
+
),
|
|
270
|
+
ResponsiveMasonry: ({ children }: { children: React.ReactNode }) => (
|
|
271
|
+
<div data-testid='mock-responsive-masonry' className='mock-responsive-masonry'>
|
|
272
|
+
{children}
|
|
273
|
+
</div>
|
|
274
|
+
),
|
|
275
|
+
};
|
|
276
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
// For TypeScript files
|
|
3
|
+
'**/*.ts?(x)': filenames => {
|
|
4
|
+
const files = filenames.join(' ');
|
|
5
|
+
return [
|
|
6
|
+
`eslint --fix ${files}`,
|
|
7
|
+
`prettier --write ${files}`,
|
|
8
|
+
// Type check the changed files
|
|
9
|
+
// Optional: Run affected tests based on changed files
|
|
10
|
+
// This uses Turborepo's filter feature to only run tests in affected packages
|
|
11
|
+
// `turbo run test --filter=[origin/main...HEAD] --filter=[${filenames.map((f) => `...${f}`).join(",")}]`,
|
|
12
|
+
];
|
|
13
|
+
},
|
|
14
|
+
// For JavaScript files
|
|
15
|
+
'**/*.js?(x)': filenames => {
|
|
16
|
+
const files = filenames.join(' ');
|
|
17
|
+
return [`eslint --fix ${files}`, `prettier --write ${files}`];
|
|
18
|
+
},
|
|
19
|
+
// For TS files
|
|
20
|
+
'**/*.ts?(x)': filenames => {
|
|
21
|
+
const files = filenames.join(' ');
|
|
22
|
+
return [`eslint --fix ${files}`, `prettier --write ${files}`];
|
|
23
|
+
},
|
|
24
|
+
// For styles
|
|
25
|
+
'**/*.css': filenames => {
|
|
26
|
+
const files = filenames.join(' ');
|
|
27
|
+
return [`prettier --write ${files}`];
|
|
28
|
+
},
|
|
29
|
+
// For JSON, YAML, etc.
|
|
30
|
+
'**/*.{json,md,yml,yaml}': filenames => {
|
|
31
|
+
const files = filenames.join(' ');
|
|
32
|
+
return [`prettier --write ${files}`];
|
|
33
|
+
},
|
|
34
|
+
// For package.json files - to keep them consistent
|
|
35
|
+
'**/package.json': filenames => {
|
|
36
|
+
const files = filenames.join(' ');
|
|
37
|
+
return [
|
|
38
|
+
`prettier --write ${files}`,
|
|
39
|
+
// Optionally add sort-package-json
|
|
40
|
+
// `sort-package-json ${files}`
|
|
41
|
+
];
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default config;
|
package/package.json
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wazobiatech/wazui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "`@repo/wazui` is a React component library that provides a set of reusable UI components, hooks, and providers for building modern web applications. It is built with TypeScript, Tailwind CSS, and integrates Shadcn UI components.",
|
|
6
|
+
"homepage": "https://bitbucket.org/wazobiatech/wazui#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://bitbucket.org/wazobiatech/wazui/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+ssh://git@bitbucket.org/wazobiatech/wazui.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"author": "",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
"./shadcn": "./src/components/shadcn/index.ts",
|
|
19
|
+
"./styles.css": "./src/index.css",
|
|
20
|
+
".": "./src/index.ts"
|
|
21
|
+
},
|
|
22
|
+
"main": "index.js",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"dev": "storybook dev -p 6007 --no-open",
|
|
25
|
+
"build": "node --max-old-space-size=16384 ./node_modules/.bin/vite build",
|
|
26
|
+
"test": "jest --passWithNoTests",
|
|
27
|
+
"lint": "eslint .",
|
|
28
|
+
"preview": "vite preview",
|
|
29
|
+
"check-types": "tsc --noEmit",
|
|
30
|
+
"prepare": "husky install",
|
|
31
|
+
"lint:staged": "lint-staged",
|
|
32
|
+
"storybook": "storybook dev -p 6006",
|
|
33
|
+
"build-storybook": "node --max-old-space-size=16384 ./node_modules/.bin/storybook build",
|
|
34
|
+
"plop": "plop",
|
|
35
|
+
"test:unit": "jest",
|
|
36
|
+
"test:e2e": "npx playwright test"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@apollo/client": "^4.0.9",
|
|
40
|
+
"@babel/core": "^7.26.10",
|
|
41
|
+
"@hookform/resolvers": "^5.0.1",
|
|
42
|
+
"@radix-ui/react-checkbox": "^1.3.2",
|
|
43
|
+
"@radix-ui/react-collapsible": "^1.1.11",
|
|
44
|
+
"@radix-ui/react-context-menu": "^2.2.16",
|
|
45
|
+
"@radix-ui/react-dialog": "^1.1.13",
|
|
46
|
+
"@radix-ui/react-dropdown-menu": "^2.1.7",
|
|
47
|
+
"@radix-ui/react-label": "^2.1.6",
|
|
48
|
+
"@radix-ui/react-popover": "^1.1.7",
|
|
49
|
+
"@radix-ui/react-progress": "^1.1.7",
|
|
50
|
+
"@radix-ui/react-radio-group": "^1.3.4",
|
|
51
|
+
"@radix-ui/react-select": "^2.1.7",
|
|
52
|
+
"@radix-ui/react-separator": "^1.1.6",
|
|
53
|
+
"@radix-ui/react-slot": "^1.2.2",
|
|
54
|
+
"@radix-ui/react-switch": "^1.2.2",
|
|
55
|
+
"@radix-ui/react-tabs": "^1.1.9",
|
|
56
|
+
"@radix-ui/react-toggle": "^1.1.3",
|
|
57
|
+
"@radix-ui/react-toggle-group": "^1.1.3",
|
|
58
|
+
"@radix-ui/react-tooltip": "^1.2.6",
|
|
59
|
+
"@tailwindcss/vite": "^4.1.3",
|
|
60
|
+
"@tanstack/react-query": "^5.90.11",
|
|
61
|
+
"@tanstack/react-table": "^8.21.2",
|
|
62
|
+
"@types/react-responsive-masonry": "^2.6.0",
|
|
63
|
+
"apollo-upload-client": "^19.0.0",
|
|
64
|
+
"axios": "^1.12.2",
|
|
65
|
+
"class-variance-authority": "^0.7.1",
|
|
66
|
+
"clsx": "^2.1.1",
|
|
67
|
+
"cmdk": "^1.1.1",
|
|
68
|
+
"context-filter-polyfill": "^0.3.23",
|
|
69
|
+
"date-fns": "^4.1.0",
|
|
70
|
+
"graphql": "^16.10.0",
|
|
71
|
+
"he": "^1.2.0",
|
|
72
|
+
"javascript-time-ago": "^2.5.11",
|
|
73
|
+
"jest-transform-stub": "^2.0.0",
|
|
74
|
+
"lodash": "^4.17.21",
|
|
75
|
+
"lucide-react": "^0.507.0",
|
|
76
|
+
"next-themes": "^0.4.6",
|
|
77
|
+
"quill": "^2.0.3",
|
|
78
|
+
"react-advanced-cropper": "^0.20.1",
|
|
79
|
+
"react-day-picker": "8.10.1",
|
|
80
|
+
"react-hook-form": "^7.56.3",
|
|
81
|
+
"react-icons": "^5.5.0",
|
|
82
|
+
"react-intersection-observer": "^9.16.0",
|
|
83
|
+
"react-responsive-masonry": "^2.7.1",
|
|
84
|
+
"react-router-dom": "^7.6.2",
|
|
85
|
+
"react-time-ago": "^7.3.3",
|
|
86
|
+
"sonner": "^2.0.3",
|
|
87
|
+
"sortablejs": "^1.15.6",
|
|
88
|
+
"tailwind-merge": "^3.2.0",
|
|
89
|
+
"tailwindcss": "^4.1.3",
|
|
90
|
+
"ts-jest": "^29.3.1",
|
|
91
|
+
"tw-animate-css": "^1.2.5",
|
|
92
|
+
"universal-cookie": "^8.0.1",
|
|
93
|
+
"uuid": "^11.1.0",
|
|
94
|
+
"zod": "^3.24.4"
|
|
95
|
+
},
|
|
96
|
+
"devDependencies": {
|
|
97
|
+
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
|
98
|
+
"@babel/preset-env": "^7.26.9",
|
|
99
|
+
"@babel/preset-react": "^7.26.3",
|
|
100
|
+
"@babel/preset-typescript": "^7.27.0",
|
|
101
|
+
"@babel/types": "^7.27.0",
|
|
102
|
+
"@changesets/cli": "^2.29.8",
|
|
103
|
+
"@chromatic-com/storybook": "3",
|
|
104
|
+
"@dnd-kit/core": "^6.3.1",
|
|
105
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
106
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
107
|
+
"@eslint/js": "^9.21.0",
|
|
108
|
+
"@playwright/test": "^1.51.1",
|
|
109
|
+
"@storybook/addon-essentials": "8.6.12",
|
|
110
|
+
"@storybook/addon-onboarding": "8.6.12",
|
|
111
|
+
"@storybook/addon-themes": "^8.6.12",
|
|
112
|
+
"@storybook/blocks": "8.6.12",
|
|
113
|
+
"@storybook/experimental-addon-test": "^8.6.12",
|
|
114
|
+
"@storybook/react": "8.6.12",
|
|
115
|
+
"@storybook/react-vite": "8.6.12",
|
|
116
|
+
"@storybook/test": "8.6.12",
|
|
117
|
+
"@testing-library/dom": "^10.4.0",
|
|
118
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
119
|
+
"@testing-library/react": "^16.3.0",
|
|
120
|
+
"@turbo/gen": "^2.5.0",
|
|
121
|
+
"@types/apollo-upload-client": "^19.0.0",
|
|
122
|
+
"@types/he": "^1.2.3",
|
|
123
|
+
"@types/jest": "^29.5.14",
|
|
124
|
+
"@types/node": "^22.14.0",
|
|
125
|
+
"@types/react": "^19.2.7",
|
|
126
|
+
"@types/react-dom": "^19.2.3",
|
|
127
|
+
"@types/react-test-renderer": "^19.1.0",
|
|
128
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
129
|
+
"@vitest/browser": "^3.1.1",
|
|
130
|
+
"@vitest/coverage-v8": "^3.1.1",
|
|
131
|
+
"ajv": "^8.17.1",
|
|
132
|
+
"ajv-draft-04": "^1.0.0",
|
|
133
|
+
"ajv-keywords": "^5.1.0",
|
|
134
|
+
"babel-jest": "^29.7.0",
|
|
135
|
+
"eslint": "^9.21.0",
|
|
136
|
+
"eslint-plugin-jest": "^28.11.0",
|
|
137
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
138
|
+
"eslint-plugin-react-refresh": "^0.4.19",
|
|
139
|
+
"eslint-plugin-storybook": "^0.12.0",
|
|
140
|
+
"globals": "^15.15.0",
|
|
141
|
+
"husky": "^9.1.7",
|
|
142
|
+
"identity-obj-proxy": "^3.0.0",
|
|
143
|
+
"jest": "^29.7.0",
|
|
144
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
145
|
+
"jest-transform-stub": "^2.0.0",
|
|
146
|
+
"lint-staged": "^15.5.0",
|
|
147
|
+
"plop": "^4.0.1",
|
|
148
|
+
"prettier": "3.5.3",
|
|
149
|
+
"storybook": "8.6.12",
|
|
150
|
+
"typescript": "~5.7.2",
|
|
151
|
+
"typescript-eslint": "^8.24.1",
|
|
152
|
+
"vite": "^6.2.0",
|
|
153
|
+
"vite-plugin-dts": "^4.5.3",
|
|
154
|
+
"vitest": "^3.1.1"
|
|
155
|
+
},
|
|
156
|
+
"peerDependencies": {
|
|
157
|
+
"@tanstack/react-query": "^5.90.11",
|
|
158
|
+
"@tanstack/react-query-devtools": "^5.0.0",
|
|
159
|
+
"react": "^19.0.0",
|
|
160
|
+
"react-dom": "^19.0.0"
|
|
161
|
+
},
|
|
162
|
+
"eslintConfig": {
|
|
163
|
+
"extends": [
|
|
164
|
+
"plugin:storybook/recommended"
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read environment variables from file.
|
|
5
|
+
* https://github.com/motdotla/dotenv
|
|
6
|
+
*/
|
|
7
|
+
// import dotenv from 'dotenv';
|
|
8
|
+
// import path from 'path';
|
|
9
|
+
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* See https://playwright.dev/docs/test-configuration.
|
|
13
|
+
*/
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
testDir: './e2e',
|
|
16
|
+
/* Run tests in files in parallel */
|
|
17
|
+
fullyParallel: true,
|
|
18
|
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
19
|
+
forbidOnly: !!process.env.CI,
|
|
20
|
+
/* Retry on CI only */
|
|
21
|
+
retries: process.env.CI ? 2 : 0,
|
|
22
|
+
/* Opt out of parallel tests on CI. */
|
|
23
|
+
workers: process.env.CI ? 1 : undefined,
|
|
24
|
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
25
|
+
reporter: 'html',
|
|
26
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
27
|
+
use: {
|
|
28
|
+
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
29
|
+
// baseURL: 'http://127.0.0.1:3000',
|
|
30
|
+
|
|
31
|
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
32
|
+
trace: 'on-first-retry',
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/* Configure projects for major browsers */
|
|
36
|
+
projects: [
|
|
37
|
+
{
|
|
38
|
+
name: 'chromium',
|
|
39
|
+
use: { ...devices['Desktop Chrome'] },
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
name: 'firefox',
|
|
44
|
+
use: { ...devices['Desktop Firefox'] },
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
name: 'webkit',
|
|
49
|
+
use: { ...devices['Desktop Safari'] },
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
/* Test against mobile viewports. */
|
|
53
|
+
// {
|
|
54
|
+
// name: 'Mobile Chrome',
|
|
55
|
+
// use: { ...devices['Pixel 5'] },
|
|
56
|
+
// },
|
|
57
|
+
// {
|
|
58
|
+
// name: 'Mobile Safari',
|
|
59
|
+
// use: { ...devices['iPhone 12'] },
|
|
60
|
+
// },
|
|
61
|
+
|
|
62
|
+
/* Test against branded browsers. */
|
|
63
|
+
// {
|
|
64
|
+
// name: 'Microsoft Edge',
|
|
65
|
+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
66
|
+
// },
|
|
67
|
+
// {
|
|
68
|
+
// name: 'Google Chrome',
|
|
69
|
+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
70
|
+
// },
|
|
71
|
+
],
|
|
72
|
+
|
|
73
|
+
/* Run your local dev server before starting the tests */
|
|
74
|
+
// webServer: {
|
|
75
|
+
// command: 'npm run start',
|
|
76
|
+
// url: 'http://127.0.0.1:3000',
|
|
77
|
+
// reuseExistingServer: !process.env.CI,
|
|
78
|
+
// },
|
|
79
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { {{pascalCase name}}Props } from './types';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const {{pascalCase name}}: React.FC<{{pascalCase name}}Props> = ({ children }) => {
|
|
6
|
+
return (
|
|
7
|
+
<div>
|
|
8
|
+
{children}
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default {{pascalCase name}};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {{pascalCase name}} from "./{{pascalCase name}}";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof {{pascalCase name}}> = {
|
|
5
|
+
title: "Components/{{pascalCase name}}",
|
|
6
|
+
component: {{pascalCase name}},
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: "centered",
|
|
9
|
+
theme: "dark",
|
|
10
|
+
},
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
argTypes: {
|
|
13
|
+
// TODO: Add argTypes here
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof {{pascalCase name}}>;
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
// TODO: Add args here
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import "@testing-library/jest-dom";
|
|
3
|
+
import {{pascalCase name}} from "./{{pascalCase name}}";
|
|
4
|
+
|
|
5
|
+
describe("{{pascalCase name}} Component", () => {
|
|
6
|
+
it("renders correctly with text", () => {
|
|
7
|
+
render(
|
|
8
|
+
<{{pascalCase name}}>
|
|
9
|
+
Primary
|
|
10
|
+
</{{pascalCase name}}>
|
|
11
|
+
);
|
|
12
|
+
const element = screen.getByText("Primary");
|
|
13
|
+
expect(element).toBeInTheDocument();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface {{pascalCase name}}Props { children: React.ReactNode; }
|
package/plopfile.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export default function (plop) {
|
|
2
|
+
// Plop generator for components
|
|
3
|
+
plop.setGenerator('component', {
|
|
4
|
+
description: 'Create a new React component without styles',
|
|
5
|
+
prompts: [
|
|
6
|
+
{
|
|
7
|
+
type: 'input',
|
|
8
|
+
name: 'name',
|
|
9
|
+
message: 'What is the name of the component?',
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
actions: [
|
|
13
|
+
{
|
|
14
|
+
type: 'add',
|
|
15
|
+
path: 'src/components/wazui/{{pascalCase name}}/{{pascalCase name}}.tsx',
|
|
16
|
+
templateFile: 'plop-templates/Component.tsx.hbs',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
type: 'add',
|
|
20
|
+
path: 'src/components/wazui/{{pascalCase name}}/{{pascalCase name}}.test.tsx',
|
|
21
|
+
templateFile: 'plop-templates/ComponentTests.tsx.hbs',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: 'add',
|
|
25
|
+
path: 'src/components/wazui/{{pascalCase name}}/{{pascalCase name}}.stories.tsx',
|
|
26
|
+
templateFile: 'plop-templates/ComponentStories.tsx.hbs',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: 'add',
|
|
30
|
+
path: 'src/components/wazui/{{pascalCase name}}/types.ts',
|
|
31
|
+
templateFile: 'plop-templates/ComponentTypes.ts.hbs',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
}
|
package/setupTests.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M18.3332 13.9501V3.89174C18.3332 2.89174 17.5165 2.15008 16.5248 2.23341H16.4748C14.7248 2.38341 12.0665 3.27508 10.5832 4.20841L10.4415 4.30008C10.1998 4.45008 9.79984 4.45008 9.55817 4.30008L9.34984 4.17508C7.8665 3.25008 5.2165 2.36674 3.4665 2.22508C2.47484 2.14174 1.6665 2.89174 1.6665 3.88341V13.9501C1.6665 14.7501 2.3165 15.5001 3.1165 15.6001L3.35817 15.6334C5.1665 15.8751 7.95817 16.7917 9.55817 17.6667L9.5915 17.6834C9.8165 17.8084 10.1748 17.8084 10.3915 17.6834C11.9915 16.8001 14.7915 15.8751 16.6082 15.6334L16.8832 15.6001C17.6832 15.5001 18.3332 14.7501 18.3332 13.9501Z" stroke="#6574FF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M10 4.57422V17.0742" stroke="#6574FF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M6.4585 7.07422H4.5835" stroke="#6574FF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
<path d="M7.0835 9.57422H4.5835" stroke="#6574FF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M9.1665 1.66602H7.49984C3.33317 1.66602 1.6665 3.33268 1.6665 7.49935V12.4993C1.6665 16.666 3.33317 18.3327 7.49984 18.3327H12.4998C16.6665 18.3327 18.3332 16.666 18.3332 12.4993V10.8327" stroke="#208B02" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M13.3666 2.51639L6.7999 9.08306C6.5499 9.33306 6.2999 9.82472 6.2499 10.1831L5.89157 12.6914C5.75823 13.5997 6.3999 14.2331 7.30823 14.1081L9.81657 13.7497C10.1666 13.6997 10.6582 13.4497 10.9166 13.1997L17.4832 6.63306C18.6166 5.49972 19.1499 4.18306 17.4832 2.51639C15.8166 0.849722 14.4999 1.38306 13.3666 2.51639Z" stroke="#208B02" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M12.4248 3.45898C12.9831 5.45065 14.5415 7.00898 16.5415 7.57565" stroke="#208B02" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
</svg>
|