pejay-ui 1.4.3 → 1.5.0
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/README.md +26 -0
- package/bin/cli.js +45 -15
- package/package.json +2 -1
- package/registry/buttons.json +3 -2
- package/registry/dropdowns.json +3 -1
- package/registry/forms.json +51 -23
- package/registry/hotkeys.json +12 -0
- package/registry/overlays.json +18 -2
- package/registry/panels.json +21 -0
- package/registry/skeleton.json +20 -0
- package/registry/spinner.json +13 -0
- package/templates/button/Button.tsx +8 -7
- package/templates/button/README.md +81 -0
- package/templates/button/index.ts +1 -2
- package/templates/form/{checkbox-group.tsx → choices/checkbox-group.tsx} +1 -1
- package/templates/form/{checkbox.tsx → choices/checkbox.tsx} +1 -1
- package/templates/form/{radio-group.tsx → choices/radio-group.tsx} +1 -1
- package/templates/form/{radio.tsx → choices/radio.tsx} +1 -1
- package/templates/form/choices/readme.checkbox-group.md +27 -0
- package/templates/form/choices/readme.checkbox.md +26 -0
- package/templates/form/choices/readme.radio-group.md +26 -0
- package/templates/form/choices/readme.radio.md +24 -0
- package/templates/form/choices/readme.switch.md +26 -0
- package/templates/form/{switch.tsx → choices/switch.tsx} +1 -1
- package/templates/form/{file-input.tsx → file/file-input.tsx} +2 -2
- package/templates/form/file/readme.file-input.md +26 -0
- package/templates/form/index.ts +19 -22
- package/templates/form/{amount-input.tsx → numeric/amount-input.tsx} +2 -2
- package/templates/form/{number-input.tsx → numeric/number-input.tsx} +2 -2
- package/templates/form/{range-slider.tsx → numeric/range-slider.tsx} +1 -1
- package/templates/form/numeric/readme.amount-input.md +27 -0
- package/templates/form/numeric/readme.number-input.md +26 -0
- package/templates/form/numeric/readme.range-slider.md +27 -0
- package/templates/form/{date-picker.tsx → pickers/date-picker.tsx} +2 -2
- package/templates/form/{date-range-picker.tsx → pickers/date-range-picker.tsx} +2 -2
- package/templates/form/pickers/readme.date-picker.md +26 -0
- package/templates/form/pickers/readme.date-range-picker.md +25 -0
- package/templates/form/pickers/readme.time-picker.md +25 -0
- package/templates/form/pickers/readme.time-range-picker.md +25 -0
- package/templates/form/{time-picker.tsx → pickers/time-picker.tsx} +1 -1
- package/templates/form/{time-range-picker.tsx → pickers/time-range-picker.tsx} +1 -1
- package/templates/form/{input.tsx → text-inputs/input.tsx} +1 -1
- package/templates/form/{password-input.tsx → text-inputs/password-input.tsx} +1 -1
- package/templates/form/text-inputs/readme.email-input.md +24 -0
- package/templates/form/text-inputs/readme.input.md +28 -0
- package/templates/form/text-inputs/readme.password-input.md +24 -0
- package/templates/form/text-inputs/readme.phone-input.md +24 -0
- package/templates/form/text-inputs/readme.textarea.md +24 -0
- package/templates/form/text-inputs/readme.url-input.md +23 -0
- package/templates/form/{textarea.tsx → text-inputs/textarea.tsx} +1 -1
- package/templates/hotkeys/README.md +134 -0
- package/templates/hotkeys/components/HotkeyProvider.tsx +78 -0
- package/templates/hotkeys/components/HotkeysHelpModal.tsx +102 -0
- package/templates/hotkeys/core/key-matcher.ts +106 -0
- package/templates/hotkeys/core/registry.ts +39 -0
- package/templates/hotkeys/core/types.ts +15 -0
- package/templates/hotkeys/hooks/useHotkey.ts +43 -0
- package/templates/hotkeys/index.ts +6 -0
- package/templates/layouts/lv1/app-layout.tsx +1 -1
- package/templates/layouts/lv1/sidebar-menu.tsx +1 -1
- package/templates/notes/app-provider/app-provider-side-panel-modals-roadmap.md +606 -0
- package/templates/notes/app-provider/manual-open-close-side-panel-and-modal.md +913 -0
- package/templates/notes/app-provider/side-panel-card-hooks-and-complexity.md +578 -0
- package/templates/notes/under-dev/AppProvider.tsx +92 -0
- package/templates/notes/under-dev/app-context.ts +14 -0
- package/templates/notes/under-dev/card/base-card.tsx +35 -0
- package/templates/notes/under-dev/card/index.ts +4 -0
- package/templates/notes/under-dev/card/modal-card.tsx +88 -0
- package/templates/notes/under-dev/card/side-panel-card.tsx +127 -0
- package/templates/notes/under-dev/form-overlay-registry.ts +42 -0
- package/templates/notes/under-dev/keyboard-shortcuts-help.tsx +79 -0
- package/templates/notes/under-dev/keyboard-utils.ts +22 -0
- package/templates/notes/under-dev/overlay/backdrop.tsx +95 -0
- package/templates/notes/under-dev/overlay/index.ts +4 -0
- package/templates/notes/under-dev/overlay/modal.tsx +43 -0
- package/templates/notes/under-dev/overlay/side-panel.tsx +126 -0
- package/templates/notes/under-dev/overlay-close.ts +50 -0
- package/templates/notes/under-dev/page-shortcut-registry.ts +9 -0
- package/templates/notes/under-dev/unsaved-changes-notify.ts +11 -0
- package/templates/notes/under-dev/use-keyboard-shortcuts.tsx +110 -0
- package/templates/notes/under-dev/useFormDirty.ts +6 -0
- package/templates/notes/under-dev/useFormOverlayRegistration.ts +47 -0
- package/templates/notes/under-dev/useFormPanel.tsx +18 -0
- package/templates/notes/under-dev/useFormTabHandler.ts +22 -0
- package/templates/notes/under-dev/useHorizontalWheelScroll.ts +27 -0
- package/templates/notes/under-dev/useOverlay.ts +41 -0
- package/templates/overlays/index.ts +2 -1
- package/templates/overlays/portal/portal.tsx +26 -0
- package/templates/overlays/tooltip/readme.tooltip.md +26 -0
- package/templates/{button → overlays/tooltip}/tooltip.tsx +1 -1
- package/templates/panels/COMPONENTS.md +103 -0
- package/templates/panels/README.md +702 -0
- package/templates/panels/components/base-card.tsx +33 -0
- package/templates/panels/components/index.ts +8 -0
- package/templates/panels/components/modal/backdrop.tsx +88 -0
- package/templates/panels/components/modal/modal-card.tsx +139 -0
- package/templates/panels/components/modal/modal-raw.tsx +36 -0
- package/templates/panels/components/modal/modal.tsx +49 -0
- package/templates/panels/components/side-panel/side-panel-card.tsx +123 -0
- package/templates/panels/components/side-panel/side-panel-raw.tsx +25 -0
- package/templates/panels/components/side-panel/side-panel.tsx +135 -0
- package/templates/panels/core/PanelProvider.tsx +145 -0
- package/templates/panels/core/constants.ts +9 -0
- package/templates/panels/core/form-overlay-registry.ts +35 -0
- package/templates/panels/core/index.ts +6 -0
- package/templates/panels/core/overlay-close.ts +11 -0
- package/templates/panels/core/panel-context.ts +41 -0
- package/templates/panels/core/types.ts +41 -0
- package/templates/panels/hooks/index.ts +7 -0
- package/templates/panels/hooks/useFormDirty.ts +6 -0
- package/templates/panels/hooks/useFormOverlayRegistration.ts +92 -0
- package/templates/panels/hooks/useFormPanel.tsx +18 -0
- package/templates/panels/hooks/useFormTabHandler.ts +25 -0
- package/templates/panels/hooks/useHorizontalWheelScroll.ts +31 -0
- package/templates/panels/hooks/useModalForm.tsx +22 -0
- package/templates/panels/hooks/useOverlay.ts +65 -0
- package/templates/panels/index.ts +3 -0
- package/templates/panels/vendor-example/by-using-modal/VendorModalPage.tsx +47 -0
- package/templates/panels/vendor-example/by-using-modal/useVendorModalForm.tsx +19 -0
- package/templates/panels/vendor-example/by-using-modal/vendor-modal-form.tsx +112 -0
- package/templates/panels/vendor-example/by-using-modal/vendor-types.ts +29 -0
- package/templates/panels/vendor-example/by-using-sidepanel/VendorsPage.tsx +47 -0
- package/templates/panels/vendor-example/by-using-sidepanel/useVendorFormPanel.tsx +15 -0
- package/templates/panels/vendor-example/by-using-sidepanel/vendor-form.tsx +108 -0
- package/templates/panels/vendor-example/by-using-sidepanel/vendor-types.ts +29 -0
- package/templates/select-dropdown/README.md +62 -0
- package/templates/select-dropdown/multiselect-input.tsx +2 -2
- package/templates/select-dropdown/select-input.tsx +2 -2
- package/templates/skeleton/README.md +53 -0
- package/templates/skeleton/index.ts +2 -0
- package/templates/skeleton/skeleton.css +36 -0
- package/templates/skeleton/skeleton.tsx +40 -0
- package/templates/skeleton/types.ts +12 -0
- package/templates/spinner/README.md +51 -0
- package/templates/spinner/index.ts +1 -0
- package/templates/spinner/spinner.css +58 -0
- package/templates/spinner/spinner.tsx +263 -0
- package/templates/toast/container.tsx +2 -2
- package/templates/utilities/formater.dateTime.md +74 -0
- package/templates/utilities/formater.dateTime.ts +310 -0
- package/templates/utilities/formater.phoneNumber.md +32 -0
- package/templates/utilities/formater.phoneNumber.ts +143 -0
- package/templates/utilities/sanitize.md +23 -0
- package/templates/utilities/sanitize.ts +148 -0
- /package/templates/form/{email-input.tsx → text-inputs/email-input.tsx} +0 -0
- /package/templates/form/{phone-input.tsx → text-inputs/phone-input.tsx} +0 -0
- /package/templates/form/{url-input.tsx → text-inputs/url-input.tsx} +0 -0
- /package/templates/{overlays → notes/under-dev/overlay}/portal.tsx +0 -0
package/README.md
CHANGED
|
@@ -129,15 +129,41 @@ npx pejay-ui add toast
|
|
|
129
129
|
```bash
|
|
130
130
|
npx pejay-ui add overlays/portal
|
|
131
131
|
```
|
|
132
|
+
```bash
|
|
133
|
+
npx pejay-ui add overlays/tooltip
|
|
134
|
+
```
|
|
132
135
|
*(Supports category-wide commands: `npx pejay-ui add overlays --all` or `npx pejay-ui add overlays --select`)*
|
|
133
136
|
|
|
137
|
+
### Spinners
|
|
138
|
+
```bash
|
|
139
|
+
npx pejay-ui add spinner
|
|
140
|
+
```
|
|
141
|
+
*(Includes a localized `README.md` showing all 9 spinner styles).*
|
|
142
|
+
|
|
143
|
+
### Skeletons
|
|
144
|
+
```bash
|
|
145
|
+
npx pejay-ui add skeleton
|
|
146
|
+
```
|
|
147
|
+
*(Includes a localized `README.md` showing all skeleton presets).*
|
|
148
|
+
|
|
134
149
|
### Scaffolds & Templates
|
|
135
150
|
```bash
|
|
136
151
|
npx pejay-ui add tanstack-query-client
|
|
152
|
+
```
|
|
153
|
+
```bash
|
|
137
154
|
npx pejay-ui add react-router-client
|
|
155
|
+
```
|
|
156
|
+
```bash
|
|
138
157
|
npx pejay-ui add tanstack-router-client
|
|
158
|
+
```
|
|
159
|
+
```bash
|
|
139
160
|
npx pejay-ui add axios-client
|
|
161
|
+
```
|
|
162
|
+
```bash
|
|
140
163
|
npx pejay-ui add redux-store-client
|
|
164
|
+
```
|
|
165
|
+
```bash
|
|
141
166
|
npx pejay-ui add rtk-query-client
|
|
142
167
|
```
|
|
143
168
|
*(Supports category-wide commands: `npx pejay-ui add scaffold --all` or `npx pejay-ui add scaffold --select`)*
|
|
169
|
+
|
package/bin/cli.js
CHANGED
|
@@ -38,6 +38,24 @@ const getFilesRecursively = async (dir) => {
|
|
|
38
38
|
return results;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
/*
|
|
42
|
+
* resolveTargetDir – single source of truth for where a component's files land.
|
|
43
|
+
*
|
|
44
|
+
* Priority:
|
|
45
|
+
* 1. category === "scaffold" → src/<targetDirName|key>/
|
|
46
|
+
* 2. outputDirectory present → <baseDir>/<outputDirectory>/
|
|
47
|
+
* 3. default → <baseDir>/components/<category>/
|
|
48
|
+
*/
|
|
49
|
+
const resolveTargetDir = (cwd, baseDir, compKey, compData) => {
|
|
50
|
+
if (compData.category === "scaffold") {
|
|
51
|
+
return path.join(cwd, "src", compData.targetDirName || compKey);
|
|
52
|
+
}
|
|
53
|
+
if (compData.outputDirectory) {
|
|
54
|
+
return path.join(cwd, baseDir, compData.outputDirectory);
|
|
55
|
+
}
|
|
56
|
+
return path.join(cwd, baseDir, "components", compData.category);
|
|
57
|
+
};
|
|
58
|
+
|
|
41
59
|
const loadRegistry = async () => {
|
|
42
60
|
const registryDir = path.join(packageRoot, "registry");
|
|
43
61
|
if (!await fs.pathExists(registryDir)) {
|
|
@@ -224,12 +242,7 @@ program
|
|
|
224
242
|
let isAlreadyPresent = !!config.installed?.[compToInstall];
|
|
225
243
|
|
|
226
244
|
if (!isAlreadyPresent) {
|
|
227
|
-
let targetDir;
|
|
228
|
-
if (componentData.category === "scaffold") {
|
|
229
|
-
targetDir = path.join(cwd, "src", componentData.targetDirName || compToInstall);
|
|
230
|
-
} else {
|
|
231
|
-
targetDir = path.join(cwd, config.baseDir, "components", componentData.category);
|
|
232
|
-
}
|
|
245
|
+
let targetDir = resolveTargetDir(cwd, config.baseDir, compToInstall, componentData);
|
|
233
246
|
|
|
234
247
|
const sourceFiles = componentData.files || (componentData.path ? [componentData.path] : []);
|
|
235
248
|
for (const srcFilePath of sourceFiles) {
|
|
@@ -355,12 +368,7 @@ program
|
|
|
355
368
|
}
|
|
356
369
|
|
|
357
370
|
// 3. Process & Copy Component Files
|
|
358
|
-
let targetDir;
|
|
359
|
-
if (componentData.category === "scaffold") {
|
|
360
|
-
targetDir = path.join(cwd, "src", componentData.targetDirName || compToInstall);
|
|
361
|
-
} else {
|
|
362
|
-
targetDir = path.join(cwd, config.baseDir, "components", componentData.category);
|
|
363
|
-
}
|
|
371
|
+
let targetDir = resolveTargetDir(cwd, config.baseDir, compToInstall, componentData);
|
|
364
372
|
|
|
365
373
|
// Determine list of files to copy
|
|
366
374
|
const sourceFiles = componentData.files || (componentData.path ? [componentData.path] : []);
|
|
@@ -391,6 +399,17 @@ program
|
|
|
391
399
|
? `${relativeToUtils}/cn`
|
|
392
400
|
: `${relativeToUtils}/cn.js`;
|
|
393
401
|
componentCode = componentCode.replace(/@\/utils\/cn/g, cnImportPath);
|
|
402
|
+
componentCode = componentCode.replace(/@\/utils/g, cnImportPath);
|
|
403
|
+
|
|
404
|
+
const relativeToBaseDir = path.relative(fileDir, path.join(cwd, config.baseDir)).replace(/\\/g, "/");
|
|
405
|
+
let pejayUiImportPath = relativeToBaseDir;
|
|
406
|
+
if (!pejayUiImportPath.startsWith(".")) {
|
|
407
|
+
pejayUiImportPath = `./${pejayUiImportPath}`;
|
|
408
|
+
}
|
|
409
|
+
if (pejayUiImportPath.endsWith("/")) {
|
|
410
|
+
pejayUiImportPath = pejayUiImportPath.slice(0, -1);
|
|
411
|
+
}
|
|
412
|
+
componentCode = componentCode.replace(/@\/pejay-ui/g, pejayUiImportPath);
|
|
394
413
|
|
|
395
414
|
if (!isTsProject) {
|
|
396
415
|
const transformed = babel.transformSync(componentCode, {
|
|
@@ -421,6 +440,17 @@ program
|
|
|
421
440
|
? `${relativeToUtils}/cn`
|
|
422
441
|
: `${relativeToUtils}/cn.js`;
|
|
423
442
|
componentCode = componentCode.replace(/@\/utils\/cn/g, cnImportPath);
|
|
443
|
+
componentCode = componentCode.replace(/@\/utils/g, cnImportPath);
|
|
444
|
+
|
|
445
|
+
const relativeToBaseDir = path.relative(fileDir, path.join(cwd, config.baseDir)).replace(/\\/g, "/");
|
|
446
|
+
let pejayUiImportPath = relativeToBaseDir;
|
|
447
|
+
if (!pejayUiImportPath.startsWith(".")) {
|
|
448
|
+
pejayUiImportPath = `./${pejayUiImportPath}`;
|
|
449
|
+
}
|
|
450
|
+
if (pejayUiImportPath.endsWith("/")) {
|
|
451
|
+
pejayUiImportPath = pejayUiImportPath.slice(0, -1);
|
|
452
|
+
}
|
|
453
|
+
componentCode = componentCode.replace(/@\/pejay-ui/g, pejayUiImportPath);
|
|
424
454
|
|
|
425
455
|
if (!isTsProject) {
|
|
426
456
|
const transformed = babel.transformSync(componentCode, {
|
|
@@ -440,7 +470,7 @@ program
|
|
|
440
470
|
}
|
|
441
471
|
|
|
442
472
|
// 3.5 Automatically generate/update category-level and global index.ts/index.js files
|
|
443
|
-
if (componentData.category && !["scaffold", "scaffolds", "script", "scripts"].includes(componentData.category.toLowerCase())) {
|
|
473
|
+
if (componentData.category && !componentData.skipIndex && !["scaffold", "scaffolds", "script", "scripts"].includes(componentData.category.toLowerCase())) {
|
|
444
474
|
const indexExt = isTsProject ? "ts" : "js";
|
|
445
475
|
const filesInDir = await fs.readdir(targetDir);
|
|
446
476
|
const exportableFiles = [];
|
|
@@ -548,9 +578,9 @@ program
|
|
|
548
578
|
}
|
|
549
579
|
|
|
550
580
|
// 1.5 Update index files
|
|
551
|
-
if (componentData.category && !["scaffold", "scaffolds", "script", "scripts"].includes(componentData.category.toLowerCase())) {
|
|
581
|
+
if (componentData.category && !componentData.skipIndex && !["scaffold", "scaffolds", "script", "scripts"].includes(componentData.category.toLowerCase())) {
|
|
552
582
|
const isTsProject = await fs.pathExists(path.join(cwd, "tsconfig.json"));
|
|
553
|
-
const targetDir =
|
|
583
|
+
const targetDir = resolveTargetDir(cwd, config.baseDir, component, componentData);
|
|
554
584
|
const indexExt = isTsProject ? "ts" : "js";
|
|
555
585
|
|
|
556
586
|
if (await fs.pathExists(targetDir)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pejay-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A powerful React UI component CLI tool to initialize, add, and scaffold premium Tailwind CSS components, layouts, overlays, and client templates.",
|
|
6
6
|
"bin": {
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"clsx": "^2.1.1",
|
|
67
67
|
"dayjs": "^1.11.21",
|
|
68
68
|
"lucide-react": "^1.17.0",
|
|
69
|
+
"motion": "^12.42.0",
|
|
69
70
|
"react": "^19.2.6",
|
|
70
71
|
"react-dom": "^19.2.6",
|
|
71
72
|
"react-router-dom": "^7.16.0",
|
package/registry/buttons.json
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
"button": {
|
|
3
3
|
"name": "Button",
|
|
4
4
|
"category": "button",
|
|
5
|
-
"files": ["templates/button/Button.tsx", "templates/button/
|
|
5
|
+
"files": ["templates/button/Button.tsx", "templates/button/README.md"],
|
|
6
6
|
"utils": ["cn.ts"],
|
|
7
|
-
"peerDependencies": ["clsx", "tailwind-merge"]
|
|
7
|
+
"peerDependencies": ["clsx", "tailwind-merge"],
|
|
8
|
+
"dependencies": ["overlays/tooltip", "spinner"]
|
|
8
9
|
}
|
|
9
10
|
}
|
package/registry/dropdowns.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"dropdown/select-input": {
|
|
3
3
|
"name": "SelectInput",
|
|
4
4
|
"category": "select-dropdown",
|
|
5
|
-
"files": ["templates/select-dropdown/select-input.tsx"],
|
|
5
|
+
"files": ["templates/select-dropdown/select-input.tsx", "templates/select-dropdown/README.md"],
|
|
6
6
|
"utils": ["cn.ts"],
|
|
7
7
|
"peerDependencies": [
|
|
8
8
|
"clsx",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"lucide-react",
|
|
11
11
|
"@floating-ui/react"
|
|
12
12
|
],
|
|
13
|
+
"dependencies": ["overlays/tooltip"],
|
|
13
14
|
"supportsCategory": true
|
|
14
15
|
},
|
|
15
16
|
"dropdown/multiselect-input": {
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
"lucide-react",
|
|
24
25
|
"@floating-ui/react"
|
|
25
26
|
],
|
|
27
|
+
"dependencies": ["overlays/tooltip"],
|
|
26
28
|
"supportsCategory": true
|
|
27
29
|
}
|
|
28
30
|
}
|
package/registry/forms.json
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
"name": "Input",
|
|
4
4
|
"category": "form",
|
|
5
5
|
"files": [
|
|
6
|
-
"templates/form/input.tsx"
|
|
6
|
+
"templates/form/text-inputs/input.tsx",
|
|
7
|
+
"templates/form/text-inputs/readme.input.md"
|
|
7
8
|
],
|
|
8
9
|
"utils": [
|
|
9
10
|
"cn.ts"
|
|
@@ -19,7 +20,8 @@
|
|
|
19
20
|
"name": "AmountInput",
|
|
20
21
|
"category": "form",
|
|
21
22
|
"files": [
|
|
22
|
-
"templates/form/amount-input.tsx"
|
|
23
|
+
"templates/form/numeric/amount-input.tsx",
|
|
24
|
+
"templates/form/numeric/readme.amount-input.md"
|
|
23
25
|
],
|
|
24
26
|
"utils": [
|
|
25
27
|
"cn.ts"
|
|
@@ -29,13 +31,17 @@
|
|
|
29
31
|
"tailwind-merge",
|
|
30
32
|
"lucide-react"
|
|
31
33
|
],
|
|
32
|
-
"supportsCategory": true
|
|
34
|
+
"supportsCategory": true,
|
|
35
|
+
"dependencies": [
|
|
36
|
+
"form/input"
|
|
37
|
+
]
|
|
33
38
|
},
|
|
34
39
|
"form/checkbox": {
|
|
35
40
|
"name": "Checkbox",
|
|
36
41
|
"category": "form",
|
|
37
42
|
"files": [
|
|
38
|
-
"templates/form/checkbox.tsx"
|
|
43
|
+
"templates/form/choices/checkbox.tsx",
|
|
44
|
+
"templates/form/choices/readme.checkbox.md"
|
|
39
45
|
],
|
|
40
46
|
"utils": [
|
|
41
47
|
"cn.ts"
|
|
@@ -51,7 +57,8 @@
|
|
|
51
57
|
"name": "CheckboxGroup",
|
|
52
58
|
"category": "form",
|
|
53
59
|
"files": [
|
|
54
|
-
"templates/form/checkbox-group.tsx"
|
|
60
|
+
"templates/form/choices/checkbox-group.tsx",
|
|
61
|
+
"templates/form/choices/readme.checkbox-group.md"
|
|
55
62
|
],
|
|
56
63
|
"utils": [
|
|
57
64
|
"cn.ts"
|
|
@@ -69,7 +76,8 @@
|
|
|
69
76
|
"name": "DatePicker",
|
|
70
77
|
"category": "form",
|
|
71
78
|
"files": [
|
|
72
|
-
"templates/form/date-picker.tsx"
|
|
79
|
+
"templates/form/pickers/date-picker.tsx",
|
|
80
|
+
"templates/form/pickers/readme.date-picker.md"
|
|
73
81
|
],
|
|
74
82
|
"utils": [
|
|
75
83
|
"cn.ts"
|
|
@@ -89,7 +97,8 @@
|
|
|
89
97
|
"name": "DateRangePicker",
|
|
90
98
|
"category": "form",
|
|
91
99
|
"files": [
|
|
92
|
-
"templates/form/date-range-picker.tsx"
|
|
100
|
+
"templates/form/pickers/date-range-picker.tsx",
|
|
101
|
+
"templates/form/pickers/readme.date-range-picker.md"
|
|
93
102
|
],
|
|
94
103
|
"utils": [
|
|
95
104
|
"cn.ts"
|
|
@@ -109,7 +118,8 @@
|
|
|
109
118
|
"name": "EmailInput",
|
|
110
119
|
"category": "form",
|
|
111
120
|
"files": [
|
|
112
|
-
"templates/form/email-input.tsx"
|
|
121
|
+
"templates/form/text-inputs/email-input.tsx",
|
|
122
|
+
"templates/form/text-inputs/readme.email-input.md"
|
|
113
123
|
],
|
|
114
124
|
"utils": [
|
|
115
125
|
"cn.ts"
|
|
@@ -125,7 +135,8 @@
|
|
|
125
135
|
"name": "FileInput",
|
|
126
136
|
"category": "form",
|
|
127
137
|
"files": [
|
|
128
|
-
"templates/form/file-input.tsx"
|
|
138
|
+
"templates/form/file/file-input.tsx",
|
|
139
|
+
"templates/form/file/readme.file-input.md"
|
|
129
140
|
],
|
|
130
141
|
"utils": [
|
|
131
142
|
"cn.ts"
|
|
@@ -135,13 +146,17 @@
|
|
|
135
146
|
"tailwind-merge",
|
|
136
147
|
"lucide-react"
|
|
137
148
|
],
|
|
138
|
-
"supportsCategory": true
|
|
149
|
+
"supportsCategory": true,
|
|
150
|
+
"dependencies": [
|
|
151
|
+
"form/input"
|
|
152
|
+
]
|
|
139
153
|
},
|
|
140
154
|
"form/number-input": {
|
|
141
155
|
"name": "NumberInput",
|
|
142
156
|
"category": "form",
|
|
143
157
|
"files": [
|
|
144
|
-
"templates/form/number-input.tsx"
|
|
158
|
+
"templates/form/numeric/number-input.tsx",
|
|
159
|
+
"templates/form/numeric/readme.number-input.md"
|
|
145
160
|
],
|
|
146
161
|
"utils": [
|
|
147
162
|
"cn.ts"
|
|
@@ -151,13 +166,17 @@
|
|
|
151
166
|
"tailwind-merge",
|
|
152
167
|
"lucide-react"
|
|
153
168
|
],
|
|
154
|
-
"supportsCategory": true
|
|
169
|
+
"supportsCategory": true,
|
|
170
|
+
"dependencies": [
|
|
171
|
+
"form/input"
|
|
172
|
+
]
|
|
155
173
|
},
|
|
156
174
|
"form/password-input": {
|
|
157
175
|
"name": "PasswordInput",
|
|
158
176
|
"category": "form",
|
|
159
177
|
"files": [
|
|
160
|
-
"templates/form/password-input.tsx"
|
|
178
|
+
"templates/form/text-inputs/password-input.tsx",
|
|
179
|
+
"templates/form/text-inputs/readme.password-input.md"
|
|
161
180
|
],
|
|
162
181
|
"utils": [
|
|
163
182
|
"cn.ts"
|
|
@@ -173,7 +192,8 @@
|
|
|
173
192
|
"name": "PhoneInput",
|
|
174
193
|
"category": "form",
|
|
175
194
|
"files": [
|
|
176
|
-
"templates/form/phone-input.tsx"
|
|
195
|
+
"templates/form/text-inputs/phone-input.tsx",
|
|
196
|
+
"templates/form/text-inputs/readme.phone-input.md"
|
|
177
197
|
],
|
|
178
198
|
"utils": [
|
|
179
199
|
"cn.ts"
|
|
@@ -189,7 +209,8 @@
|
|
|
189
209
|
"name": "Radio",
|
|
190
210
|
"category": "form",
|
|
191
211
|
"files": [
|
|
192
|
-
"templates/form/radio.tsx"
|
|
212
|
+
"templates/form/choices/radio.tsx",
|
|
213
|
+
"templates/form/choices/readme.radio.md"
|
|
193
214
|
],
|
|
194
215
|
"utils": [
|
|
195
216
|
"cn.ts"
|
|
@@ -204,7 +225,8 @@
|
|
|
204
225
|
"name": "RadioGroup",
|
|
205
226
|
"category": "form",
|
|
206
227
|
"files": [
|
|
207
|
-
"templates/form/radio-group.tsx"
|
|
228
|
+
"templates/form/choices/radio-group.tsx",
|
|
229
|
+
"templates/form/choices/readme.radio-group.md"
|
|
208
230
|
],
|
|
209
231
|
"utils": [
|
|
210
232
|
"cn.ts"
|
|
@@ -222,7 +244,8 @@
|
|
|
222
244
|
"name": "RangeSlider",
|
|
223
245
|
"category": "form",
|
|
224
246
|
"files": [
|
|
225
|
-
"templates/form/range-slider.tsx"
|
|
247
|
+
"templates/form/numeric/range-slider.tsx",
|
|
248
|
+
"templates/form/numeric/readme.range-slider.md"
|
|
226
249
|
],
|
|
227
250
|
"utils": [
|
|
228
251
|
"cn.ts"
|
|
@@ -237,7 +260,8 @@
|
|
|
237
260
|
"name": "Switch",
|
|
238
261
|
"category": "form",
|
|
239
262
|
"files": [
|
|
240
|
-
"templates/form/switch.tsx"
|
|
263
|
+
"templates/form/choices/switch.tsx",
|
|
264
|
+
"templates/form/choices/readme.switch.md"
|
|
241
265
|
],
|
|
242
266
|
"utils": [
|
|
243
267
|
"cn.ts"
|
|
@@ -252,7 +276,8 @@
|
|
|
252
276
|
"name": "Textarea",
|
|
253
277
|
"category": "form",
|
|
254
278
|
"files": [
|
|
255
|
-
"templates/form/textarea.tsx"
|
|
279
|
+
"templates/form/text-inputs/textarea.tsx",
|
|
280
|
+
"templates/form/text-inputs/readme.textarea.md"
|
|
256
281
|
],
|
|
257
282
|
"utils": [
|
|
258
283
|
"cn.ts"
|
|
@@ -267,7 +292,8 @@
|
|
|
267
292
|
"name": "TimePicker",
|
|
268
293
|
"category": "form",
|
|
269
294
|
"files": [
|
|
270
|
-
"templates/form/time-picker.tsx"
|
|
295
|
+
"templates/form/pickers/time-picker.tsx",
|
|
296
|
+
"templates/form/pickers/readme.time-picker.md"
|
|
271
297
|
],
|
|
272
298
|
"utils": [
|
|
273
299
|
"cn.ts"
|
|
@@ -287,7 +313,8 @@
|
|
|
287
313
|
"name": "TimeRangePicker",
|
|
288
314
|
"category": "form",
|
|
289
315
|
"files": [
|
|
290
|
-
"templates/form/time-range-picker.tsx"
|
|
316
|
+
"templates/form/pickers/time-range-picker.tsx",
|
|
317
|
+
"templates/form/pickers/readme.time-range-picker.md"
|
|
291
318
|
],
|
|
292
319
|
"utils": [
|
|
293
320
|
"cn.ts"
|
|
@@ -307,7 +334,8 @@
|
|
|
307
334
|
"name": "UrlInput",
|
|
308
335
|
"category": "form",
|
|
309
336
|
"files": [
|
|
310
|
-
"templates/form/url-input.tsx"
|
|
337
|
+
"templates/form/text-inputs/url-input.tsx",
|
|
338
|
+
"templates/form/text-inputs/readme.url-input.md"
|
|
311
339
|
],
|
|
312
340
|
"utils": [
|
|
313
341
|
"cn.ts"
|
|
@@ -319,4 +347,4 @@
|
|
|
319
347
|
],
|
|
320
348
|
"supportsCategory": true
|
|
321
349
|
}
|
|
322
|
-
}
|
|
350
|
+
}
|
package/registry/overlays.json
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
"overlays/portal": {
|
|
3
3
|
"name": "Portal",
|
|
4
4
|
"category": "overlays",
|
|
5
|
-
"files": [
|
|
5
|
+
"files": [
|
|
6
|
+
"templates/overlays/portal/portal.tsx"
|
|
7
|
+
],
|
|
6
8
|
"supportsCategory": true
|
|
9
|
+
},
|
|
10
|
+
"overlays/tooltip": {
|
|
11
|
+
"name": "Tooltip",
|
|
12
|
+
"category": "overlays",
|
|
13
|
+
"files": [
|
|
14
|
+
"templates/overlays/tooltip/tooltip.tsx",
|
|
15
|
+
"templates/overlays/tooltip/readme.tooltip.md"
|
|
16
|
+
],
|
|
17
|
+
"supportsCategory": true,
|
|
18
|
+
"peerDependencies": [
|
|
19
|
+
"clsx",
|
|
20
|
+
"tailwind-merge",
|
|
21
|
+
"@floating-ui/react"
|
|
22
|
+
]
|
|
7
23
|
}
|
|
8
|
-
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"panels": {
|
|
3
|
+
"name": "Panels",
|
|
4
|
+
"category": "panels",
|
|
5
|
+
"outputDirectory": "panels",
|
|
6
|
+
"skipIndex": true,
|
|
7
|
+
"files": ["templates/panels"],
|
|
8
|
+
"utils": ["cn.ts"],
|
|
9
|
+
"dependencies": [
|
|
10
|
+
"overlays/portal",
|
|
11
|
+
"toast",
|
|
12
|
+
"hotkeys"
|
|
13
|
+
],
|
|
14
|
+
"peerDependencies": [
|
|
15
|
+
"clsx",
|
|
16
|
+
"tailwind-merge",
|
|
17
|
+
"lucide-react",
|
|
18
|
+
"motion"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skeleton": {
|
|
3
|
+
"name": "Skeleton",
|
|
4
|
+
"category": "skeleton",
|
|
5
|
+
"files": [
|
|
6
|
+
"templates/skeleton/skeleton.tsx",
|
|
7
|
+
"templates/skeleton/types.ts",
|
|
8
|
+
"templates/skeleton/skeleton.css",
|
|
9
|
+
"templates/skeleton/README.md"
|
|
10
|
+
],
|
|
11
|
+
"utils": [
|
|
12
|
+
"cn.ts"
|
|
13
|
+
],
|
|
14
|
+
"peerDependencies": [
|
|
15
|
+
"clsx",
|
|
16
|
+
"tailwind-merge"
|
|
17
|
+
],
|
|
18
|
+
"supportsCategory": true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { cn } from "@/utils/cn";
|
|
2
|
+
import { cn } from "@/pejay-ui/utils/cn";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { Spinner } from "@/pejay-ui/spinner";
|
|
5
|
+
import { Tooltip } from "@/pejay-ui/components/overlays";
|
|
5
6
|
|
|
6
7
|
/* ─────────────────────────────────────────────
|
|
7
8
|
Types
|
|
@@ -28,7 +29,8 @@ export type ButtonVariant =
|
|
|
28
29
|
| "success-ghost"
|
|
29
30
|
| "warning-ghost"
|
|
30
31
|
| "black-ghost"
|
|
31
|
-
| "white-ghost"
|
|
32
|
+
| "white-ghost"
|
|
33
|
+
| "soft";
|
|
32
34
|
export type RoundedStyle = "full" | "lg" | "md" | "sm" | "none";
|
|
33
35
|
|
|
34
36
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
@@ -67,6 +69,7 @@ const variantMap: Record<ButtonVariant, string> = {
|
|
|
67
69
|
warning: "bg-amber-500 hover:bg-amber-600 active:bg-amber-700 text-white",
|
|
68
70
|
black: "bg-black hover:bg-black/80 active:bg-black/70 text-white",
|
|
69
71
|
white: "bg-white hover:bg-white/80 active:bg-white/70 text-black",
|
|
72
|
+
soft: "bg-sky-500/10 hover:bg-sky-500/20 active:bg-sky-500/30 text-sky-500",
|
|
70
73
|
|
|
71
74
|
/* ── Soft (coloured text, always-visible tint) ───────── */
|
|
72
75
|
"primary-soft": "text-sky-500 bg-current/10 hover:bg-current/15 active:bg-current/20",
|
|
@@ -119,10 +122,8 @@ export const Button = ({
|
|
|
119
122
|
? stripInteractive(variantMap[variant])
|
|
120
123
|
: variantMap[variant];
|
|
121
124
|
|
|
122
|
-
/* Render content: loader node /
|
|
123
|
-
const content = isLoading
|
|
124
|
-
? (loader ?? <span className="text-sm font-medium">Loading…</span>)
|
|
125
|
-
: children;
|
|
125
|
+
/* Render content: loader node / spinner / normal children */
|
|
126
|
+
const content = isLoading ? (loader ?? <Spinner size="sm" />) : children;
|
|
126
127
|
|
|
127
128
|
return (
|
|
128
129
|
<Tooltip content={tooltipContent}>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Button & Tooltip Components
|
|
2
|
+
|
|
3
|
+
A highly flexible button component with built-in loading states, visual style presets (variants), size options, prefix/suffix icon slots, and hover tooltip support.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Button Usage & API
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Button } from "@/pejay-ui/components/button";
|
|
11
|
+
|
|
12
|
+
// Basic Button
|
|
13
|
+
<Button onClick={handleClick}>Click Me</Button>
|
|
14
|
+
|
|
15
|
+
// Custom Styling & Icons
|
|
16
|
+
<Button variant="danger" size="lg" icon={TrashIcon} loading={isDeleting}>
|
|
17
|
+
Delete Record
|
|
18
|
+
</Button>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Component Props
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Default | Description |
|
|
24
|
+
| :--- | :--- | :--- | :--- |
|
|
25
|
+
| `children` | `ReactNode` | — | Text or elements inside the button. |
|
|
26
|
+
| `variant` | `ButtonVariant` | `"primary"` | Visual preset theme style. (See options below) |
|
|
27
|
+
| `rounded` | `"none" \| "sm" \| "md" \| "lg" \| "full"` | `"lg"` | Controls the button border radius. |
|
|
28
|
+
| `disableHoverEffect` | `boolean` | `false` | Removes hover/active style transforms (keeps it static). |
|
|
29
|
+
| `isLoading` | `boolean` | `false` | Displays a loading spinner and disables clicks. |
|
|
30
|
+
| `loader` | `ReactNode` | — | Custom loading component override. |
|
|
31
|
+
| `fullWidth` | `boolean` | `false` | Sets button width to `w-full` (100% parent container width). |
|
|
32
|
+
| `tooltipContent` | `ReactNode \| string` | — | Display a hover tooltip panel with this content. |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. Visual Variants & Color Palette Reference
|
|
37
|
+
|
|
38
|
+
We categorize button variants into 3 distinct styling structures. Colors are predefined and tailored for dark/light contrast:
|
|
39
|
+
|
|
40
|
+
### A. Solid Variants (Filled background, white/black text)
|
|
41
|
+
* **`primary`** : Sky Blue (`bg-sky-500` $\rightarrow$ hover `bg-sky-600` $\rightarrow$ active `bg-sky-700`)
|
|
42
|
+
* **`danger`** : Red (`bg-red-600` $\rightarrow$ hover `bg-red-700` $\rightarrow$ active `bg-red-800`)
|
|
43
|
+
* **`success`** : Emerald (`bg-emerald-600` $\rightarrow$ hover `bg-emerald-700` $\rightarrow$ active `bg-emerald-800`)
|
|
44
|
+
* **`warning`** : Amber (`bg-amber-500` $\rightarrow$ hover `bg-amber-600` $\rightarrow$ active `bg-amber-700`)
|
|
45
|
+
* **`black`** : Black (`bg-black` $\rightarrow$ hover `bg-black/80` $\rightarrow$ active `bg-black/70`)
|
|
46
|
+
* **`white`** : White (`bg-white`, text black $\rightarrow$ hover `bg-white/80` $\rightarrow$ active `bg-white/70`)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### B. Soft Variants (Always-visible colored tint background + matching text color)
|
|
51
|
+
*Soft variants use `bg-current` opacity mappings, meaning the background tint color automatically inherits and matches the text color:*
|
|
52
|
+
* **`primary-soft`** / **`soft`** : Sky Blue text + 10% opacity Sky Blue background.
|
|
53
|
+
* **`danger-soft`** : Red text + 10% opacity Red background.
|
|
54
|
+
* **`success-soft`** : Emerald text + 10% opacity Emerald background.
|
|
55
|
+
* **`warning-soft`** : Amber text + 10% opacity Amber background.
|
|
56
|
+
* **`black-soft`** : Black text + 10% opacity Black background.
|
|
57
|
+
* **`white-soft`** : White text + 10% opacity White background.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### C. Ghost Variants (Transparent background $\rightarrow$ fades in soft tint on hover)
|
|
62
|
+
* **`primary-ghost`** : Sky Blue text.
|
|
63
|
+
* **`danger-ghost`** : Red text.
|
|
64
|
+
* **`success-ghost`** : Emerald text.
|
|
65
|
+
* **`warning-ghost`** : Amber text.
|
|
66
|
+
* **`black-ghost`** : Black text.
|
|
67
|
+
* **`white-ghost`** : White text.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 3. Tooltip Component
|
|
72
|
+
|
|
73
|
+
A standalone utility to show extra info bubbles on hover for any parent component.
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import { Tooltip } from "@/pejay-ui/components/overlays/tooltip";
|
|
77
|
+
|
|
78
|
+
<Tooltip content="Upload CSV file" placement="bottom">
|
|
79
|
+
<div className="p-2 border rounded">Hover Over Me</div>
|
|
80
|
+
</Tooltip>
|
|
81
|
+
```
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export * from "./Button";
|
|
2
|
-
export * from "./tooltip";
|
|
1
|
+
export * from "./Button";
|