@openviking/react 0.1.6 → 0.1.8-beta.10.1.g8e5299efeb0a
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 +13 -1
- package/dist/1~0.js +57 -0
- package/dist/2~0.js +6 -5
- package/dist/3c~0.js +10 -4
- package/dist/3~0.js +189 -13
- package/dist/5~0.js +181 -0
- package/dist/6~0.js +48 -0
- package/dist/ae~0.js +8 -1
- package/dist/ark-message-list-view~0.js +9 -4
- package/dist/a~0.js +12 -6
- package/dist/c7r~0.js +50 -0
- package/dist/ck~0.js +3 -0
- package/dist/client/paths.d.ts +6 -0
- package/dist/client/provider.d.ts +6 -1
- package/dist/components/agent-connect/style.css +224 -35
- package/dist/components/api-key-login-form/api-key-login-form.d.ts +2 -0
- package/dist/components/api-key-login-form/index.d.ts +3 -0
- package/dist/components/api-key-login-form/style.css +438 -0
- package/dist/components/api-key-login-form/style.js +0 -0
- package/dist/components/api-key-login-form/types.d.ts +7 -0
- package/dist/components/api-key-login-form.js +1 -0
- package/dist/components/directory-tour/directory-tour-intro.d.ts +3 -0
- package/dist/components/directory-tour/index.d.ts +2 -1
- package/dist/components/directory-tour/style.css +367 -39
- package/dist/components/directory-tour/tour-card.d.ts +14 -0
- package/dist/components/directory-tour/types.d.ts +24 -1
- package/dist/components/directory-tour/use-tour-anchor.d.ts +1 -0
- package/dist/components/directory-tour/use-tour-position.d.ts +4 -1
- package/dist/components/directory-tour/use-tour-theme.d.ts +2 -0
- package/dist/components/directory-tour.js +53 -2
- package/dist/components/email-login-form/email-login-form.d.ts +2 -0
- package/dist/components/email-login-form/index.d.ts +3 -0
- package/dist/components/email-login-form/style.css +438 -0
- package/dist/components/email-login-form/style.js +0 -0
- package/dist/components/email-login-form/types.d.ts +11 -0
- package/dist/components/email-login-form.js +1 -0
- package/dist/components/experience-dashboard/experience-impact.d.ts +3 -1
- package/dist/components/experience-dashboard/style.css +229 -12
- package/dist/components/experience-dashboard.js +1 -1
- package/dist/components/file-browser-entries/style.css +331 -80
- package/dist/components/file-preview/file-preview-header.d.ts +4 -21
- package/dist/components/file-preview/file-preview-toolbar.d.ts +7 -0
- package/dist/components/file-preview/locales/en-US.d.ts +9 -0
- package/dist/components/file-preview/locales/zh-CN.d.ts +9 -0
- package/dist/components/file-preview/style.css +335 -76
- package/dist/components/file-preview/types.d.ts +14 -21
- package/dist/components/file-tree/file-tree-toolbar.d.ts +3 -3
- package/dist/components/file-tree/locales/en-US.d.ts +3 -0
- package/dist/components/file-tree/locales/zh-CN.d.ts +3 -0
- package/dist/components/file-tree/style.css +313 -86
- package/dist/components/file-tree/types.d.ts +13 -4
- package/dist/components/invitation-confirmation/index.d.ts +3 -0
- package/dist/components/invitation-confirmation/invitation-confirmation.d.ts +2 -0
- package/dist/components/invitation-confirmation/style.css +438 -0
- package/dist/components/invitation-confirmation/style.js +0 -0
- package/dist/components/invitation-confirmation/types.d.ts +20 -0
- package/dist/components/invitation-confirmation.js +1 -0
- package/dist/components/login-method-selector/index.d.ts +2 -0
- package/dist/components/login-method-selector/login-method-selector.d.ts +2 -0
- package/dist/components/login-method-selector/style.css +438 -0
- package/dist/components/login-method-selector/style.js +0 -0
- package/dist/components/login-method-selector/types.d.ts +14 -0
- package/dist/components/login-method-selector.js +1 -0
- package/dist/components/password-reset-request-form/index.d.ts +3 -0
- package/dist/components/password-reset-request-form/password-reset-request-form.d.ts +2 -0
- package/dist/components/password-reset-request-form/style.css +438 -0
- package/dist/components/password-reset-request-form/style.js +0 -0
- package/dist/components/password-reset-request-form/types.d.ts +13 -0
- package/dist/components/password-reset-request-form.js +1 -0
- package/dist/components/password-setup-form/index.d.ts +3 -0
- package/dist/components/password-setup-form/password-setup-form.d.ts +2 -0
- package/dist/components/password-setup-form/style.css +438 -0
- package/dist/components/password-setup-form/style.js +0 -0
- package/dist/components/password-setup-form/types.d.ts +10 -0
- package/dist/components/password-setup-form.js +1 -0
- package/dist/components/scope-switcher/style.css +368 -37
- package/dist/components/style.css +13071 -7474
- package/dist/components/tui/style.css +271 -35
- package/dist/components/viking-bot/interaction/style.css +143 -22
- package/dist/components/viking-bot/style.css +951 -295
- package/dist/components/wiki-dashboard/index.d.ts +1 -1
- package/dist/components/wiki-dashboard/style.css +241 -14
- package/dist/components/wiki-dashboard/types.d.ts +12 -16
- package/dist/components/wiki-dashboard/wiki-action-button.d.ts +2 -9
- package/dist/components/wiki-dashboard/wiki-conflict-card.d.ts +3 -10
- package/dist/c~0.js +16 -8
- package/dist/d~0.js +28 -0
- package/dist/ep~0.js +493 -0
- package/dist/e~0.js +33 -328
- package/dist/fi~0.js +13 -28
- package/dist/fj~0.js +38 -69
- package/dist/fl~0.js +710 -0
- package/dist/f~0.js +61 -685
- package/dist/g~0.js +135 -0
- package/dist/icons/index.d.ts +2 -0
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +9 -3
- package/dist/k~0.js +44 -4
- package/dist/l5~0.js +3813 -0
- package/dist/lk~0.js +5 -2
- package/dist/l~0.js +49 -2369
- package/dist/modules/console/style.css +1485 -351
- package/dist/modules/file-browser/acl/acl-add-principal.d.ts +12 -0
- package/dist/modules/file-browser/acl/acl-candidate.d.ts +8 -0
- package/dist/modules/file-browser/acl/acl-client.d.ts +13 -0
- package/dist/modules/file-browser/acl/acl-confirmation.d.ts +6 -0
- package/dist/modules/file-browser/acl/acl-entry.d.ts +13 -0
- package/dist/modules/file-browser/acl/acl-labels.d.ts +47 -0
- package/dist/modules/file-browser/acl/acl-menu.d.ts +10 -0
- package/dist/modules/file-browser/acl/acl-modal.d.ts +17 -0
- package/dist/modules/file-browser/acl/acl-model.d.ts +17 -0
- package/dist/modules/file-browser/acl/acl-principal-tabs.d.ts +6 -0
- package/dist/modules/file-browser/acl/acl-tag.d.ts +7 -0
- package/dist/modules/file-browser/acl/locales/en-US.d.ts +44 -0
- package/dist/modules/file-browser/acl/locales/zh-CN.d.ts +44 -0
- package/dist/modules/file-browser/acl/use-acl-principals.d.ts +17 -0
- package/dist/modules/file-browser/acl/use-acl-report.d.ts +27 -0
- package/dist/modules/file-browser/acl-types.d.ts +86 -0
- package/dist/modules/file-browser/dashboard-model.d.ts +3 -0
- package/dist/modules/file-browser/file-browser-detail-icons.d.ts +0 -6
- package/dist/modules/file-browser/file-browser-detail.d.ts +5 -23
- package/dist/modules/file-browser/file-browser-labels.d.ts +1 -1
- package/dist/modules/file-browser/file-browser-search.d.ts +20 -0
- package/dist/modules/file-browser/file-browser-toolbar.d.ts +3 -10
- package/dist/modules/file-browser/file-browser-tree-pane.d.ts +2 -6
- package/dist/modules/file-browser/file-browser.d.ts +1 -1
- package/dist/modules/file-browser/fs-directories.d.ts +1 -0
- package/dist/modules/file-browser/fs-file-editing.d.ts +4 -0
- package/dist/modules/file-browser/fs-model.d.ts +3 -1
- package/dist/modules/file-browser/fs-preview-images.d.ts +3 -0
- package/dist/modules/file-browser/fs-read-file.d.ts +1 -1
- package/dist/modules/file-browser/index.d.ts +1 -0
- package/dist/modules/file-browser/locales/en-US.d.ts +5 -0
- package/dist/modules/file-browser/locales/zh-CN.d.ts +5 -0
- package/dist/modules/file-browser/style.css +2595 -703
- package/dist/modules/file-browser/types.d.ts +22 -20
- package/dist/modules/file-browser/use-file-browser-acl.d.ts +16 -0
- package/dist/modules/file-browser/use-file-browser.d.ts +5 -7
- package/dist/modules/file-browser/use-fs-tree.d.ts +1 -0
- package/dist/modules/file-browser/wiki-dashboard-pane.d.ts +2 -4
- package/dist/modules/file-browser.js +1 -1
- package/dist/modules/scope-cascade/style.css +537 -37
- package/dist/modules/style.css +12429 -8855
- package/dist/n~0.js +61 -37
- package/dist/p0~0.js +27 -0
- package/dist/p~0.js +34 -25
- package/dist/rt~0.js +107 -4
- package/dist/r~0.js +1 -1
- package/dist/shared/auth/agreements.d.ts +10 -0
- package/dist/shared/auth/fields.d.ts +15 -0
- package/dist/shared/auth/form-frame.d.ts +12 -0
- package/dist/shared/auth/locales/en-US.d.ts +24 -0
- package/dist/shared/auth/locales/zh-CN.d.ts +24 -0
- package/dist/shared/auth/types.d.ts +61 -0
- package/dist/shared/auth/use-auth-labels.d.ts +3 -0
- package/dist/shared/auth/use-form.d.ts +8 -0
- package/dist/shared/components/button/button.d.ts +20 -0
- package/dist/shared/components/input/input.d.ts +17 -0
- package/dist/shared/components/modal/locales/en-US.d.ts +4 -0
- package/dist/shared/components/modal/locales/zh-CN.d.ts +4 -0
- package/dist/shared/components/modal/modal.d.ts +2 -0
- package/dist/shared/components/modal/types.d.ts +18 -0
- package/dist/shared/components/overlay/lock-body-scroll.d.ts +1 -0
- package/dist/style.css +15477 -6258
- package/dist/s~0.js +16 -0
- package/dist/u~0.js +15 -6
- package/dist/viking-bot-composer~0.js +29 -11
- package/dist/viking-bot-interaction~0.js +2 -1
- package/package.json +34 -3
- package/dist/modules/file-browser/fs-selection.d.ts +0 -4
- package/dist/o~0.js +0 -106
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Public UI components, composed modules accept optional `locale: 'zh-CN' | 'en-US
|
|
|
6
6
|
|
|
7
7
|
React foundations for OpenViking AI application interfaces: build tooling, documentation, layered directories, and scoped styles. FileTree, Tui and FilePreview provide working views, alongside five file-type icons. FileBrowser coordinates browsing, previews and dashboards; Console provides a native command panel; ScopeCascade provides an integrated cascade selector.
|
|
8
8
|
|
|
9
|
-
This package inherits the repository's AGPL-3.0-only license. The release workflow publishes it to npm when a `react@<version>` tag matches
|
|
9
|
+
This package inherits the repository's AGPL-3.0-only license. The release workflow publishes it to npm when the Changesets version PR is merged, or when a `react@<version>` tag matches this package's version.
|
|
10
10
|
|
|
11
11
|
## Module map
|
|
12
12
|
|
|
@@ -98,3 +98,15 @@ Built-in translations live alongside each component or module in `locales/en-US.
|
|
|
98
98
|
Dynamic messages use typed formatter functions; dates and numbers use `Intl`. `npm test` checks matching keys, string placeholders and formatter arity across languages, while type checking validates parameter types. Undefined `labels` entries inherit the selected language; empty strings remain explicit overrides.
|
|
99
99
|
|
|
100
100
|
Set `locale` on `OpenVikingProvider` for a subtree. Optional module and component Props override the nearest scope, then fall back to `en-US`. Standalone Hooks also inherit the Provider. The private `src/shared/locale-context.tsx` is shared across public entries and remains separate from request-client configuration, so language changes preserve requests and state.
|
|
101
|
+
|
|
102
|
+
The internal Input, Button, Modal and Drawer adapt Arco Design logic (MIT); its notice ships in `LICENSE.arco-design`. Input and Button visual rules are adapted from the console's `@arco-design/theme-ve-o-aml-design@0.0.36` (MIT), rather than Arco's default skin. They have no public component entry.
|
|
103
|
+
|
|
104
|
+
## Authentication forms
|
|
105
|
+
|
|
106
|
+
`EmailLoginForm`, `ApiKeyLoginForm`, `PasswordResetRequestForm`, `PasswordSetupForm`,
|
|
107
|
+
`LoginMethodSelector` and `InvitationConfirmation` are request-free React views.
|
|
108
|
+
Import components from the package root or their individual `components/<kebab-case-name>`
|
|
109
|
+
entries and import the matching `style.css`. Optional actions and agreements are configured
|
|
110
|
+
by the host. Password strength, asynchronous loading/errors, mail delivery, session/CSRF,
|
|
111
|
+
invitation routing and persistence are host responsibilities. No internal UI or theme
|
|
112
|
+
packages are required. See the authentication form examples in the UI documentation.
|
package/dist/1~0.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAuthLabels, Action } from "./g~0.js";
|
|
3
|
+
function InvitationConfirmation({ details, loading, disabled, error, decline, defer, className, onAccept, title, description, locale, acceptLabel }) {
|
|
4
|
+
const labels = useAuthLabels(locale);
|
|
5
|
+
return /*#__PURE__*/ jsxs("section", {
|
|
6
|
+
className: `ov-auth ${className ?? ''}`,
|
|
7
|
+
"aria-busy": loading || void 0,
|
|
8
|
+
children: [
|
|
9
|
+
title && /*#__PURE__*/ jsx("h2", {
|
|
10
|
+
children: title
|
|
11
|
+
}),
|
|
12
|
+
description && /*#__PURE__*/ jsx("p", {
|
|
13
|
+
className: "ov-auth__description",
|
|
14
|
+
children: description
|
|
15
|
+
}),
|
|
16
|
+
/*#__PURE__*/ jsx("dl", {
|
|
17
|
+
className: "ov-auth__details",
|
|
18
|
+
children: details.map((item, index)=>/*#__PURE__*/ jsxs("div", {
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ jsx("dt", {
|
|
21
|
+
children: item.label
|
|
22
|
+
}),
|
|
23
|
+
/*#__PURE__*/ jsx("dd", {
|
|
24
|
+
children: item.value
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
}, index))
|
|
28
|
+
}),
|
|
29
|
+
error && /*#__PURE__*/ jsx("div", {
|
|
30
|
+
className: "ov-auth__error",
|
|
31
|
+
role: "alert",
|
|
32
|
+
children: error
|
|
33
|
+
}),
|
|
34
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
35
|
+
disabled: loading || disabled,
|
|
36
|
+
children: [
|
|
37
|
+
/*#__PURE__*/ jsxs("button", {
|
|
38
|
+
type: "button",
|
|
39
|
+
className: "ov-auth__primary ov-auth__submit",
|
|
40
|
+
onClick: onAccept,
|
|
41
|
+
children: [
|
|
42
|
+
acceptLabel ?? labels.acceptInvitation,
|
|
43
|
+
loading && ' …'
|
|
44
|
+
]
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ jsx(Action, {
|
|
47
|
+
action: decline
|
|
48
|
+
}),
|
|
49
|
+
/*#__PURE__*/ jsx(Action, {
|
|
50
|
+
action: defer
|
|
51
|
+
})
|
|
52
|
+
]
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
export { InvitationConfirmation };
|
package/dist/2~0.js
CHANGED
|
@@ -8,6 +8,7 @@ import { resolveLocale } from "./nx~0.js";
|
|
|
8
8
|
import { removereact } from "./4~0.js";
|
|
9
9
|
import { usePortalTheme } from "./9~0.js";
|
|
10
10
|
import { useLocale } from "./28~0.js";
|
|
11
|
+
import { button_Button } from "./e~0.js";
|
|
11
12
|
import { AgentConnect } from "./u~0.js";
|
|
12
13
|
import * as __rspack_external_react from "react";
|
|
13
14
|
__webpack_require__.add({
|
|
@@ -2282,8 +2283,8 @@ function FileBrowserEntries({ locale: localeProp, agentConnect, onConnectAgent,
|
|
|
2282
2283
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
2283
2284
|
const text = resolveFileBrowserEntriesLabels(locale, labels);
|
|
2284
2285
|
const showConnect = Boolean(agentConnect || onConnectAgent);
|
|
2285
|
-
const importButton = /*#__PURE__*/ jsxs(
|
|
2286
|
-
|
|
2286
|
+
const importButton = /*#__PURE__*/ jsxs(button_Button, {
|
|
2287
|
+
htmlType: "button",
|
|
2287
2288
|
className: "ov-file-browser-entries__entry",
|
|
2288
2289
|
onClick: onImportResources,
|
|
2289
2290
|
children: [
|
|
@@ -2308,9 +2309,9 @@ function FileBrowserEntries({ locale: localeProp, agentConnect, onConnectAgent,
|
|
|
2308
2309
|
className
|
|
2309
2310
|
].filter(Boolean).join(' '),
|
|
2310
2311
|
children: [
|
|
2311
|
-
showConnect ? /*#__PURE__*/ jsxs(
|
|
2312
|
+
showConnect ? /*#__PURE__*/ jsxs(button_Button, {
|
|
2312
2313
|
ref: triggerRef,
|
|
2313
|
-
|
|
2314
|
+
htmlType: "button",
|
|
2314
2315
|
className: "ov-file-browser-entries__entry",
|
|
2315
2316
|
"aria-haspopup": agentConnect ? 'dialog' : void 0,
|
|
2316
2317
|
"aria-controls": agentConnect ? drawerId : void 0,
|
|
@@ -2360,4 +2361,4 @@ function FileBrowserEntries({ locale: localeProp, agentConnect, onConnectAgent,
|
|
|
2360
2361
|
]
|
|
2361
2362
|
});
|
|
2362
2363
|
}
|
|
2363
|
-
export { FileBrowserEntries };
|
|
2364
|
+
export { FileBrowserEntries, es2015, lockBodyScroll };
|
package/dist/3c~0.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ArrowRightIcon } from "./k~0.js";
|
|
|
6
6
|
import { resolveLocale } from "./nx~0.js";
|
|
7
7
|
import { checkreact } from "./0~0.js";
|
|
8
8
|
import { Tooltip } from "./rt~0.js";
|
|
9
|
+
import { button_Button } from "./e~0.js";
|
|
9
10
|
import { useLocale } from "./28~0.js";
|
|
10
11
|
function getTuiCommandInputText(command) {
|
|
11
12
|
return command.inputText?.trim() || command.name;
|
|
@@ -1170,8 +1171,11 @@ function TuiCopyButton({ text, label, copiedLabel, onCopy, className }) {
|
|
|
1170
1171
|
};
|
|
1171
1172
|
return /*#__PURE__*/ jsx(Tooltip, {
|
|
1172
1173
|
content: copied ? copiedLabel : label,
|
|
1173
|
-
children: /*#__PURE__*/ jsx(
|
|
1174
|
-
|
|
1174
|
+
children: /*#__PURE__*/ jsx(button_Button, {
|
|
1175
|
+
size: "mini",
|
|
1176
|
+
type: "text",
|
|
1177
|
+
iconOnly: true,
|
|
1178
|
+
htmlType: "button",
|
|
1175
1179
|
className: [
|
|
1176
1180
|
'ov-tui__copy',
|
|
1177
1181
|
className
|
|
@@ -1537,8 +1541,10 @@ function TuiResourceTree({ content, onOpenUri, loadMoreLabel, noResultLabel, res
|
|
|
1537
1541
|
})
|
|
1538
1542
|
}, item.id))
|
|
1539
1543
|
}),
|
|
1540
|
-
hiddenCount > 0 ? /*#__PURE__*/ jsxs(
|
|
1541
|
-
|
|
1544
|
+
hiddenCount > 0 ? /*#__PURE__*/ jsxs(button_Button, {
|
|
1545
|
+
size: "small",
|
|
1546
|
+
type: "default",
|
|
1547
|
+
htmlType: "button",
|
|
1542
1548
|
className: "ov-tui__load-more",
|
|
1543
1549
|
onClick: ()=>setVisibleCount((count)=>count + PAGE_SIZE),
|
|
1544
1550
|
children: [
|
package/dist/3~0.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment as external_react_Fragment, Suspense, forwardRef, lazy, useCallback, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { button_Button } from "./e~0.js";
|
|
4
|
+
import { WikiEditIcon } from "./k~0.js";
|
|
3
5
|
import { Tooltip } from "./rt~0.js";
|
|
4
6
|
import { resolveLocale, mergeLabels } from "./nx~0.js";
|
|
5
7
|
import { useLocale } from "./28~0.js";
|
|
@@ -37,8 +39,10 @@ function FilePreviewEditor({ draft, text, loading, failed, saveFailed, saving, o
|
|
|
37
39
|
className: "ov-file-preview__state-title",
|
|
38
40
|
children: text.loadFailed
|
|
39
41
|
}),
|
|
40
|
-
/*#__PURE__*/ jsx(
|
|
41
|
-
|
|
42
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
43
|
+
size: "small",
|
|
44
|
+
type: "default",
|
|
45
|
+
htmlType: "button",
|
|
42
46
|
className: "ov-file-preview__button",
|
|
43
47
|
onClick: onCancel,
|
|
44
48
|
children: text.leaveEditing
|
|
@@ -140,8 +144,10 @@ function LoadFailedState({ text, description, onRetry }) {
|
|
|
140
144
|
return /*#__PURE__*/ jsx(StatePanel, {
|
|
141
145
|
title: text.loadFailed,
|
|
142
146
|
description: description,
|
|
143
|
-
action: onRetry ? /*#__PURE__*/ jsx(
|
|
144
|
-
|
|
147
|
+
action: onRetry ? /*#__PURE__*/ jsx(button_Button, {
|
|
148
|
+
size: "small",
|
|
149
|
+
type: "default",
|
|
150
|
+
htmlType: "button",
|
|
145
151
|
className: "ov-file-preview__button",
|
|
146
152
|
onClick: onRetry,
|
|
147
153
|
children: text.retry
|
|
@@ -151,8 +157,10 @@ function LoadFailedState({ text, description, onRetry }) {
|
|
|
151
157
|
function UnsupportedState({ text, onDownload }) {
|
|
152
158
|
return /*#__PURE__*/ jsx(StatePanel, {
|
|
153
159
|
title: text.unsupported,
|
|
154
|
-
action: onDownload ? /*#__PURE__*/ jsx(
|
|
155
|
-
|
|
160
|
+
action: onDownload ? /*#__PURE__*/ jsx(button_Button, {
|
|
161
|
+
size: "small",
|
|
162
|
+
type: "default",
|
|
163
|
+
htmlType: "button",
|
|
156
164
|
className: "ov-file-preview__button",
|
|
157
165
|
onClick: onDownload,
|
|
158
166
|
children: text.download
|
|
@@ -216,6 +224,119 @@ function FilePreviewBody({ fileTab, text, locale, viewMode, editing, onViewModeC
|
|
|
216
224
|
fileTab.source.url
|
|
217
225
|
]));
|
|
218
226
|
}
|
|
227
|
+
function FilePreviewToolbar({ actions, text, extraActions }) {
|
|
228
|
+
const [copyResult, setCopyResult] = useState();
|
|
229
|
+
if (actions.editing) return null;
|
|
230
|
+
const hasActions = actions.canCopyContent || actions.canEdit || actions.canDownload || extraActions;
|
|
231
|
+
if (!actions.canSwitchView && !hasActions) return null;
|
|
232
|
+
const copyLabel = void 0 === copyResult ? text.copyContent : copyResult ? text.copied : text.copyFailed;
|
|
233
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
234
|
+
className: "ov-file-preview__toolbar",
|
|
235
|
+
children: [
|
|
236
|
+
actions.canSwitchView ? /*#__PURE__*/ jsx("div", {
|
|
237
|
+
className: "ov-file-preview__switch",
|
|
238
|
+
role: "group",
|
|
239
|
+
"aria-label": text.viewSwitch,
|
|
240
|
+
children: [
|
|
241
|
+
'preview',
|
|
242
|
+
'source'
|
|
243
|
+
].map((mode)=>/*#__PURE__*/ jsx("button", {
|
|
244
|
+
type: "button",
|
|
245
|
+
className: "ov-file-preview__switch-item",
|
|
246
|
+
"aria-pressed": actions.viewMode === mode,
|
|
247
|
+
disabled: actions.busy,
|
|
248
|
+
onClick: ()=>actions.setViewMode(mode),
|
|
249
|
+
children: 'preview' === mode ? text.previewMode : text.sourceMode
|
|
250
|
+
}, mode))
|
|
251
|
+
}) : null,
|
|
252
|
+
actions.canSwitchView && hasActions ? /*#__PURE__*/ jsx("span", {
|
|
253
|
+
className: "ov-file-preview__toolbar-divider",
|
|
254
|
+
"aria-hidden": "true"
|
|
255
|
+
}) : null,
|
|
256
|
+
actions.canCopyContent ? /*#__PURE__*/ jsxs(Fragment, {
|
|
257
|
+
children: [
|
|
258
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
259
|
+
size: "small",
|
|
260
|
+
type: "default",
|
|
261
|
+
iconOnly: true,
|
|
262
|
+
className: "ov-file-preview__toolbar-button",
|
|
263
|
+
"aria-label": text.copyContent,
|
|
264
|
+
title: copyLabel,
|
|
265
|
+
disabled: actions.busy,
|
|
266
|
+
onBlur: ()=>setCopyResult(void 0),
|
|
267
|
+
onClick: ()=>void actions.copyContent().then(setCopyResult),
|
|
268
|
+
children: /*#__PURE__*/ jsxs("svg", {
|
|
269
|
+
"aria-hidden": "true",
|
|
270
|
+
width: "14",
|
|
271
|
+
height: "14",
|
|
272
|
+
viewBox: "0 0 16 16",
|
|
273
|
+
fill: "none",
|
|
274
|
+
stroke: "currentColor",
|
|
275
|
+
strokeWidth: "1.4",
|
|
276
|
+
children: [
|
|
277
|
+
/*#__PURE__*/ jsx("rect", {
|
|
278
|
+
x: "5.5",
|
|
279
|
+
y: "5.5",
|
|
280
|
+
width: "8",
|
|
281
|
+
height: "8",
|
|
282
|
+
rx: "1.5"
|
|
283
|
+
}),
|
|
284
|
+
/*#__PURE__*/ jsx("path", {
|
|
285
|
+
d: "M10.5 5.5v-1a1.5 1.5 0 0 0-1.5-1.5H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 11h1"
|
|
286
|
+
})
|
|
287
|
+
]
|
|
288
|
+
})
|
|
289
|
+
}),
|
|
290
|
+
void 0 !== copyResult ? /*#__PURE__*/ jsx("span", {
|
|
291
|
+
className: "ov-file-preview__sr-only",
|
|
292
|
+
role: "status",
|
|
293
|
+
children: copyLabel
|
|
294
|
+
}) : null
|
|
295
|
+
]
|
|
296
|
+
}) : null,
|
|
297
|
+
actions.canEdit ? /*#__PURE__*/ jsxs(button_Button, {
|
|
298
|
+
size: "small",
|
|
299
|
+
type: "default",
|
|
300
|
+
className: "ov-file-preview__toolbar-button",
|
|
301
|
+
disabled: actions.busy,
|
|
302
|
+
onClick: actions.startEditing,
|
|
303
|
+
children: [
|
|
304
|
+
/*#__PURE__*/ jsx(WikiEditIcon, {
|
|
305
|
+
width: 14,
|
|
306
|
+
height: 14,
|
|
307
|
+
"aria-hidden": "true"
|
|
308
|
+
}),
|
|
309
|
+
text.edit
|
|
310
|
+
]
|
|
311
|
+
}) : null,
|
|
312
|
+
actions.canDownload ? /*#__PURE__*/ jsx(button_Button, {
|
|
313
|
+
size: "small",
|
|
314
|
+
type: "default",
|
|
315
|
+
iconOnly: true,
|
|
316
|
+
className: "ov-file-preview__toolbar-button",
|
|
317
|
+
"aria-label": text.download,
|
|
318
|
+
title: text.download,
|
|
319
|
+
disabled: actions.busy,
|
|
320
|
+
onClick: actions.download,
|
|
321
|
+
children: /*#__PURE__*/ jsx("svg", {
|
|
322
|
+
"aria-hidden": "true",
|
|
323
|
+
width: "14",
|
|
324
|
+
height: "14",
|
|
325
|
+
viewBox: "0 0 16 16",
|
|
326
|
+
fill: "none",
|
|
327
|
+
stroke: "currentColor",
|
|
328
|
+
strokeWidth: "1.4",
|
|
329
|
+
strokeLinecap: "round",
|
|
330
|
+
strokeLinejoin: "round",
|
|
331
|
+
children: /*#__PURE__*/ jsx("path", {
|
|
332
|
+
d: "M8 2.5v8m-3-3 3 3 3-3M2.5 12.5h11"
|
|
333
|
+
})
|
|
334
|
+
})
|
|
335
|
+
}) : null,
|
|
336
|
+
extraActions
|
|
337
|
+
]
|
|
338
|
+
});
|
|
339
|
+
}
|
|
219
340
|
function FilePreviewLevelTabs({ levels, activeKey, disabled, onSelect }) {
|
|
220
341
|
if (!levels?.length) return null;
|
|
221
342
|
return /*#__PURE__*/ jsx("div", {
|
|
@@ -451,8 +572,11 @@ function FilePreviewBreadcrumb({ hiddenPathLabel, segments, title, canOpen, disa
|
|
|
451
572
|
function FilePreviewCopyPath({ label, disabled, onClick }) {
|
|
452
573
|
return /*#__PURE__*/ jsx(Tooltip, {
|
|
453
574
|
content: label,
|
|
454
|
-
children: /*#__PURE__*/ jsx(
|
|
455
|
-
|
|
575
|
+
children: /*#__PURE__*/ jsx(button_Button, {
|
|
576
|
+
size: "small",
|
|
577
|
+
type: "text",
|
|
578
|
+
iconOnly: true,
|
|
579
|
+
htmlType: "button",
|
|
456
580
|
className: "ov-file-preview__action",
|
|
457
581
|
"aria-label": label,
|
|
458
582
|
disabled: disabled,
|
|
@@ -502,10 +626,14 @@ function getPathFileName(path) {
|
|
|
502
626
|
const parts = trimmed.split(SEPARATOR).filter(Boolean);
|
|
503
627
|
return parts[parts.length - 1];
|
|
504
628
|
}
|
|
505
|
-
function FilePreviewHeader({ levels, levelKey, onLevelChange, path, fileName, canOpenParent, titleExtra, slotActions, actions, text, onOpenParent }) {
|
|
629
|
+
function FilePreviewHeader({ levels, levelKey, onLevelChange, path, fileName, canOpenParent, titleExtra, slotActions, extraActions, actions, text, onOpenParent }) {
|
|
506
630
|
const segments = splitPathSegments(path);
|
|
507
631
|
const title = getPathFileName(path) ?? fileName;
|
|
508
|
-
const actionNode = 'function' == typeof slotActions ? slotActions(actions) : slotActions
|
|
632
|
+
const actionNode = 'function' == typeof slotActions ? slotActions(actions) : void 0 === slotActions ? /*#__PURE__*/ jsx(FilePreviewToolbar, {
|
|
633
|
+
actions: actions,
|
|
634
|
+
text: text,
|
|
635
|
+
extraActions: extraActions
|
|
636
|
+
}) : slotActions;
|
|
509
637
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
510
638
|
children: [
|
|
511
639
|
/*#__PURE__*/ jsxs("div", {
|
|
@@ -574,8 +702,8 @@ function FilePreviewDirectoryBody({ tab, text, locale, actions, editing, viewMod
|
|
|
574
702
|
const active = root.querySelector('[aria-selected="true"]');
|
|
575
703
|
if (!active) return;
|
|
576
704
|
setIndicator({
|
|
577
|
-
left: active.offsetLeft,
|
|
578
|
-
width:
|
|
705
|
+
left: active.offsetLeft + (active.offsetWidth - 14) / 2,
|
|
706
|
+
width: 14
|
|
579
707
|
});
|
|
580
708
|
};
|
|
581
709
|
measure();
|
|
@@ -618,6 +746,7 @@ function FilePreviewDirectoryBody({ tab, text, locale, actions, editing, viewMod
|
|
|
618
746
|
canOpenParent: Boolean(tab.operations?.openParent),
|
|
619
747
|
titleExtra: tab.slots?.titleExtra,
|
|
620
748
|
slotActions: tab.slots?.actions,
|
|
749
|
+
extraActions: tab.slots?.extraActions,
|
|
621
750
|
actions: actions,
|
|
622
751
|
text: text,
|
|
623
752
|
onOpenParent: (uri)=>void tab.operations?.openParent?.(uri)
|
|
@@ -638,6 +767,7 @@ function FilePreviewDirectoryBody({ tab, text, locale, actions, editing, viewMod
|
|
|
638
767
|
canOpenParent: Boolean(tab.operations?.openParent),
|
|
639
768
|
titleExtra: tab.slots?.titleExtra,
|
|
640
769
|
slotActions: tab.slots?.actions,
|
|
770
|
+
extraActions: tab.slots?.extraActions,
|
|
641
771
|
actions: actions,
|
|
642
772
|
text: text,
|
|
643
773
|
onOpenParent: (uri)=>void tab.operations?.openParent?.(uri)
|
|
@@ -728,10 +858,38 @@ function FilePreviewPanels({ levelKey, onLevelChange, contentTab, directoryTab,
|
|
|
728
858
|
canOpenParent: Boolean(fileTab.operations?.openParent),
|
|
729
859
|
titleExtra: fileTab.slots?.titleExtra,
|
|
730
860
|
slotActions: fileTab.slots?.actions,
|
|
861
|
+
extraActions: fileTab.slots?.extraActions,
|
|
731
862
|
actions: actionContext,
|
|
732
863
|
text: text,
|
|
733
864
|
onOpenParent: (uri)=>void actions.openParent(activeTab, uri)
|
|
734
865
|
}),
|
|
866
|
+
editing.editing && fileTab.slots?.actions === void 0 ? /*#__PURE__*/ jsxs("div", {
|
|
867
|
+
className: "ov-file-preview__edit-toolbar",
|
|
868
|
+
children: [
|
|
869
|
+
/*#__PURE__*/ jsx("span", {
|
|
870
|
+
children: text.editFile
|
|
871
|
+
}),
|
|
872
|
+
/*#__PURE__*/ jsxs("div", {
|
|
873
|
+
className: "ov-file-preview__toolbar",
|
|
874
|
+
children: [
|
|
875
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
876
|
+
size: "small",
|
|
877
|
+
type: "default",
|
|
878
|
+
disabled: editing.saving,
|
|
879
|
+
onClick: actionContext.cancelEditing,
|
|
880
|
+
children: text.leaveEditing
|
|
881
|
+
}),
|
|
882
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
883
|
+
size: "small",
|
|
884
|
+
type: "primary",
|
|
885
|
+
loading: editing.saving,
|
|
886
|
+
onClick: ()=>void actionContext.saveEditing(),
|
|
887
|
+
children: text.save
|
|
888
|
+
})
|
|
889
|
+
]
|
|
890
|
+
})
|
|
891
|
+
]
|
|
892
|
+
}) : null,
|
|
735
893
|
/*#__PURE__*/ jsx("div", {
|
|
736
894
|
className: "ov-file-preview__body",
|
|
737
895
|
children: /*#__PURE__*/ jsx(FilePreviewBody, {
|
|
@@ -823,6 +981,15 @@ function useFilePreviewLevels(selected) {
|
|
|
823
981
|
const messages = {
|
|
824
982
|
showHiddenPath: 'Show hidden path levels',
|
|
825
983
|
copyPath: 'Copy path',
|
|
984
|
+
copyContent: 'Copy content',
|
|
985
|
+
copied: 'Copied',
|
|
986
|
+
copyFailed: 'Could not copy',
|
|
987
|
+
previewMode: 'Preview',
|
|
988
|
+
sourceMode: 'Source',
|
|
989
|
+
viewSwitch: 'View mode',
|
|
990
|
+
edit: 'Edit',
|
|
991
|
+
editFile: 'Edit file',
|
|
992
|
+
save: 'Save',
|
|
826
993
|
editor: 'Edit content',
|
|
827
994
|
leaveEditing: 'Cancel',
|
|
828
995
|
retry: 'Retry',
|
|
@@ -839,6 +1006,15 @@ const en_US = messages;
|
|
|
839
1006
|
const zh_CN_messages = {
|
|
840
1007
|
showHiddenPath: '显示隐藏的路径层级',
|
|
841
1008
|
copyPath: '复制路径',
|
|
1009
|
+
copyContent: '复制正文',
|
|
1010
|
+
copied: '已复制',
|
|
1011
|
+
copyFailed: '复制失败',
|
|
1012
|
+
previewMode: '预览',
|
|
1013
|
+
sourceMode: '源码',
|
|
1014
|
+
viewSwitch: '显示模式',
|
|
1015
|
+
edit: '编辑',
|
|
1016
|
+
editFile: '编辑文件',
|
|
1017
|
+
save: '保存',
|
|
842
1018
|
editor: '编辑正文',
|
|
843
1019
|
leaveEditing: '取消',
|
|
844
1020
|
retry: '重试',
|
|
@@ -1275,7 +1451,7 @@ const file_preview_FilePreview = /*#__PURE__*/ forwardRef(function({ tabs, activ
|
|
|
1275
1451
|
switchTab,
|
|
1276
1452
|
viewerHandle
|
|
1277
1453
|
]);
|
|
1278
|
-
const canSwitchView = Boolean(fileTab) && viewModes.includes('preview') && viewModes.includes('source');
|
|
1454
|
+
const canSwitchView = Boolean(fileTab || directoryTab) && viewModes.includes('preview') && viewModes.includes('source');
|
|
1279
1455
|
const onLinkClick = useCallback((_event, link)=>{
|
|
1280
1456
|
if (fileTab) actions.openUri(fileTab, link.url);
|
|
1281
1457
|
}, [
|
package/dist/5~0.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { Action } from "./g~0.js";
|
|
4
|
+
function AgreementLinks({ agreements }) {
|
|
5
|
+
return /*#__PURE__*/ jsx(Fragment, {
|
|
6
|
+
children: agreements.items.map((item, index)=>/*#__PURE__*/ jsxs("span", {
|
|
7
|
+
children: [
|
|
8
|
+
' ',
|
|
9
|
+
/*#__PURE__*/ jsx("a", {
|
|
10
|
+
href: item.href,
|
|
11
|
+
target: "_blank",
|
|
12
|
+
rel: "noopener noreferrer",
|
|
13
|
+
children: item.label
|
|
14
|
+
})
|
|
15
|
+
]
|
|
16
|
+
}, `${item.href}-${index}`))
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function AgreementDialog({ agreements, labels, onCancel, onAgree }) {
|
|
20
|
+
const dialog = useRef(null);
|
|
21
|
+
const titleId = useId();
|
|
22
|
+
const descriptionId = useId();
|
|
23
|
+
useEffect(()=>{
|
|
24
|
+
const element = dialog.current;
|
|
25
|
+
element?.showModal();
|
|
26
|
+
return ()=>element?.close();
|
|
27
|
+
}, []);
|
|
28
|
+
const text = agreements.confirmation;
|
|
29
|
+
return /*#__PURE__*/ jsxs("dialog", {
|
|
30
|
+
ref: dialog,
|
|
31
|
+
className: "ov-auth ov-auth__dialog",
|
|
32
|
+
"aria-labelledby": titleId,
|
|
33
|
+
"aria-describedby": descriptionId,
|
|
34
|
+
onCancel: (event)=>{
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
onCancel();
|
|
37
|
+
},
|
|
38
|
+
children: [
|
|
39
|
+
/*#__PURE__*/ jsx("h2", {
|
|
40
|
+
id: titleId,
|
|
41
|
+
children: text?.title ?? labels.agreementTitle
|
|
42
|
+
}),
|
|
43
|
+
/*#__PURE__*/ jsxs("p", {
|
|
44
|
+
id: descriptionId,
|
|
45
|
+
children: [
|
|
46
|
+
text?.description ?? labels.agreementDescription,
|
|
47
|
+
/*#__PURE__*/ jsx(AgreementLinks, {
|
|
48
|
+
agreements: agreements
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
}),
|
|
52
|
+
/*#__PURE__*/ jsxs("div", {
|
|
53
|
+
className: "ov-auth__actions",
|
|
54
|
+
children: [
|
|
55
|
+
/*#__PURE__*/ jsx("button", {
|
|
56
|
+
type: "button",
|
|
57
|
+
onClick: onCancel,
|
|
58
|
+
children: text?.cancelText ?? labels.cancel
|
|
59
|
+
}),
|
|
60
|
+
/*#__PURE__*/ jsx("button", {
|
|
61
|
+
className: "ov-auth__primary",
|
|
62
|
+
type: "button",
|
|
63
|
+
onClick: onAgree,
|
|
64
|
+
children: text?.confirmText ?? labels.agree
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
})
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function FormFrame({ children, labels, submitLabel, validate, onSubmit, secondaryAction, ...options }) {
|
|
72
|
+
const [accepted, setAccepted] = useState(false);
|
|
73
|
+
const [confirming, setConfirming] = useState(false);
|
|
74
|
+
const agreements = options.agreements?.items.length ? options.agreements : void 0;
|
|
75
|
+
const blocked = options.loading || options.disabled;
|
|
76
|
+
const submit = (agreed = false)=>{
|
|
77
|
+
if (blocked || !validate()) return;
|
|
78
|
+
if (agreements && !accepted && !agreed) return void setConfirming(true);
|
|
79
|
+
if (agreed) setAccepted(true);
|
|
80
|
+
onSubmit();
|
|
81
|
+
};
|
|
82
|
+
return /*#__PURE__*/ jsxs("form", {
|
|
83
|
+
className: `ov-auth ${options.className ?? ''}`,
|
|
84
|
+
noValidate: true,
|
|
85
|
+
"aria-busy": options.loading || void 0,
|
|
86
|
+
onSubmit: (event)=>{
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
submit();
|
|
89
|
+
},
|
|
90
|
+
children: [
|
|
91
|
+
/*#__PURE__*/ jsx(Action, {
|
|
92
|
+
action: options.back
|
|
93
|
+
}),
|
|
94
|
+
options.title && /*#__PURE__*/ jsx("h2", {
|
|
95
|
+
children: options.title
|
|
96
|
+
}),
|
|
97
|
+
options.description && /*#__PURE__*/ jsx("p", {
|
|
98
|
+
className: "ov-auth__description",
|
|
99
|
+
children: options.description
|
|
100
|
+
}),
|
|
101
|
+
/*#__PURE__*/ jsx("fieldset", {
|
|
102
|
+
disabled: blocked,
|
|
103
|
+
children: children
|
|
104
|
+
}),
|
|
105
|
+
options.error && /*#__PURE__*/ jsx("div", {
|
|
106
|
+
className: "ov-auth__error",
|
|
107
|
+
role: "alert",
|
|
108
|
+
children: options.error
|
|
109
|
+
}),
|
|
110
|
+
/*#__PURE__*/ jsxs("button", {
|
|
111
|
+
className: "ov-auth__primary ov-auth__submit",
|
|
112
|
+
type: "submit",
|
|
113
|
+
disabled: blocked,
|
|
114
|
+
children: [
|
|
115
|
+
submitLabel,
|
|
116
|
+
options.loading && /*#__PURE__*/ jsx("span", {
|
|
117
|
+
"aria-hidden": "true",
|
|
118
|
+
children: " …"
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}),
|
|
122
|
+
agreements && /*#__PURE__*/ jsxs("label", {
|
|
123
|
+
className: "ov-auth__consent",
|
|
124
|
+
children: [
|
|
125
|
+
/*#__PURE__*/ jsx("input", {
|
|
126
|
+
type: "checkbox",
|
|
127
|
+
checked: accepted,
|
|
128
|
+
disabled: blocked,
|
|
129
|
+
onChange: (event)=>setAccepted(event.target.checked)
|
|
130
|
+
}),
|
|
131
|
+
/*#__PURE__*/ jsxs("span", {
|
|
132
|
+
children: [
|
|
133
|
+
labels.agreementPrefix,
|
|
134
|
+
/*#__PURE__*/ jsx(AgreementLinks, {
|
|
135
|
+
agreements: agreements
|
|
136
|
+
})
|
|
137
|
+
]
|
|
138
|
+
})
|
|
139
|
+
]
|
|
140
|
+
}),
|
|
141
|
+
/*#__PURE__*/ jsx(Action, {
|
|
142
|
+
action: secondaryAction
|
|
143
|
+
}),
|
|
144
|
+
confirming && agreements && /*#__PURE__*/ jsx(AgreementDialog, {
|
|
145
|
+
agreements: agreements,
|
|
146
|
+
labels: labels,
|
|
147
|
+
onCancel: ()=>setConfirming(false),
|
|
148
|
+
onAgree: ()=>{
|
|
149
|
+
setConfirming(false);
|
|
150
|
+
submit(true);
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function useForm(initial, validate) {
|
|
157
|
+
const [values, setValues] = useState(initial);
|
|
158
|
+
const [errors, setErrors] = useState({});
|
|
159
|
+
const update = (key, value)=>{
|
|
160
|
+
setValues((current)=>({
|
|
161
|
+
...current,
|
|
162
|
+
[key]: value
|
|
163
|
+
}));
|
|
164
|
+
setErrors((current)=>({
|
|
165
|
+
...current,
|
|
166
|
+
[key]: void 0
|
|
167
|
+
}));
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
values,
|
|
171
|
+
errors,
|
|
172
|
+
update,
|
|
173
|
+
validate: ()=>{
|
|
174
|
+
const next = validate(values);
|
|
175
|
+
setErrors(next);
|
|
176
|
+
return !Object.values(next).some((issue)=>void 0 !== issue);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const validEmail = (value)=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
|
|
181
|
+
export { FormFrame, useForm, validEmail };
|