@falcondev-oss/nuxt-layers-base 0.40.1 → 0.40.3
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.
|
@@ -39,9 +39,9 @@ const props = defineProps<{
|
|
|
39
39
|
const slots = defineSlots<
|
|
40
40
|
{
|
|
41
41
|
'default': any
|
|
42
|
-
'navbar-title'
|
|
43
|
-
'navbar-trailing'
|
|
44
|
-
'navbar-actions'
|
|
42
|
+
'navbar-title'?: any
|
|
43
|
+
'navbar-trailing'?: any
|
|
44
|
+
'navbar-actions'?: any
|
|
45
45
|
} & AddPropertyPrefix<DashboardNavbarSlots, 'navbar'>
|
|
46
46
|
>()
|
|
47
47
|
|
|
@@ -10,7 +10,7 @@ export function usePreventPageLeave(
|
|
|
10
10
|
) {
|
|
11
11
|
useEventListener('beforeunload', (event) => {
|
|
12
12
|
if (!toValue(preventPageLeave)) return
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
event.returnValue = opts?.leaveDescription
|
|
15
15
|
return opts?.leaveDescription
|
|
16
16
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
/* eslint-disable ts/no-empty-object-type */
|
|
2
|
-
import type { AllUnionFields,
|
|
1
|
+
/* eslint-disable ts/no-empty-object-type, ts/no-unsafe-return, ts/no-unsafe-argument */
|
|
2
|
+
import type { AllUnionFields, Simplify } from 'type-fest'
|
|
3
3
|
import type {
|
|
4
|
+
Attrs,
|
|
4
5
|
ComponentOptionsMixin,
|
|
5
6
|
CreateComponentPublicInstanceWithMixins,
|
|
6
7
|
EmitsToProps,
|
|
@@ -8,13 +9,17 @@ import type {
|
|
|
8
9
|
PublicProps,
|
|
9
10
|
RenderFunction,
|
|
10
11
|
SetupContext,
|
|
11
|
-
Slots as SlotOptions,
|
|
12
12
|
SlotsType,
|
|
13
13
|
} from 'vue'
|
|
14
|
+
import { defineComponent } from 'vue'
|
|
14
15
|
|
|
15
16
|
declare module 'vue' {
|
|
16
17
|
interface ComponentCustomProps {
|
|
17
|
-
vSlots
|
|
18
|
+
// Deliberately loose: this only makes `vSlots` an accepted prop name on every
|
|
19
|
+
// component. `Slots` would reject it for any component whose slots are declared as an
|
|
20
|
+
// interface without an index signature (most of @nuxt/ui). The real check is the
|
|
21
|
+
// `vSlots()` helper below, which types the object against the target's own slots.
|
|
22
|
+
vSlots?: Record<string, any>
|
|
18
23
|
}
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -22,6 +27,18 @@ interface ComponentTypes {
|
|
|
22
27
|
props?: Record<string, any>
|
|
23
28
|
emits?: ObjectEmitsOptions
|
|
24
29
|
slots?: Record<string, any>
|
|
30
|
+
/**
|
|
31
|
+
* Prop names to register when they are deliberately fewer than `keyof props`; the rest
|
|
32
|
+
* arrive as `attrs`. See `docs/agents/vue-to-tsx-migration.md` for when that is right.
|
|
33
|
+
*/
|
|
34
|
+
propKeys?: string
|
|
35
|
+
/**
|
|
36
|
+
* What `ctx.expose()` publishes, so parents holding a template ref see it.
|
|
37
|
+
*
|
|
38
|
+
* `expose()` alone only works at runtime; without this the instance type has no trace
|
|
39
|
+
* of it and `ref.value.selectDate()` is a type error at every call site.
|
|
40
|
+
*/
|
|
41
|
+
expose?: Record<string, any>
|
|
25
42
|
}
|
|
26
43
|
|
|
27
44
|
/**
|
|
@@ -35,15 +52,38 @@ type Field<T extends ComponentTypes, K extends keyof ComponentTypes> = K extends
|
|
|
35
52
|
: {}
|
|
36
53
|
|
|
37
54
|
/**
|
|
38
|
-
*
|
|
55
|
+
* Every key of `T`, flattened across union members. `never` when `T` has no keys,
|
|
56
|
+
* which makes `readonly Keys<T>[]` accept only `[]`.
|
|
57
|
+
*/
|
|
58
|
+
type Keys<T> = [keyof T] extends [never] ? never : Extract<keyof AllUnionFields<T>, string>
|
|
59
|
+
|
|
60
|
+
/** The runtime prop names: `propKeys` when declared, the keys of `props` otherwise. */
|
|
61
|
+
type PropKeys<T extends ComponentTypes> = 'propKeys' extends keyof T
|
|
62
|
+
? Extract<NonNullable<T['propKeys']>, string>
|
|
63
|
+
: Keys<Field<T, 'props'>>
|
|
64
|
+
|
|
65
|
+
/** Props not registered in `propKeys` arrive through `attrs` with Vue's `unknown` index signature. */
|
|
66
|
+
type AttrProps<T extends ComponentTypes> = Simplify<Omit<Field<T, 'props'>, PropKeys<T>> & Attrs>
|
|
67
|
+
|
|
68
|
+
type EmitKeys<T extends ComponentTypes> = Keys<Field<T, 'emits'>>
|
|
69
|
+
|
|
70
|
+
/** The shape no array satisfies; generic so the alias head names the missing keys. */
|
|
71
|
+
type MissingEntries<K extends string> = { readonly [P in K]: true }
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `unknown` when `Given` covers every key in `All`, otherwise an object that no array
|
|
75
|
+
* satisfies. Intersected onto the `props`/`emits` parameter it turns a forgotten key
|
|
76
|
+
* into an error that names the key.
|
|
39
77
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
78
|
+
* Deliberately *not* `UnionToTuple`: that fixes an order which TypeScript derives from
|
|
79
|
+
* union member order, an implementation detail that shifts when unrelated declarations
|
|
80
|
+
* move. A component would compile today and demand a reshuffled array tomorrow.
|
|
43
81
|
*/
|
|
44
|
-
type
|
|
45
|
-
|
|
46
|
-
|
|
82
|
+
export type Exhaustive<All extends string, Given extends readonly string[]> = [
|
|
83
|
+
Exclude<All, Given[number]>,
|
|
84
|
+
] extends [never]
|
|
85
|
+
? unknown
|
|
86
|
+
: MissingEntries<Exclude<All, Given[number]>>
|
|
47
87
|
|
|
48
88
|
/**
|
|
49
89
|
* Vue's own `emit` type (`SetupContext<E>['emit']`) for declared emits, but an empty
|
|
@@ -57,12 +97,23 @@ type StrictEmitFn<E extends ObjectEmitsOptions> = [keyof E] extends [never]
|
|
|
57
97
|
|
|
58
98
|
/** Runtime config for a component, derived from its declared types `T`. */
|
|
59
99
|
interface SetupConfig<T extends ComponentTypes> {
|
|
60
|
-
|
|
61
|
-
|
|
100
|
+
/**
|
|
101
|
+
* The component's name, as Vue Devtools and warning traces show it.
|
|
102
|
+
*
|
|
103
|
+
* Without it every component built here reports as `<Setup>`, because the setup
|
|
104
|
+
* function it is derived from is anonymous.
|
|
105
|
+
*/
|
|
106
|
+
name?: string
|
|
107
|
+
/** Vue's `inheritAttrs`. Set to `false` to place `ctx.attrs` yourself. */
|
|
108
|
+
inheritAttrs?: boolean
|
|
62
109
|
setup: (
|
|
63
110
|
props: Field<T, 'props'> & EmitsToProps<Field<T, 'emits'>>,
|
|
64
|
-
ctx: Omit<
|
|
111
|
+
ctx: Omit<
|
|
112
|
+
SetupContext<Field<T, 'emits'>, SlotsType<Partial<Field<T, 'slots'>>>>,
|
|
113
|
+
'emit' | 'attrs'
|
|
114
|
+
> & {
|
|
65
115
|
emit: StrictEmitFn<Field<T, 'emits'>>
|
|
116
|
+
attrs: AttrProps<T>
|
|
66
117
|
},
|
|
67
118
|
) => RenderFunction | Promise<RenderFunction>
|
|
68
119
|
}
|
|
@@ -72,7 +123,10 @@ interface SetupConfig<T extends ComponentTypes> {
|
|
|
72
123
|
// be returned as a raw object literal. The key is a readable string so bypassing it
|
|
73
124
|
// reports `Property '"use the options() helper"' is missing`.
|
|
74
125
|
type OptionsBrand = { readonly ['use the options() helper']: true }
|
|
75
|
-
type ViaOptions<T extends ComponentTypes> = SetupConfig<T> &
|
|
126
|
+
type ViaOptions<T extends ComponentTypes> = SetupConfig<T> & {
|
|
127
|
+
props: readonly PropKeys<T>[]
|
|
128
|
+
emits: readonly EmitKeys<T>[]
|
|
129
|
+
} & OptionsBrand
|
|
76
130
|
|
|
77
131
|
// `defineSetupComponent`'s callback must return an `options()` result. This shape is
|
|
78
132
|
// intentionally independent of `T`: `options()` already validated everything and typed
|
|
@@ -81,52 +135,55 @@ type ViaOptions<T extends ComponentTypes> = SetupConfig<T> & OptionsBrand
|
|
|
81
135
|
type LooseSetupConfig = {
|
|
82
136
|
props: readonly string[]
|
|
83
137
|
emits: readonly string[]
|
|
138
|
+
name?: string
|
|
139
|
+
inheritAttrs?: boolean
|
|
84
140
|
setup: (...args: any) => any
|
|
85
141
|
} & OptionsBrand
|
|
86
142
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
*/
|
|
94
|
-
export function options<const T extends ComponentTypes>(
|
|
143
|
+
/** `_` binds `T`, so key mismatches are reported on the offending config property. */
|
|
144
|
+
export function options<
|
|
145
|
+
const T extends ComponentTypes,
|
|
146
|
+
const P extends readonly PropKeys<T>[],
|
|
147
|
+
const E extends readonly EmitKeys<T>[],
|
|
148
|
+
>(
|
|
95
149
|
_: T,
|
|
96
|
-
config: SetupConfig<T
|
|
150
|
+
config: SetupConfig<T> & {
|
|
151
|
+
props: P & Exhaustive<PropKeys<T>, P>
|
|
152
|
+
emits: E & Exhaustive<EmitKeys<T>, E>
|
|
153
|
+
},
|
|
97
154
|
): ViaOptions<T> {
|
|
98
|
-
return config as ViaOptions<T>
|
|
155
|
+
return config as unknown as ViaOptions<T>
|
|
99
156
|
}
|
|
100
157
|
|
|
101
158
|
export function defineSetupComponent<const T extends ComponentTypes>(
|
|
102
159
|
options_: (opts: T) => LooseSetupConfig,
|
|
103
|
-
): new (
|
|
104
|
-
props: Field<T, 'props'>,
|
|
105
|
-
) => CreateComponentPublicInstanceWithMixins<
|
|
160
|
+
): new (props: Field<T, 'props'>) => CreateComponentPublicInstanceWithMixins<
|
|
106
161
|
Field<T, 'props'> & EmitsToProps<Field<T, 'emits'>>,
|
|
107
|
-
|
|
162
|
+
Field<T, 'expose'>,
|
|
108
163
|
{},
|
|
109
164
|
{},
|
|
110
165
|
{},
|
|
111
166
|
ComponentOptionsMixin,
|
|
112
167
|
ComponentOptionsMixin,
|
|
113
168
|
Field<T, 'emits'>,
|
|
114
|
-
|
|
169
|
+
// `Partial`, to match `SlotsType<Partial<...>>` below and the partial type `vSlots()`
|
|
170
|
+
PublicProps & { vSlots?: Partial<Field<T, 'slots'>> },
|
|
115
171
|
{},
|
|
116
172
|
false,
|
|
117
173
|
{},
|
|
118
174
|
SlotsType<Partial<Field<T, 'slots'>>>
|
|
119
175
|
> {
|
|
120
|
-
//
|
|
176
|
+
// oxlint-disable-next-line typescript/no-unsafe-argument
|
|
121
177
|
const opts = options_({} as any)
|
|
122
|
-
//
|
|
178
|
+
// oxlint-disable-next-line typescript/no-unsafe-return, typescript/no-unsafe-argument
|
|
123
179
|
return defineComponent(opts.setup as any, {
|
|
124
180
|
props: opts.props as unknown as string[],
|
|
125
181
|
emits: opts.emits as unknown as string[],
|
|
182
|
+
name: opts.name,
|
|
183
|
+
inheritAttrs: opts.inheritAttrs,
|
|
126
184
|
}) as any
|
|
127
185
|
}
|
|
128
186
|
|
|
129
|
-
// https://github.com/vuejs/language-tools/blob/master/packages/component-type-helpers/index.ts
|
|
130
187
|
type ComponentSlots<T> = T extends new (...args: any) => { $slots: infer S }
|
|
131
188
|
? NonNullable<S>
|
|
132
189
|
: T extends (props: any, ctx: { slots: infer S; attrs: any; emit: any }, ...args: any) => any
|
|
@@ -136,3 +193,33 @@ type ComponentSlots<T> = T extends new (...args: any) => { $slots: infer S }
|
|
|
136
193
|
export function vSlots<C>(component: C, slots: ComponentSlots<C>) {
|
|
137
194
|
return slots
|
|
138
195
|
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Vue's short emit declaration (`{ change: [event: Event] }`) rewritten as the call
|
|
199
|
+
* signatures `ComponentTypes['emits']` expects. Component libraries ship the short form,
|
|
200
|
+
* so a wrapper forwarding their emits would otherwise have to restate every signature.
|
|
201
|
+
*/
|
|
202
|
+
export type AsEmits<E> = {
|
|
203
|
+
[K in keyof E]: E[K] extends readonly any[] ? (...args: E[K]) => void : never
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A reusable, exhaustively checked list of the prop names of `T`.
|
|
208
|
+
*
|
|
209
|
+
* `defineSetupComponent` needs every prop spelled out at runtime, which is pure
|
|
210
|
+
* repetition for the many wrapper components that re-declare a shared props type
|
|
211
|
+
* (`FormGroupProps`, `GenericInputProps`, ...). Declare the list once here and spread
|
|
212
|
+
* it into `options({ props: [...] })`; the spread keeps the literal types, so the
|
|
213
|
+
* component's own exhaustiveness check still applies.
|
|
214
|
+
*
|
|
215
|
+
* ```ts
|
|
216
|
+
* export const formGroupPropNames = propNames<FormGroupProps>()(['label', 'help'])
|
|
217
|
+
* // ...
|
|
218
|
+
* props: [...formGroupPropNames, 'field']
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export function propNames<T>() {
|
|
222
|
+
return <const P extends readonly Extract<keyof T, string>[]>(
|
|
223
|
+
names: P & Exhaustive<Extract<keyof T, string>, P>,
|
|
224
|
+
): P => names
|
|
225
|
+
}
|