@simplysm/solid 13.0.98 → 13.0.99
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 +166 -259
- package/docs/data.md +246 -120
- package/docs/disclosure.md +85 -61
- package/docs/display.md +87 -44
- package/docs/features.md +186 -155
- package/docs/feedback.md +130 -107
- package/docs/form-control.md +337 -254
- package/docs/helpers.md +120 -82
- package/docs/hooks.md +69 -70
- package/docs/layout.md +115 -85
- package/docs/providers.md +130 -110
- package/docs/styles.md +91 -85
- package/package.json +5 -5
package/docs/helpers.md
CHANGED
|
@@ -1,41 +1,67 @@
|
|
|
1
1
|
# Helpers
|
|
2
2
|
|
|
3
|
-
Source: `src/helpers
|
|
3
|
+
Source: `src/helpers/**`
|
|
4
4
|
|
|
5
|
-
## mergeStyles
|
|
5
|
+
## `mergeStyles`
|
|
6
6
|
|
|
7
|
-
Utility function that merges CSS styles
|
|
7
|
+
Utility function that merges CSS styles. Supports string, object, and mixed formats. Converts kebab-case CSS strings to camelCase object properties. Later values take precedence.
|
|
8
8
|
|
|
9
|
-
```
|
|
10
|
-
function mergeStyles(
|
|
9
|
+
```typescript
|
|
10
|
+
export function mergeStyles(
|
|
11
11
|
...styles: (JSX.CSSProperties | string | undefined)[]
|
|
12
12
|
): JSX.CSSProperties;
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- String styles are parsed (semicolon-delimited, kebab-case converted to camelCase).
|
|
17
|
-
- `undefined` values are ignored.
|
|
15
|
+
---
|
|
18
16
|
|
|
19
|
-
## createAppStructure
|
|
17
|
+
## `createAppStructure`
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
Factory function for defining app navigation structure with type-safe permission inference. Generates routes, menus, and permission trees from a declarative item definition.
|
|
22
20
|
|
|
23
|
-
```
|
|
24
|
-
function createAppStructure<TModule, const TItems extends AppStructureItem<TModule>[]>(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
enabledPerms?: string[];
|
|
30
|
-
homeCode?: string;
|
|
21
|
+
```typescript
|
|
22
|
+
export function createAppStructure<TModule, const TItems extends AppStructureItem<TModule>[]>(
|
|
23
|
+
getOpts: () => {
|
|
24
|
+
items: TItems;
|
|
25
|
+
usableModules?: Accessor<TModule[] | undefined>;
|
|
26
|
+
permRecord?: Accessor<Record<string, boolean> | undefined>;
|
|
31
27
|
},
|
|
32
|
-
):
|
|
28
|
+
): {
|
|
29
|
+
AppStructureProvider: ParentComponent;
|
|
30
|
+
useAppStructure: () => AppStructure<TModule> & { perms: InferPerms<TItems> };
|
|
31
|
+
};
|
|
33
32
|
```
|
|
34
33
|
|
|
34
|
+
### `AppStructure`
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
export interface AppStructure<TModule> {
|
|
38
|
+
items: AppStructureItem<TModule>[];
|
|
39
|
+
usableRoutes: Accessor<AppRoute[]>;
|
|
40
|
+
usableMenus: Accessor<AppMenu[]>;
|
|
41
|
+
usableFlatMenus: Accessor<AppFlatMenu[]>;
|
|
42
|
+
usablePerms: Accessor<AppPerm<TModule>[]>;
|
|
43
|
+
allFlatPerms: AppFlatPerm<TModule>[];
|
|
44
|
+
getTitleChainByHref(href: string): string[];
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| Field | Type | Description |
|
|
49
|
+
|-------|------|-------------|
|
|
50
|
+
| `usableRoutes` | `Accessor<AppRoute[]>` | Routes filtered by module and permission |
|
|
51
|
+
| `usableMenus` | `Accessor<AppMenu[]>` | Menu tree filtered by module and permission |
|
|
52
|
+
| `usableFlatMenus` | `Accessor<AppFlatMenu[]>` | Flat menu list with title chains |
|
|
53
|
+
| `usablePerms` | `Accessor<AppPerm[]>` | Permission tree filtered by module |
|
|
54
|
+
| `allFlatPerms` | `AppFlatPerm[]` | All permissions flattened (static) |
|
|
55
|
+
| `getTitleChainByHref` | `(href) => string[]` | Get breadcrumb title chain for URL |
|
|
56
|
+
|
|
35
57
|
### Input Types
|
|
36
58
|
|
|
37
|
-
```
|
|
38
|
-
|
|
59
|
+
```typescript
|
|
60
|
+
export type AppStructureItem<TModule> =
|
|
61
|
+
| AppStructureGroupItem<TModule>
|
|
62
|
+
| AppStructureLeafItem<TModule>;
|
|
63
|
+
|
|
64
|
+
export interface AppStructureGroupItem<TModule> {
|
|
39
65
|
code: string;
|
|
40
66
|
title: string;
|
|
41
67
|
icon?: Component<IconProps>;
|
|
@@ -44,7 +70,7 @@ interface AppStructureGroupItem<TModule> {
|
|
|
44
70
|
children: AppStructureItem<TModule>[];
|
|
45
71
|
}
|
|
46
72
|
|
|
47
|
-
interface AppStructureLeafItem<TModule> {
|
|
73
|
+
export interface AppStructureLeafItem<TModule> {
|
|
48
74
|
code: string;
|
|
49
75
|
title: string;
|
|
50
76
|
icon?: Component<IconProps>;
|
|
@@ -56,11 +82,7 @@ interface AppStructureLeafItem<TModule> {
|
|
|
56
82
|
isNotMenu?: boolean;
|
|
57
83
|
}
|
|
58
84
|
|
|
59
|
-
|
|
60
|
-
| AppStructureGroupItem<TModule>
|
|
61
|
-
| AppStructureLeafItem<TModule>;
|
|
62
|
-
|
|
63
|
-
interface AppStructureSubPerm<TModule> {
|
|
85
|
+
export interface AppStructureSubPerm<TModule> {
|
|
64
86
|
code: string;
|
|
65
87
|
title: string;
|
|
66
88
|
modules?: TModule[];
|
|
@@ -69,27 +91,37 @@ interface AppStructureSubPerm<TModule> {
|
|
|
69
91
|
}
|
|
70
92
|
```
|
|
71
93
|
|
|
72
|
-
|
|
94
|
+
| Field | Type | Description |
|
|
95
|
+
|-------|------|-------------|
|
|
96
|
+
| `code` | `string` | Unique item identifier |
|
|
97
|
+
| `title` | `string` | Display title |
|
|
98
|
+
| `icon` | `Component<IconProps>` | Navigation icon |
|
|
99
|
+
| `modules` | `TModule[]` | Required modules (any match) |
|
|
100
|
+
| `requiredModules` | `TModule[]` | Strictly required modules (all match) |
|
|
101
|
+
| `children` | `AppStructureItem[]` | Child items (group only) |
|
|
102
|
+
| `component` | `Component` | Page component (leaf only) |
|
|
103
|
+
| `perms` | `("use" \| "edit")[]` | Permission types (leaf only) |
|
|
104
|
+
| `subPerms` | `AppStructureSubPerm[]` | Sub-permission definitions (leaf only) |
|
|
105
|
+
| `isNotMenu` | `boolean` | Exclude from menu (leaf only) |
|
|
106
|
+
|
|
107
|
+
Discriminated union: items with `children` are groups; items without are leaves.
|
|
73
108
|
|
|
74
|
-
|
|
75
|
-
interface AppStructure<TModule> {
|
|
76
|
-
items: AppStructureItem<TModule>[];
|
|
77
|
-
usableRoutes: Accessor<AppRoute[]>;
|
|
78
|
-
usableMenus: Accessor<AppMenu[]>;
|
|
79
|
-
usableFlatMenus: Accessor<AppFlatMenu[]>;
|
|
80
|
-
usablePerms: Accessor<AppPerm<TModule>[]>;
|
|
81
|
-
allFlatPerms: AppFlatPerm<TModule>[];
|
|
82
|
-
getTitleChainByHref(href: string): string[];
|
|
83
|
-
}
|
|
109
|
+
### Output Types
|
|
84
110
|
|
|
85
|
-
|
|
111
|
+
```typescript
|
|
112
|
+
export interface AppMenu {
|
|
86
113
|
title: string;
|
|
87
114
|
href?: string;
|
|
88
115
|
icon?: Component<IconProps>;
|
|
89
116
|
children?: AppMenu[];
|
|
90
117
|
}
|
|
91
118
|
|
|
92
|
-
interface
|
|
119
|
+
export interface AppRoute {
|
|
120
|
+
path: string;
|
|
121
|
+
component: Component;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface AppPerm<TModule = string> {
|
|
93
125
|
title: string;
|
|
94
126
|
href?: string;
|
|
95
127
|
modules?: TModule[];
|
|
@@ -97,72 +129,78 @@ interface AppPerm<TModule = string> {
|
|
|
97
129
|
children?: AppPerm<TModule>[];
|
|
98
130
|
}
|
|
99
131
|
|
|
100
|
-
interface
|
|
101
|
-
path: string;
|
|
102
|
-
component: Component;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
interface AppFlatMenu {
|
|
106
|
-
titleChain: string[];
|
|
107
|
-
href: string;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
interface AppFlatPerm<TModule = string> {
|
|
132
|
+
export interface AppFlatPerm<TModule = string> {
|
|
111
133
|
titleChain: string[];
|
|
112
134
|
code: string;
|
|
113
135
|
modulesChain: TModule[][];
|
|
114
136
|
requiredModulesChain: TModule[][];
|
|
115
137
|
}
|
|
138
|
+
|
|
139
|
+
export interface AppFlatMenu {
|
|
140
|
+
titleChain: string[];
|
|
141
|
+
href: string;
|
|
142
|
+
}
|
|
116
143
|
```
|
|
117
144
|
|
|
118
|
-
|
|
145
|
+
---
|
|
119
146
|
|
|
120
|
-
|
|
147
|
+
## `createSlot`
|
|
121
148
|
|
|
122
|
-
|
|
123
|
-
|
|
149
|
+
Creates a single-occupancy slot pattern for compound components.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
export function createSlot<TItem>(): [
|
|
124
153
|
SlotComponent: (props: TItem) => null,
|
|
125
154
|
createSlotAccessor: () => [Accessor<TItem | undefined>, ParentComponent],
|
|
126
155
|
];
|
|
127
156
|
```
|
|
128
157
|
|
|
129
|
-
|
|
158
|
+
Returns a tuple of `[SlotComponent, createSlotAccessor]`:
|
|
159
|
+
- **`SlotComponent`** -- Rendered inside provider to register slot content (throws if slot already occupied)
|
|
160
|
+
- **`createSlotAccessor`** -- Returns `[accessor, Provider]` for reading and providing the slot
|
|
130
161
|
|
|
131
|
-
|
|
132
|
-
// 1. Create slot at module level
|
|
133
|
-
const [HeaderSlot, createHeaderAccessor] = createSlot<{ children: JSX.Element }>();
|
|
162
|
+
---
|
|
134
163
|
|
|
135
|
-
|
|
136
|
-
const [header, HeaderProvider] = createHeaderAccessor();
|
|
164
|
+
## `createSlots`
|
|
137
165
|
|
|
138
|
-
|
|
139
|
-
<HeaderProvider>
|
|
140
|
-
{props.children}
|
|
141
|
-
<Show when={header()}>{header()!.children}</Show>
|
|
142
|
-
</HeaderProvider>
|
|
143
|
-
);
|
|
166
|
+
Creates a multi-occupancy slot pattern for compound components (multiple items).
|
|
144
167
|
|
|
145
|
-
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
168
|
+
```typescript
|
|
169
|
+
export function createSlots<TItem>(): [
|
|
170
|
+
SlotComponent: (props: TItem) => null,
|
|
171
|
+
createSlotsAccessor: () => [Accessor<TItem[]>, ParentComponent],
|
|
172
|
+
];
|
|
150
173
|
```
|
|
151
174
|
|
|
152
|
-
|
|
175
|
+
### `SlotRegistrar`
|
|
153
176
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
interface SlotRegistrar<TItem> {
|
|
177
|
+
```typescript
|
|
178
|
+
export interface SlotRegistrar<TItem> {
|
|
158
179
|
add: (item: TItem) => void;
|
|
159
180
|
remove: (item: TItem) => void;
|
|
160
181
|
}
|
|
182
|
+
```
|
|
161
183
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## `startPointerDrag`
|
|
187
|
+
|
|
188
|
+
Sets up pointer capture and manages pointermove/pointerup lifecycle for drag operations.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
export function startPointerDrag(
|
|
192
|
+
target: HTMLElement,
|
|
193
|
+
pointerId: number,
|
|
194
|
+
options: {
|
|
195
|
+
onMove: (e: PointerEvent) => void;
|
|
196
|
+
onEnd: (e: PointerEvent) => void;
|
|
197
|
+
},
|
|
198
|
+
): void;
|
|
166
199
|
```
|
|
167
200
|
|
|
168
|
-
|
|
201
|
+
| Parameter | Type | Description |
|
|
202
|
+
|-----------|------|-------------|
|
|
203
|
+
| `target` | `HTMLElement` | Element to capture pointer on |
|
|
204
|
+
| `pointerId` | `number` | Pointer ID from the initiating PointerEvent |
|
|
205
|
+
| `options.onMove` | `(e: PointerEvent) => void` | Called on each pointermove |
|
|
206
|
+
| `options.onEnd` | `(e: PointerEvent) => void` | Called on pointerup or pointercancel |
|
package/docs/hooks.md
CHANGED
|
@@ -1,95 +1,99 @@
|
|
|
1
1
|
# Hooks
|
|
2
2
|
|
|
3
|
-
Source: `src/hooks
|
|
3
|
+
Source: `src/hooks/**`
|
|
4
4
|
|
|
5
|
-
## useLocalStorage
|
|
5
|
+
## `useLocalStorage`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
LocalStorage-based storage hook. Always uses localStorage regardless of SyncStorage settings. Keys are prefixed with `clientName`.
|
|
8
8
|
|
|
9
|
-
```
|
|
10
|
-
function useLocalStorage<TValue>(
|
|
9
|
+
```typescript
|
|
10
|
+
export function useLocalStorage<TValue>(
|
|
11
11
|
key: string,
|
|
12
12
|
initialValue?: TValue,
|
|
13
13
|
): [Accessor<TValue | undefined>, StorageSetter<TValue>];
|
|
14
|
-
|
|
15
|
-
type StorageSetter<TValue> = (
|
|
16
|
-
value: TValue | undefined | ((prev: TValue | undefined) => TValue | undefined),
|
|
17
|
-
) => TValue | undefined;
|
|
18
14
|
```
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
| Parameter | Type | Description |
|
|
17
|
+
|-----------|------|-------------|
|
|
18
|
+
| `key` | `string` | Storage key (auto-prefixed with `clientName`) |
|
|
19
|
+
| `initialValue` | `TValue` | Default value if nothing stored |
|
|
20
|
+
|
|
21
|
+
---
|
|
23
22
|
|
|
24
|
-
## useSyncConfig
|
|
23
|
+
## `useSyncConfig`
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
Reactive signal that syncs to storage via SyncStorageProvider (falls back to localStorage). Designed for data that should persist and sync across devices.
|
|
27
26
|
|
|
28
|
-
```
|
|
29
|
-
function useSyncConfig<TValue>(
|
|
27
|
+
```typescript
|
|
28
|
+
export function useSyncConfig<TValue>(
|
|
30
29
|
key: string,
|
|
31
30
|
defaultValue: TValue,
|
|
32
31
|
): [Accessor<TValue>, Setter<TValue>, Accessor<boolean>];
|
|
33
32
|
```
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
| Parameter | Type | Description |
|
|
35
|
+
|-----------|------|-------------|
|
|
36
|
+
| `key` | `string` | Storage key (auto-prefixed with `clientName`) |
|
|
37
|
+
| `defaultValue` | `TValue` | Default value |
|
|
38
|
+
|
|
39
|
+
Returns `[value, setValue, ready]` where `ready()` is `true` after initial storage read completes.
|
|
40
|
+
|
|
41
|
+
---
|
|
39
42
|
|
|
40
|
-
## useLogger
|
|
43
|
+
## `useLogger`
|
|
41
44
|
|
|
42
|
-
Logging hook
|
|
45
|
+
Logging hook that delegates to LoggerProvider adapter (defaults to consola).
|
|
43
46
|
|
|
44
|
-
```
|
|
45
|
-
|
|
47
|
+
```typescript
|
|
48
|
+
export function useLogger(): Logger;
|
|
49
|
+
|
|
50
|
+
export interface Logger {
|
|
46
51
|
log: (...args: unknown[]) => void;
|
|
47
52
|
info: (...args: unknown[]) => void;
|
|
48
53
|
warn: (...args: unknown[]) => void;
|
|
49
54
|
error: (...args: unknown[]) => void;
|
|
50
55
|
configure: (fn: (origin: LogAdapter) => LogAdapter) => void;
|
|
51
56
|
}
|
|
52
|
-
|
|
53
|
-
function useLogger(): Logger;
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
---
|
|
57
60
|
|
|
58
|
-
## createControllableSignal
|
|
61
|
+
## `createControllableSignal`
|
|
59
62
|
|
|
60
|
-
Signal hook supporting the controlled/uncontrolled pattern.
|
|
63
|
+
Signal hook supporting the controlled/uncontrolled pattern.
|
|
61
64
|
|
|
62
|
-
```
|
|
63
|
-
function createControllableSignal<TValue>(options: {
|
|
65
|
+
```typescript
|
|
66
|
+
export function createControllableSignal<TValue>(options: {
|
|
64
67
|
value: Accessor<TValue>;
|
|
65
68
|
onChange: Accessor<((value: TValue) => void) | undefined>;
|
|
66
69
|
}): [Accessor<TValue>, (newValue: TValue | ((prev: TValue) => TValue)) => TValue];
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
- When `onChange` is provided: controlled mode
|
|
70
|
-
- When `onChange`
|
|
71
|
-
- Supports functional setter: `setValue(prev => !prev)
|
|
72
|
+
- When `onChange` is provided: controlled mode (value managed externally)
|
|
73
|
+
- When `onChange` is absent: uncontrolled mode (uses internal state)
|
|
74
|
+
- Supports functional setter: `setValue(prev => !prev)`
|
|
75
|
+
|
|
76
|
+
---
|
|
72
77
|
|
|
73
|
-
## createControllableStore
|
|
78
|
+
## `createControllableStore`
|
|
74
79
|
|
|
75
|
-
Store hook supporting the controlled/uncontrolled pattern.
|
|
80
|
+
Store hook supporting the controlled/uncontrolled pattern. Supports all `SetStoreFunction` overloads (path-based, produce, reconcile).
|
|
76
81
|
|
|
77
|
-
```
|
|
78
|
-
function createControllableStore<TValue extends object>(options: {
|
|
82
|
+
```typescript
|
|
83
|
+
export function createControllableStore<TValue extends object>(options: {
|
|
79
84
|
value: () => TValue;
|
|
80
85
|
onChange: () => ((value: TValue) => void) | undefined;
|
|
81
86
|
}): [TValue, SetStoreFunction<TValue>];
|
|
82
87
|
```
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
- In controlled mode: calls `onChange` with a deep clone when the store changes.
|
|
89
|
+
---
|
|
86
90
|
|
|
87
|
-
## createIMEHandler
|
|
91
|
+
## `createIMEHandler`
|
|
88
92
|
|
|
89
|
-
IME composition handling hook. Delays value
|
|
93
|
+
IME composition handling hook. Delays value changes during IME composition (e.g., Korean) to prevent DOM recreation.
|
|
90
94
|
|
|
91
|
-
```
|
|
92
|
-
function createIMEHandler(setValue: (value: string) => void): {
|
|
95
|
+
```typescript
|
|
96
|
+
export function createIMEHandler(setValue: (value: string) => void): {
|
|
93
97
|
composingValue: Accessor<string | null>;
|
|
94
98
|
handleCompositionStart: () => void;
|
|
95
99
|
handleInput: (value: string, isComposing: boolean) => void;
|
|
@@ -98,46 +102,41 @@ function createIMEHandler(setValue: (value: string) => void): {
|
|
|
98
102
|
};
|
|
99
103
|
```
|
|
100
104
|
|
|
101
|
-
|
|
102
|
-
- On `compositionEnd`: delays `setValue` via `setTimeout(0)`.
|
|
103
|
-
- `flushComposition()`: immediately commits any pending value.
|
|
105
|
+
---
|
|
104
106
|
|
|
105
|
-
## createMountTransition
|
|
107
|
+
## `createMountTransition`
|
|
106
108
|
|
|
107
|
-
Mount/
|
|
109
|
+
Mount transition hook for open/close CSS animations. Returns `mounted` for DOM rendering and `animating` for CSS class toggling.
|
|
108
110
|
|
|
109
|
-
```
|
|
110
|
-
function createMountTransition(open: () => boolean): {
|
|
111
|
+
```typescript
|
|
112
|
+
export function createMountTransition(open: () => boolean): {
|
|
111
113
|
mounted: () => boolean;
|
|
112
114
|
animating: () => boolean;
|
|
113
115
|
unmount: () => void;
|
|
114
116
|
};
|
|
115
117
|
```
|
|
116
118
|
|
|
117
|
-
- `open=true`:
|
|
118
|
-
- `open=false`:
|
|
119
|
-
- Use `mounted()` for DOM rendering, `animating()` for CSS class toggling.
|
|
120
|
-
- Call `unmount()` to manually remove from DOM (e.g., in `onTransitionEnd`).
|
|
119
|
+
- `open=true`: `mounted=true` immediately, `animating=true` after double rAF
|
|
120
|
+
- `open=false`: `animating=false` immediately, `mounted=false` after transitionend or 200ms fallback
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
---
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
## `useRouterLink`
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
interface RouterLinkOptions {
|
|
128
|
-
href: string;
|
|
129
|
-
state?: Record<string, unknown>;
|
|
130
|
-
window?: {
|
|
131
|
-
width?: number; // default: 800
|
|
132
|
-
height?: number; // default: 800
|
|
133
|
-
};
|
|
134
|
-
}
|
|
126
|
+
Router navigation hook with modifier key support.
|
|
135
127
|
|
|
136
|
-
|
|
128
|
+
```typescript
|
|
129
|
+
export function useRouterLink(): (
|
|
137
130
|
options: RouterLinkOptions,
|
|
138
131
|
) => (e: MouseEvent | KeyboardEvent) => void;
|
|
132
|
+
|
|
133
|
+
export interface RouterLinkOptions {
|
|
134
|
+
href: string;
|
|
135
|
+
state?: Record<string, unknown>;
|
|
136
|
+
window?: { width?: number; height?: number };
|
|
137
|
+
}
|
|
139
138
|
```
|
|
140
139
|
|
|
141
|
-
- Normal click: SPA routing via `useNavigate
|
|
142
|
-
- Ctrl/Alt + click:
|
|
143
|
-
- Shift + click:
|
|
140
|
+
- Normal click: SPA routing via `useNavigate`
|
|
141
|
+
- Ctrl/Alt + click: new tab
|
|
142
|
+
- Shift + click: new window with configurable size
|