@modern-admin/web 0.3.5 → 0.4.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/README.md +42 -0
- package/dist/config/runtime-config.d.ts +84 -0
- package/dist/config/runtime-config.js +19 -0
- package/dist/config/vite.d.ts +84 -0
- package/dist/config/vite.js +166 -0
- package/dist/lib/index.js +0 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/mount.d.ts.map +1 -1
- package/dist/standalone/assets/{action-component-host-CXIbN-8V.js → action-component-host-BrEZDHZt.js} +2 -2
- package/dist/standalone/assets/action-component-host-BrEZDHZt.js.br +0 -0
- package/dist/standalone/assets/action-component-host-BrEZDHZt.js.gz +0 -0
- package/dist/standalone/assets/{action-component-host-CXIbN-8V.js.map → action-component-host-BrEZDHZt.js.map} +1 -1
- package/dist/standalone/assets/{action-page-OsWfKQ6C.js → action-page-Bx7kzeK7.js} +2 -2
- package/dist/standalone/assets/action-page-Bx7kzeK7.js.br +0 -0
- package/dist/standalone/assets/action-page-Bx7kzeK7.js.gz +0 -0
- package/dist/standalone/assets/{action-page-OsWfKQ6C.js.map → action-page-Bx7kzeK7.js.map} +1 -1
- package/dist/standalone/assets/{ai-assistant-widget-Bt4Z7Fmr.js → ai-assistant-widget-BbIXVrSu.js} +2 -2
- package/dist/standalone/assets/ai-assistant-widget-BbIXVrSu.js.br +0 -0
- package/dist/standalone/assets/ai-assistant-widget-BbIXVrSu.js.gz +0 -0
- package/dist/standalone/assets/{ai-assistant-widget-Bt4Z7Fmr.js.map → ai-assistant-widget-BbIXVrSu.js.map} +1 -1
- package/dist/standalone/assets/{audit-log-page-2wuGiWg-.js → audit-log-page-BoZh23oQ.js} +2 -2
- package/dist/standalone/assets/audit-log-page-BoZh23oQ.js.br +0 -0
- package/dist/standalone/assets/audit-log-page-BoZh23oQ.js.gz +0 -0
- package/dist/standalone/assets/{audit-log-page-2wuGiWg-.js.map → audit-log-page-BoZh23oQ.js.map} +1 -1
- package/dist/standalone/assets/{calendar-BZVUWakC.js → calendar-nvD_z7KQ.js} +2 -2
- package/dist/standalone/assets/calendar-nvD_z7KQ.js.br +0 -0
- package/dist/standalone/assets/calendar-nvD_z7KQ.js.gz +0 -0
- package/dist/standalone/assets/{calendar-BZVUWakC.js.map → calendar-nvD_z7KQ.js.map} +1 -1
- package/dist/standalone/assets/{chart-widget-BtJb6YXV.js → chart-widget-YeCL7jdB.js} +2 -2
- package/dist/standalone/assets/chart-widget-YeCL7jdB.js.br +0 -0
- package/dist/standalone/assets/chart-widget-YeCL7jdB.js.gz +0 -0
- package/dist/standalone/assets/{chart-widget-BtJb6YXV.js.map → chart-widget-YeCL7jdB.js.map} +1 -1
- package/dist/standalone/assets/{command-BNF_evMy.js → command-Sb0xL-se.js} +2 -2
- package/dist/standalone/assets/command-Sb0xL-se.js.br +0 -0
- package/dist/standalone/assets/command-Sb0xL-se.js.gz +0 -0
- package/dist/standalone/assets/{command-BNF_evMy.js.map → command-Sb0xL-se.js.map} +1 -1
- package/dist/standalone/assets/date-picker-C4HcgidQ.js +2 -0
- package/dist/standalone/assets/date-picker-C4HcgidQ.js.br +0 -0
- package/dist/standalone/assets/date-picker-C4HcgidQ.js.gz +0 -0
- package/dist/standalone/assets/date-picker-C4HcgidQ.js.map +1 -0
- package/dist/standalone/assets/{edit-page-DCRB9Y_q.js → edit-page-CW7-FAPC.js} +2 -2
- package/dist/standalone/assets/edit-page-CW7-FAPC.js.br +0 -0
- package/dist/standalone/assets/edit-page-CW7-FAPC.js.gz +0 -0
- package/dist/standalone/assets/{edit-page-DCRB9Y_q.js.map → edit-page-CW7-FAPC.js.map} +1 -1
- package/dist/standalone/assets/{empty-DAEAjFd3.js → empty-Cposcczv.js} +2 -2
- package/dist/standalone/assets/empty-Cposcczv.js.br +0 -0
- package/dist/standalone/assets/empty-Cposcczv.js.gz +0 -0
- package/dist/standalone/assets/{empty-DAEAjFd3.js.map → empty-Cposcczv.js.map} +1 -1
- package/dist/standalone/assets/{global-search-dialog-HMLztOho.js → global-search-dialog-DLv_nIvM.js} +2 -2
- package/dist/standalone/assets/global-search-dialog-DLv_nIvM.js.br +0 -0
- package/dist/standalone/assets/global-search-dialog-DLv_nIvM.js.gz +0 -0
- package/dist/standalone/assets/{global-search-dialog-HMLztOho.js.map → global-search-dialog-DLv_nIvM.js.map} +1 -1
- package/dist/standalone/assets/{heavy-fields-ZuqfOFMv.js → heavy-fields-BiCEgD2L.js} +2 -2
- package/dist/standalone/assets/heavy-fields-BiCEgD2L.js.br +0 -0
- package/dist/standalone/assets/heavy-fields-BiCEgD2L.js.gz +0 -0
- package/dist/standalone/assets/{heavy-fields-ZuqfOFMv.js.map → heavy-fields-BiCEgD2L.js.map} +1 -1
- package/dist/standalone/assets/{home-page-HmheewiP.js → home-page-BSz1wGk0.js} +3 -3
- package/dist/standalone/assets/home-page-BSz1wGk0.js.br +0 -0
- package/dist/standalone/assets/home-page-BSz1wGk0.js.gz +0 -0
- package/dist/standalone/assets/{home-page-HmheewiP.js.map → home-page-BSz1wGk0.js.map} +1 -1
- package/dist/standalone/assets/{icon-registry-BV44--RL.js → icon-registry-BQU4fIc4.js} +2 -2
- package/dist/standalone/assets/icon-registry-BQU4fIc4.js.br +0 -0
- package/dist/standalone/assets/{icon-registry-BV44--RL.js.gz → icon-registry-BQU4fIc4.js.gz} +0 -0
- package/dist/standalone/assets/{icon-registry-BV44--RL.js.map → icon-registry-BQU4fIc4.js.map} +1 -1
- package/dist/standalone/assets/index-BL8keDxQ.js +15 -0
- package/dist/standalone/assets/index-BL8keDxQ.js.br +0 -0
- package/dist/standalone/assets/index-BL8keDxQ.js.gz +0 -0
- package/dist/standalone/assets/{index-t4woXGa-.js.map → index-BL8keDxQ.js.map} +1 -1
- package/dist/standalone/assets/{json-editor-sGw4fDoj.js → json-editor-CAIgxYb3.js} +2 -2
- package/dist/standalone/assets/json-editor-CAIgxYb3.js.br +0 -0
- package/dist/standalone/assets/json-editor-CAIgxYb3.js.gz +0 -0
- package/dist/standalone/assets/{json-editor-sGw4fDoj.js.map → json-editor-CAIgxYb3.js.map} +1 -1
- package/dist/standalone/assets/{property-renderer-DyCwdVkh.js → property-renderer-B8Md-EqW.js} +4 -4
- package/dist/standalone/assets/property-renderer-B8Md-EqW.js.br +0 -0
- package/dist/standalone/assets/property-renderer-B8Md-EqW.js.gz +0 -0
- package/dist/standalone/assets/property-renderer-B8Md-EqW.js.map +1 -0
- package/dist/standalone/assets/{reference-Dfd804y3.js → reference-WPaf6IdD.js} +2 -2
- package/dist/standalone/assets/reference-WPaf6IdD.js.br +0 -0
- package/dist/standalone/assets/reference-WPaf6IdD.js.gz +0 -0
- package/dist/standalone/assets/{reference-Dfd804y3.js.map → reference-WPaf6IdD.js.map} +1 -1
- package/dist/standalone/assets/{revisions-button-DXZAh2Lu.js → revisions-button-0WtL6bsZ.js} +2 -2
- package/dist/standalone/assets/revisions-button-0WtL6bsZ.js.br +0 -0
- package/dist/standalone/assets/revisions-button-0WtL6bsZ.js.gz +0 -0
- package/dist/standalone/assets/{revisions-button-DXZAh2Lu.js.map → revisions-button-0WtL6bsZ.js.map} +1 -1
- package/dist/standalone/assets/{select-BWf6walM.js → select-CR4acjX0.js} +2 -2
- package/dist/standalone/assets/select-CR4acjX0.js.br +0 -0
- package/dist/standalone/assets/select-CR4acjX0.js.gz +0 -0
- package/dist/standalone/assets/{select-BWf6walM.js.map → select-CR4acjX0.js.map} +1 -1
- package/dist/standalone/assets/{settings-page-Co7sWbbL.js → settings-page-DtguXLAP.js} +2 -2
- package/dist/standalone/assets/settings-page-DtguXLAP.js.br +0 -0
- package/dist/standalone/assets/settings-page-DtguXLAP.js.gz +0 -0
- package/dist/standalone/assets/{settings-page-Co7sWbbL.js.map → settings-page-DtguXLAP.js.map} +1 -1
- package/dist/standalone/assets/{show-page-D-_vldWV.js → show-page-Dnox2NwO.js} +2 -2
- package/dist/standalone/assets/show-page-Dnox2NwO.js.br +0 -0
- package/dist/standalone/assets/show-page-Dnox2NwO.js.gz +0 -0
- package/dist/standalone/assets/{show-page-D-_vldWV.js.map → show-page-Dnox2NwO.js.map} +1 -1
- package/dist/standalone/assets/{tabs-khcHka8W.js → tabs-DUS8e6dR.js} +2 -2
- package/dist/standalone/assets/tabs-DUS8e6dR.js.br +0 -0
- package/dist/standalone/assets/tabs-DUS8e6dR.js.gz +0 -0
- package/dist/standalone/assets/{tabs-khcHka8W.js.map → tabs-DUS8e6dR.js.map} +1 -1
- package/dist/standalone/assets/{value-format-CPnbnlE6.js → value-format-Cgau0meh.js} +2 -2
- package/dist/standalone/assets/value-format-Cgau0meh.js.br +0 -0
- package/dist/standalone/assets/{value-format-CPnbnlE6.js.gz → value-format-Cgau0meh.js.gz} +0 -0
- package/dist/standalone/assets/{value-format-CPnbnlE6.js.map → value-format-Cgau0meh.js.map} +1 -1
- package/dist/standalone/assets/{wizard-create-page-CFwMs8E3.js → wizard-create-page-v2-Aw8Oj.js} +2 -2
- package/dist/standalone/assets/wizard-create-page-v2-Aw8Oj.js.br +0 -0
- package/dist/standalone/assets/wizard-create-page-v2-Aw8Oj.js.gz +0 -0
- package/dist/standalone/assets/{wizard-create-page-CFwMs8E3.js.map → wizard-create-page-v2-Aw8Oj.js.map} +1 -1
- package/dist/standalone/assets/{zod-BbfEBA4A.js → zod-BrelKLfy.js} +2 -2
- package/dist/standalone/assets/zod-BrelKLfy.js.br +0 -0
- package/dist/standalone/assets/zod-BrelKLfy.js.gz +0 -0
- package/dist/standalone/assets/{zod-BbfEBA4A.js.map → zod-BrelKLfy.js.map} +1 -1
- package/dist/standalone/index.html +4 -4
- package/dist/standalone/index.html.br +0 -0
- package/dist/standalone/index.html.gz +0 -0
- package/package.json +28 -6
- package/src/mount.tsx +8 -2
- package/src/standalone.tsx +1 -0
- package/src/vite.ts +219 -0
- package/vite.config.ts +13 -104
- package/dist/standalone/assets/action-component-host-CXIbN-8V.js.br +0 -0
- package/dist/standalone/assets/action-component-host-CXIbN-8V.js.gz +0 -0
- package/dist/standalone/assets/action-page-OsWfKQ6C.js.br +0 -0
- package/dist/standalone/assets/action-page-OsWfKQ6C.js.gz +0 -0
- package/dist/standalone/assets/ai-assistant-widget-Bt4Z7Fmr.js.br +0 -0
- package/dist/standalone/assets/ai-assistant-widget-Bt4Z7Fmr.js.gz +0 -0
- package/dist/standalone/assets/audit-log-page-2wuGiWg-.js.br +0 -0
- package/dist/standalone/assets/audit-log-page-2wuGiWg-.js.gz +0 -0
- package/dist/standalone/assets/calendar-BZVUWakC.js.br +0 -0
- package/dist/standalone/assets/calendar-BZVUWakC.js.gz +0 -0
- package/dist/standalone/assets/chart-widget-BtJb6YXV.js.br +0 -0
- package/dist/standalone/assets/chart-widget-BtJb6YXV.js.gz +0 -0
- package/dist/standalone/assets/command-BNF_evMy.js.br +0 -0
- package/dist/standalone/assets/command-BNF_evMy.js.gz +0 -0
- package/dist/standalone/assets/date-picker-LfbUehd1.js +0 -2
- package/dist/standalone/assets/date-picker-LfbUehd1.js.br +0 -0
- package/dist/standalone/assets/date-picker-LfbUehd1.js.gz +0 -0
- package/dist/standalone/assets/date-picker-LfbUehd1.js.map +0 -1
- package/dist/standalone/assets/edit-page-DCRB9Y_q.js.br +0 -0
- package/dist/standalone/assets/edit-page-DCRB9Y_q.js.gz +0 -0
- package/dist/standalone/assets/empty-DAEAjFd3.js.br +0 -0
- package/dist/standalone/assets/empty-DAEAjFd3.js.gz +0 -0
- package/dist/standalone/assets/global-search-dialog-HMLztOho.js.br +0 -0
- package/dist/standalone/assets/global-search-dialog-HMLztOho.js.gz +0 -0
- package/dist/standalone/assets/heavy-fields-ZuqfOFMv.js.br +0 -0
- package/dist/standalone/assets/heavy-fields-ZuqfOFMv.js.gz +0 -0
- package/dist/standalone/assets/home-page-HmheewiP.js.br +0 -0
- package/dist/standalone/assets/home-page-HmheewiP.js.gz +0 -0
- package/dist/standalone/assets/icon-registry-BV44--RL.js.br +0 -0
- package/dist/standalone/assets/index-t4woXGa-.js +0 -15
- package/dist/standalone/assets/index-t4woXGa-.js.br +0 -0
- package/dist/standalone/assets/index-t4woXGa-.js.gz +0 -0
- package/dist/standalone/assets/json-editor-sGw4fDoj.js.br +0 -0
- package/dist/standalone/assets/json-editor-sGw4fDoj.js.gz +0 -0
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js.br +0 -0
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js.gz +0 -0
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js.map +0 -1
- package/dist/standalone/assets/reference-Dfd804y3.js.br +0 -0
- package/dist/standalone/assets/reference-Dfd804y3.js.gz +0 -0
- package/dist/standalone/assets/revisions-button-DXZAh2Lu.js.br +0 -0
- package/dist/standalone/assets/revisions-button-DXZAh2Lu.js.gz +0 -0
- package/dist/standalone/assets/select-BWf6walM.js.br +0 -0
- package/dist/standalone/assets/select-BWf6walM.js.gz +0 -0
- package/dist/standalone/assets/settings-page-Co7sWbbL.js.br +0 -0
- package/dist/standalone/assets/settings-page-Co7sWbbL.js.gz +0 -0
- package/dist/standalone/assets/show-page-D-_vldWV.js.br +0 -0
- package/dist/standalone/assets/show-page-D-_vldWV.js.gz +0 -0
- package/dist/standalone/assets/tabs-khcHka8W.js.br +0 -0
- package/dist/standalone/assets/tabs-khcHka8W.js.gz +0 -0
- package/dist/standalone/assets/value-format-CPnbnlE6.js.br +0 -0
- package/dist/standalone/assets/wizard-create-page-CFwMs8E3.js.br +0 -0
- package/dist/standalone/assets/wizard-create-page-CFwMs8E3.js.gz +0 -0
- package/dist/standalone/assets/zod-BbfEBA4A.js.br +0 -0
- package/dist/standalone/assets/zod-BbfEBA4A.js.gz +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
smoke tests), the standalone entry falls back to same-origin defaults.
|
|
13
13
|
-->
|
|
14
14
|
<!--MODERN_ADMIN_CONFIG-->
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-BL8keDxQ.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/createLucideIcon-CUopU_LC.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/with-selector-NDLhu4dT.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/dist-BSbFjTlr.js">
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
<link rel="modulepreload" crossorigin href="./assets/router-wFvtgo77.js">
|
|
22
22
|
<link rel="modulepreload" crossorigin href="./assets/dist-BcL2U6dT.js">
|
|
23
23
|
<link rel="stylesheet" crossorigin href="./assets/index-95cwJ2RY.css">
|
|
24
|
-
<link rel="prefetch" as="script" href="./assets/home-page-
|
|
25
|
-
<link rel="prefetch" as="script" href="./assets/icon-registry-
|
|
26
|
-
<link rel="prefetch" as="script" href="./assets/property-renderer-
|
|
24
|
+
<link rel="prefetch" as="script" href="./assets/home-page-BSz1wGk0.js">
|
|
25
|
+
<link rel="prefetch" as="script" href="./assets/icon-registry-BQU4fIc4.js">
|
|
26
|
+
<link rel="prefetch" as="script" href="./assets/property-renderer-B8Md-EqW.js">
|
|
27
27
|
</head>
|
|
28
28
|
<body>
|
|
29
29
|
<div id="root"></div>
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modern-admin/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Pre-built React admin SPA. Mount it into a host page or let @modern-admin/nest serve the standalone bundle.",
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
"types": "./dist/lib/index.d.ts",
|
|
36
36
|
"default": "./dist/lib/index.js"
|
|
37
37
|
},
|
|
38
|
+
"./vite": {
|
|
39
|
+
"types": "./dist/config/vite.d.ts",
|
|
40
|
+
"default": "./dist/config/vite.js"
|
|
41
|
+
},
|
|
38
42
|
"./standalone/*": "./dist/standalone/*",
|
|
39
43
|
"./package.json": "./package.json"
|
|
40
44
|
},
|
|
@@ -48,23 +52,30 @@
|
|
|
48
52
|
"types": "./dist/lib/index.d.ts",
|
|
49
53
|
"default": "./dist/lib/index.js"
|
|
50
54
|
},
|
|
55
|
+
"./vite": {
|
|
56
|
+
"types": "./dist/config/vite.d.ts",
|
|
57
|
+
"default": "./dist/config/vite.js"
|
|
58
|
+
},
|
|
51
59
|
"./standalone/*": "./dist/standalone/*",
|
|
52
60
|
"./package.json": "./package.json"
|
|
53
61
|
}
|
|
54
62
|
},
|
|
55
63
|
"peerDependencies": {
|
|
56
64
|
"react": "^19.2.6",
|
|
57
|
-
"react-dom": "^19.2.6"
|
|
65
|
+
"react-dom": "^19.2.6",
|
|
66
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
67
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
68
|
+
"vite": "^8.0.10"
|
|
58
69
|
},
|
|
59
70
|
"dependencies": {
|
|
60
|
-
"@modern-admin/core": "^0.
|
|
71
|
+
"@modern-admin/core": "^0.4.1",
|
|
61
72
|
"@modern-admin/i18n": "^0.3.4",
|
|
62
|
-
"@modern-admin/react": "^0.
|
|
63
|
-
"@modern-admin/ui": "^0.
|
|
73
|
+
"@modern-admin/react": "^0.4.1",
|
|
74
|
+
"@modern-admin/ui": "^0.4.1",
|
|
64
75
|
"@tanstack/react-query": "^5.100.9"
|
|
65
76
|
},
|
|
66
77
|
"devDependencies": {
|
|
67
|
-
"@modern-admin/tsconfig": "0.
|
|
78
|
+
"@modern-admin/tsconfig": "0.4.0",
|
|
68
79
|
"@tailwindcss/vite": "^4.2.4",
|
|
69
80
|
"@types/react": "^19.2.14",
|
|
70
81
|
"@types/react-dom": "^19.2.3",
|
|
@@ -75,5 +86,16 @@
|
|
|
75
86
|
"typescript": "^6.0.3",
|
|
76
87
|
"vite": "^8.0.10",
|
|
77
88
|
"vite-plugin-dts": "^5.0.1"
|
|
89
|
+
},
|
|
90
|
+
"peerDependenciesMeta": {
|
|
91
|
+
"@tailwindcss/vite": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"@vitejs/plugin-react": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"vite": {
|
|
98
|
+
"optional": true
|
|
99
|
+
}
|
|
78
100
|
}
|
|
79
101
|
}
|
package/src/mount.tsx
CHANGED
|
@@ -5,15 +5,21 @@
|
|
|
5
5
|
* import { mount } from '@modern-admin/web'
|
|
6
6
|
* mount(document.getElementById('root')!, { apiUrl: 'https://api.example.com' })
|
|
7
7
|
*
|
|
8
|
+
* This module deliberately does **not** import the stylesheet: an app that
|
|
9
|
+
* registers its own components needs to own the Tailwind root so its classes
|
|
10
|
+
* get scanned, and a second root here would compile Tailwind twice. Import it
|
|
11
|
+
* yourself, either directly or from your own CSS:
|
|
12
|
+
*
|
|
13
|
+
* import '@modern-admin/react/styles.css'
|
|
14
|
+
*
|
|
8
15
|
* For the prebuilt standalone bundle, `src/standalone.tsx` calls this for
|
|
9
|
-
* you using `window.__MODERN_ADMIN__
|
|
16
|
+
* you using `window.__MODERN_ADMIN__` and pulls in the stylesheet.
|
|
10
17
|
*/
|
|
11
18
|
|
|
12
19
|
import { StrictMode } from 'react'
|
|
13
20
|
import { createRoot, type Root } from 'react-dom/client'
|
|
14
21
|
import { type ComponentLoader } from '@modern-admin/react'
|
|
15
22
|
import { initTheme } from '@modern-admin/ui'
|
|
16
|
-
import '@modern-admin/ui/styles.css'
|
|
17
23
|
import { App } from './app.js'
|
|
18
24
|
import type { ModernAdminRuntimeConfig } from './runtime-config.js'
|
|
19
25
|
|
package/src/standalone.tsx
CHANGED
package/src/vite.ts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite config kit for apps that build their own copy of the admin SPA.
|
|
3
|
+
*
|
|
4
|
+
* The prebuilt `@modern-admin/web` standalone bundle registers no custom
|
|
5
|
+
* components, so any app that uses `component: '…'` on an action or
|
|
6
|
+
* `components: { edit: '…' }` on a property has to build its own bundle. That
|
|
7
|
+
* bundle has to match what `@modern-admin/nest`'s StaticUiMiddleware expects
|
|
8
|
+
* — `dist/standalone/{index.html,assets/**}` with relative `./assets/` URLs —
|
|
9
|
+
* which used to mean copying this package's `vite.config.ts` wholesale.
|
|
10
|
+
*
|
|
11
|
+
* // vite.config.ts
|
|
12
|
+
* import { defineAdminAppConfig } from '@modern-admin/web/vite'
|
|
13
|
+
* export default defineAdminAppConfig({ apiProxy: 'http://localhost:3011' })
|
|
14
|
+
*
|
|
15
|
+
* // src/main.tsx
|
|
16
|
+
* import { mount, readWindowConfig } from '@modern-admin/web'
|
|
17
|
+
* import './styles.css'
|
|
18
|
+
* mount(document.getElementById('root')!, {
|
|
19
|
+
* config: readWindowConfig(),
|
|
20
|
+
* components: new ComponentLoader().add('SendPushForm', SendPushForm),
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* `packages/web/vite.config.ts` consumes this same factory, so the kit can't
|
|
24
|
+
* drift from the bundle we ship.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import path from 'node:path'
|
|
28
|
+
import { promises as fs } from 'node:fs'
|
|
29
|
+
import { promisify } from 'node:util'
|
|
30
|
+
import zlib from 'node:zlib'
|
|
31
|
+
import type { ConfigEnv, Plugin, PluginOption, UserConfig } from 'vite'
|
|
32
|
+
import react from '@vitejs/plugin-react'
|
|
33
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
34
|
+
import type { ModernAdminRuntimeConfig } from './runtime-config.js'
|
|
35
|
+
|
|
36
|
+
const brotli = promisify(zlib.brotliCompress)
|
|
37
|
+
const gzip = promisify(zlib.gzip)
|
|
38
|
+
|
|
39
|
+
/** Layout StaticUiMiddleware resolves as `<webPackage>/dist/standalone`. */
|
|
40
|
+
const STANDALONE_OUT_DIR = 'dist/standalone'
|
|
41
|
+
|
|
42
|
+
export interface AdminAppConfigOptions {
|
|
43
|
+
/** Dev server port. Defaults to `WEB_PORT`, then 3000. */
|
|
44
|
+
port?: number
|
|
45
|
+
/**
|
|
46
|
+
* Origin of the NestJS admin API, proxied during `vite dev` so the SPA and
|
|
47
|
+
* the API stay same-origin and session cookies work (e.g.
|
|
48
|
+
* `http://localhost:3011`). Omit if you serve both yourself.
|
|
49
|
+
*/
|
|
50
|
+
apiProxy?: string
|
|
51
|
+
/**
|
|
52
|
+
* Path prefixes forwarded to `apiProxy`. Defaults to the REST/auth prefix
|
|
53
|
+
* every `@modern-admin/nest` controller lives under plus the socket.io
|
|
54
|
+
* endpoint used by `@modern-admin/realtime`.
|
|
55
|
+
*/
|
|
56
|
+
apiProxyPath?: string | string[]
|
|
57
|
+
/**
|
|
58
|
+
* Runtime config for `vite dev` only. In production the host server
|
|
59
|
+
* injects `window.__MODERN_ADMIN__` into the shell, so there is nothing to
|
|
60
|
+
* configure at build time — this fills the same slot while developing.
|
|
61
|
+
*/
|
|
62
|
+
devConfig?: ModernAdminRuntimeConfig
|
|
63
|
+
/** Directory the standalone build writes to. Rarely worth changing. */
|
|
64
|
+
outDir?: string
|
|
65
|
+
/** Extra plugins, appended after the built-in ones. */
|
|
66
|
+
plugins?: PluginOption[]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Emits `.br` and `.gz` siblings next to every compressible standalone
|
|
71
|
+
* asset. StaticUiMiddleware serves whichever variant the browser's
|
|
72
|
+
* `Accept-Encoding` allows and falls back to the plain file, so this is an
|
|
73
|
+
* optimisation rather than a correctness requirement.
|
|
74
|
+
*/
|
|
75
|
+
export function precompressPlugin(outDir = STANDALONE_OUT_DIR): Plugin {
|
|
76
|
+
const COMPRESSIBLE = new Set(['.js', '.mjs', '.css', '.html', '.svg', '.json'])
|
|
77
|
+
const MIN_SIZE = 1024
|
|
78
|
+
return {
|
|
79
|
+
name: 'modern-admin:precompress',
|
|
80
|
+
apply: 'build',
|
|
81
|
+
async writeBundle(options) {
|
|
82
|
+
const dir = options.dir ?? path.resolve(process.cwd(), outDir)
|
|
83
|
+
const walk = async (d: string): Promise<string[]> => {
|
|
84
|
+
const entries = await fs.readdir(d, { withFileTypes: true })
|
|
85
|
+
const nested = await Promise.all(
|
|
86
|
+
entries.map((e) => (e.isDirectory() ? walk(path.join(d, e.name)) : [path.join(d, e.name)])),
|
|
87
|
+
)
|
|
88
|
+
return nested.flat()
|
|
89
|
+
}
|
|
90
|
+
const files = (await walk(dir)).filter((f) => COMPRESSIBLE.has(path.extname(f)))
|
|
91
|
+
await Promise.all(
|
|
92
|
+
files.map(async (file) => {
|
|
93
|
+
const source = await fs.readFile(file)
|
|
94
|
+
if (source.length < MIN_SIZE) return
|
|
95
|
+
const [br, gz] = await Promise.all([
|
|
96
|
+
brotli(source, { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 11 } }),
|
|
97
|
+
gzip(source, { level: zlib.constants.Z_BEST_COMPRESSION }),
|
|
98
|
+
])
|
|
99
|
+
await Promise.all([fs.writeFile(`${file}.br`, br), fs.writeFile(`${file}.gz`, gz)])
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Injects low-priority `<link rel="prefetch">` hints for the lazy chunks a
|
|
108
|
+
* fresh session is almost certain to need right after the shell renders:
|
|
109
|
+
* the dashboard landing page, the full icon registry (sidebar), and the
|
|
110
|
+
* resource list page + property renderer (first sidebar click). The browser
|
|
111
|
+
* fetches them during idle time instead of on first navigation, without
|
|
112
|
+
* competing with the critical-path entry chunk. Relative `./assets/` hrefs
|
|
113
|
+
* are rewritten to the mount path by StaticUiMiddleware like every other
|
|
114
|
+
* asset reference.
|
|
115
|
+
*/
|
|
116
|
+
export function prefetchHintsPlugin(): Plugin {
|
|
117
|
+
const PREFETCH_CHUNKS = new Set(['home-page', 'icon-registry', 'list-page', 'property-renderer'])
|
|
118
|
+
return {
|
|
119
|
+
name: 'modern-admin:prefetch-hints',
|
|
120
|
+
apply: 'build',
|
|
121
|
+
transformIndexHtml: {
|
|
122
|
+
order: 'post',
|
|
123
|
+
handler(_html, ctx) {
|
|
124
|
+
const chunks = Object.values(ctx.bundle ?? {}).filter(
|
|
125
|
+
(out) => out.type === 'chunk' && out.name && PREFETCH_CHUNKS.has(out.name),
|
|
126
|
+
)
|
|
127
|
+
return chunks.map((chunk) => ({
|
|
128
|
+
tag: 'link',
|
|
129
|
+
attrs: { rel: 'prefetch', as: 'script', href: `./${chunk.fileName}` },
|
|
130
|
+
injectTo: 'head' as const,
|
|
131
|
+
}))
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Injects `window.__MODERN_ADMIN__` while developing. In production the same
|
|
139
|
+
* slot is filled per-request by the host server (StaticUiMiddleware replaces
|
|
140
|
+
* the `<!--MODERN_ADMIN_CONFIG-->` marker, or falls back to `</head>`), so
|
|
141
|
+
* this plugin is dev-only and never affects the built bundle.
|
|
142
|
+
*/
|
|
143
|
+
export function devRuntimeConfigPlugin(config: ModernAdminRuntimeConfig): Plugin {
|
|
144
|
+
return {
|
|
145
|
+
name: 'modern-admin:dev-runtime-config',
|
|
146
|
+
apply: 'serve',
|
|
147
|
+
transformIndexHtml: {
|
|
148
|
+
order: 'pre',
|
|
149
|
+
handler() {
|
|
150
|
+
// `</script>` inside the JSON would close the tag early.
|
|
151
|
+
const json = JSON.stringify(config).replace(/</g, '\\u003c')
|
|
152
|
+
return [
|
|
153
|
+
{
|
|
154
|
+
tag: 'script',
|
|
155
|
+
children: `window.__MODERN_ADMIN__ = ${json};`,
|
|
156
|
+
injectTo: 'head-prepend' as const,
|
|
157
|
+
},
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* `ws: true` so the realtime gateway's socket.io upgrade survives the proxy;
|
|
166
|
+
* `changeOrigin` keeps the session cookie's Origin check happy.
|
|
167
|
+
*/
|
|
168
|
+
function buildProxy(
|
|
169
|
+
target: string,
|
|
170
|
+
paths: string | string[],
|
|
171
|
+
): Record<string, { target: string; changeOrigin: boolean; ws: boolean }> {
|
|
172
|
+
const list = Array.isArray(paths) ? paths : [paths]
|
|
173
|
+
return Object.fromEntries(list.map((p) => [p, { target, changeOrigin: true, ws: true }]))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Builds the Vite config for a custom admin SPA. Pass the result straight to
|
|
178
|
+
* `export default` — it resolves `vite dev` and `vite build` itself, so no
|
|
179
|
+
* `--mode` flag is required.
|
|
180
|
+
*/
|
|
181
|
+
export function defineAdminAppConfig(
|
|
182
|
+
options: AdminAppConfigOptions = {},
|
|
183
|
+
): (env: ConfigEnv) => UserConfig {
|
|
184
|
+
const {
|
|
185
|
+
apiProxy,
|
|
186
|
+
apiProxyPath = ['/admin/api', '/socket.io'],
|
|
187
|
+
devConfig,
|
|
188
|
+
outDir = STANDALONE_OUT_DIR,
|
|
189
|
+
plugins: extraPlugins = [],
|
|
190
|
+
} = options
|
|
191
|
+
return ({ command }) => {
|
|
192
|
+
const shared: PluginOption[] = [react(), tailwindcss()]
|
|
193
|
+
if (command === 'build') {
|
|
194
|
+
return {
|
|
195
|
+
plugins: [...shared, precompressPlugin(outDir), prefetchHintsPlugin(), ...extraPlugins],
|
|
196
|
+
// Relative base so one bundle can be mounted under any path — the
|
|
197
|
+
// host server rewrites `./assets/` to its own mount prefix.
|
|
198
|
+
base: './',
|
|
199
|
+
build: {
|
|
200
|
+
outDir,
|
|
201
|
+
emptyOutDir: true,
|
|
202
|
+
sourcemap: true,
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
plugins: [
|
|
208
|
+
...shared,
|
|
209
|
+
...(devConfig ? [devRuntimeConfigPlugin(devConfig)] : []),
|
|
210
|
+
...extraPlugins,
|
|
211
|
+
],
|
|
212
|
+
server: {
|
|
213
|
+
port: options.port ?? Number(process.env.WEB_PORT ?? 3000),
|
|
214
|
+
host: true,
|
|
215
|
+
...(apiProxy ? { proxy: buildProxy(apiProxy, apiProxyPath) } : {}),
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
package/vite.config.ts
CHANGED
|
@@ -7,61 +7,23 @@
|
|
|
7
7
|
* `mode` is set by Vite from the `--mode` CLI flag. Other modes (dev,
|
|
8
8
|
* preview) get the standalone SPA config — that's what you serve from
|
|
9
9
|
* `bun run dev`.
|
|
10
|
+
*
|
|
11
|
+
* The standalone/dev half is `defineAdminAppConfig()` from `src/vite.ts`,
|
|
12
|
+
* i.e. the very config we hand to apps that build their own bundle
|
|
13
|
+
* (`@modern-admin/web/vite`). Dogfooding it here is what stops the two from
|
|
14
|
+
* drifting apart.
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
|
-
import { defineConfig, type
|
|
17
|
+
import { defineConfig, type UserConfig } from 'vite'
|
|
13
18
|
import react from '@vitejs/plugin-react'
|
|
14
19
|
import tailwindcss from '@tailwindcss/vite'
|
|
15
20
|
import dts from 'vite-plugin-dts'
|
|
16
21
|
import { fileURLToPath } from 'node:url'
|
|
17
22
|
import path from 'node:path'
|
|
18
|
-
import {
|
|
19
|
-
import { promisify } from 'node:util'
|
|
20
|
-
import zlib from 'node:zlib'
|
|
23
|
+
import { defineAdminAppConfig } from './src/vite.js'
|
|
21
24
|
|
|
22
25
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
23
26
|
|
|
24
|
-
const brotli = promisify(zlib.brotliCompress)
|
|
25
|
-
const gzip = promisify(zlib.gzip)
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Emits `.br` and `.gz` siblings next to every compressible standalone
|
|
29
|
-
* asset. `@modern-admin/nest`'s StaticUiMiddleware picks whichever variant
|
|
30
|
-
* the browser's `Accept-Encoding` allows — no runtime compression cost.
|
|
31
|
-
* Sourcemaps are skipped (fetched only with devtools open) and so are
|
|
32
|
-
* files that compression wouldn't meaningfully shrink.
|
|
33
|
-
*/
|
|
34
|
-
function precompressPlugin(): Plugin {
|
|
35
|
-
const COMPRESSIBLE = new Set(['.js', '.mjs', '.css', '.html', '.svg', '.json'])
|
|
36
|
-
const MIN_SIZE = 1024
|
|
37
|
-
return {
|
|
38
|
-
name: 'modern-admin:precompress',
|
|
39
|
-
apply: 'build',
|
|
40
|
-
async writeBundle(options) {
|
|
41
|
-
const dir = options.dir ?? path.resolve(__dirname, 'dist/standalone')
|
|
42
|
-
const walk = async (d: string): Promise<string[]> => {
|
|
43
|
-
const entries = await fs.readdir(d, { withFileTypes: true })
|
|
44
|
-
const nested = await Promise.all(
|
|
45
|
-
entries.map((e) => (e.isDirectory() ? walk(path.join(d, e.name)) : [path.join(d, e.name)])),
|
|
46
|
-
)
|
|
47
|
-
return nested.flat()
|
|
48
|
-
}
|
|
49
|
-
const files = (await walk(dir)).filter((f) => COMPRESSIBLE.has(path.extname(f)))
|
|
50
|
-
await Promise.all(
|
|
51
|
-
files.map(async (file) => {
|
|
52
|
-
const source = await fs.readFile(file)
|
|
53
|
-
if (source.length < MIN_SIZE) return
|
|
54
|
-
const [br, gz] = await Promise.all([
|
|
55
|
-
brotli(source, { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 11 } }),
|
|
56
|
-
gzip(source, { level: zlib.constants.Z_BEST_COMPRESSION }),
|
|
57
|
-
])
|
|
58
|
-
await Promise.all([fs.writeFile(`${file}.br`, br), fs.writeFile(`${file}.gz`, gz)])
|
|
59
|
-
}),
|
|
60
|
-
)
|
|
61
|
-
},
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
27
|
// External deps for the library build — host apps provide their own copy
|
|
66
28
|
// (deduped by the workspace / package manager). The standalone SPA bundle
|
|
67
29
|
// inlines all of these so the served `<script>` is self-contained.
|
|
@@ -101,7 +63,7 @@ const libConfig: UserConfig = {
|
|
|
101
63
|
entryRoot: 'src',
|
|
102
64
|
outDirs: 'dist/lib',
|
|
103
65
|
include: ['src/**/*.ts', 'src/**/*.tsx'],
|
|
104
|
-
exclude: ['src/standalone.tsx'],
|
|
66
|
+
exclude: ['src/standalone.tsx', 'src/vite.ts'],
|
|
105
67
|
}),
|
|
106
68
|
],
|
|
107
69
|
// Don't copy public/ (favicon.svg etc.) into the library output — those
|
|
@@ -122,62 +84,9 @@ const libConfig: UserConfig = {
|
|
|
122
84
|
},
|
|
123
85
|
}
|
|
124
86
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* resource list page + property renderer (first sidebar click). The browser
|
|
130
|
-
* fetches them during idle time instead of on first navigation, without
|
|
131
|
-
* competing with the critical-path entry chunk. Relative `./assets/` hrefs
|
|
132
|
-
* are rewritten to the mount path by StaticUiMiddleware like every other
|
|
133
|
-
* asset reference.
|
|
134
|
-
*/
|
|
135
|
-
function prefetchHintsPlugin(): Plugin {
|
|
136
|
-
const PREFETCH_CHUNKS = new Set(['home-page', 'icon-registry', 'list-page', 'property-renderer'])
|
|
137
|
-
return {
|
|
138
|
-
name: 'modern-admin:prefetch-hints',
|
|
139
|
-
apply: 'build',
|
|
140
|
-
transformIndexHtml: {
|
|
141
|
-
order: 'post',
|
|
142
|
-
handler(_html, ctx) {
|
|
143
|
-
const chunks = Object.values(ctx.bundle ?? {}).filter(
|
|
144
|
-
(out) => out.type === 'chunk' && out.name && PREFETCH_CHUNKS.has(out.name),
|
|
145
|
-
)
|
|
146
|
-
return chunks.map((chunk) => ({
|
|
147
|
-
tag: 'link',
|
|
148
|
-
attrs: { rel: 'prefetch', as: 'script', href: `./${chunk.fileName}` },
|
|
149
|
-
injectTo: 'head' as const,
|
|
150
|
-
}))
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const standaloneConfig: UserConfig = {
|
|
157
|
-
plugins: [react(), tailwindcss(), precompressPlugin(), prefetchHintsPlugin()],
|
|
158
|
-
// Relative base so the same bundle can be mounted under any path
|
|
159
|
-
// (e.g. `/admin/`) — the server rewrites asset URLs in index.html.
|
|
160
|
-
base: './',
|
|
161
|
-
build: {
|
|
162
|
-
outDir: 'dist/standalone',
|
|
163
|
-
emptyOutDir: true,
|
|
164
|
-
sourcemap: true,
|
|
165
|
-
rollupOptions: {
|
|
166
|
-
input: path.resolve(__dirname, 'index.html'),
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const devConfig: UserConfig = {
|
|
172
|
-
plugins: [react(), tailwindcss()],
|
|
173
|
-
server: {
|
|
174
|
-
port: Number(process.env.WEB_PORT ?? 3000),
|
|
175
|
-
host: true,
|
|
176
|
-
},
|
|
177
|
-
}
|
|
87
|
+
// `vite build --mode standalone` arrives as command 'build'; `vite` and
|
|
88
|
+
// `vite preview` as 'serve'. Rollup's input defaults to `<root>/index.html`,
|
|
89
|
+
// which is exactly the shell this package ships.
|
|
90
|
+
const adminApp = defineAdminAppConfig()
|
|
178
91
|
|
|
179
|
-
export default defineConfig((
|
|
180
|
-
if (mode === 'lib') return libConfig
|
|
181
|
-
if (mode === 'standalone') return standaloneConfig
|
|
182
|
-
return devConfig
|
|
183
|
-
})
|
|
92
|
+
export default defineConfig((env) => (env.mode === 'lib' ? libConfig : adminApp(env)))
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e,n as t}from"./createLucideIcon-CUopU_LC.js";import{S as n,s as r}from"./with-selector-NDLhu4dT.js";import{n as i}from"./refresh-cw-DHvUQTMb.js";import{s as a}from"./dist-Dpg8xy_r.js";import{a as o,i as s,n as c,s as l,t as u}from"./calendar-BZVUWakC.js";import{a as d,i as f,n as p}from"./useQueries-BCUhWYX4.js";import{Y as m}from"./index-t4woXGa-.js";var h=e(t(),1),g=n(),_=`yyyy-MM-dd`,v=`yyyy-MM-dd'T'HH:mm`,y=`yyyy-MM-dd HH:mm`;function b(e){if(!e)return;let t=e.length<=10?s(e,_,new Date):c(e);return Number.isNaN(t.getTime())?void 0:t}function x(e,t){let n=e.trim();if(n===``)return;let r=t===`datetime`?[v,y,`yyyy-MM-dd'T'HH:mm:ss`,_]:[_];for(let e of r){let t=s(n,e,new Date);if(l(t))return t}let i=c(n);return l(i)?i:null}function S(e,t){return e?o(e,t===`datetime`?y:_):``}function C(e,t){return o(e,t===`datetime`?v:_)}function w({value:e,onChange:t,mode:n=`date`,disabled:s,placeholder:c,className:l,inputClassName:_,ariaLabel:v,openCalendarLabel:y=`Open calendar`,timeLabel:w=`Time`}){let[T,E]=h.useState(!1),D=b(e),[O,k]=h.useState(()=>S(D,n)),A=h.useRef(S(D,n));h.useEffect(()=>{let e=S(D,n);e!==A.current&&(A.current=e,k(e))},[e,n]);let j=D?o(D,`HH:mm`):`00:00`,M=e=>{if(!e){A.current=``,k(``),t(``);return}if(n===`datetime`){let[t,n]=j.split(`:`).map(Number);e.setHours(t??0,n??0,0,0)}let r=S(e,n);A.current=r,k(r),t(C(e,n))},N=e=>{if(!D)return;let[r,i]=e.split(`:`).map(Number),a=new Date(D);a.setHours(r??0,i??0,0,0);let o=S(a,n);A.current=o,k(o),t(C(a,n))},P=e=>{let r=e.target.value;k(r);let i=x(r,n);i===void 0?(A.current=``,t(``)):i&&(A.current=S(i,n),t(C(i,n)))},F=()=>{if(x(O,n)===null){let e=S(D,n);A.current=e,k(e)}},I=c??(n===`datetime`?`YYYY-MM-DD HH:MM`:`YYYY-MM-DD`);return(0,g.jsxs)(p,{open:T,onOpenChange:E,children:[(0,g.jsxs)(`div`,{className:r(`relative w-full`,l),children:[(0,g.jsx)(m,{type:`text`,inputMode:`numeric`,value:O,onChange:P,onBlur:F,placeholder:I,disabled:s,"aria-label":v,className:r(_,`pr-10`)}),(0,g.jsx)(d,{asChild:!0,children:(0,g.jsx)(a,{type:`button`,variant:`ghost`,size:`icon`,disabled:s,"aria-label":y,className:`absolute right-1 top-1/2 size-8 -translate-y-1/2 text-muted-foreground hover:text-foreground`,children:(0,g.jsx)(i,{className:`size-4`})})})]}),(0,g.jsxs)(f,{className:`w-auto p-0`,align:`start`,children:[(0,g.jsx)(u,{mode:`single`,selected:D,defaultMonth:D,onSelect:e=>{M(e),n===`date`&&E(!1)},autoFocus:!0}),n===`datetime`&&(0,g.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border p-3`,children:[(0,g.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:w}),(0,g.jsx)(m,{type:`time`,value:j,disabled:!D,onChange:e=>N(e.target.value),className:`h-8 w-32`})]})]})]})}w.displayName=`DatePicker`;export{w as t};
|
|
2
|
-
//# sourceMappingURL=date-picker-LfbUehd1.js.map
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date-picker-LfbUehd1.js","names":[],"sources":["../../../../ui/src/components/date-picker.tsx"],"sourcesContent":["// Popover-driven date / datetime input. Single picker handles both modes:\n// pass `mode=\"datetime\"` to surface an HH:MM time input below the calendar.\n//\n// Value is an ISO-ish string (`yyyy-MM-dd` for dates, `yyyy-MM-ddTHH:mm` for\n// datetime — same shape <input type=\"date\">/<input type=\"datetime-local\">\n// produce, so callers can stay format-stable). The trigger is a real text\n// input so users can also type the date manually; clicks on the trailing\n// calendar icon open the popover with the inline picker.\n\nimport * as React from 'react'\nimport { format, isValid, parse, parseISO } from 'date-fns'\nimport { Calendar as CalendarIcon } from 'lucide-react'\nimport { cn } from '../lib/utils.js'\nimport { Button } from './button.js'\nimport { Calendar } from './calendar.js'\nimport { Input } from './input.js'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover.js'\n\nexport type DatePickerMode = 'date' | 'datetime'\n\nexport interface DatePickerProps {\n value: string | null | undefined\n onChange(next: string): void\n mode?: DatePickerMode\n disabled?: boolean\n placeholder?: string\n /** Applied to the outer wrapper div (controls width, etc.). */\n className?: string\n /** Applied to the inner text Input — use to override height / font size. */\n inputClassName?: string\n /** ARIA label forwarded to the trigger input (mobile users / screen readers). */\n ariaLabel?: string\n /** ARIA label for the calendar icon button. Default: \"Open calendar\". */\n openCalendarLabel?: string\n /** Label for the time input shown in datetime mode. Default: \"Time\". */\n timeLabel?: string\n}\n\nconst DATE_FMT = 'yyyy-MM-dd'\nconst DATETIME_FMT = \"yyyy-MM-dd'T'HH:mm\"\n// Friendlier display format for the datetime input — space instead of `T`.\nconst DATETIME_DISPLAY_FMT = 'yyyy-MM-dd HH:mm'\n\nfunction parseValue(value: string | null | undefined): Date | undefined {\n if (!value) return undefined\n const direct = value.length <= 10 ? parse(value, DATE_FMT, new Date()) : parseISO(value)\n return Number.isNaN(direct.getTime()) ? undefined : direct\n}\n\n/**\n * Try to parse a manually-typed string in any of the supported shapes.\n * Returns `undefined` on blank, `null` on invalid (non-blank) input so the\n * caller can distinguish \"cleared\" from \"typo\".\n */\nfunction parseTyped(raw: string, mode: DatePickerMode): Date | undefined | null {\n const trimmed = raw.trim()\n if (trimmed === '') return undefined\n const candidates =\n mode === 'datetime'\n ? [DATETIME_FMT, DATETIME_DISPLAY_FMT, \"yyyy-MM-dd'T'HH:mm:ss\", DATE_FMT]\n : [DATE_FMT]\n for (const fmt of candidates) {\n const parsed = parse(trimmed, fmt, new Date())\n if (isValid(parsed)) return parsed\n }\n // Last resort: ISO with timezone, etc.\n const iso = parseISO(trimmed)\n return isValid(iso) ? iso : null\n}\n\nfunction formatForInput(date: Date | undefined, mode: DatePickerMode): string {\n if (!date) return ''\n return format(date, mode === 'datetime' ? DATETIME_DISPLAY_FMT : DATE_FMT)\n}\n\nfunction formatForApi(date: Date, mode: DatePickerMode): string {\n return format(date, mode === 'datetime' ? DATETIME_FMT : DATE_FMT)\n}\n\nexport function DatePicker({\n value,\n onChange,\n mode = 'date',\n disabled,\n placeholder,\n className,\n inputClassName,\n ariaLabel,\n openCalendarLabel = 'Open calendar',\n timeLabel = 'Time',\n}: DatePickerProps): React.ReactElement {\n const [open, setOpen] = React.useState(false)\n const date = parseValue(value)\n // Local draft for the text input — keeps user typing intact even when\n // intermediate strings don't yet parse.\n const [draft, setDraft] = React.useState(() => formatForInput(date, mode))\n // Re-sync draft whenever the canonical value changes from outside (e.g.\n // calendar selection or form reset). Compare via formatted shape so a noop\n // update doesn't clobber what the user is typing.\n const lastFormatted = React.useRef(formatForInput(date, mode))\n React.useEffect(() => {\n const next = formatForInput(date, mode)\n if (next !== lastFormatted.current) {\n lastFormatted.current = next\n setDraft(next)\n }\n }, [value, mode]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const time = date ? format(date, 'HH:mm') : '00:00'\n\n const commitDate = (next: Date | undefined): void => {\n if (!next) {\n lastFormatted.current = ''\n setDraft('')\n onChange('')\n return\n }\n if (mode === 'datetime') {\n const [h, m] = time.split(':').map(Number)\n next.setHours(h ?? 0, m ?? 0, 0, 0)\n }\n const formatted = formatForInput(next, mode)\n lastFormatted.current = formatted\n setDraft(formatted)\n onChange(formatForApi(next, mode))\n }\n\n const setTime = (raw: string): void => {\n if (!date) return\n const [h, m] = raw.split(':').map(Number)\n const next = new Date(date)\n next.setHours(h ?? 0, m ?? 0, 0, 0)\n const formatted = formatForInput(next, mode)\n lastFormatted.current = formatted\n setDraft(formatted)\n onChange(formatForApi(next, mode))\n }\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const text = e.target.value\n setDraft(text)\n const parsed = parseTyped(text, mode)\n if (parsed === undefined) {\n // cleared\n lastFormatted.current = ''\n onChange('')\n } else if (parsed) {\n lastFormatted.current = formatForInput(parsed, mode)\n onChange(formatForApi(parsed, mode))\n }\n // parsed === null → keep draft, don't fire onChange yet\n }\n\n const handleInputBlur: React.FocusEventHandler<HTMLInputElement> = () => {\n // On blur, if the draft is invalid, snap back to the canonical value.\n const parsed = parseTyped(draft, mode)\n if (parsed === null) {\n const restored = formatForInput(date, mode)\n lastFormatted.current = restored\n setDraft(restored)\n }\n }\n\n const inputPlaceholder =\n placeholder ?? (mode === 'datetime' ? 'YYYY-MM-DD HH:MM' : 'YYYY-MM-DD')\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <div className={cn('relative w-full', className)}>\n <Input\n type=\"text\"\n inputMode=\"numeric\"\n value={draft}\n onChange={handleInputChange}\n onBlur={handleInputBlur}\n placeholder={inputPlaceholder}\n disabled={disabled}\n aria-label={ariaLabel}\n className={cn(inputClassName, 'pr-10')}\n />\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n disabled={disabled}\n aria-label={openCalendarLabel}\n className=\"absolute right-1 top-1/2 size-8 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n <CalendarIcon className=\"size-4\" />\n </Button>\n </PopoverTrigger>\n </div>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={date}\n defaultMonth={date}\n onSelect={(d) => {\n commitDate(d)\n if (mode === 'date') setOpen(false)\n }}\n autoFocus\n />\n {mode === 'datetime' && (\n <div className=\"flex items-center gap-2 border-t border-border p-3\">\n <span className=\"text-xs text-muted-foreground\">{timeLabel}</span>\n <Input\n type=\"time\"\n value={time}\n disabled={!date}\n onChange={(e) => setTime(e.target.value)}\n className=\"h-8 w-32\"\n />\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\nDatePicker.displayName = 'DatePicker'\n"],"mappings":"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"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|