@vobs/ui 0.3.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +60 -0
- package/package.json +52 -110
- package/src/activity-rail.ts +125 -0
- package/src/alert.ts +65 -0
- package/src/assets/icons/alert-circle.svg +1 -0
- package/src/assets/icons/alert-triangle.svg +1 -0
- package/src/assets/icons/alert.d27e24.svg +1 -0
- package/src/assets/icons/alert.svg +1 -0
- package/src/assets/icons/apple.svg +1 -0
- package/src/assets/icons/arrow-down.svg +1 -0
- package/src/assets/icons/arrow-expand.svg +1 -0
- package/src/assets/icons/arrow-left.svg +1 -0
- package/src/assets/icons/arrow-minimize.svg +1 -0
- package/src/assets/icons/arrow-right-to-line.svg +1 -0
- package/src/assets/icons/arrow-right.svg +1 -0
- package/src/assets/icons/arrow-up-right.svg +1 -0
- package/src/assets/icons/arrow-up.0c0c0d.svg +1 -0
- package/src/assets/icons/arrow-up.svg +1 -0
- package/src/assets/icons/at.svg +1 -0
- package/src/assets/icons/atom.0c0c0d.svg +1 -0
- package/src/assets/icons/atom.svg +1 -0
- package/src/assets/icons/bar.svg +1 -0
- package/src/assets/icons/bell.svg +1 -0
- package/src/assets/icons/box.svg +1 -0
- package/src/assets/icons/bug.svg +1 -0
- package/src/assets/icons/calendar.svg +1 -0
- package/src/assets/icons/check-circle.33c192.svg +1 -0
- package/src/assets/icons/check-circle.svg +1 -0
- package/src/assets/icons/check.d1d3db.svg +1 -0
- package/src/assets/icons/check.svg +1 -0
- package/src/assets/icons/chevron-down.svg +1 -0
- package/src/assets/icons/chevron-right.svg +1 -0
- package/src/assets/icons/chevron-up.svg +1 -0
- package/src/assets/icons/circle.svg +1 -0
- package/src/assets/icons/clock.svg +1 -0
- package/src/assets/icons/cmd.svg +1 -0
- package/src/assets/icons/code.svg +1 -0
- package/src/assets/icons/columns.svg +1 -0
- package/src/assets/icons/copy.svg +1 -0
- package/src/assets/icons/cpu.svg +1 -0
- package/src/assets/icons/dashboard.0c0c0d.svg +1 -0
- package/src/assets/icons/dashboard.svg +1 -0
- package/src/assets/icons/dollar.svg +1 -0
- package/src/assets/icons/download.svg +1 -0
- package/src/assets/icons/edit.svg +1 -0
- package/src/assets/icons/extensions.svg +1 -0
- package/src/assets/icons/external.svg +1 -0
- package/src/assets/icons/eye.svg +1 -0
- package/src/assets/icons/file-text.svg +1 -0
- package/src/assets/icons/file.svg +1 -0
- package/src/assets/icons/files.svg +1 -0
- package/src/assets/icons/filter.svg +1 -0
- package/src/assets/icons/folder.svg +1 -0
- package/src/assets/icons/gear.svg +1 -0
- package/src/assets/icons/git.svg +1 -0
- package/src/assets/icons/github.svg +1 -0
- package/src/assets/icons/globe.svg +1 -0
- package/src/assets/icons/grid-2x2.svg +1 -0
- package/src/assets/icons/hash.svg +1 -0
- package/src/assets/icons/heart.svg +1 -0
- package/src/assets/icons/help.svg +1 -0
- package/src/assets/icons/home.svg +1 -0
- package/src/assets/icons/image.svg +1 -0
- package/src/assets/icons/info-circle.svg +1 -0
- package/src/assets/icons/info-square.svg +1 -0
- package/src/assets/icons/info.387bff.svg +1 -0
- package/src/assets/icons/info.svg +1 -0
- package/src/assets/icons/key.svg +1 -0
- package/src/assets/icons/layers.svg +1 -0
- package/src/assets/icons/layout.svg +1 -0
- package/src/assets/icons/link.svg +1 -0
- package/src/assets/icons/list.svg +1 -0
- package/src/assets/icons/lock.svg +1 -0
- package/src/assets/icons/log-out.svg +1 -0
- package/src/assets/icons/logo.svg +1 -0
- package/src/assets/icons/mail.svg +1 -0
- package/src/assets/icons/menu.svg +1 -0
- package/src/assets/icons/message-circle.svg +1 -0
- package/src/assets/icons/message-plus.svg +1 -0
- package/src/assets/icons/message-square.svg +1 -0
- package/src/assets/icons/mic.svg +1 -0
- package/src/assets/icons/minus.svg +1 -0
- package/src/assets/icons/moon.svg +1 -0
- package/src/assets/icons/more-h.svg +1 -0
- package/src/assets/icons/mouse.svg +1 -0
- package/src/assets/icons/palette.svg +1 -0
- package/src/assets/icons/panel-bottom.svg +1 -0
- package/src/assets/icons/pause.svg +1 -0
- package/src/assets/icons/play.svg +1 -0
- package/src/assets/icons/plug.svg +1 -0
- package/src/assets/icons/plus.0c0c0d.svg +1 -0
- package/src/assets/icons/plus.svg +1 -0
- package/src/assets/icons/refresh.svg +1 -0
- package/src/assets/icons/ruler.svg +1 -0
- package/src/assets/icons/scroll-text.svg +1 -0
- package/src/assets/icons/search-menu.svg +1 -0
- package/src/assets/icons/search.svg +1 -0
- package/src/assets/icons/send.0c0c0d.svg +1 -0
- package/src/assets/icons/send.svg +1 -0
- package/src/assets/icons/settings.0c0c0d.svg +1 -0
- package/src/assets/icons/settings.svg +1 -0
- package/src/assets/icons/shield.svg +1 -0
- package/src/assets/icons/sidebar-left.svg +1 -0
- package/src/assets/icons/sidebar-right.svg +1 -0
- package/src/assets/icons/sliders.svg +1 -0
- package/src/assets/icons/sparkles.32f08c.svg +1 -0
- package/src/assets/icons/sparkles.svg +1 -0
- package/src/assets/icons/square.svg +1 -0
- package/src/assets/icons/star.svg +1 -0
- package/src/assets/icons/sun.svg +1 -0
- package/src/assets/icons/terminal.svg +1 -0
- package/src/assets/icons/trash.svg +1 -0
- package/src/assets/icons/trending-down.svg +1 -0
- package/src/assets/icons/trending-up.svg +1 -0
- package/src/assets/icons/type.svg +1 -0
- package/src/assets/icons/upload.svg +1 -0
- package/src/assets/icons/user-circle.svg +1 -0
- package/src/assets/icons/user.svg +1 -0
- package/src/assets/icons/users.svg +1 -0
- package/src/assets/icons/wrench.svg +1 -0
- package/src/assets/icons/x-circle.svg +1 -0
- package/src/assets/icons/x.svg +1 -0
- package/src/assets/icons/zap.0c0c0d.svg +1 -0
- package/src/assets/icons/zap.svg +1 -0
- package/src/avatar.ts +64 -0
- package/src/button.ts +88 -0
- package/src/card.ts +59 -0
- package/src/chat-composer.ts +156 -0
- package/src/dialog.ts +127 -0
- package/src/drawer.ts +131 -0
- package/src/editor-tabs.ts +184 -0
- package/src/file-tree.ts +214 -0
- package/src/forms.ts +270 -0
- package/src/icon.ts +117 -0
- package/src/icons.js +165 -0
- package/src/index.test.ts +213 -0
- package/src/index.ts +94 -0
- package/src/kbd.ts +72 -0
- package/src/menu.ts +119 -0
- package/src/nav-list.ts +157 -0
- package/src/overlay.test.ts +66 -0
- package/src/overlay.ts +205 -0
- package/src/page-header.ts +97 -0
- package/src/pagination.ts +163 -0
- package/src/second-batch.test.ts +205 -0
- package/src/stat-card.ts +92 -0
- package/src/status-bar.ts +108 -0
- package/src/styles/base.css +240 -0
- package/src/styles/components.css +1234 -0
- package/{dist → src/styles}/styles.css +2 -0
- package/src/styles/toast.css +57 -0
- package/src/styles/tokens.css +438 -0
- package/src/styles/vui.css +47 -0
- package/src/table.ts +191 -0
- package/src/tabs.ts +100 -0
- package/src/tag.ts +33 -0
- package/src/third-batch.test.ts +137 -0
- package/src/toast.test.ts +55 -0
- package/src/toast.ts +79 -0
- package/src/types.ts +25 -0
- package/src/utils.ts +221 -0
- package/src/workbench-titlebar.ts +137 -0
- package/dist/app-shell-dom.d.ts +0 -30
- package/dist/app-shell-dom.js +0 -913
- package/dist/app-shell.d.ts +0 -235
- package/dist/app-shell.js +0 -415
- package/dist/base.css +0 -51
- package/dist/calendar-picker.d.ts +0 -45
- package/dist/calendar-picker.js +0 -217
- package/dist/calendar.d.ts +0 -95
- package/dist/calendar.js +0 -194
- package/dist/complex-inputs.d.ts +0 -300
- package/dist/complex-inputs.js +0 -866
- package/dist/components.css +0 -4756
- package/dist/data-display.d.ts +0 -1094
- package/dist/data-display.js +0 -2341
- package/dist/dialog.d.ts +0 -26
- package/dist/dialog.js +0 -94
- package/dist/feedback.d.ts +0 -88
- package/dist/feedback.js +0 -281
- package/dist/forms.d.ts +0 -378
- package/dist/forms.js +0 -1019
- package/dist/icons-config.d.ts +0 -25
- package/dist/icons-config.js +0 -14
- package/dist/icons.d.ts +0 -41
- package/dist/icons.js +0 -185
- package/dist/index.d.ts +0 -31
- package/dist/index.js +0 -40
- package/dist/locale/en-US.d.ts +0 -31
- package/dist/locale/en-US.js +0 -20
- package/dist/locale/zh-CN.d.ts +0 -31
- package/dist/locale/zh-CN.js +0 -20
- package/dist/navigation.d.ts +0 -609
- package/dist/navigation.js +0 -1707
- package/dist/overlay.d.ts +0 -308
- package/dist/overlay.js +0 -974
- package/dist/page-state.d.ts +0 -23
- package/dist/page-state.js +0 -96
- package/dist/primitives.d.ts +0 -268
- package/dist/primitives.js +0 -764
- package/dist/theme-data.d.ts +0 -394
- package/dist/theme-data.js +0 -417
- package/dist/theme.d.ts +0 -97
- package/dist/theme.js +0 -301
- package/dist/tokens.css +0 -570
- package/dist/tree.d.ts +0 -144
- package/dist/tree.js +0 -475
- package/dist/virtual-list.d.ts +0 -190
- package/dist/virtual-list.js +0 -538
- package/dist/workbench.d.ts +0 -136
- package/dist/workbench.js +0 -156
package/dist/app-shell.d.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/** @license MIT
|
|
2
|
-
* Copyright (c) 2026 vobsjs
|
|
3
|
-
* @vobs/ui
|
|
4
|
-
*/
|
|
5
|
-
import { type UiAttributes, type UiDensity, type UiDomPlan } from './primitives.js';
|
|
6
|
-
import { type ReadonlySignal } from '@vobs/reactivity';
|
|
7
|
-
import { type I18nInstance } from '@vobs/i18n';
|
|
8
|
-
import { type RouteLocation } from '@vobs/router';
|
|
9
|
-
import type { TranslationAdapter } from '@vobs/runtime-core';
|
|
10
|
-
import { type ComponentProps, type InjectionKey } from '@vobs/runtime-dom';
|
|
11
|
-
import { type UiEnvironment } from './icons.js';
|
|
12
|
-
import type { BrandInput, ThemePreference } from './theme.js';
|
|
13
|
-
export type AppShellContentMode = 'contained' | 'scroll';
|
|
14
|
-
export type AppShellSidebarMode = 'collapsed' | 'expanded' | 'hidden';
|
|
15
|
-
export type AppShellNavItemTone = 'danger' | 'default' | 'success' | 'warning';
|
|
16
|
-
export interface AppShellTextConfig {
|
|
17
|
-
readonly key: string;
|
|
18
|
-
readonly fallback?: string;
|
|
19
|
-
}
|
|
20
|
-
export type AppShellText = string | AppShellTextConfig;
|
|
21
|
-
export interface AppShellNavItem {
|
|
22
|
-
readonly id: string;
|
|
23
|
-
readonly label: AppShellText;
|
|
24
|
-
readonly route?: string;
|
|
25
|
-
readonly href?: string;
|
|
26
|
-
readonly icon?: string;
|
|
27
|
-
readonly match?: string | readonly string[];
|
|
28
|
-
readonly active?: boolean;
|
|
29
|
-
readonly disabled?: boolean;
|
|
30
|
-
readonly badge?: string | number;
|
|
31
|
-
readonly tone?: AppShellNavItemTone;
|
|
32
|
-
readonly state?: string;
|
|
33
|
-
}
|
|
34
|
-
export interface AppShellAction {
|
|
35
|
-
readonly id: string;
|
|
36
|
-
readonly label: AppShellText;
|
|
37
|
-
readonly icon?: string;
|
|
38
|
-
readonly badge?: string | number;
|
|
39
|
-
readonly intent?: string;
|
|
40
|
-
readonly pressed?: boolean;
|
|
41
|
-
readonly disabled?: boolean;
|
|
42
|
-
}
|
|
43
|
-
export type AppShellAccountMenuItemTone = 'danger' | 'default';
|
|
44
|
-
export type AppShellAccountMenuItemKind = 'item' | 'separator';
|
|
45
|
-
export interface AppShellAccountMenuItem {
|
|
46
|
-
readonly id: string;
|
|
47
|
-
readonly label?: AppShellText;
|
|
48
|
-
readonly kind?: AppShellAccountMenuItemKind;
|
|
49
|
-
readonly route?: string;
|
|
50
|
-
readonly href?: string;
|
|
51
|
-
readonly icon?: string;
|
|
52
|
-
readonly disabled?: boolean;
|
|
53
|
-
readonly tone?: AppShellAccountMenuItemTone;
|
|
54
|
-
}
|
|
55
|
-
export interface AppShellBrandConfig {
|
|
56
|
-
readonly label: AppShellText;
|
|
57
|
-
readonly href?: string;
|
|
58
|
-
readonly mark?: string;
|
|
59
|
-
}
|
|
60
|
-
export interface AppShellNavigationConfig {
|
|
61
|
-
readonly primary?: readonly AppShellNavItem[];
|
|
62
|
-
readonly utility?: readonly AppShellNavItem[];
|
|
63
|
-
}
|
|
64
|
-
export interface AppShellAccountConfig {
|
|
65
|
-
readonly label: AppShellText;
|
|
66
|
-
readonly initials?: string;
|
|
67
|
-
readonly icon?: string;
|
|
68
|
-
readonly menu?: readonly AppShellAccountMenuItem[];
|
|
69
|
-
readonly menuExpanded?: boolean;
|
|
70
|
-
}
|
|
71
|
-
export interface AppShellLanguageOption {
|
|
72
|
-
readonly locale: string;
|
|
73
|
-
readonly label: AppShellText;
|
|
74
|
-
}
|
|
75
|
-
export interface AppShellLanguageConfig {
|
|
76
|
-
readonly label?: AppShellText;
|
|
77
|
-
readonly icon?: string;
|
|
78
|
-
readonly options: readonly AppShellLanguageOption[];
|
|
79
|
-
}
|
|
80
|
-
export interface AppShellTopbarConfig {
|
|
81
|
-
readonly actions?: readonly AppShellAction[];
|
|
82
|
-
readonly language?: AppShellLanguageConfig;
|
|
83
|
-
readonly account?: AppShellAccountConfig;
|
|
84
|
-
}
|
|
85
|
-
export interface AppShellPageHeaderConfig {
|
|
86
|
-
readonly visible?: boolean;
|
|
87
|
-
readonly kicker?: AppShellText;
|
|
88
|
-
readonly titleFallback?: AppShellText;
|
|
89
|
-
readonly descriptionFallback?: AppShellText;
|
|
90
|
-
}
|
|
91
|
-
export interface AppShellRoutePageHeaderConfig {
|
|
92
|
-
readonly visible?: boolean;
|
|
93
|
-
readonly kicker?: AppShellText;
|
|
94
|
-
readonly title?: AppShellText;
|
|
95
|
-
readonly description?: AppShellText;
|
|
96
|
-
}
|
|
97
|
-
export interface AppShellStatusbarConfig {
|
|
98
|
-
readonly text?: AppShellText;
|
|
99
|
-
readonly icon?: string;
|
|
100
|
-
readonly version?: AppShellText;
|
|
101
|
-
readonly pendingText?: AppShellText;
|
|
102
|
-
readonly pendingIcon?: string;
|
|
103
|
-
}
|
|
104
|
-
export interface AppShellThemeIconConfig {
|
|
105
|
-
readonly dark?: string;
|
|
106
|
-
readonly light?: string;
|
|
107
|
-
}
|
|
108
|
-
export interface AppShellThemeConfig {
|
|
109
|
-
readonly mode?: ThemePreference;
|
|
110
|
-
readonly brand?: BrandInput;
|
|
111
|
-
readonly brands?: readonly BrandInput[];
|
|
112
|
-
readonly icons?: AppShellThemeIconConfig;
|
|
113
|
-
readonly accent?: BrandInput;
|
|
114
|
-
readonly persist?: boolean;
|
|
115
|
-
}
|
|
116
|
-
export interface AppShellRouteConfig {
|
|
117
|
-
readonly path?: string;
|
|
118
|
-
readonly route?: string;
|
|
119
|
-
readonly title?: AppShellText;
|
|
120
|
-
readonly description?: AppShellText;
|
|
121
|
-
readonly status?: AppShellText;
|
|
122
|
-
readonly activeNav?: string;
|
|
123
|
-
readonly pageHeader?: false | AppShellRoutePageHeaderConfig;
|
|
124
|
-
}
|
|
125
|
-
export interface AppShellDefinition {
|
|
126
|
-
readonly id: string;
|
|
127
|
-
readonly title?: AppShellText;
|
|
128
|
-
readonly brand: AppShellBrandConfig;
|
|
129
|
-
readonly navigation?: AppShellNavigationConfig;
|
|
130
|
-
readonly routes?: readonly AppShellRouteConfig[];
|
|
131
|
-
readonly pageHeader?: AppShellPageHeaderConfig;
|
|
132
|
-
readonly topbar?: AppShellTopbarConfig;
|
|
133
|
-
readonly statusbar?: AppShellStatusbarConfig;
|
|
134
|
-
readonly sidebarMode?: AppShellSidebarMode;
|
|
135
|
-
readonly contentMode?: AppShellContentMode;
|
|
136
|
-
readonly theme?: AppShellThemeConfig;
|
|
137
|
-
readonly className?: string;
|
|
138
|
-
}
|
|
139
|
-
export type AppShellDefinitionRecord = Readonly<Record<string, Omit<AppShellDefinition, 'id'> & {
|
|
140
|
-
readonly id?: string;
|
|
141
|
-
}>>;
|
|
142
|
-
export type AppShellConfigInput = AppShellDefinition | readonly AppShellDefinition[] | AppShellDefinitionRecord;
|
|
143
|
-
export interface AppShellRegistry {
|
|
144
|
-
readonly shells: readonly AppShellDefinition[];
|
|
145
|
-
get(id: string): AppShellDefinition | undefined;
|
|
146
|
-
}
|
|
147
|
-
export interface UiAppShellEnvironment {
|
|
148
|
-
readonly appShells: AppShellRegistry;
|
|
149
|
-
}
|
|
150
|
-
export interface UiAppShellProviderContext {
|
|
151
|
-
provide<T>(key: InjectionKey<T>, value: T): () => void;
|
|
152
|
-
}
|
|
153
|
-
export interface AppShellProps {
|
|
154
|
-
readonly shell?: string;
|
|
155
|
-
}
|
|
156
|
-
export interface ResolvedAppShellState {
|
|
157
|
-
readonly activeId: string | undefined;
|
|
158
|
-
readonly title: string;
|
|
159
|
-
readonly description: string;
|
|
160
|
-
readonly status: string;
|
|
161
|
-
readonly page: AppShellRouteConfig | undefined;
|
|
162
|
-
readonly pageHeader: ResolvedAppShellPageHeader;
|
|
163
|
-
}
|
|
164
|
-
export interface ResolvedAppShellPageHeader {
|
|
165
|
-
readonly visible: boolean;
|
|
166
|
-
readonly kicker: string;
|
|
167
|
-
readonly title: string;
|
|
168
|
-
readonly description: string;
|
|
169
|
-
}
|
|
170
|
-
export interface ResolvedAppShellStatus {
|
|
171
|
-
readonly state: 'idle' | 'pending';
|
|
172
|
-
readonly text: string;
|
|
173
|
-
readonly icon?: string;
|
|
174
|
-
}
|
|
175
|
-
export declare const UiAppShellEnvironmentKey: InjectionKey<UiAppShellEnvironment>;
|
|
176
|
-
export declare function defineAppShell<const Shell extends AppShellDefinition>(shell: Shell): Shell;
|
|
177
|
-
export declare function defineAppShellConfig<const Config extends AppShellConfigInput>(config: Config): Config;
|
|
178
|
-
export declare function createAppShellRegistry(config: AppShellConfigInput): AppShellRegistry;
|
|
179
|
-
export declare function provideUiAppShells(context: UiAppShellProviderContext, config: AppShellConfigInput): () => void;
|
|
180
|
-
export declare function resolveAppShellState(shell: AppShellDefinition, route: RouteLocation | string | null | undefined, translate?: (key: string) => string): ResolvedAppShellState;
|
|
181
|
-
export declare function resolveAppShellStatus(shell: AppShellDefinition, route: RouteLocation | string | null | undefined, pendingRoute: RouteLocation | string | null | undefined, translate?: (key: string) => string): ResolvedAppShellStatus;
|
|
182
|
-
export declare function resolveAppShellText(value: AppShellText | undefined, translate?: (key: string) => string): string | undefined;
|
|
183
|
-
export declare function resolveActiveAppShellNavItemId(routePath: string | undefined, items: readonly AppShellNavItem[], activeNav: string | undefined): string | undefined;
|
|
184
|
-
export declare const AppShell: import("@vobs/runtime-core").ComponentDefinition<AppShellProps, Record<string, never>, AppShellComponentScope, Readonly<Record<string, Readonly<Record<string, unknown>>>>>;
|
|
185
|
-
export interface AppShellComponentScope {
|
|
186
|
-
readonly props: ComponentProps<AppShellProps>;
|
|
187
|
-
readonly appShells: AppShellRegistry;
|
|
188
|
-
readonly icons: UiEnvironment;
|
|
189
|
-
readonly i18n: I18nInstance | undefined;
|
|
190
|
-
readonly translation: TranslationAdapter | undefined;
|
|
191
|
-
readonly currentRoute: ReadonlySignal<RouteLocation | null>;
|
|
192
|
-
readonly pendingRoute: ReadonlySignal<RouteLocation | null>;
|
|
193
|
-
}
|
|
194
|
-
export interface AppShellPlanOptions {
|
|
195
|
-
readonly id?: string;
|
|
196
|
-
readonly brandLabel: string;
|
|
197
|
-
readonly brandHref?: string;
|
|
198
|
-
readonly navItems: readonly AppShellNavItem[];
|
|
199
|
-
readonly utilityItems?: readonly AppShellNavItem[];
|
|
200
|
-
readonly actions?: readonly AppShellAction[];
|
|
201
|
-
readonly activeId?: string;
|
|
202
|
-
readonly sidebarMode?: AppShellSidebarMode;
|
|
203
|
-
readonly contentMode?: AppShellContentMode;
|
|
204
|
-
readonly pageHeaderVisible?: boolean;
|
|
205
|
-
readonly title?: string;
|
|
206
|
-
readonly subtitle?: string;
|
|
207
|
-
readonly commandLabel?: string;
|
|
208
|
-
readonly commandShortcut?: string;
|
|
209
|
-
readonly density?: UiDensity;
|
|
210
|
-
readonly className?: string;
|
|
211
|
-
readonly attrs?: UiAttributes;
|
|
212
|
-
}
|
|
213
|
-
export interface AppShellPlans {
|
|
214
|
-
readonly root: UiDomPlan<'div'>;
|
|
215
|
-
readonly sidebar: UiDomPlan<'aside'>;
|
|
216
|
-
readonly brand: UiDomPlan<'a'>;
|
|
217
|
-
readonly nav: UiDomPlan<'nav'>;
|
|
218
|
-
readonly navItems: readonly UiDomPlan<'a'>[];
|
|
219
|
-
readonly navBadges: readonly UiDomPlan<'span'>[];
|
|
220
|
-
readonly utilityNav: UiDomPlan<'nav'> | undefined;
|
|
221
|
-
readonly utilityItems: readonly UiDomPlan<'a'>[];
|
|
222
|
-
readonly topbar: UiDomPlan<'header'>;
|
|
223
|
-
readonly commandTrigger: UiDomPlan<'button'> | undefined;
|
|
224
|
-
readonly actions: readonly UiDomPlan<'button'>[];
|
|
225
|
-
readonly main: UiDomPlan<'main'>;
|
|
226
|
-
readonly pageFrame: UiDomPlan<'section'>;
|
|
227
|
-
readonly pageHeader: UiDomPlan<'header'>;
|
|
228
|
-
readonly pageTitle: UiDomPlan<'h1'> | undefined;
|
|
229
|
-
readonly pageSubtitle: UiDomPlan<'p'> | undefined;
|
|
230
|
-
readonly pageToolbar: UiDomPlan<'div'>;
|
|
231
|
-
readonly pageBody: UiDomPlan<'section'>;
|
|
232
|
-
}
|
|
233
|
-
export declare function createAppShellPlans(options: AppShellPlanOptions): AppShellPlans;
|
|
234
|
-
export declare function resolveAppShellSidebarMode(viewportWidth: number, preferred?: AppShellSidebarMode): AppShellSidebarMode;
|
|
235
|
-
export declare function getNextAppShellNavItemId(items: readonly AppShellNavItem[], activeId: string | undefined, key: string): string | undefined;
|
package/dist/app-shell.js
DELETED
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
/** @license MIT
|
|
2
|
-
* Copyright (c) 2026 vobsjs
|
|
3
|
-
* @vobs/ui
|
|
4
|
-
*/
|
|
5
|
-
import { createUiDomPlan, } from './primitives.js';
|
|
6
|
-
import { effect, signal } from '@vobs/reactivity';
|
|
7
|
-
import { I18nKey } from '@vobs/i18n';
|
|
8
|
-
import { CurrentRouteKey, PendingRouteKey } from '@vobs/router';
|
|
9
|
-
import { createCompiledTemplate, createInjectionKey, createRuntimeError, defineComponent, mountSlot, TranslationAdapterKey, } from '@vobs/runtime-dom';
|
|
10
|
-
import { bindAppShellAccountMenu, bindAppShellActions, bindAppShellLanguageMenu, bindAppShellThemeControls, createAppShellFrame, syncAppShellFrame, } from './app-shell-dom.js';
|
|
11
|
-
import { createUiEnvironment, UiIconEnvironmentKey } from './icons.js';
|
|
12
|
-
export const UiAppShellEnvironmentKey = createInjectionKey('vobs.ui.appShells');
|
|
13
|
-
export function defineAppShell(shell) {
|
|
14
|
-
return shell;
|
|
15
|
-
}
|
|
16
|
-
export function defineAppShellConfig(config) {
|
|
17
|
-
return config;
|
|
18
|
-
}
|
|
19
|
-
export function createAppShellRegistry(config) {
|
|
20
|
-
const shells = normalizeAppShellConfig(config);
|
|
21
|
-
const map = new Map(shells.map((shell) => [shell.id, shell]));
|
|
22
|
-
return {
|
|
23
|
-
shells,
|
|
24
|
-
get(id) {
|
|
25
|
-
return map.get(id);
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export function provideUiAppShells(context, config) {
|
|
30
|
-
return context.provide(UiAppShellEnvironmentKey, {
|
|
31
|
-
appShells: createAppShellRegistry(config),
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
export function resolveAppShellState(shell, route, translate) {
|
|
35
|
-
const routePath = typeof route === 'string' ? route : route?.path;
|
|
36
|
-
const page = resolveAppShellPage(shell, routePath);
|
|
37
|
-
const navItems = collectAppShellNavItems(shell);
|
|
38
|
-
const activeId = resolveActiveAppShellNavItemId(routePath, navItems, page?.activeNav);
|
|
39
|
-
const pageHeader = resolveAppShellPageHeader(shell, page, translate);
|
|
40
|
-
return {
|
|
41
|
-
activeId,
|
|
42
|
-
title: pageHeader.title,
|
|
43
|
-
description: pageHeader.description,
|
|
44
|
-
status: resolveAppShellText(page?.status ?? shell.statusbar?.text, translate) ?? '',
|
|
45
|
-
page,
|
|
46
|
-
pageHeader,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
export function resolveAppShellStatus(shell, route, pendingRoute, translate) {
|
|
50
|
-
if (pendingRoute !== null && pendingRoute !== undefined) {
|
|
51
|
-
const pending = resolveAppShellState(shell, pendingRoute, translate);
|
|
52
|
-
const textBase = resolveAppShellText(shell.statusbar?.pendingText, translate) ?? 'Loading';
|
|
53
|
-
return {
|
|
54
|
-
state: 'pending',
|
|
55
|
-
text: pending.title.length === 0 ? textBase : `${textBase} ${pending.title}`,
|
|
56
|
-
...(shell.statusbar?.pendingIcon === undefined && shell.statusbar?.icon === undefined
|
|
57
|
-
? {}
|
|
58
|
-
: { icon: shell.statusbar?.pendingIcon ?? shell.statusbar?.icon }),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
const current = resolveAppShellState(shell, route, translate);
|
|
62
|
-
return {
|
|
63
|
-
state: 'idle',
|
|
64
|
-
text: current.status || resolveAppShellText(shell.statusbar?.text, translate) || '',
|
|
65
|
-
...(shell.statusbar?.icon === undefined ? {} : { icon: shell.statusbar.icon }),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
export function resolveAppShellText(value, translate) {
|
|
69
|
-
if (value === undefined)
|
|
70
|
-
return undefined;
|
|
71
|
-
if (typeof value === 'string')
|
|
72
|
-
return value;
|
|
73
|
-
return translate?.(value.key) ?? value.fallback ?? value.key;
|
|
74
|
-
}
|
|
75
|
-
export function resolveActiveAppShellNavItemId(routePath, items, activeNav) {
|
|
76
|
-
if (activeNav !== undefined && items.some((item) => item.id === activeNav))
|
|
77
|
-
return activeNav;
|
|
78
|
-
if (routePath === undefined)
|
|
79
|
-
return items.find((item) => item.active === true)?.id;
|
|
80
|
-
const path = normalizeRoutePath(routePath);
|
|
81
|
-
const patternMatched = items.find((item) => {
|
|
82
|
-
const patterns = normalizeMatchPatterns(item.match);
|
|
83
|
-
return patterns.some((pattern) => matchRoutePattern(pattern, path));
|
|
84
|
-
});
|
|
85
|
-
if (patternMatched !== undefined)
|
|
86
|
-
return patternMatched.id;
|
|
87
|
-
let best;
|
|
88
|
-
for (const item of items) {
|
|
89
|
-
const href = routeItemPath(item);
|
|
90
|
-
if (href === undefined)
|
|
91
|
-
continue;
|
|
92
|
-
if (path !== href && !path.startsWith(`${href}/`))
|
|
93
|
-
continue;
|
|
94
|
-
if (best === undefined || href.length > best.length) {
|
|
95
|
-
best = { id: item.id, length: href.length };
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return best?.id;
|
|
99
|
-
}
|
|
100
|
-
export const AppShell = defineComponent({
|
|
101
|
-
template: createCompiledTemplate({
|
|
102
|
-
templateId: 'k-app-shell',
|
|
103
|
-
sourceId: '@vobs/ui/app-shell',
|
|
104
|
-
rootTag: 'div',
|
|
105
|
-
mount(owner, scope, environment) {
|
|
106
|
-
return mountAppShell(owner, scope, environment);
|
|
107
|
-
},
|
|
108
|
-
}),
|
|
109
|
-
props: ['shell'],
|
|
110
|
-
setup(context) {
|
|
111
|
-
const currentRoute = context.maybeInject(CurrentRouteKey) ?? signal(null);
|
|
112
|
-
const pendingRoute = context.maybeInject(PendingRouteKey) ?? signal(null);
|
|
113
|
-
const appShellEnvironment = context.maybeInject(UiAppShellEnvironmentKey);
|
|
114
|
-
if (appShellEnvironment === undefined) {
|
|
115
|
-
throw createRuntimeError('KUI010', 'App shell config is not provided');
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
props: context.props,
|
|
119
|
-
appShells: appShellEnvironment.appShells,
|
|
120
|
-
icons: context.maybeInject(UiIconEnvironmentKey) ?? createUiEnvironment(),
|
|
121
|
-
i18n: context.maybeInject(I18nKey),
|
|
122
|
-
translation: context.maybeInject(TranslationAdapterKey),
|
|
123
|
-
currentRoute,
|
|
124
|
-
pendingRoute,
|
|
125
|
-
};
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
export function createAppShellPlans(options) {
|
|
129
|
-
const sidebarMode = options.sidebarMode ?? 'expanded';
|
|
130
|
-
const activeId = options.activeId ?? options.navItems.find((item) => item.active === true)?.id;
|
|
131
|
-
const utilityItems = options.utilityItems ?? [];
|
|
132
|
-
return {
|
|
133
|
-
root: createUiDomPlan('div', 'app-shell', {
|
|
134
|
-
...(options.className === undefined ? {} : { className: options.className }),
|
|
135
|
-
...(options.density === undefined ? {} : { density: options.density }),
|
|
136
|
-
state: sidebarMode,
|
|
137
|
-
attrs: {
|
|
138
|
-
id: options.id,
|
|
139
|
-
...options.attrs,
|
|
140
|
-
'data-sidebar-mode': sidebarMode,
|
|
141
|
-
'data-content-mode': options.contentMode ?? 'contained',
|
|
142
|
-
},
|
|
143
|
-
}),
|
|
144
|
-
sidebar: createUiDomPlan('aside', 'app-shell-sidebar', {
|
|
145
|
-
state: sidebarMode,
|
|
146
|
-
attrs: {
|
|
147
|
-
id: options.id === undefined ? undefined : `${options.id}-sidebar`,
|
|
148
|
-
'aria-label': 'Primary',
|
|
149
|
-
'data-sidebar-mode': sidebarMode,
|
|
150
|
-
},
|
|
151
|
-
}),
|
|
152
|
-
brand: createUiDomPlan('a', 'app-shell-brand', {
|
|
153
|
-
attrs: {
|
|
154
|
-
href: options.brandHref ?? '#',
|
|
155
|
-
'aria-label': options.brandLabel,
|
|
156
|
-
'data-label': options.brandLabel,
|
|
157
|
-
},
|
|
158
|
-
}),
|
|
159
|
-
nav: createUiDomPlan('nav', 'app-shell-nav', {
|
|
160
|
-
attrs: {
|
|
161
|
-
'aria-label': 'Primary navigation',
|
|
162
|
-
'data-count': options.navItems.length,
|
|
163
|
-
},
|
|
164
|
-
}),
|
|
165
|
-
navItems: options.navItems.map((item) => createNavItemPlan(options, item, activeId)),
|
|
166
|
-
navBadges: options.navItems.map((item) => createNavBadgePlan(item)),
|
|
167
|
-
utilityNav: utilityItems.length === 0
|
|
168
|
-
? undefined
|
|
169
|
-
: createUiDomPlan('nav', 'app-shell-utility-nav', {
|
|
170
|
-
attrs: {
|
|
171
|
-
'aria-label': 'Utility navigation',
|
|
172
|
-
'data-count': utilityItems.length,
|
|
173
|
-
},
|
|
174
|
-
}),
|
|
175
|
-
utilityItems: utilityItems.map((item) => createNavItemPlan(options, item, activeId)),
|
|
176
|
-
topbar: createUiDomPlan('header', 'app-shell-topbar', {
|
|
177
|
-
attrs: {
|
|
178
|
-
id: options.id === undefined ? undefined : `${options.id}-topbar`,
|
|
179
|
-
'data-action-count': options.actions?.length ?? 0,
|
|
180
|
-
},
|
|
181
|
-
}),
|
|
182
|
-
commandTrigger: options.commandLabel === undefined
|
|
183
|
-
? undefined
|
|
184
|
-
: createUiDomPlan('button', 'app-shell-command-trigger', {
|
|
185
|
-
attrs: {
|
|
186
|
-
type: 'button',
|
|
187
|
-
'aria-label': options.commandLabel,
|
|
188
|
-
'data-label': options.commandLabel,
|
|
189
|
-
'data-shortcut': options.commandShortcut,
|
|
190
|
-
},
|
|
191
|
-
}),
|
|
192
|
-
actions: (options.actions ?? []).map((action) => createUiDomPlan('button', 'app-shell-action', {
|
|
193
|
-
...(action.disabled === undefined ? {} : { disabled: action.disabled }),
|
|
194
|
-
state: action.disabled === true ? 'disabled' : action.pressed === true ? 'pressed' : 'idle',
|
|
195
|
-
attrs: {
|
|
196
|
-
type: 'button',
|
|
197
|
-
'aria-label': resolveAppShellText(action.label),
|
|
198
|
-
'aria-pressed': action.pressed === undefined ? undefined : action.pressed ? 'true' : 'false',
|
|
199
|
-
'data-action-id': action.id,
|
|
200
|
-
'data-label': resolveAppShellText(action.label),
|
|
201
|
-
},
|
|
202
|
-
})),
|
|
203
|
-
main: createUiDomPlan('main', 'app-shell-main', {
|
|
204
|
-
attrs: {
|
|
205
|
-
id: options.id === undefined ? undefined : `${options.id}-main`,
|
|
206
|
-
},
|
|
207
|
-
}),
|
|
208
|
-
pageFrame: createUiDomPlan('section', 'app-shell-page-frame'),
|
|
209
|
-
pageHeader: createUiDomPlan('header', 'app-shell-page-header', {
|
|
210
|
-
state: options.pageHeaderVisible === false ? 'hidden' : 'visible',
|
|
211
|
-
attrs: {
|
|
212
|
-
hidden: options.pageHeaderVisible === false,
|
|
213
|
-
'aria-hidden': options.pageHeaderVisible === false ? 'true' : undefined,
|
|
214
|
-
},
|
|
215
|
-
}),
|
|
216
|
-
pageTitle: options.title === undefined
|
|
217
|
-
? undefined
|
|
218
|
-
: createUiDomPlan('h1', 'app-shell-page-title', {
|
|
219
|
-
attrs: { 'data-title': options.title },
|
|
220
|
-
}),
|
|
221
|
-
pageSubtitle: options.subtitle === undefined
|
|
222
|
-
? undefined
|
|
223
|
-
: createUiDomPlan('p', 'app-shell-page-subtitle', {
|
|
224
|
-
attrs: { 'data-subtitle': options.subtitle },
|
|
225
|
-
}),
|
|
226
|
-
pageToolbar: createUiDomPlan('div', 'app-shell-page-toolbar', {
|
|
227
|
-
attrs: { role: 'toolbar' },
|
|
228
|
-
}),
|
|
229
|
-
pageBody: createUiDomPlan('section', 'app-shell-page-body', {
|
|
230
|
-
state: options.contentMode ?? 'contained',
|
|
231
|
-
attrs: {
|
|
232
|
-
'data-mode': options.contentMode ?? 'contained',
|
|
233
|
-
},
|
|
234
|
-
}),
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
export function resolveAppShellSidebarMode(viewportWidth, preferred = 'expanded') {
|
|
238
|
-
if (!Number.isFinite(viewportWidth) || viewportWidth < 768)
|
|
239
|
-
return 'hidden';
|
|
240
|
-
if (viewportWidth < 1100)
|
|
241
|
-
return preferred === 'hidden' ? 'hidden' : 'collapsed';
|
|
242
|
-
return preferred;
|
|
243
|
-
}
|
|
244
|
-
export function getNextAppShellNavItemId(items, activeId, key) {
|
|
245
|
-
const enabled = items.filter((item) => item.disabled !== true);
|
|
246
|
-
if (enabled.length === 0)
|
|
247
|
-
return activeId;
|
|
248
|
-
const currentIndex = Math.max(-1, enabled.findIndex((item) => item.id === activeId));
|
|
249
|
-
if (key === 'Home')
|
|
250
|
-
return enabled[0]?.id;
|
|
251
|
-
if (key === 'End')
|
|
252
|
-
return enabled.at(-1)?.id;
|
|
253
|
-
if (key === 'ArrowUp')
|
|
254
|
-
return enabled.at(currentIndex - 1)?.id ?? enabled.at(-1)?.id;
|
|
255
|
-
if (key === 'ArrowDown')
|
|
256
|
-
return enabled[(currentIndex + 1) % enabled.length]?.id;
|
|
257
|
-
return activeId;
|
|
258
|
-
}
|
|
259
|
-
function createNavItemPlan(options, item, activeId) {
|
|
260
|
-
const active = item.id === activeId || item.active === true;
|
|
261
|
-
return createUiDomPlan('a', 'app-shell-nav-item', {
|
|
262
|
-
...(item.disabled === undefined ? {} : { disabled: item.disabled }),
|
|
263
|
-
state: item.disabled === true ? 'disabled' : active ? 'active' : 'idle',
|
|
264
|
-
attrs: {
|
|
265
|
-
id: options.id === undefined ? undefined : `${options.id}-${item.id}-nav`,
|
|
266
|
-
href: item.disabled === true ? undefined : (item.href ?? item.route ?? '#'),
|
|
267
|
-
'aria-current': active ? 'page' : undefined,
|
|
268
|
-
tabindex: active && item.disabled !== true ? 0 : -1,
|
|
269
|
-
'data-nav-id': item.id,
|
|
270
|
-
'data-label': resolveAppShellText(item.label),
|
|
271
|
-
'data-tone': item.tone ?? 'default',
|
|
272
|
-
'data-has-badge': item.badge === undefined ? undefined : 'true',
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
function createNavBadgePlan(item) {
|
|
277
|
-
return createUiDomPlan('span', 'app-shell-nav-badge', {
|
|
278
|
-
attrs: {
|
|
279
|
-
'aria-hidden': 'true',
|
|
280
|
-
'data-value': item.badge,
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
function mountAppShell(owner, scope, environment) {
|
|
285
|
-
const shell = readAppShell(scope);
|
|
286
|
-
const frame = createAppShellFrame(shell, scope, environment);
|
|
287
|
-
const pageBody = frame.root.querySelector('.kui-app-shell-page-body');
|
|
288
|
-
if (pageBody !== null) {
|
|
289
|
-
mountSlot(owner, pageBody, 'default', environment.slots?.default, undefined);
|
|
290
|
-
}
|
|
291
|
-
bindAppShellThemeControls(owner, frame, shell, scope, environment);
|
|
292
|
-
bindAppShellActions(owner, frame, shell);
|
|
293
|
-
bindAppShellAccountMenu(owner, frame, shell);
|
|
294
|
-
bindAppShellLanguageMenu(owner, frame, shell, scope, environment);
|
|
295
|
-
syncAppShellFrame(frame, shell, resolveShellState(shell, scope), resolveShellStatus(shell, scope), scope, environment);
|
|
296
|
-
owner.run(() => {
|
|
297
|
-
const stop = effect(() => {
|
|
298
|
-
void scope.translation?.locale?.value;
|
|
299
|
-
const state = resolveShellState(shell, scope);
|
|
300
|
-
const status = resolveShellStatus(shell, scope);
|
|
301
|
-
syncAppShellFrame(frame, shell, state, status, scope, environment);
|
|
302
|
-
}, { scheduler: environment.scheduler });
|
|
303
|
-
owner.own(stop);
|
|
304
|
-
});
|
|
305
|
-
return { root: frame.root, refs: {} };
|
|
306
|
-
}
|
|
307
|
-
function resolveShellState(shell, scope) {
|
|
308
|
-
return resolveAppShellState(shell, scope.currentRoute.value, appShellTranslate(scope));
|
|
309
|
-
}
|
|
310
|
-
function resolveShellStatus(shell, scope) {
|
|
311
|
-
return resolveAppShellStatus(shell, scope.currentRoute.value, scope.pendingRoute.value, appShellTranslate(scope));
|
|
312
|
-
}
|
|
313
|
-
function appShellTranslate(scope) {
|
|
314
|
-
const translation = scope.translation;
|
|
315
|
-
return translation === undefined ? undefined : (key) => translation.t(key);
|
|
316
|
-
}
|
|
317
|
-
function readAppShell(scope) {
|
|
318
|
-
const id = readOptionalString(scope.props.shell?.value);
|
|
319
|
-
if (id === undefined)
|
|
320
|
-
throw createRuntimeError('KUI011', 'App shell requires `shell`');
|
|
321
|
-
const shell = scope.appShells.get(id);
|
|
322
|
-
if (shell === undefined)
|
|
323
|
-
throw createRuntimeError('KUI012', `App shell is not registered: ${id}`);
|
|
324
|
-
return shell;
|
|
325
|
-
}
|
|
326
|
-
function normalizeAppShellConfig(config) {
|
|
327
|
-
if (Array.isArray(config)) {
|
|
328
|
-
const list = config;
|
|
329
|
-
return list;
|
|
330
|
-
}
|
|
331
|
-
if ('brand' in config && typeof config.id === 'string') {
|
|
332
|
-
const single = config;
|
|
333
|
-
return [single];
|
|
334
|
-
}
|
|
335
|
-
const record = config;
|
|
336
|
-
const definitions = [];
|
|
337
|
-
for (const id of Object.keys(record)) {
|
|
338
|
-
const shell = record[id];
|
|
339
|
-
if (shell === undefined)
|
|
340
|
-
continue;
|
|
341
|
-
definitions.push(shell.id === undefined ? { ...shell, id } : shell);
|
|
342
|
-
}
|
|
343
|
-
return definitions;
|
|
344
|
-
}
|
|
345
|
-
function collectAppShellNavItems(shell) {
|
|
346
|
-
return [...(shell.navigation?.primary ?? []), ...(shell.navigation?.utility ?? [])];
|
|
347
|
-
}
|
|
348
|
-
function resolveAppShellPage(shell, routePath) {
|
|
349
|
-
if (routePath === undefined)
|
|
350
|
-
return undefined;
|
|
351
|
-
const path = normalizeRoutePath(routePath);
|
|
352
|
-
return [...(shell.routes ?? [])]
|
|
353
|
-
.map((page) => ({ page, score: scoreRoutePattern(page.path ?? page.route, path) }))
|
|
354
|
-
.filter((candidate) => candidate.score >= 0)
|
|
355
|
-
.sort((left, right) => right.score - left.score)[0]?.page;
|
|
356
|
-
}
|
|
357
|
-
function resolveAppShellPageHeader(shell, page, translate) {
|
|
358
|
-
const routeHeader = page?.pageHeader;
|
|
359
|
-
const header = routeHeader === false ? undefined : routeHeader;
|
|
360
|
-
const title = resolveAppShellText(header?.title ?? page?.title ?? shell.pageHeader?.titleFallback ?? shell.title, translate) ?? '';
|
|
361
|
-
const description = resolveAppShellText(header?.description ?? page?.description ?? shell.pageHeader?.descriptionFallback, translate) ?? '';
|
|
362
|
-
return {
|
|
363
|
-
visible: routeHeader === false ? false : (header?.visible ?? shell.pageHeader?.visible ?? true),
|
|
364
|
-
kicker: resolveAppShellText(header?.kicker ?? shell.pageHeader?.kicker ?? shell.title, translate) ??
|
|
365
|
-
resolveAppShellText(shell.brand.label, translate) ??
|
|
366
|
-
'',
|
|
367
|
-
title,
|
|
368
|
-
description,
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
function scoreRoutePattern(pattern, path) {
|
|
372
|
-
if (pattern === undefined)
|
|
373
|
-
return -1;
|
|
374
|
-
if (!matchRoutePattern(pattern, path))
|
|
375
|
-
return -1;
|
|
376
|
-
const normalized = normalizeRoutePath(pattern);
|
|
377
|
-
const staticSegments = normalized.split('/').filter((segment) => !isDynamicSegment(segment));
|
|
378
|
-
return normalized.length + staticSegments.length * 10;
|
|
379
|
-
}
|
|
380
|
-
function matchRoutePattern(pattern, routePath) {
|
|
381
|
-
const patternSegments = normalizeRoutePath(pattern).split('/').filter(Boolean);
|
|
382
|
-
const routeSegments = normalizeRoutePath(routePath).split('/').filter(Boolean);
|
|
383
|
-
for (let index = 0; index < patternSegments.length; index += 1) {
|
|
384
|
-
const segment = patternSegments[index];
|
|
385
|
-
if (segment === '*')
|
|
386
|
-
return true;
|
|
387
|
-
if (routeSegments[index] === undefined)
|
|
388
|
-
return false;
|
|
389
|
-
if (segment !== undefined && !isDynamicSegment(segment) && segment !== routeSegments[index]) {
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
return patternSegments.length === routeSegments.length;
|
|
394
|
-
}
|
|
395
|
-
function isDynamicSegment(segment) {
|
|
396
|
-
return segment !== undefined && (segment.startsWith(':') || /^\[[^\]]+\]$/u.test(segment));
|
|
397
|
-
}
|
|
398
|
-
function normalizeMatchPatterns(match) {
|
|
399
|
-
if (match === undefined)
|
|
400
|
-
return [];
|
|
401
|
-
return typeof match === 'string' ? [match] : match;
|
|
402
|
-
}
|
|
403
|
-
function routeItemPath(item) {
|
|
404
|
-
const path = item.route ?? item.href;
|
|
405
|
-
return path === undefined ? undefined : normalizeRoutePath(path);
|
|
406
|
-
}
|
|
407
|
-
function normalizeRoutePath(path) {
|
|
408
|
-
const [withoutHash] = path.split('#', 1);
|
|
409
|
-
const [withoutQuery] = (withoutHash ?? path).split('?', 1);
|
|
410
|
-
const normalized = withoutQuery === '' ? '/' : (withoutQuery ?? '/');
|
|
411
|
-
return normalized.length > 1 ? normalized.replace(/\/+$/u, '') : normalized;
|
|
412
|
-
}
|
|
413
|
-
function readOptionalString(value) {
|
|
414
|
-
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
415
|
-
}
|