@cloudron/pankow 4.3.2 → 4.3.4

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.
@@ -0,0 +1,92 @@
1
+ <script setup>
2
+
3
+ import { ref } from 'vue';
4
+ import { Icon } from '@cloudron/pankow';
5
+
6
+ function useSaveIndicator() {
7
+ const visible = ref(false);
8
+ const success = ref(false);
9
+ const TIMEOUT = 1500;
10
+ let timeoutId;
11
+
12
+ function flash(state) {
13
+ clearTimeout(timeoutId);
14
+
15
+ success.value = state;
16
+
17
+ if (visible.value) {
18
+ visible.value = false;
19
+ setTimeout(() => visible.value = true, 0);
20
+ } else {
21
+ visible.value = true;
22
+ }
23
+
24
+ timeoutId = setTimeout(() => {
25
+ visible.value = false;
26
+ }, TIMEOUT);
27
+ }
28
+
29
+ function showSuccess() { flash(true); }
30
+ function showError() { flash(false); }
31
+
32
+ return { visible, success, showSuccess, showError };
33
+ }
34
+
35
+ const { visible, success, showSuccess, showError } = useSaveIndicator();
36
+
37
+ defineExpose({ success: showSuccess, error: showError });
38
+
39
+ </script>
40
+
41
+ <template>
42
+ <div class="pankow-save-indicator-wrapper">
43
+ <slot />
44
+ <Transition name="pankow-save-indicator-bounce">
45
+ <div class="pankow-save-indicator" v-if="visible" :class="{ success: success, error: !success }"><Icon :icon="success ? 'fa-solid fa-check' : 'fa-solid fa-xmark'"/></div>
46
+ </Transition>
47
+ </div>
48
+ </template>
49
+
50
+ <style>
51
+
52
+ .pankow-save-indicator-wrapper {
53
+ position: relative;
54
+ display: inline-block;
55
+ }
56
+
57
+ .pankow-save-indicator {
58
+ position: absolute;
59
+ right: -2em;
60
+ top: 50%;
61
+ transform: translateY(-50%);
62
+ }
63
+
64
+ .pankow-save-indicator.success {
65
+ color: var(--pankow-color-success);
66
+ }
67
+
68
+ .pankow-save-indicator.error {
69
+ color: var(--pankow-color-danger);
70
+ }
71
+
72
+ .pankow-save-indicator-bounce-enter-active {
73
+ animation: pankow-save-indicator-bounce-in 0.5s;
74
+ }
75
+
76
+ .pankow-save-indicator-bounce-leave-active {
77
+ animation: pankow-save-indicator-bounce-in 0.5s reverse;
78
+ }
79
+
80
+ @keyframes pankow-save-indicator-bounce-in {
81
+ 0% {
82
+ transform: translateY(-50%) scale(0);
83
+ }
84
+ 50% {
85
+ transform: translateY(-50%) scale(1.5);
86
+ }
87
+ 100% {
88
+ transform: translateY(-50%) scale(1);
89
+ }
90
+ }
91
+
92
+ </style>
@@ -29,6 +29,7 @@ onUnmounted(() => {
29
29
  <div class="pankow-section-item">
30
30
  <h2 class="pankow-section-item-header">
31
31
  <div>
32
+ <slot name="header-buttons-left"></slot>
32
33
  <div class="pankow-section-item-header-title-text">
33
34
  <slot name="header-title">{{ title }}</slot>
34
35
  <slot name="header-title-extra"></slot>
package/index.js CHANGED
@@ -38,6 +38,7 @@ import PasswordInput from './components/PasswordInput.vue';
38
38
  import Popover from './components/Popover.vue';
39
39
  import ProgressBar from './components/ProgressBar.vue';
40
40
  import RadioButton from './components/RadioButton.vue';
41
+ import SaveIndicator from './components/SaveIndicator.vue';
41
42
  import SectionItem from './components/SectionItem.vue';
42
43
  import SideBar from './components/SideBar.vue';
43
44
  import SplitLayout from './components/SplitLayout.vue';
@@ -91,6 +92,7 @@ export {
91
92
  Popover,
92
93
  ProgressBar,
93
94
  RadioButton,
95
+ SaveIndicator,
94
96
  SectionItem,
95
97
  SideBar,
96
98
  SplitLayout,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudron/pankow",
3
3
  "private": false,
4
- "version": "4.3.2",
4
+ "version": "4.3.4",
5
5
  "description": "Vue 3 UI component library for Cloudron apps",
6
6
  "main": "index.js",
7
7
  "types": "types/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  ],
30
30
  "scripts": {
31
31
  "gallery": "cd gallery && vite",
32
- "build": "cd gallery && vite build",
32
+ "build": "cd gallery && vite-ssg build",
33
33
  "types": "tsc --allowJs --emitDeclarationOnly --declaration index.js --outDir types --skipLibCheck",
34
34
  "prepack": "npm run types"
35
35
  },
@@ -39,7 +39,7 @@
39
39
  "dependencies": {
40
40
  "@fontsource/inter": "^5.2.8",
41
41
  "@fortawesome/fontawesome-free": "^7.3.0",
42
- "filesize": "^11.0.19",
42
+ "filesize": "^11.0.22",
43
43
  "monaco-editor": "^0.55.1",
44
44
  "online-3d-viewer": "^0.18.0"
45
45
  },
@@ -48,10 +48,12 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@highlightjs/vue-plugin": "^2.1.0",
51
- "@vitejs/plugin-vue": "^6.0.7",
51
+ "@unhead/vue": "^2.1.15",
52
+ "@vitejs/plugin-vue": "^6.0.8",
52
53
  "highlight.js": "^11.11.1",
53
- "typescript": "^6.0.3",
54
- "vite": "^8.1.3",
54
+ "typescript": "^7.0.2",
55
+ "vite": "^8.1.4",
56
+ "vite-ssg": "^28.3.0",
55
57
  "vue": "^3.5.39",
56
58
  "vue-router": "^5.1.0"
57
59
  }
package/plugin.js CHANGED
@@ -25,7 +25,7 @@ export default {
25
25
  setNotifyPosition(options.notification.position);
26
26
  }
27
27
 
28
- if (typeof document !== 'undefined') {
28
+ if (typeof document !== 'undefined' && !import.meta.env.SSR) {
29
29
  const existing = document.getElementById(CONTAINER_ID);
30
30
  if (existing) existing.remove();
31
31
 
@@ -1,6 +1,16 @@
1
- export default fallbackImage;
1
+ /**
2
+ * FallbackImage Directive
3
+ *
4
+ * Usage:
5
+ * ```
6
+ * import fallbackImage from 'pankow/fallbackImage';
7
+ * app.directive('fallback-image', fallbackImage);
8
+ * // <img v-fallback-image="'/fallback.png'"/>
9
+ * ```
10
+ */
2
11
  /**
3
12
  * Vue directive for image fallback. Register via `app.directive('fallback-image', fallbackImage)`.
4
13
  * @type {import('vue').Directive}
5
14
  */
6
- declare const fallbackImage: import("vue").Directive;
15
+ declare const fallbackImage: import('vue').Directive;
16
+ export default fallbackImage;
@@ -1,15 +1,9 @@
1
- declare namespace _default {
2
- export { globalOptions };
3
- export { head };
4
- export { get };
5
- export { post };
6
- export { put };
7
- export { del };
8
- export { del as delete };
9
- }
10
- export default _default;
11
1
  /**
12
2
  * Shared configuration for all HTTP requests.
3
+ * @typedef {Object} FetcherGlobalOptions
4
+ * @property {string} credentials - Fetch credentials mode
5
+ * @property {string} redirect - Fetch redirect mode
6
+ * @property {?function(Response|Error): void} errorHook - Called on non-2xx responses or network errors
13
7
  */
14
8
  export type FetcherGlobalOptions = {
15
9
  /**
@@ -21,15 +15,10 @@ export type FetcherGlobalOptions = {
21
15
  */
22
16
  redirect: string;
23
17
  /**
24
- * - Called on non-2xx responses or network errors
18
+ * (Response|Error): void} errorHook - Called on non-2xx responses or network errors
25
19
  */
26
- errorHook: ((arg0: Response | Error) => void) | null;
20
+ : Function | null;
27
21
  };
28
- declare namespace globalOptions {
29
- let credentials: string;
30
- let redirect: string;
31
- let errorHook: null;
32
- }
33
22
  /**
34
23
  * Sends a HEAD request.
35
24
  * @param {string} uri
@@ -88,3 +77,17 @@ declare function del(uri: string, body: Object | FormData, query?: Object, optio
88
77
  status: number;
89
78
  body: any;
90
79
  }>;
80
+ declare const _default: {
81
+ globalOptions: {
82
+ credentials: string;
83
+ redirect: string;
84
+ errorHook: null;
85
+ };
86
+ head: typeof head;
87
+ get: typeof get;
88
+ post: typeof post;
89
+ put: typeof put;
90
+ del: typeof del;
91
+ delete: typeof del;
92
+ };
93
+ export default _default;
@@ -1,7 +1,3 @@
1
- declare namespace _default {
2
- export { onSwipe };
3
- }
4
- export default _default;
5
1
  /**
6
2
  * Swipe handler
7
3
  *
@@ -17,4 +13,9 @@ export default _default;
17
13
  * @param {function('left'|'right'|'up'|'down'): void} callback
18
14
  * @param {number} [threshold=50] - Minimum pixel distance to trigger a swipe
19
15
  */
20
- export function onSwipe(elem: HTMLElement, callback: (arg0: "left" | "right" | "up" | "down") => void, threshold?: number): void;
16
+ declare function onSwipe(elem: HTMLElement, callback: Function, threshold?: number): void;
17
+ declare const _default: {
18
+ onSwipe: typeof onSwipe;
19
+ };
20
+ export default _default;
21
+ export { onSwipe };
package/types/index.d.ts CHANGED
@@ -1,9 +1,61 @@
1
- export { useNotify } from "./notifyState.js";
2
- export default pankowPlugin;
1
+ import "@fontsource/inter/400.css";
2
+ import "@fontsource/inter/500.css";
3
+ import '@fortawesome/fontawesome-free/css/all.min.css';
4
+ import './style.css';
5
+ import pankowPlugin from './plugin.js';
6
+ import BottomBar from './components/BottomBar.vue';
7
+ import BreadCrumb from './components/BreadCrumb.vue';
8
+ import Button from './components/Button.vue';
9
+ import ButtonGroup from './components/ButtonGroup.vue';
10
+ import ClipboardAction from './components/ClipboardAction.vue';
11
+ import ClipboardButton from './components/ClipboardButton.vue';
12
+ import CheckBox from './components/CheckBox.vue';
13
+ import DateTimeInput from './components/DateTimeInput.vue';
14
+ import Dialog from './components/Dialog.vue';
15
+ import DirectoryView from './components/DirectoryView.vue';
16
+ import EmailInput from './components/EmailInput.vue';
17
+ import FileUploader from './components/FileUploader.vue';
18
+ import FormGroup from './components/FormGroup.vue';
19
+ import Icon from './components/Icon.vue';
20
+ import InputDialog from './components/InputDialog.vue';
21
+ import ListItem from './components/ListItem.vue';
22
+ import LoginView from './components/LoginView.vue';
23
+ import MainLayout from './components/MainLayout.vue';
24
+ import MaskedInput from './components/MaskedInput.vue';
25
+ import Menu from './components/Menu.vue';
26
+ import MenuItem from './components/MenuItem.vue';
27
+ import SingleSelect from './components/SingleSelect.vue';
28
+ import MultiSelect from './components/MultiSelect.vue';
29
+ import Notification from './components/Notification.vue';
30
+ import NumberInput from './components/NumberInput.vue';
31
+ import OfflineBanner from './components/OfflineBanner.vue';
32
+ import PasswordInput from './components/PasswordInput.vue';
33
+ import Popover from './components/Popover.vue';
34
+ import ProgressBar from './components/ProgressBar.vue';
35
+ import RadioButton from './components/RadioButton.vue';
36
+ import SaveIndicator from './components/SaveIndicator.vue';
37
+ import SectionItem from './components/SectionItem.vue';
38
+ import SideBar from './components/SideBar.vue';
39
+ import SplitLayout from './components/SplitLayout.vue';
40
+ import Spinner from './components/Spinner.vue';
41
+ import Switch from './components/Switch.vue';
42
+ import TableView from './components/TableView.vue';
43
+ import TableViewActionBar from './components/TableViewActionBar.vue';
44
+ import TabView from './components/TabView.vue';
45
+ import TagInput from './components/TagInput.vue';
46
+ import TextInput from './components/TextInput.vue';
47
+ import TextInputRaw from './components/TextInputRaw.vue';
48
+ import TopBar from './components/TopBar.vue';
49
+ import TreeView from './components/TreeView.vue';
50
+ import InputGroup from './components/InputGroup.vue';
3
51
  import fetcher from './fetcher.js';
4
52
  import gestures from './gestures.js';
53
+ import utils from './utils.js';
5
54
  import tooltip from './tooltip.js';
6
55
  import fallbackImage from './fallbackImage.js';
7
- import utils from './utils.js';
8
- import pankowPlugin from './plugin.js';
9
- export { BottomBar, BreadCrumb, Button, ButtonGroup, ClipboardAction, ClipboardButton, CheckBox, DateTimeInput, Dialog, DirectoryView, EmailInput, FileUploader, FormGroup, InputGroup, Icon, ListItem, InputDialog, LoginView, MainLayout, MaskedInput, Menu, MenuItem, SingleSelect, MultiSelect, Notification, NumberInput, OfflineBanner, PasswordInput, Popover, ProgressBar, RadioButton, SectionItem, SideBar, SplitLayout, Spinner, Switch, TableView, TableViewActionBar, TabView, TagInput, TextInput, TextInputRaw, TopBar, TreeView, fetcher, gestures, tooltip, fallbackImage, utils, CheckBox as Checkbox, RadioButton as Radiobutton, BreadCrumb as Breadcrumb };
56
+ export { BottomBar, BreadCrumb, Button, ButtonGroup, ClipboardAction, ClipboardButton, CheckBox, DateTimeInput, Dialog, DirectoryView, EmailInput, FileUploader, FormGroup, InputGroup, Icon, ListItem, InputDialog, LoginView, MainLayout, MaskedInput, Menu, MenuItem, SingleSelect, MultiSelect, Notification, NumberInput, OfflineBanner, PasswordInput, Popover, ProgressBar, RadioButton, SaveIndicator, SectionItem, SideBar, SplitLayout, Spinner, Switch, TableView, TableViewActionBar, TabView, TagInput, TextInput, TextInputRaw, TopBar, TreeView, fetcher, gestures, tooltip, fallbackImage, utils, };
57
+ export { CheckBox as Checkbox };
58
+ export { RadioButton as Radiobutton };
59
+ export { BreadCrumb as Breadcrumb };
60
+ export { useNotify } from './notifyState.js';
61
+ export default pankowPlugin;
@@ -1,8 +1,9 @@
1
- export const messages: import("vue").Reactive<never[]>;
2
- export const position: import("vue").Ref<string, string>;
3
- export function pushNotify(options: any): void;
4
- export function removeNotify(id: any): void;
5
- export function setNotifyPosition(pos: any): void;
6
- export function useNotify(): {
1
+ declare const messages: import("vue").Reactive<never[]>;
2
+ declare const position: import("vue").Ref<string, string>;
3
+ declare function pushNotify(options: any): void;
4
+ declare function removeNotify(id: any): void;
5
+ declare function useNotify(): {
7
6
  notify: typeof pushNotify;
8
7
  };
8
+ declare function setNotifyPosition(pos: any): void;
9
+ export { messages, position, pushNotify, removeNotify, setNotifyPosition, useNotify };
package/types/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- declare namespace _default {
2
- function install(app: any, options?: {}): void;
3
- }
1
+ declare const _default: {
2
+ install(app: any, options?: {}): void;
3
+ };
4
4
  export default _default;
@@ -1,6 +1,18 @@
1
- export default tooltip;
1
+ /**
2
+ * Tooltip Directive
3
+ *
4
+ * Usage:
5
+ * ```
6
+ * import tooltip from 'pankow/tooltip';
7
+ * app.directive('tooltip', tooltip);
8
+ * // <div v-tooltip.top="'hello'"></div>
9
+ * ```
10
+ *
11
+ * Position modifiers: `.top`, `.left`, `.right` (default: bottom).
12
+ */
2
13
  /**
3
14
  * Vue directive for tooltips. Register via `app.directive('tooltip', tooltip)`.
4
15
  * @type {import('vue').Directive}
5
16
  */
6
- declare const tooltip: import("vue").Directive;
17
+ declare const tooltip: import('vue').Directive;
18
+ export default tooltip;
package/types/utils.d.ts CHANGED
@@ -1,74 +1,39 @@
1
- declare namespace _default {
2
- export { getFileTypeGroup };
3
- export { translation };
4
- export { useDebouncedRef };
5
- export { isValidDomain };
6
- export { isValidDomainOrURL };
7
- export { isValidEmail };
8
- export { prettyBinarySize };
9
- export { prettyDecimalSize };
10
- export { prettyDate };
11
- export { prettyShortDate };
12
- export { prettyLongDate };
13
- export { prettyFileSize };
14
- export { prettyEmailAddresses };
15
- export { prettyDuration };
16
- export { sanitize };
17
- export { pathJoin };
18
- export { download };
19
- export { getExtension };
20
- export { copyToClipboard };
21
- export { urlSearchQuery };
22
- export { parseResourcePath };
23
- export { getEntryIdentifier };
24
- export { entryListSort };
25
- export { sleep };
26
- export { uuidv4 };
27
- }
28
- export default _default;
1
+ /**
2
+ * Creates a debounced reactive ref that delays value updates.
3
+ * @see https://vuejs.org/api/reactivity-advanced.html#customref
4
+ * @param {any} value
5
+ * @param {number} [delay=300] - Debounce delay in milliseconds
6
+ * @returns {import('vue').Ref}
7
+ */
8
+ declare function useDebouncedRef(value: any, delay?: number): import('vue').Ref;
29
9
  /**
30
10
  * Extracts the MIME type group from an item (e.g. "image" from "image/png").
31
11
  * @param {{ mimeType: string }} item
32
12
  * @returns {string}
33
13
  * @throws {string} If item has no mimeType string property
34
14
  */
35
- export function getFileTypeGroup(item: {
15
+ declare function getFileTypeGroup(item: {
36
16
  mimeType: string;
37
17
  }): string;
38
18
  /**
39
- * Looks up a translation string by dot-separated key (e.g. "filemanager.title").
40
- * Falls back to the key itself if the translation is not found.
41
- * @param {string} id - Dot-separated translation key
42
- * @returns {string}
43
- */
44
- export function translation(id: string): string;
45
- /**
46
- * Creates a debounced reactive ref that delays value updates.
47
- * @see https://vuejs.org/api/reactivity-advanced.html#customref
48
- * @param {any} value
49
- * @param {number} [delay=300] - Debounce delay in milliseconds
50
- * @returns {import('vue').Ref}
51
- */
52
- export function useDebouncedRef(value: any, delay?: number): import("vue").Ref;
53
- /**
54
- * Validates whether a string is a valid domain name.
19
+ * Validates whether a string is a valid domain or URL (extracts hostname from URLs first).
55
20
  * @param {string} domain
56
21
  * @returns {boolean}
57
22
  */
58
- export function isValidDomain(domain: string): boolean;
23
+ declare function isValidDomainOrURL(domain: string): boolean;
59
24
  /**
60
- * Validates whether a string is a valid domain or URL (extracts hostname from URLs first).
25
+ * Validates whether a string is a valid domain name.
61
26
  * @param {string} domain
62
27
  * @returns {boolean}
63
28
  */
64
- export function isValidDomainOrURL(domain: string): boolean;
29
+ declare function isValidDomain(domain: string): boolean;
65
30
  /**
66
31
  * Validates whether a string is a valid email address.
67
32
  * Does not match: quoted local-parts, IP-literal domains, comments, or internationalized addresses.
68
33
  * @param {string} email
69
34
  * @returns {boolean}
70
35
  */
71
- export function isValidEmail(email: string): boolean;
36
+ declare function isValidEmail(email: string): boolean;
72
37
  /**
73
38
  * Formats a byte count into human-readable IEC binary units (KiB, MiB, GiB, TiB).
74
39
  * @see https://en.wikipedia.org/wiki/Binary_prefix
@@ -76,69 +41,69 @@ export function isValidEmail(email: string): boolean;
76
41
  * @param {string|number} [fallback] - Value returned when size is falsy (0, null, undefined)
77
42
  * @returns {string|number}
78
43
  */
79
- export function prettyBinarySize(size: number, fallback?: string | number): string | number;
44
+ declare function prettyBinarySize(size: number, fallback?: string | number): string | number;
80
45
  /**
81
46
  * Formats a byte count into human-readable SI decimal units (kB, MB, GB, TB).
82
47
  * @param {number} size - Byte count
83
48
  * @param {string|number} [fallback] - Value returned when size is falsy
84
49
  * @returns {string|number}
85
50
  */
86
- export function prettyDecimalSize(size: number, fallback?: string | number): string | number;
51
+ declare function prettyDecimalSize(size: number, fallback?: string | number): string | number;
87
52
  /**
88
53
  * Formats a value as a human-friendly relative time offset from now (e.g. "2 days ago").
89
54
  * @param {string|number} value - Date string or timestamp; falsy returns "never"
90
55
  * @returns {string}
91
56
  */
92
- export function prettyDate(value: string | number): string;
93
- /**
94
- * Formats a value as a short time string (medium time style via Intl.DateTimeFormat).
95
- * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
96
- * @returns {string}
97
- */
98
- export function prettyShortDate(value: string | number): string;
57
+ declare function prettyDate(value: string | number): string;
99
58
  /**
100
59
  * Formats a date using a named format preset.
101
60
  * @param {'hh:mm A'|'hh:mm:ss A'|'DD MMM'|'DD MMM hh:mm A'} format - Preset format key
102
61
  * @param {string|number} value - Date string or timestamp
103
62
  * @returns {string}
104
63
  */
105
- export function formatDate(format: "hh:mm A" | "hh:mm:ss A" | "DD MMM" | "DD MMM hh:mm A", value: string | number): string;
64
+ declare function formatDate(format: 'hh:mm A' | 'hh:mm:ss A' | 'DD MMM' | 'DD MMM hh:mm A', value: string | number): string;
65
+ /**
66
+ * Formats a value as a short time string (medium time style via Intl.DateTimeFormat).
67
+ * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
68
+ * @returns {string}
69
+ */
70
+ declare function prettyShortDate(value: string | number): string;
106
71
  /**
107
72
  * Formats a value as a long date string (day, month, year, time).
108
73
  * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
109
74
  * @returns {string}
110
75
  */
111
- export function prettyLongDate(value: string | number): string;
76
+ declare function prettyLongDate(value: string | number): string;
112
77
  /**
113
78
  * Formats a numeric value as a human-readable file size string (uses the `filesize` library).
114
79
  * @param {number} value - Byte count
115
80
  * @returns {string}
116
81
  */
117
- export function prettyFileSize(value: number): string;
82
+ declare function prettyFileSize(value: number): string;
118
83
  /**
119
84
  * Strips angle brackets from email address strings or arrays.
120
85
  * @param {string|string[]} addresses - Format: "<name@example.com>"; returns empty string if falsy
121
86
  * @returns {string}
122
87
  */
123
- export function prettyEmailAddresses(addresses: string | string[]): string;
88
+ declare function prettyEmailAddresses(addresses: string | string[]): string;
124
89
  /**
125
90
  * Formats milliseconds as a human-readable duration string using Intl.DurationFormat.
126
91
  * @param {number} ms - Duration in milliseconds
127
92
  * @returns {string}
128
93
  */
129
- export function prettyDuration(ms: number): string;
94
+ declare function prettyDuration(ms: number): string;
130
95
  /**
131
96
  * Normalizes a file path: ensures leading slash and collapses consecutive slashes.
132
97
  * @param {string} path
133
98
  * @returns {string}
134
99
  */
135
- export function sanitize(path: string): string;
100
+ declare function sanitize(path: string): string;
136
101
  /**
137
102
  * Joins path segments and normalizes the result (via sanitize).
138
103
  * @param {...string} args - Path segments to join
139
104
  * @returns {string}
140
105
  */
141
- export function pathJoin(...args: string[]): string;
106
+ declare function pathJoin(): string;
142
107
  /**
143
108
  * Triggers a file download via the browser. Single entry: direct download.
144
109
  * Multiple entries: zipped archive download via /api/v1/download.
@@ -146,7 +111,7 @@ export function pathJoin(...args: string[]): string;
146
111
  * @param {string} [name] - Archive name for multi-file downloads
147
112
  * @returns {void}
148
113
  */
149
- export function download(entries: Array<{
114
+ declare function download(entries: Array<{
150
115
  filePath: string;
151
116
  share?: {
152
117
  id: string;
@@ -157,7 +122,7 @@ export function download(entries: Array<{
157
122
  * @param {{ isFile: boolean, fileName: string }} entry
158
123
  * @returns {string} Extension without leading dot (empty string for directories or files without extension)
159
124
  */
160
- export function getExtension(entry: {
125
+ declare function getExtension(entry: {
161
126
  isFile: boolean;
162
127
  fileName: string;
163
128
  }): string;
@@ -167,21 +132,19 @@ export function getExtension(entry: {
167
132
  * @returns {void}
168
133
  * @deprecated Prefer the native `navigator.clipboard.writeText()` API.
169
134
  */
170
- export function copyToClipboard(value: string): void;
135
+ declare function copyToClipboard(value: string): void;
171
136
  /**
172
137
  * Parses the current page's URL query string into a key/value object.
173
138
  * @returns {Object<string, string>}
174
139
  */
175
- export function urlSearchQuery(): {
176
- [x: string]: string;
177
- };
140
+ declare function urlSearchQuery(): Record<string, string>;
178
141
  /**
179
142
  * Parses a Cloudron resource path into its components (type, path, shareId, apiPath).
180
143
  * Handles paths like "files/folder/filename" or "shares/:shareId/folder/filename".
181
144
  * @param {string} resourcePath
182
145
  * @returns {{ type: string, path: string, shareId: string, apiPath: string, resourcePath: string }}
183
146
  */
184
- export function parseResourcePath(resourcePath: string): {
147
+ declare function parseResourcePath(resourcePath: string): {
185
148
  type: string;
186
149
  path: string;
187
150
  shareId: string;
@@ -193,7 +156,7 @@ export function parseResourcePath(resourcePath: string): {
193
156
  * @param {{ share?: { id: string }, filePath: string }} entry
194
157
  * @returns {string}
195
158
  */
196
- export function getEntryIdentifier(entry: {
159
+ declare function getEntryIdentifier(entry: {
197
160
  share?: {
198
161
  id: string;
199
162
  };
@@ -206,15 +169,51 @@ export function getEntryIdentifier(entry: {
206
169
  * @param {boolean} desc - If falsey, reverses the sort (descending order)
207
170
  * @returns {Array<Object>}
208
171
  */
209
- export function entryListSort(list: Array<Object>, prop: string, desc: boolean): Array<Object>;
172
+ declare function entryListSort(list: Array<Object>, prop: string, desc: boolean): Array<Object>;
210
173
  /**
211
174
  * Returns a promise that resolves after the specified number of milliseconds.
212
175
  * @param {number} ms
213
176
  * @returns {Promise<void>}
214
177
  */
215
- export function sleep(ms: number): Promise<void>;
178
+ declare function sleep(ms: number): Promise<void>;
179
+ /**
180
+ * Looks up a translation string by dot-separated key (e.g. "filemanager.title").
181
+ * Falls back to the key itself if the translation is not found.
182
+ * @param {string} id - Dot-separated translation key
183
+ * @returns {string}
184
+ */
185
+ declare function translation(id: string): string;
216
186
  /**
217
187
  * Generates a random UUID v4 string using crypto.getRandomValues.
218
188
  * @returns {string}
219
189
  */
220
- export function uuidv4(): string;
190
+ declare function uuidv4(): string;
191
+ export { getFileTypeGroup, translation, useDebouncedRef, isValidDomain, isValidDomainOrURL, isValidEmail, prettyBinarySize, prettyDecimalSize, prettyDate, prettyShortDate, formatDate, prettyLongDate, prettyFileSize, prettyEmailAddresses, prettyDuration, sanitize, pathJoin, download, getExtension, copyToClipboard, urlSearchQuery, parseResourcePath, getEntryIdentifier, entryListSort, sleep, uuidv4 };
192
+ declare const _default: {
193
+ getFileTypeGroup: typeof getFileTypeGroup;
194
+ translation: typeof translation;
195
+ useDebouncedRef: typeof useDebouncedRef;
196
+ isValidDomain: typeof isValidDomain;
197
+ isValidDomainOrURL: typeof isValidDomainOrURL;
198
+ isValidEmail: typeof isValidEmail;
199
+ prettyBinarySize: typeof prettyBinarySize;
200
+ prettyDecimalSize: typeof prettyDecimalSize;
201
+ prettyDate: typeof prettyDate;
202
+ prettyShortDate: typeof prettyShortDate;
203
+ prettyLongDate: typeof prettyLongDate;
204
+ prettyFileSize: typeof prettyFileSize;
205
+ prettyEmailAddresses: typeof prettyEmailAddresses;
206
+ prettyDuration: typeof prettyDuration;
207
+ sanitize: typeof sanitize;
208
+ pathJoin: typeof pathJoin;
209
+ download: typeof download;
210
+ getExtension: typeof getExtension;
211
+ copyToClipboard: typeof copyToClipboard;
212
+ urlSearchQuery: typeof urlSearchQuery;
213
+ parseResourcePath: typeof parseResourcePath;
214
+ getEntryIdentifier: typeof getEntryIdentifier;
215
+ entryListSort: typeof entryListSort;
216
+ sleep: typeof sleep;
217
+ uuidv4: typeof uuidv4;
218
+ };
219
+ export default _default;
@@ -175,6 +175,8 @@ function onNext() {
175
175
  open(entries.value[curIndex.value+1], entries.value, false);
176
176
  }
177
177
 
178
+ defineExpose({ canHandle, open });
179
+
178
180
  </script>
179
181
 
180
182
  <style scoped>
@@ -57,6 +57,8 @@ function onDownload() {
57
57
  window.location.href = entry.value.downloadFileUrl;
58
58
  }
59
59
 
60
+ defineExpose({ canHandle, open });
61
+
60
62
  </script>
61
63
 
62
64
  <style scoped>
@@ -196,6 +196,8 @@ onBeforeUnmount(() => {
196
196
  window.removeEventListener('beforeunload', beforeunloadHandler);
197
197
  });
198
198
 
199
+ defineExpose({ canHandle, open });
200
+
199
201
  </script>
200
202
 
201
203
  <style scoped>
package/vite-plugin.js CHANGED
@@ -3,9 +3,23 @@ import { fileURLToPath } from 'node:url';
3
3
 
4
4
  const __dirname = dirname(fileURLToPath(import.meta.url));
5
5
 
6
+ const PANKOW_PACKAGE = '@cloudron/pankow';
7
+
6
8
  export default function pankowPlugin() {
7
9
  return {
8
10
  name: 'vite-plugin-pankow',
11
+ config(config) {
12
+ const existing = config.optimizeDeps?.exclude;
13
+ const exclude = Array.isArray(existing)
14
+ ? existing.includes(PANKOW_PACKAGE) ? existing : [...existing, PANKOW_PACKAGE]
15
+ : [PANKOW_PACKAGE];
16
+ return {
17
+ optimizeDeps: {
18
+ ...config.optimizeDeps,
19
+ exclude,
20
+ },
21
+ };
22
+ },
9
23
  configureServer(server) {
10
24
  const allow = server.config.server.fs.allow;
11
25
  if (Array.isArray(allow) && !allow.includes(__dirname)) {