@svadmin/ui 0.46.0 → 0.48.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/dist/components/AboutSettings.svelte +21 -96
- package/dist/components/AdminApp.svelte +20 -0
- package/dist/components/AdminApp.svelte.d.ts +5 -1
- package/dist/components/ApiSettings.svelte +153 -246
- package/dist/components/AppearanceSettings.svelte +36 -165
- package/dist/components/AutoForm.svelte +21 -3
- package/dist/components/DetailDrawer.svelte +74 -0
- package/dist/components/DetailDrawer.svelte.d.ts +16 -0
- package/dist/components/FieldRenderer.svelte +70 -2
- package/dist/components/FieldRenderer.svelte.d.ts +2 -0
- package/dist/components/IntegrationsSettings.svelte +22 -61
- package/dist/components/Layout.svelte +15 -1
- package/dist/components/NotificationsSettings.svelte +22 -103
- package/dist/components/PasswordInput.svelte +4 -0
- package/dist/components/PasswordInput.svelte.d.ts +1 -0
- package/dist/components/PermissionMatrix.svelte +17 -8
- package/dist/components/RowActions.svelte +154 -0
- package/dist/components/RowActions.svelte.d.ts +26 -0
- package/dist/components/SecuritySettings.svelte +165 -140
- package/dist/components/SecuritySettings.svelte.d.ts +1 -2
- package/dist/components/SettingsPage.svelte +12 -2
- package/dist/components/account/CompanyProfilePage.svelte +10 -4
- package/dist/components/account/SettingsEnterprisePage.svelte +227 -23
- package/dist/components/account/SettingsSidebarPage.svelte +12 -1
- package/dist/components/account/UserProfilePage.svelte +5 -4
- package/dist/components/content/ApiKeyList.svelte +30 -5
- package/dist/components/content/ApiKeyList.svelte.d.ts +3 -0
- package/dist/components/content/WorkspaceLayout.svelte +7 -4
- package/dist/components/content/WorkspaceLayout.svelte.d.ts +1 -0
- package/dist/components/ui/sheet/sheet.svelte +122 -10
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/package.json +5 -2
|
@@ -1,8 +1,51 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
let bodyScrollLockDepth = 0;
|
|
3
|
+
let bodyOverflowBeforeLock = "";
|
|
4
|
+
const openSheets: HTMLElement[] = [];
|
|
5
|
+
|
|
6
|
+
function lockBodyScroll() {
|
|
7
|
+
if (bodyScrollLockDepth === 0) bodyOverflowBeforeLock = document.body.style.overflow;
|
|
8
|
+
bodyScrollLockDepth += 1;
|
|
9
|
+
document.body.style.overflow = "hidden";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function unlockBodyScroll() {
|
|
13
|
+
bodyScrollLockDepth = Math.max(0, bodyScrollLockDepth - 1);
|
|
14
|
+
if (bodyScrollLockDepth > 0) return;
|
|
15
|
+
document.body.style.overflow = bodyOverflowBeforeLock;
|
|
16
|
+
bodyOverflowBeforeLock = "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function registerSheet(panel: HTMLElement) {
|
|
20
|
+
openSheets.push(panel);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function unregisterSheet(panel: HTMLElement) {
|
|
24
|
+
const index = openSheets.lastIndexOf(panel);
|
|
25
|
+
if (index >= 0) openSheets.splice(index, 1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isTopmostSheet(panel: HTMLElement) {
|
|
29
|
+
return openSheets.at(-1) === panel;
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
1
33
|
<script lang="ts">
|
|
2
34
|
/* eslint-disable svelte/no-unused-svelte-ignore */
|
|
35
|
+
import { tick } from "svelte";
|
|
3
36
|
import { cn, type WithElementRef } from "../../../utils.js";
|
|
4
37
|
import type { HTMLAttributes } from "svelte/elements";
|
|
5
38
|
|
|
39
|
+
const focusableSelector = [
|
|
40
|
+
'a[href]',
|
|
41
|
+
'button',
|
|
42
|
+
'input',
|
|
43
|
+
'select',
|
|
44
|
+
'textarea',
|
|
45
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
46
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
47
|
+
].join(",");
|
|
48
|
+
|
|
6
49
|
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
|
7
50
|
open?: boolean;
|
|
8
51
|
side?: "left" | "right";
|
|
@@ -15,6 +58,7 @@
|
|
|
15
58
|
side = "right",
|
|
16
59
|
onClose,
|
|
17
60
|
class: className,
|
|
61
|
+
tabindex = -1,
|
|
18
62
|
children,
|
|
19
63
|
...restProps
|
|
20
64
|
}: Props = $props();
|
|
@@ -24,22 +68,88 @@
|
|
|
24
68
|
onClose?.();
|
|
25
69
|
}
|
|
26
70
|
|
|
27
|
-
function
|
|
28
|
-
|
|
71
|
+
function isContentEditableHost(element: HTMLElement) {
|
|
72
|
+
const contentEditable = element.getAttribute("contenteditable");
|
|
73
|
+
const isEditable = element.isContentEditable || (contentEditable !== null && contentEditable.toLowerCase() !== "false");
|
|
74
|
+
return isEditable && !element.parentElement?.isContentEditable;
|
|
29
75
|
}
|
|
30
76
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
document.removeEventListener("keydown", handleKeydown);
|
|
37
|
-
document.body.style.overflow = "";
|
|
38
|
-
};
|
|
77
|
+
function isVisible(element: HTMLElement) {
|
|
78
|
+
for (let current: HTMLElement | null = element; current; current = current.parentElement) {
|
|
79
|
+
const style = getComputedStyle(current);
|
|
80
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
81
|
+
if (current === ref) break;
|
|
39
82
|
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function isTabbable(element: HTMLElement) {
|
|
87
|
+
if (element.matches(":disabled, [aria-disabled='true']")) return false;
|
|
88
|
+
if (element.closest("[hidden], [inert], [aria-hidden='true']")) return false;
|
|
89
|
+
if (element.hasAttribute("tabindex") && element.tabIndex < 0) return false;
|
|
90
|
+
if (!element.hasAttribute("tabindex") && !isContentEditableHost(element) && element.tabIndex < 0) return false;
|
|
91
|
+
return isVisible(element);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function tabbableElements() {
|
|
95
|
+
return ref ? [...ref.querySelectorAll<HTMLElement>(focusableSelector)].filter(isTabbable) : [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
99
|
+
if (event.defaultPrevented || !open || !ref || !isTopmostSheet(ref)) return;
|
|
100
|
+
if (event.key === "Escape") {
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
close();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (event.key !== "Tab") return;
|
|
106
|
+
|
|
107
|
+
const tabbable = tabbableElements();
|
|
108
|
+
if (tabbable.length === 0) {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
ref.focus();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const first = tabbable[0];
|
|
115
|
+
const last = tabbable.at(-1);
|
|
116
|
+
const activeIndex = tabbable.indexOf(document.activeElement as HTMLElement);
|
|
117
|
+
if (!ref.contains(document.activeElement) || activeIndex === -1) {
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
(event.shiftKey ? last : first)?.focus();
|
|
120
|
+
} else if (event.shiftKey && activeIndex === 0) {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
last?.focus();
|
|
123
|
+
} else if (!event.shiftKey && activeIndex === tabbable.length - 1) {
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
first.focus();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
$effect(() => {
|
|
130
|
+
if (!open || !ref) return;
|
|
131
|
+
const panel = ref;
|
|
132
|
+
const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
133
|
+
registerSheet(panel);
|
|
134
|
+
lockBodyScroll();
|
|
135
|
+
void tick().then(() => {
|
|
136
|
+
if (open && ref === panel && isTopmostSheet(panel)) {
|
|
137
|
+
(tabbableElements()[0] ?? panel).focus();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
return () => {
|
|
141
|
+
unregisterSheet(panel);
|
|
142
|
+
unlockBodyScroll();
|
|
143
|
+
const remainingSheet = openSheets.at(-1);
|
|
144
|
+
if (!remainingSheet || (previousFocus && remainingSheet.contains(previousFocus))) {
|
|
145
|
+
previousFocus?.focus();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
40
148
|
});
|
|
41
149
|
</script>
|
|
42
150
|
|
|
151
|
+
<svelte:document onkeydown={handleKeydown} />
|
|
152
|
+
|
|
43
153
|
{#if open}
|
|
44
154
|
<!-- Overlay -->
|
|
45
155
|
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
|
@@ -50,9 +160,11 @@
|
|
|
50
160
|
></div>
|
|
51
161
|
|
|
52
162
|
<!-- Sheet panel -->
|
|
163
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
53
164
|
<div
|
|
54
165
|
bind:this={ref}
|
|
55
166
|
data-slot="sheet"
|
|
167
|
+
{tabindex}
|
|
56
168
|
class={cn(
|
|
57
169
|
"fixed z-50 flex translate-x-0 flex-col gap-4 bg-background p-6 shadow-lg",
|
|
58
170
|
side === "right"
|
package/dist/index.d.ts
CHANGED
|
@@ -194,3 +194,6 @@ export { default as TwoFactorStepper } from './components/content/TwoFactorStepp
|
|
|
194
194
|
export { default as SystemErrorState } from './components/content/SystemErrorState.svelte';
|
|
195
195
|
export { referenceDemoData } from './reference-data.js';
|
|
196
196
|
export type { DemoMember, DemoProject, DemoTeam, DemoIntegration, DemoApiKey, DemoSecurityEvent, DemoNotification } from './reference-data.js';
|
|
197
|
+
export { default as RowActions } from './components/RowActions.svelte';
|
|
198
|
+
export type { RowActionItem } from './components/RowActions.svelte';
|
|
199
|
+
export { default as DetailDrawer } from './components/DetailDrawer.svelte';
|
package/dist/index.js
CHANGED
|
@@ -195,3 +195,5 @@ export { default as OtpInput } from './components/content/OtpInput.svelte';
|
|
|
195
195
|
export { default as TwoFactorStepper } from './components/content/TwoFactorStepper.svelte';
|
|
196
196
|
export { default as SystemErrorState } from './components/content/SystemErrorState.svelte';
|
|
197
197
|
export { referenceDemoData } from './reference-data.js';
|
|
198
|
+
export { default as RowActions } from './components/RowActions.svelte';
|
|
199
|
+
export { default as DetailDrawer } from './components/DetailDrawer.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.0",
|
|
4
4
|
"description": "Pre-built admin UI components — AdminApp, AutoTable, AutoForm, Sidebar, Layout",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"./components/*": "./dist/components/*"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@svadmin/core": "^0.
|
|
42
|
+
"@svadmin/core": "^0.39.0",
|
|
43
43
|
"@tanstack/svelte-query": "^6.1.38",
|
|
44
44
|
"highlight.js": "^11.11.1",
|
|
45
45
|
"isomorphic-dompurify": "^3.22.0",
|
|
@@ -96,6 +96,9 @@
|
|
|
96
96
|
"bugs": {
|
|
97
97
|
"url": "https://github.com/vibeunion/svadmin/issues"
|
|
98
98
|
},
|
|
99
|
+
"publishConfig": {
|
|
100
|
+
"access": "public"
|
|
101
|
+
},
|
|
99
102
|
"devDependencies": {
|
|
100
103
|
"@happy-dom/global-registrator": "^20.11.2",
|
|
101
104
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|