feat(unplugin): routing support for inertia (#3845)

Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
Romain Hamel
2025-04-14 10:47:26 +02:00
committed by GitHub
parent eea14155aa
commit d059efca25
8 changed files with 564 additions and 15 deletions

View File

@@ -152,9 +152,7 @@
"unplugin": "^2.3.0",
"unplugin-auto-import": "^19.1.2",
"unplugin-vue-components": "^28.4.1",
"vaul-vue": "^0.4.1",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
"vaul-vue": "^0.4.1"
},
"devDependencies": {
"@nuxt/eslint-config": "^1.3.0",
@@ -172,14 +170,19 @@
"vue-tsc": "^2.2.0"
},
"peerDependencies": {
"@inertiajs/vue3": "^2.0.7",
"joi": "^17.13.0",
"superstruct": "^2.0.0",
"typescript": "^5.6.3",
"valibot": "^1.0.0",
"vue-router": "^4.5.0",
"yup": "^1.6.0",
"zod": "^3.24.0"
},
"peerDependenciesMeta": {
"@inertiajs/vue3": {
"optional": true
},
"joi": {
"optional": true
},
@@ -189,6 +192,9 @@
"superstruct": {
"optional": true
},
"vue-router": {
"optional": true
},
"yup": {
"optional": true
},

263
pnpm-lock.yaml generated
View File

@@ -19,6 +19,9 @@ importers:
'@iconify/vue':
specifier: ^4.3.0
version: 4.3.0(vue@3.5.13(typescript@5.8.3))
'@inertiajs/vue3':
specifier: ^2.0.7
version: 2.0.7(vue@3.5.13(typescript@5.8.3))
'@internationalized/date':
specifier: ^3.7.0
version: 3.7.0
@@ -60,7 +63,7 @@ importers:
version: 13.1.0(vue@3.5.13(typescript@5.8.3))
'@vueuse/integrations':
specifier: ^13.1.0
version: 13.1.0(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.13(typescript@5.8.3))
version: 13.1.0(axios@1.8.4)(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.13(typescript@5.8.3))
colortranslator:
specifier: ^4.1.0
version: 4.1.0
@@ -151,9 +154,6 @@ importers:
vaul-vue:
specifier: ^0.4.1
version: 0.4.1(reka-ui@2.2.0(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3))
vue:
specifier: ^3.5.13
version: 3.5.13(typescript@5.8.3)
vue-router:
specifier: ^4.5.0
version: 4.5.0(vue@3.5.13(typescript@5.8.3))
@@ -262,7 +262,7 @@ importers:
version: 4.1.2(rollup@4.34.9)
'@vueuse/integrations':
specifier: ^13.1.0
version: 13.1.0(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.13(typescript@5.8.3))
version: 13.1.0(axios@1.8.4)(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.13(typescript@5.8.3))
'@vueuse/nuxt':
specifier: ^13.1.0
version: 13.1.0(magicast@0.3.5)(nuxt@3.16.2(@parcel/watcher@2.5.1)(@types/node@22.13.14)(better-sqlite3@11.9.1)(db0@0.3.1(better-sqlite3@11.9.1))(eslint@9.24.0(jiti@2.4.2))(ioredis@5.6.0)(lightningcss@1.29.2)(magicast@0.3.5)(meow@13.2.0)(optionator@0.9.4)(rollup@4.34.9)(terser@5.39.0)(typescript@5.8.3)(vite@6.2.6(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.39.0)(yaml@2.7.1))(vue-tsc@2.2.0(typescript@5.8.3))(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))
@@ -1170,6 +1170,14 @@ packages:
cpu: [x64]
os: [win32]
'@inertiajs/core@2.0.7':
resolution: {integrity: sha512-3xJHeeIQCc6NW0Tsh22fqT/B8j30P2wWLpGswv0ew3w8MoyYQTCNY/MeGwYvmej5q1V+BiK1S8iB+BpRXhwpJw==}
'@inertiajs/vue3@2.0.7':
resolution: {integrity: sha512-LaRfp/Yjt6/xhhug28iSmxtTxJg/5FoEZVTIgMRlOamMELh3qFajeQglofv7oUVUDW4kIGVxSEIOHT6sRTVKkw==}
peerDependencies:
vue: ^3.0.0
'@inquirer/checkbox@4.1.4':
resolution: {integrity: sha512-d30576EZdApjAMceijXA5jDzRQHT/MygbC+J8I7EqA6f/FRpYxlRtRJbHF8gHeWYeSdOuTEJqonn7QLB1ELezA==}
engines: {node: '>=18'}
@@ -2828,6 +2836,9 @@ packages:
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
atomically@2.0.3:
resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==}
@@ -2838,6 +2849,9 @@ packages:
peerDependencies:
postcss: ^8.1.0
axios@1.8.4:
resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
b4a@1.6.7:
resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==}
@@ -2977,6 +2991,14 @@ packages:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
call-bound@1.0.4:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -3123,6 +3145,10 @@ packages:
colortranslator@4.1.0:
resolution: {integrity: sha512-bwa5awaMnQ6dpm9D3nbsFwUr6x6FrTKmxPdolNtSYfxCNR7ZM93GG1OF5Y3Sy1LvYdalb3riKC9uTn0X5NB36g==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
@@ -3466,6 +3492,10 @@ packages:
resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
engines: {node: '>= 14'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
@@ -3545,6 +3575,10 @@ packages:
resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
engines: {node: '>=12'}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
@@ -3663,9 +3697,28 @@ packages:
errx@0.1.0:
resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-module-lexer@1.6.0:
resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
es-toolkit@1.34.1:
resolution: {integrity: sha512-OA6cd94fJV9bm8dWhIySkWq4xV+rAQnBZUr2dnpXam0QJ8c+hurLbKA8/QooL9Mx4WCAxvIDsiEkid5KPQ5xgQ==}
esbuild@0.24.2:
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
engines: {node: '>=18'}
@@ -3945,6 +3998,15 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
fontaine@0.5.0:
resolution: {integrity: sha512-vPDSWKhVAfTx4hRKT777+N6Szh2pAosAuzLpbppZ6O3UdD/1m6OlHjNcC3vIbgkRTIcLjzySLHXzPeLO2rE8cA==}
@@ -3955,6 +4017,10 @@ packages:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
form-data@4.0.2:
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
engines: {node: '>= 6'}
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
@@ -4006,9 +4072,17 @@ packages:
resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
engines: {node: '>=18'}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-port-please@3.1.2:
resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
get-source@2.0.12:
resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
@@ -4107,6 +4181,10 @@ packages:
resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==}
engines: {node: '>=18'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
graceful-fs@4.2.10:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
@@ -4136,6 +4214,14 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
@@ -4759,6 +4845,10 @@ packages:
marky@1.2.5:
resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
mdast-util-find-and-replace@3.0.2:
resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
@@ -5198,6 +5288,10 @@ packages:
engines: {node: ^14.16.0 || >=16.10.0}
hasBin: true
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
ofetch@1.4.1:
resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==}
@@ -5676,6 +5770,10 @@ packages:
engines: {node: '>=18'}
hasBin: true
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
quansync@0.2.10:
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
@@ -5993,6 +6091,22 @@ packages:
shiki@3.2.1:
resolution: {integrity: sha512-VML/2o1/KGYkEf/stJJ+s9Ypn7jUKQPomGLGYso4JJFMFxVDyPNsjsI3MB3KLjlMOeH44gyaPdXC6rik2WXvUQ==}
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
side-channel-map@1.0.1:
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
engines: {node: '>= 0.4'}
side-channel-weakmap@1.0.2:
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
engines: {node: '>= 0.4'}
side-channel@1.1.0:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
@@ -7817,6 +7931,22 @@ snapshots:
'@img/sharp-win32-x64@0.33.5':
optional: true
'@inertiajs/core@2.0.7':
dependencies:
axios: 1.8.4
deepmerge: 4.3.1
qs: 6.14.0
transitivePeerDependencies:
- debug
'@inertiajs/vue3@2.0.7(vue@3.5.13(typescript@5.8.3))':
dependencies:
'@inertiajs/core': 2.0.7
es-toolkit: 1.34.1
vue: 3.5.13(typescript@5.8.3)
transitivePeerDependencies:
- debug
'@inquirer/checkbox@4.1.4(@types/node@22.13.14)':
dependencies:
'@inquirer/core': 10.1.9(@types/node@22.13.14)
@@ -9725,12 +9855,13 @@ snapshots:
'@vueuse/shared': 13.1.0(vue@3.5.13(typescript@5.8.3))
vue: 3.5.13(typescript@5.8.3)
'@vueuse/integrations@13.1.0(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.13(typescript@5.8.3))':
'@vueuse/integrations@13.1.0(axios@1.8.4)(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.13(typescript@5.8.3))':
dependencies:
'@vueuse/core': 13.1.0(vue@3.5.13(typescript@5.8.3))
'@vueuse/shared': 13.1.0(vue@3.5.13(typescript@5.8.3))
vue: 3.5.13(typescript@5.8.3)
optionalDependencies:
axios: 1.8.4
fuse.js: 7.1.0
sortablejs: 1.15.6
@@ -9902,6 +10033,8 @@ snapshots:
async@3.2.6: {}
asynckit@0.4.0: {}
atomically@2.0.3:
dependencies:
stubborn-fs: 1.2.5
@@ -9917,6 +10050,14 @@ snapshots:
postcss: 8.5.3
postcss-value-parser: 4.2.0
axios@1.8.4:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.2
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
b4a@1.6.7: {}
bail@2.0.2: {}
@@ -10059,6 +10200,16 @@ snapshots:
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
call-bound@1.0.4:
dependencies:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
callsites@3.1.0: {}
camelcase@8.0.0: {}
@@ -10209,6 +10360,10 @@ snapshots:
colortranslator@4.1.0: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
comma-separated-tokens@2.0.3: {}
commander@10.0.1: {}
@@ -10542,6 +10697,8 @@ snapshots:
escodegen: 2.1.0
esprima: 4.0.1
delayed-stream@1.0.0: {}
denque@2.1.0: {}
depd@2.0.0: {}
@@ -10604,6 +10761,12 @@ snapshots:
dotenv@16.4.7: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
duplexer@0.1.2: {}
eastasianwidth@0.2.0: {}
@@ -10707,8 +10870,25 @@ snapshots:
errx@0.1.0: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-module-lexer@1.6.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
es-toolkit@1.34.1: {}
esbuild@0.24.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.24.2
@@ -11107,6 +11287,8 @@ snapshots:
flatted@3.3.3: {}
follow-redirects@1.15.9: {}
fontaine@0.5.0:
dependencies:
'@capsizecss/metrics': 2.2.0
@@ -11136,6 +11318,13 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data@4.0.2:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
fraction.js@4.3.7: {}
framer-motion@12.5.0(react@19.1.0):
@@ -11165,8 +11354,26 @@ snapshots:
get-east-asian-width@1.3.0: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-port-please@3.1.2: {}
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
get-source@2.0.12:
dependencies:
data-uri-to-buffer: 2.0.2
@@ -11295,6 +11502,8 @@ snapshots:
slash: 5.1.0
unicorn-magic: 0.3.0
gopd@1.2.0: {}
graceful-fs@4.2.10: {}
graceful-fs@4.2.11: {}
@@ -11333,6 +11542,12 @@ snapshots:
has-flag@4.0.0: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
@@ -12015,6 +12230,8 @@ snapshots:
marky@1.2.5: {}
math-intrinsics@1.1.0: {}
mdast-util-find-and-replace@3.0.2:
dependencies:
'@types/mdast': 4.0.4
@@ -12864,6 +13081,8 @@ snapshots:
pkg-types: 2.1.0
tinyexec: 0.3.2
object-inspect@1.13.4: {}
ofetch@1.4.1:
dependencies:
destr: 2.0.5
@@ -13384,6 +13603,10 @@ snapshots:
- typescript
- utf-8-validate
qs@6.14.0:
dependencies:
side-channel: 1.1.0
quansync@0.2.10: {}
queue-microtask@1.2.3: {}
@@ -13894,6 +14117,34 @@ snapshots:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-map@1.0.1:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-weakmap@1.0.2:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-map: 1.0.1
side-channel@1.1.0:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-list: 1.0.0
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
siginfo@2.0.0: {}
signal-exit@4.1.0: {}

View File

@@ -18,6 +18,9 @@ export default function ComponentImportPlugin(options: NuxtUIOptions & { prefix:
const overrides = globSync('**/*.vue', { cwd: join(runtimeDir, 'vue/components') })
const overrideNames = new Set(overrides.map(c => `${options.prefix}${c.replace(/\.vue$/, '')}`))
const inertiaOverrides = globSync('**/*.vue', { cwd: join(runtimeDir, 'inertia/components') })
const inertiaOverrideNames = new Set(inertiaOverrides.map(c => `${options.prefix}${c.replace(/\.vue$/, '')}`))
const pluginOptions = defu(options.components, <ComponentsOptions>{
dts: options.dts ?? true,
exclude: [
@@ -27,6 +30,9 @@ export default function ComponentImportPlugin(options: NuxtUIOptions & { prefix:
],
resolvers: [
(componentName) => {
if (options.inertia && inertiaOverrideNames.has(componentName)) {
return { name: 'default', from: join(runtimeDir, 'inertia/components', `${componentName.slice(options.prefix.length)}.vue`) }
}
if (overrideNames.has(componentName))
return { name: 'default', from: join(runtimeDir, 'vue/components', `${componentName.slice(options.prefix.length)}.vue`) }
if (componentNames.has(componentName))
@@ -55,6 +61,9 @@ export default function ComponentImportPlugin(options: NuxtUIOptions & { prefix:
}
const filename = id.match(/([^/]+)\.vue$/)?.[1]
if (filename && options.inertia && inertiaOverrideNames.has(`${options.prefix}${filename}`)) {
return join(runtimeDir, 'inertia/components', `${filename}.vue`)
}
if (filename && overrideNames.has(`${options.prefix}${filename}`)) {
return join(runtimeDir, 'vue/components', `${filename}.vue`)
}

View File

@@ -3,13 +3,13 @@ import { normalize } from 'pathe'
import { resolvePathSync } from 'mlly'
import MagicString from 'magic-string'
import { runtimeDir } from '../unplugin'
import { runtimeDir, type NuxtUIOptions } from '../unplugin'
/**
* This plugin normalises Nuxt environment (#imports) and `import.meta.client` within the Nuxt UI components.
*/
export default function NuxtEnvironmentPlugin() {
const stubPath = resolvePathSync('../runtime/vue/stubs', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url })
export default function NuxtEnvironmentPlugin(options: NuxtUIOptions) {
const stubPath = resolvePathSync(options.inertia ? '../runtime/inertia/stubs' : '../runtime/vue/stubs', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url })
return {
name: 'nuxt:ui',

View File

@@ -0,0 +1,181 @@
<script lang="ts">
import type { ButtonHTMLAttributes } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import type { InertiaLinkProps } from '@inertiajs/vue3'
import theme from '#build/ui/link'
import type { ComponentConfig } from '../../types/utils'
type Link = ComponentConfig<typeof theme, AppConfig, 'link'>
interface NuxtLinkProps extends Omit<InertiaLinkProps, 'href'> {
activeClass?: string
/**
* Route Location the link should navigate to when clicked on.
*/
to?: string // need to manually type to avoid breaking typedPages
/**
* An alias for `to`. If used with `to`, `href` will be ignored
*/
href?: NuxtLinkProps['to']
/**
* Forces the link to be considered as external (true) or internal (false). This is helpful to handle edge-cases
*/
external?: boolean
/**
* Where to display the linked URL, as the name for a browsing context.
*/
target?: '_blank' | '_parent' | '_self' | '_top' | (string & {}) | null
ariaCurrentValue?: string
}
export interface LinkProps extends NuxtLinkProps {
/**
* The element or component this component should render as when not a link.
* @defaultValue 'button'
*/
as?: any
/**
* The type of the button when not a link.
* @defaultValue 'button'
*/
type?: ButtonHTMLAttributes['type']
disabled?: boolean
/** Force the link to be active independent of the current route. */
active?: boolean
/** Will only be active if the current route is an exact match. */
exact?: boolean
/** The class to apply when the link is inactive. */
inactiveClass?: string
custom?: boolean
/** When `true`, only styles from `class`, `activeClass`, and `inactiveClass` will be applied. */
raw?: boolean
class?: any
}
export interface LinkSlots {
default(props: { active: boolean }): any
}
</script>
<script setup lang="ts">
import { computed } from 'vue'
import { defu } from 'defu'
import { useForwardProps } from 'reka-ui'
import { reactiveOmit } from '@vueuse/core'
import { usePage, Link as InertiaLink } from '@inertiajs/vue3'
import { hasProtocol } from 'ufo'
import { useAppConfig } from '#imports'
import { tv } from '../../utils/tv'
defineOptions({ inheritAttrs: false })
const props = withDefaults(defineProps<LinkProps>(), {
as: 'button',
type: 'button',
active: undefined,
activeClass: '',
inactiveClass: ''
})
defineSlots<LinkSlots>()
const appConfig = useAppConfig() as Link['AppConfig']
const routerLinkProps = useForwardProps(reactiveOmit(props, 'as', 'type', 'disabled', 'active', 'exact', 'activeClass', 'inactiveClass', 'to', 'raw', 'class'))
const ui = computed(() => tv({
extend: tv(theme),
...defu({
variants: {
active: {
true: props.activeClass,
false: props.inactiveClass
}
}
}, appConfig.ui?.link || {})
}))
const isExternal = computed(() => {
if (!props.to) return false
return typeof props.to === 'string' && hasProtocol(props.to, { acceptRelative: true })
})
const linkClass = computed(() => {
const active = isActive.value
if (props.raw) {
return [props.class, active ? props.activeClass : props.inactiveClass]
}
return ui.value({ class: props.class, active, disabled: props.disabled })
})
const page = usePage()
const url = computed(() => props.to ?? props.href ?? '#')
const isActive = computed(() => props.active || (props.exact ? url.value === props.href : page?.url.startsWith(url.value)))
</script>
<template>
<template v-if="!isExternal">
<InertiaLink v-bind="routerLinkProps" :href="url" custom>
<template v-if="custom">
<slot
v-bind="{
...$attrs,
as,
type,
disabled,
href: url,
active: isActive
}"
/>
</template>
<ULinkBase
v-else
v-bind="{
...$attrs,
as,
type,
disabled,
href: url,
active: isActive
}"
:class="linkClass"
>
<slot :active="isActive" />
</ULinkBase>
</InertiaLink>
</template>
<template v-else>
<template v-if="custom">
<slot
v-bind="{
...$attrs,
as,
type,
disabled,
href: to,
target: isExternal ? '_blank' : undefined,
active: isActive
}"
/>
</template>
<ULinkBase
v-else
v-bind="{
...$attrs,
as,
type,
disabled,
href: url,
target: isExternal ? '_blank' : undefined,
active: isActive
}"
:is-external="isExternal"
:class="linkClass"
>
<slot :active="isActive" />
</ULinkBase>
</template>
</template>

View File

@@ -0,0 +1,98 @@
import { ref, onScopeDispose } from 'vue'
import type { Ref, Plugin as VuePlugin } from 'vue'
import { createHooks } from 'hookable'
import appConfig from '#build/app.config'
import type { NuxtApp } from '#app'
import { useColorMode as useColorModeVueUse } from '@vueuse/core'
import { usePage } from '@inertiajs/vue3'
export { useHead } from '@unhead/vue'
export { defineShortcuts } from '../composables/defineShortcuts'
export { defineLocale } from '../composables/defineLocale'
export { useLocale } from '../composables/useLocale'
export const useRoute = () => {
const page = usePage()
return {
fullPath: page.url
}
}
export const useRouter = () => {
}
export const useColorMode = () => {
if (!appConfig.colorMode) {
return {
forced: true
}
}
const { store, system } = useColorModeVueUse()
return {
get preference() { return store.value === 'auto' ? 'system' : store.value },
set preference(value) { store.value = value === 'system' ? 'auto' : value },
get value() { return store.value === 'auto' ? system.value : store.value },
forced: false
}
}
export const useAppConfig = () => appConfig
export const useCookie = <T = string>(
_name: string,
_options: Record<string, any> = {}
) => {
const value = ref(null) as Ref<T>
return {
value,
get: () => value.value,
set: () => {},
update: () => {},
refresh: () => Promise.resolve(value.value),
remove: () => {}
}
}
const state: Record<string, any> = {}
export const useState = <T>(key: string, init: () => T): Ref<T> => {
if (state[key]) {
return state[key] as Ref<T>
}
const value = ref(init())
state[key] = value
return value as Ref<T>
}
const hooks = createHooks()
export function useNuxtApp() {
return {
isHydrating: true,
payload: { serverRendered: false },
hooks,
hook: hooks.hook
}
}
export function useRuntimeHook(name: string, fn: (...args: any[]) => void): void {
const nuxtApp = useNuxtApp()
const unregister = nuxtApp.hook(name, fn)
onScopeDispose(unregister)
}
export function defineNuxtPlugin(plugin: (nuxtApp: NuxtApp) => void) {
return {
install(app) {
app.runWithContext(() => plugin({ vueApp: app } as NuxtApp))
}
} satisfies VuePlugin
}

View File

@@ -93,8 +93,8 @@ import { isEqual, diff } from 'ohash/utils'
import { useForwardProps } from 'reka-ui'
import { reactiveOmit } from '@vueuse/core'
import { hasProtocol } from 'ufo'
import { useRoute, useAppConfig } from '#imports'
import { RouterLink } from 'vue-router'
import { useRoute, RouterLink } from 'vue-router'
import { useAppConfig } from '#imports'
import { tv } from '../../utils/tv'
defineOptions({ inheritAttrs: false })

View File

@@ -50,6 +50,10 @@ export interface NuxtUIOptions extends Omit<ModuleOptions, 'fonts' | 'colorMode'
* Override options for `unplugin-vue-components`
*/
components?: Partial<ComponentsOptions>
/**
* Enables compatibility layer for InertiaJS
*/
inertia?: boolean
}
export const runtimeDir = normalize(fileURLToPath(new URL('./runtime', import.meta.url)))
@@ -63,7 +67,7 @@ export const NuxtUIPlugin = createUnplugin<NuxtUIOptions | undefined>((_options
const appConfig = defu({ ui: options.ui, colorMode: options.colorMode }, { ui: getDefaultUiConfig(options.theme.colors) })
return [
NuxtEnvironmentPlugin(),
NuxtEnvironmentPlugin(options),
ComponentImportPlugin(options, meta),
AutoImportPlugin(options, meta),
tailwind(),