@brftech/filex-core 0.42.1 → 0.43.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/README.md +14 -2
- package/dist/ArchiveViewer-BqU761Wk.js +149 -0
- package/dist/ArchiveViewer-BqU761Wk.js.map +1 -0
- package/dist/CsvViewer-ByHVK5ga.js +172 -0
- package/dist/CsvViewer-ByHVK5ga.js.map +1 -0
- package/dist/{DrawioViewer-BuhZOAx6.js → DrawioViewer-Bgrj8-zG.js} +45 -44
- package/dist/DrawioViewer-Bgrj8-zG.js.map +1 -0
- package/dist/{EpubViewer-DS3mb3k8.js → EpubViewer-DJwUKlHW.js} +50 -50
- package/dist/EpubViewer-DJwUKlHW.js.map +1 -0
- package/dist/IpynbViewer-Bz0eJ4NS.js +184 -0
- package/dist/IpynbViewer-Bz0eJ4NS.js.map +1 -0
- package/dist/MermaidViewer-CEDTD_pp.js +136 -0
- package/dist/MermaidViewer-CEDTD_pp.js.map +1 -0
- package/dist/PsdViewer-CZcxUpZO.js +121 -0
- package/dist/PsdViewer-CZcxUpZO.js.map +1 -0
- package/dist/TiffViewer-BwI62CbQ.js +141 -0
- package/dist/TiffViewer-BwI62CbQ.js.map +1 -0
- package/dist/{Viewer3D-CIrOn63I.js → Viewer3D-DoeZcuMm.js} +16 -16
- package/dist/Viewer3D-DoeZcuMm.js.map +1 -0
- package/dist/filex-core.js +475 -219
- package/dist/filex-core.umd.cjs +165 -108
- package/dist/filex-core.umd.cjs.map +1 -1
- package/dist/fonts/caveat-latin-ext.woff2 +0 -0
- package/dist/fonts/caveat-latin.woff2 +0 -0
- package/dist/fonts/dancing-script-latin-ext.woff2 +0 -0
- package/dist/fonts/dancing-script-latin.woff2 +0 -0
- package/dist/fonts/homemade-apple-latin.woff2 +0 -0
- package/dist/fonts/source-serif-4-latin-ext.woff2 +0 -0
- package/dist/fonts/source-serif-4-latin.woff2 +0 -0
- package/dist/index-DuWnGuv5.js +35901 -0
- package/dist/index-DuWnGuv5.js.map +1 -0
- package/dist/index.d.ts +5241 -553
- package/dist/pdf-CaPYsOUo.js +21302 -0
- package/dist/pdf-CaPYsOUo.js.map +1 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/FileExplorer.vue +1207 -343
- package/src/assets/fonts/LICENSE-Apache-2.0.txt +202 -0
- package/src/assets/fonts/LICENSE-OFL-1.1.txt +93 -0
- package/src/assets/fonts/README.md +58 -0
- package/src/assets/fonts/caveat-latin-ext.woff2 +0 -0
- package/src/assets/fonts/caveat-latin.woff2 +0 -0
- package/src/assets/fonts/dancing-script-latin-ext.woff2 +0 -0
- package/src/assets/fonts/dancing-script-latin.woff2 +0 -0
- package/src/assets/fonts/homemade-apple-latin.woff2 +0 -0
- package/src/assets/fonts/source-serif-4-latin-ext.woff2 +0 -0
- package/src/assets/fonts/source-serif-4-latin.woff2 +0 -0
- package/src/components/AdvancedSearch.vue +49 -0
- package/src/components/Breadcrumb.vue +5 -5
- package/src/components/ChoiceButtons.vue +152 -0
- package/src/components/CommandPalette.vue +5 -5
- package/src/components/ConnectionGuideView.vue +1 -1
- package/src/components/ConnectionNotice.vue +59 -0
- package/src/components/ConnectionsPanel.vue +30 -568
- package/src/components/ContextMenu.vue +31 -5
- package/src/components/DataTable.vue +1331 -0
- package/src/components/FilePane.vue +3 -0
- package/src/components/FilterBar.vue +12 -5
- package/src/components/GalleryView.vue +50 -2
- package/src/components/GridView.vue +51 -3
- package/src/components/HomeView.vue +18 -6
- package/src/components/InspectorPanel.vue +134 -17
- package/src/components/ListView.vue +366 -900
- package/src/components/LogoMark.vue +57 -0
- package/src/components/NFSExportsPanel.vue +76 -28
- package/src/components/OnboardingTour.vue +19 -7
- package/src/components/OperationsCenter.vue +77 -1
- package/src/components/PendingOpsTray.vue +59 -5
- package/src/components/PresenceBar.vue +7 -7
- package/src/components/ProductVersion.vue +31 -0
- package/src/components/QuickLook.vue +10 -14
- package/src/components/RecentlyOpened.vue +47 -17
- package/src/components/RecoveryKeyModal.vue +1 -1
- package/src/components/RowActions.vue +134 -0
- package/src/components/S3KeysPanel.vue +98 -56
- package/src/components/SSHKeysPanel.vue +79 -26
- package/src/components/SideNav.vue +260 -96
- package/src/components/StarButton.vue +1 -0
- package/src/components/StorageFields.vue +74 -6
- package/src/components/StorageTags.vue +62 -0
- package/src/components/TabBar.vue +1 -1
- package/src/components/TagKindIcon.vue +56 -0
- package/src/components/TagPicker.vue +226 -40
- package/src/components/ThemePalette.vue +4 -4
- package/src/components/TimeZonePicker.vue +29 -10
- package/src/components/TokensPanel.vue +82 -27
- package/src/components/Toolbar.vue +28 -6
- package/src/components/plugin/PluginConfirmModal.vue +54 -0
- package/src/components/plugin/PluginInspectorSection.vue +149 -0
- package/src/components/plugin/PluginPageView.vue +339 -0
- package/src/components/plugin/PluginViewModal.vue +159 -0
- package/src/components/plugin/SurfaceConversation.vue +76 -0
- package/src/components/plugin/SurfaceFooterButtons.vue +73 -0
- package/src/components/plugin/SurfaceRenderer.vue +299 -0
- package/src/components/plugin/SurfaceSections.vue +91 -0
- package/src/components/plugin/nodes/PdfFieldEditor.vue +509 -0
- package/src/components/plugin/nodes/SurfaceFileChooser.vue +94 -0
- package/src/components/plugin/nodes/SurfaceForm.vue +82 -0
- package/src/components/plugin/nodes/SurfaceList.vue +127 -0
- package/src/components/plugin/nodes/SurfacePdfFields.vue +1285 -0
- package/src/components/plugin/nodes/SurfacePeoplePicker.vue +213 -0
- package/src/components/plugin/nodes/SurfacePinInput.vue +57 -0
- package/src/components/plugin/nodes/SurfacePreview.vue +119 -0
- package/src/components/plugin/nodes/SurfaceProgress.vue +48 -0
- package/src/components/plugin/nodes/SurfaceSignaturePad.vue +472 -0
- package/src/components/plugin/nodes/SurfaceSteps.vue +53 -0
- package/src/components/public/PublicLanguagePicker.vue +58 -0
- package/src/components/public/PublicLinkPage.vue +286 -0
- package/src/components/public/PublicLinkPreview.vue +85 -0
- package/src/components/public/PublicPinGate.vue +108 -0
- package/src/components/public/PublicRequestBody.vue +204 -0
- package/src/components/public/PublicShareBody.vue +188 -0
- package/src/components/public/PublicShell.vue +332 -0
- package/src/composables/useConnections.ts +8 -2
- package/src/composables/useFileApi.ts +183 -44
- package/src/composables/useLocale.ts +277 -41
- package/src/composables/useNFSExports.ts +8 -10
- package/src/composables/useOperations.ts +44 -3
- package/src/composables/usePendingOps.ts +59 -8
- package/src/composables/usePluginActions.ts +121 -0
- package/src/composables/usePluginSurface.ts +223 -0
- package/src/composables/usePublicBranding.ts +172 -0
- package/src/composables/usePublicLink.ts +573 -0
- package/src/composables/usePublicPage.ts +61 -0
- package/src/composables/useS3Keys.ts +17 -12
- package/src/composables/useSSHKeys.ts +8 -10
- package/src/composables/useTokens.ts +8 -12
- package/src/composables/useUploadChunked.ts +18 -8
- package/src/composables/useViewerFetch.ts +6 -3
- package/src/index.ts +404 -8
- package/src/lib/actionIcons.ts +46 -1
- package/src/lib/advSearch.ts +14 -7
- package/src/lib/appLock.ts +130 -0
- package/src/lib/connection.ts +110 -0
- package/src/lib/destinationTree.ts +19 -3
- package/src/lib/direction.ts +353 -0
- package/src/lib/dragGhost.ts +6 -0
- package/src/lib/dropLimits.ts +69 -0
- package/src/lib/errorWords.ts +394 -0
- package/src/lib/externalReach.ts +5 -1
- package/src/lib/fileFilters.ts +7 -2
- package/src/lib/fileIcons.ts +4 -0
- package/src/lib/internalPaths.ts +77 -0
- package/src/lib/listInput.ts +64 -0
- package/src/lib/listing.ts +58 -23
- package/src/lib/modalStack.ts +26 -0
- package/src/lib/nodeRow.ts +121 -0
- package/src/lib/pdfFieldRules.ts +126 -0
- package/src/lib/pdfFields.ts +589 -0
- package/src/lib/pdfFieldsGeom.ts +203 -0
- package/src/lib/pdfjsLoader.ts +51 -0
- package/src/lib/personName.ts +47 -0
- package/src/lib/pluginApplies.ts +123 -0
- package/src/lib/pluginLabel.ts +72 -0
- package/src/lib/pluginMenu.ts +253 -0
- package/src/lib/pluginPage.ts +58 -0
- package/src/lib/plural.ts +181 -0
- package/src/lib/popupLayer.ts +103 -0
- package/src/lib/prefs.ts +563 -0
- package/src/lib/productVersion.ts +35 -0
- package/src/lib/publicLayout.ts +39 -0
- package/src/lib/serviceGate.ts +104 -0
- package/src/lib/shareTtl.ts +25 -11
- package/src/lib/signFonts.ts +85 -0
- package/src/lib/signaturePad.ts +111 -0
- package/src/lib/sortOrder.ts +100 -38
- package/src/lib/star.ts +7 -1
- package/src/lib/surfaceCell.ts +41 -0
- package/src/lib/surfaceConditions.ts +156 -0
- package/src/lib/surfaceOpen.ts +106 -0
- package/src/lib/surfaceSteps.ts +68 -0
- package/src/lib/surfaceValues.ts +191 -0
- package/src/lib/symlink.ts +150 -0
- package/src/lib/tableColumns.ts +493 -0
- package/src/lib/tableEnv.ts +34 -0
- package/src/lib/tablePrefs.ts +84 -0
- package/src/lib/tags.ts +121 -12
- package/src/lib/themes.ts +286 -18
- package/src/lib/tour.ts +152 -0
- package/src/lib/trashEmpty.ts +111 -0
- package/src/lib/trashTimeLeft.ts +23 -0
- package/src/lib/uiLocales.ts +460 -0
- package/src/lib/viewPrefs.ts +696 -660
- package/src/lib/viewPrefsHttp.ts +78 -0
- package/src/locales/en.ts +522 -119
- package/src/locales/resolve.ts +17 -8
- package/src/locales/tr.ts +539 -155
- package/src/modals/ConvertModal.vue +62 -11
- package/src/modals/DestinationPickerModal.vue +59 -16
- package/src/modals/Modal.vue +113 -23
- package/src/modals/NewDocumentModal.vue +16 -6
- package/src/modals/NewFolderModal.vue +8 -0
- package/src/modals/PermissionsModal.vue +272 -163
- package/src/modals/PreviewModal.vue +119 -20
- package/src/modals/RenameModal.vue +37 -1
- package/src/styles/base.css +2895 -241
- package/src/styles/sign-fonts.css +118 -0
- package/src/styles/variables.css +60 -0
- package/src/types/Connections.ts +17 -0
- package/src/types/ExplorerConfig.ts +117 -1
- package/src/types/FileNode.ts +58 -0
- package/src/types/Plugins.ts +494 -0
- package/src/types/Public.ts +212 -0
- package/src/viewers/ArchiveViewer.vue +93 -48
- package/src/viewers/CsvViewer.vue +99 -53
- package/src/viewers/DrawioViewer.vue +35 -9
- package/src/viewers/EpubViewer.vue +7 -8
- package/src/viewers/IpynbViewer.vue +3 -1
- package/src/viewers/MermaidViewer.vue +4 -5
- package/src/viewers/PdfViewer.vue +8 -17
- package/src/viewers/PsdViewer.vue +2 -4
- package/src/viewers/TiffViewer.vue +4 -5
- package/src/viewers/Viewer3D.vue +1 -1
- package/LICENSE +0 -21
- package/dist/ArchiveViewer-CLNevfPE.js +0 -124
- package/dist/ArchiveViewer-CLNevfPE.js.map +0 -1
- package/dist/CsvViewer-K8XA3z7N.js +0 -141
- package/dist/CsvViewer-K8XA3z7N.js.map +0 -1
- package/dist/DrawioViewer-BuhZOAx6.js.map +0 -1
- package/dist/EpubViewer-DS3mb3k8.js.map +0 -1
- package/dist/IpynbViewer-BTk7p4Dn.js +0 -184
- package/dist/IpynbViewer-BTk7p4Dn.js.map +0 -1
- package/dist/MermaidViewer-DqucH_io.js +0 -137
- package/dist/MermaidViewer-DqucH_io.js.map +0 -1
- package/dist/PsdViewer-CwiVENmq.js +0 -122
- package/dist/PsdViewer-CwiVENmq.js.map +0 -1
- package/dist/TiffViewer-CpewSVmQ.js +0 -142
- package/dist/TiffViewer-CpewSVmQ.js.map +0 -1
- package/dist/Viewer3D-CIrOn63I.js.map +0 -1
- package/dist/index-Dx0IbBcI.js +0 -26831
- package/dist/index-Dx0IbBcI.js.map +0 -1
- package/dist/useViewerFetch-czqbd2Lj.js +0 -25
- package/dist/useViewerFetch-czqbd2Lj.js.map +0 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SurfaceRenderer — draws a plugin's declarative screen with filex's own
|
|
4
|
+
* components. The plugin sends data (`wire.Surface.nodes`); nothing it sends
|
|
5
|
+
* is ever markup, a script or a frame — a node type this file does not know
|
|
6
|
+
* is shown AS unknown, not skipped and not interpreted.
|
|
7
|
+
*
|
|
8
|
+
* M1 drew `text` (and layout `row` / `divider`). M2 adds the rest of the
|
|
9
|
+
* v1 catalogue — form, steps, list, progress, people-picker, pin-input,
|
|
10
|
+
* file-chooser, preview — one `<template v-else-if>` each, each a small
|
|
11
|
+
* component under `./nodes/`. M3 (the sign track) adds `signature-pad` and
|
|
12
|
+
* `pdf-fields`, and lets `preview` show a public page's exposed copy by
|
|
13
|
+
* `ref` through the host's `fileUrl` resolver.
|
|
14
|
+
*
|
|
15
|
+
* Values: nodes that hold one read and write the ONE map the host owns
|
|
16
|
+
* (`values`, v-model style), keyed by node id — a `form`'s fields flat by
|
|
17
|
+
* field key. Events up: `update:values` on any edit, `change` on a form
|
|
18
|
+
* edit (the host debounces it into the contract's `change` event), `action`
|
|
19
|
+
* for a list row's button. Nested rows forward all three.
|
|
20
|
+
*/
|
|
21
|
+
import type { LocaleCode, ThemeMode } from '../../types/ExplorerConfig';
|
|
22
|
+
import type { FileApi } from '../../composables/useFileApi';
|
|
23
|
+
import type {
|
|
24
|
+
FileChooserNodeProps,
|
|
25
|
+
FileRefResolver,
|
|
26
|
+
FormNodeProps,
|
|
27
|
+
ListNodeProps,
|
|
28
|
+
PdfFieldsNodeProps,
|
|
29
|
+
PeoplePickerNodeProps,
|
|
30
|
+
PinInputNodeProps,
|
|
31
|
+
PluginPerson,
|
|
32
|
+
PluginText,
|
|
33
|
+
PreviewNodeProps,
|
|
34
|
+
ProgressNodeProps,
|
|
35
|
+
SignaturePadNodeProps,
|
|
36
|
+
StepsNodeProps,
|
|
37
|
+
SurfaceNode,
|
|
38
|
+
TextNodeProps,
|
|
39
|
+
} from '../../types/Plugins';
|
|
40
|
+
import { isSignatureValue } from '../../lib/signaturePad';
|
|
41
|
+
import { useLocale } from '../../composables/useLocale';
|
|
42
|
+
import { labelOf } from '../../lib/pluginLabel';
|
|
43
|
+
import SurfaceForm from './nodes/SurfaceForm.vue';
|
|
44
|
+
import SurfaceSteps from './nodes/SurfaceSteps.vue';
|
|
45
|
+
import SurfaceList from './nodes/SurfaceList.vue';
|
|
46
|
+
import SurfaceProgress from './nodes/SurfaceProgress.vue';
|
|
47
|
+
import SurfacePeoplePicker from './nodes/SurfacePeoplePicker.vue';
|
|
48
|
+
import SurfacePinInput from './nodes/SurfacePinInput.vue';
|
|
49
|
+
import SurfaceFileChooser from './nodes/SurfaceFileChooser.vue';
|
|
50
|
+
import SurfacePreview from './nodes/SurfacePreview.vue';
|
|
51
|
+
import SurfaceSignaturePad from './nodes/SurfaceSignaturePad.vue';
|
|
52
|
+
import SurfacePdfFields from './nodes/SurfacePdfFields.vue';
|
|
53
|
+
|
|
54
|
+
/** What the value-holding and file-reading nodes need from the explorer's API. */
|
|
55
|
+
export type SurfaceApi = Pick<FileApi, 'index' | 'pluginUsers' | 'fetchBlob'>;
|
|
56
|
+
|
|
57
|
+
const props = defineProps<{
|
|
58
|
+
nodes: SurfaceNode[];
|
|
59
|
+
locale: LocaleCode;
|
|
60
|
+
theme?: ThemeMode;
|
|
61
|
+
/** Field-level errors the surface carries, keyed by node id / field key. */
|
|
62
|
+
errors?: Record<string, PluginText>;
|
|
63
|
+
/** The surface's values (node id → value; form fields flat). */
|
|
64
|
+
values?: Record<string, unknown>;
|
|
65
|
+
/** Absent in a bare render: choosers and previews say so instead of failing. */
|
|
66
|
+
api?: SurfaceApi;
|
|
67
|
+
/** The plugin the surface belongs to (the people-picker's lookup asks for it). */
|
|
68
|
+
plugin?: string;
|
|
69
|
+
/** Storage names a file-chooser may span; where its picker opens. */
|
|
70
|
+
storages?: string[];
|
|
71
|
+
startAt?: string;
|
|
72
|
+
/** The host is talking to the server: inputs and buttons stay put. */
|
|
73
|
+
disabled?: boolean;
|
|
74
|
+
/** A public page's exposed copies (`pub:N`) → a URL the browser may load (M3). */
|
|
75
|
+
fileUrl?: FileRefResolver;
|
|
76
|
+
/** Where pdf.js fetches its worker from; the pinned CDN copy when absent. */
|
|
77
|
+
pdfWorkerUrl?: string | null;
|
|
78
|
+
/**
|
|
79
|
+
* v3 §2.1 — field keys a refused submit is waiting for. Passed down to the
|
|
80
|
+
* form so the star and the "required" line land on the FIELD, not in a
|
|
81
|
+
* banner the person has to map back onto a box themselves.
|
|
82
|
+
*/
|
|
83
|
+
invalidKeys?: string[];
|
|
84
|
+
/**
|
|
85
|
+
* v3 §3.2 — `page` means this surface owns the viewport, so a `pdf-fields`
|
|
86
|
+
* node fits the document to the screen instead of to the text column. The
|
|
87
|
+
* frame says which; a node never measures the window itself.
|
|
88
|
+
*/
|
|
89
|
+
layout?: 'inline' | 'page';
|
|
90
|
+
/** The box a `page` layout's document may fill (a CSS length). */
|
|
91
|
+
pageHeight?: string;
|
|
92
|
+
}>();
|
|
93
|
+
|
|
94
|
+
const emit = defineEmits<{
|
|
95
|
+
(e: 'update:values', v: Record<string, unknown>): void;
|
|
96
|
+
/** A form field was edited (the host debounces into `event: "change"`). */
|
|
97
|
+
(e: 'change'): void;
|
|
98
|
+
(e: 'action', p: { action_id: string; row_id: string }): void;
|
|
99
|
+
}>();
|
|
100
|
+
|
|
101
|
+
const { t } = useLocale(() => props.locale);
|
|
102
|
+
|
|
103
|
+
const vals = () => props.values ?? {};
|
|
104
|
+
|
|
105
|
+
function set(id: string, v: unknown) {
|
|
106
|
+
emit('update:values', { ...vals(), [id]: v });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function onFormValues(v: Record<string, unknown>) {
|
|
110
|
+
emit('update:values', v);
|
|
111
|
+
emit('change');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** A `pdf-fields` edit is authoring: it posts `change` like a form does. Filling rides on the next submit. */
|
|
115
|
+
function onPdfValue(n: SurfaceNode, v: unknown) {
|
|
116
|
+
set(n.id as string, v);
|
|
117
|
+
if (p<PdfFieldsNodeProps>(n).mode !== 'fill') emit('change');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function p<T>(n: SurfaceNode): T {
|
|
121
|
+
return (n.props ?? {}) as unknown as T;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** A `text` node's words: `props.text` (a Text or a string), else `props.value`. */
|
|
125
|
+
function textOf(n: SurfaceNode): string {
|
|
126
|
+
const tp = p<TextNodeProps>(n);
|
|
127
|
+
return labelOf(tp.text ?? tp.value ?? '', props.locale);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function toneOf(n: SurfaceNode): string {
|
|
131
|
+
const tone = String(p<TextNodeProps>(n).tone ?? '');
|
|
132
|
+
return tone === 'muted' || tone === 'danger' || tone === 'info' ? `fe-surface__text--${tone}` : '';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function errorOf(n: SurfaceNode): string {
|
|
136
|
+
if (!n.id || !props.errors) return '';
|
|
137
|
+
return labelOf(props.errors[n.id], props.locale);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function str(v: unknown): string {
|
|
141
|
+
return typeof v === 'string' ? v : '';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function people(v: unknown): PluginPerson[] {
|
|
145
|
+
return Array.isArray(v) ? (v as PluginPerson[]) : [];
|
|
146
|
+
}
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<template>
|
|
150
|
+
<div class="fe-surface">
|
|
151
|
+
<template v-for="(n, i) in nodes" :key="n.id || i">
|
|
152
|
+
<p
|
|
153
|
+
v-if="n.type === 'text'"
|
|
154
|
+
class="fe-surface__text"
|
|
155
|
+
:class="[toneOf(n), p<TextNodeProps>(n).heading ? 'fe-surface__text--heading' : '']"
|
|
156
|
+
:data-node="n.id || undefined"
|
|
157
|
+
>{{ textOf(n) }}</p>
|
|
158
|
+
<hr v-else-if="n.type === 'divider'" class="fe-surface__divider" />
|
|
159
|
+
<div v-else-if="n.type === 'row'" class="fe-surface__row">
|
|
160
|
+
<SurfaceRenderer
|
|
161
|
+
:nodes="n.children ?? []"
|
|
162
|
+
:locale="locale"
|
|
163
|
+
:theme="theme"
|
|
164
|
+
:errors="errors"
|
|
165
|
+
:values="values"
|
|
166
|
+
:api="api"
|
|
167
|
+
:plugin="plugin"
|
|
168
|
+
:storages="storages"
|
|
169
|
+
:start-at="startAt"
|
|
170
|
+
:disabled="disabled"
|
|
171
|
+
:file-url="fileUrl"
|
|
172
|
+
:pdf-worker-url="pdfWorkerUrl"
|
|
173
|
+
:invalid-keys="invalidKeys"
|
|
174
|
+
:layout="layout"
|
|
175
|
+
:page-height="pageHeight"
|
|
176
|
+
@update:values="(v) => emit('update:values', v)"
|
|
177
|
+
@change="emit('change')"
|
|
178
|
+
@action="(a) => emit('action', a)"
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
<SurfaceForm
|
|
182
|
+
v-else-if="n.type === 'form'"
|
|
183
|
+
:fields="p<FormNodeProps>(n).fields ?? []"
|
|
184
|
+
:values="vals()"
|
|
185
|
+
:locale="locale"
|
|
186
|
+
:errors="errors"
|
|
187
|
+
:invalid="invalidKeys"
|
|
188
|
+
:disabled="disabled"
|
|
189
|
+
@update:values="onFormValues"
|
|
190
|
+
/>
|
|
191
|
+
<SurfaceSteps v-else-if="n.type === 'steps'" :items="p<StepsNodeProps>(n).items ?? []" :locale="locale" />
|
|
192
|
+
<SurfaceList
|
|
193
|
+
v-else-if="n.type === 'list'"
|
|
194
|
+
:columns="p<ListNodeProps>(n).columns ?? []"
|
|
195
|
+
:rows="p<ListNodeProps>(n).rows ?? []"
|
|
196
|
+
:empty="p<ListNodeProps>(n).empty"
|
|
197
|
+
:locale="locale"
|
|
198
|
+
:disabled="disabled"
|
|
199
|
+
:table-id="plugin ? `app.${plugin}.${n.id || 'list'}` : undefined"
|
|
200
|
+
@action="(a) => emit('action', a)"
|
|
201
|
+
/>
|
|
202
|
+
<SurfaceProgress
|
|
203
|
+
v-else-if="n.type === 'progress'"
|
|
204
|
+
:value="p<ProgressNodeProps>(n).value"
|
|
205
|
+
:label="p<ProgressNodeProps>(n).label"
|
|
206
|
+
:locale="locale"
|
|
207
|
+
/>
|
|
208
|
+
<SurfacePeoplePicker
|
|
209
|
+
v-else-if="n.type === 'people-picker' && n.id"
|
|
210
|
+
:id="n.id"
|
|
211
|
+
:model-value="people(vals()[n.id])"
|
|
212
|
+
:multi="p<PeoplePickerNodeProps>(n).multi === true"
|
|
213
|
+
:allow-external="p<PeoplePickerNodeProps>(n).allow_external === true"
|
|
214
|
+
:api="api"
|
|
215
|
+
:plugin="plugin"
|
|
216
|
+
:locale="locale"
|
|
217
|
+
:disabled="disabled"
|
|
218
|
+
:invalid="!!errorOf(n)"
|
|
219
|
+
@update:model-value="(v) => set(n.id as string, v)"
|
|
220
|
+
/>
|
|
221
|
+
<SurfacePinInput
|
|
222
|
+
v-else-if="n.type === 'pin-input' && n.id"
|
|
223
|
+
:id="n.id"
|
|
224
|
+
:length="p<PinInputNodeProps>(n).length"
|
|
225
|
+
:model-value="str(vals()[n.id])"
|
|
226
|
+
:locale="locale"
|
|
227
|
+
:disabled="disabled"
|
|
228
|
+
:invalid="!!errorOf(n)"
|
|
229
|
+
@update:model-value="(v) => set(n.id as string, v)"
|
|
230
|
+
/>
|
|
231
|
+
<SurfaceFileChooser
|
|
232
|
+
v-else-if="n.type === 'file-chooser' && n.id"
|
|
233
|
+
:id="n.id"
|
|
234
|
+
:kind="p<FileChooserNodeProps>(n).kind"
|
|
235
|
+
:model-value="str(vals()[n.id])"
|
|
236
|
+
:api="api"
|
|
237
|
+
:storages="storages"
|
|
238
|
+
:start-at="startAt"
|
|
239
|
+
:locale="locale"
|
|
240
|
+
:theme="theme"
|
|
241
|
+
:disabled="disabled"
|
|
242
|
+
:invalid="!!errorOf(n)"
|
|
243
|
+
@update:model-value="(v) => set(n.id as string, v)"
|
|
244
|
+
/>
|
|
245
|
+
<SurfacePreview
|
|
246
|
+
v-else-if="n.type === 'preview'"
|
|
247
|
+
:path="str(p<PreviewNodeProps>(n).path)"
|
|
248
|
+
:file-ref="str(p<PreviewNodeProps>(n).ref)"
|
|
249
|
+
:file-url="fileUrl"
|
|
250
|
+
:api="api"
|
|
251
|
+
:locale="locale"
|
|
252
|
+
/>
|
|
253
|
+
<SurfaceSignaturePad
|
|
254
|
+
v-else-if="n.type === 'signature-pad' && n.id"
|
|
255
|
+
:id="n.id"
|
|
256
|
+
:modes="p<SignaturePadNodeProps>(n).modes"
|
|
257
|
+
:width="p<SignaturePadNodeProps>(n).width"
|
|
258
|
+
:height="p<SignaturePadNodeProps>(n).height"
|
|
259
|
+
:font="p<SignaturePadNodeProps>(n).font"
|
|
260
|
+
:fonts="p<SignaturePadNodeProps>(n).fonts"
|
|
261
|
+
:label="labelOf(p<SignaturePadNodeProps>(n).label ?? '', locale)"
|
|
262
|
+
:required="p<SignaturePadNodeProps>(n).required === true"
|
|
263
|
+
:model-value="isSignatureValue(vals()[n.id]) ? (vals()[n.id] as never) : null"
|
|
264
|
+
:locale="locale"
|
|
265
|
+
:disabled="disabled"
|
|
266
|
+
:invalid="!!errorOf(n)"
|
|
267
|
+
@update:model-value="(v) => set(n.id as string, v)"
|
|
268
|
+
/>
|
|
269
|
+
<SurfacePdfFields
|
|
270
|
+
v-else-if="n.type === 'pdf-fields' && n.id"
|
|
271
|
+
:id="n.id"
|
|
272
|
+
:src="p<PdfFieldsNodeProps>(n).src"
|
|
273
|
+
:mode="p<PdfFieldsNodeProps>(n).mode"
|
|
274
|
+
:fields="p<PdfFieldsNodeProps>(n).fields"
|
|
275
|
+
:layout="layout"
|
|
276
|
+
:page-height="pageHeight"
|
|
277
|
+
:signers="p<PdfFieldsNodeProps>(n).signers"
|
|
278
|
+
:signer="p<PdfFieldsNodeProps>(n).signer"
|
|
279
|
+
:types="p<PdfFieldsNodeProps>(n).types"
|
|
280
|
+
:formats="p<PdfFieldsNodeProps>(n).formats"
|
|
281
|
+
:date-labels="p<PdfFieldsNodeProps>(n).date_labels"
|
|
282
|
+
:stamp-lines="p<PdfFieldsNodeProps>(n).stamp_lines"
|
|
283
|
+
:model-value="vals()[n.id]"
|
|
284
|
+
:api="api"
|
|
285
|
+
:file-url="fileUrl"
|
|
286
|
+
:pdf-worker-url="pdfWorkerUrl"
|
|
287
|
+
:locale="locale"
|
|
288
|
+
:theme="theme"
|
|
289
|
+
:disabled="disabled"
|
|
290
|
+
:invalid="!!errorOf(n)"
|
|
291
|
+
@update:model-value="(v) => onPdfValue(n, v)"
|
|
292
|
+
/>
|
|
293
|
+
<p v-else class="fe-surface__unknown" :data-node-type="n.type">
|
|
294
|
+
{{ t('plugin.view.unsupported', { type: n.type }) }}
|
|
295
|
+
</p>
|
|
296
|
+
<p v-if="errorOf(n) && n.type !== 'form'" class="fe-surface__error">{{ errorOf(n) }}</p>
|
|
297
|
+
</template>
|
|
298
|
+
</div>
|
|
299
|
+
</template>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SurfaceSections — a home page's menu: one entry per section the plugin
|
|
4
|
+
* declared (`surface.sections`), the open one marked.
|
|
5
|
+
*
|
|
6
|
+
* ⚠⚠ Drawn by the FRAME, never by a node. The owner, 2026-09-21: the
|
|
7
|
+
* Signatures screen should be "its own page … each in a separate menu",
|
|
8
|
+
* with the browser's Back working and a notification landing on the right
|
|
9
|
+
* section. A node can draw tabs, but only the frame owns the address bar,
|
|
10
|
+
* so the frame keeps the open section in its URL and this component only
|
|
11
|
+
* says which entry was chosen (`select`). Every frame that can show a home
|
|
12
|
+
* view draws the same menu: the in-app page, the admin panel's Apps page,
|
|
13
|
+
* and the dialog an embed without a page falls back to.
|
|
14
|
+
*
|
|
15
|
+
* The look is the product's own underlined tab strip (the Connections and
|
|
16
|
+
* Plugins screens), scrolled sideways on a phone rather than wrapped.
|
|
17
|
+
*/
|
|
18
|
+
import { computed } from 'vue';
|
|
19
|
+
import type { LocaleCode } from '../../types/ExplorerConfig';
|
|
20
|
+
import type { SurfaceSection } from '../../types/Plugins';
|
|
21
|
+
import { labelOf } from '../../lib/pluginLabel';
|
|
22
|
+
|
|
23
|
+
const props = defineProps<{
|
|
24
|
+
sections: SurfaceSection[];
|
|
25
|
+
/** The section on screen. */
|
|
26
|
+
active?: string;
|
|
27
|
+
locale: LocaleCode | string;
|
|
28
|
+
/** A label for the menu itself — the page's title. */
|
|
29
|
+
label?: string;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
}>();
|
|
32
|
+
|
|
33
|
+
const emit = defineEmits<{
|
|
34
|
+
(e: 'select', id: string): void;
|
|
35
|
+
}>();
|
|
36
|
+
|
|
37
|
+
const items = computed(() =>
|
|
38
|
+
props.sections
|
|
39
|
+
.filter((s) => s && typeof s.id === 'string' && s.id)
|
|
40
|
+
.map((s) => ({
|
|
41
|
+
id: s.id,
|
|
42
|
+
label: labelOf(s.label, props.locale as LocaleCode) || s.id,
|
|
43
|
+
count: typeof s.count === 'number' && Number.isFinite(s.count) ? s.count : null,
|
|
44
|
+
})),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
function pick(id: string): void {
|
|
48
|
+
if (props.disabled || id === props.active) return;
|
|
49
|
+
emit('select', id);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Arrow keys move along the strip, as a tab list does. */
|
|
53
|
+
function onKey(e: KeyboardEvent, index: number): void {
|
|
54
|
+
const keys = ['ArrowRight', 'ArrowLeft', 'Home', 'End'];
|
|
55
|
+
if (!keys.includes(e.key)) return;
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
const n = items.value.length;
|
|
58
|
+
if (!n) return;
|
|
59
|
+
let next = index;
|
|
60
|
+
if (e.key === 'ArrowRight') next = (index + 1) % n;
|
|
61
|
+
else if (e.key === 'ArrowLeft') next = (index - 1 + n) % n;
|
|
62
|
+
else if (e.key === 'Home') next = 0;
|
|
63
|
+
else if (e.key === 'End') next = n - 1;
|
|
64
|
+
const buttons = (e.currentTarget as HTMLElement).parentElement?.querySelectorAll<HTMLElement>('[role="tab"]');
|
|
65
|
+
buttons?.[next]?.focus();
|
|
66
|
+
pick(items.value[next].id);
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<nav class="fe-sections" role="tablist" :aria-label="label" data-testid="surface-sections">
|
|
72
|
+
<button
|
|
73
|
+
v-for="(s, i) in items"
|
|
74
|
+
:key="s.id"
|
|
75
|
+
type="button"
|
|
76
|
+
role="tab"
|
|
77
|
+
class="fe-sections__tab"
|
|
78
|
+
:class="{ 'is-active': s.id === active }"
|
|
79
|
+
:aria-selected="s.id === active ? 'true' : 'false'"
|
|
80
|
+
:tabindex="s.id === active || (!active && i === 0) ? 0 : -1"
|
|
81
|
+
:disabled="disabled"
|
|
82
|
+
:data-testid="`surface-section-${s.id}`"
|
|
83
|
+
:data-section="s.id"
|
|
84
|
+
@click="pick(s.id)"
|
|
85
|
+
@keydown="onKey($event, i)"
|
|
86
|
+
>
|
|
87
|
+
<span class="fe-sections__label">{{ s.label }}</span>
|
|
88
|
+
<span v-if="s.count !== null" class="fe-sections__count" :data-testid="`surface-section-count-${s.id}`">{{ s.count }}</span>
|
|
89
|
+
</button>
|
|
90
|
+
</nav>
|
|
91
|
+
</template>
|