@nextcloud/files 4.0.0-beta.9 → 4.0.0-rc.1

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 CHANGED
@@ -53,6 +53,123 @@ const myEntry: Entry = {
53
53
  addNewFileMenuEntry(myEntry)
54
54
  ```
55
55
 
56
+ #### Register a sidebar tab
57
+
58
+ It is possible to provide your own sidebar tabs for the files app.
59
+ For this you need to create a [custom web component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components),
60
+ which can either be done without any framework by using vanilla JavaScript but is also [possible with Vue](https://vuejs.org/guide/extras/web-components#building-custom-elements-with-vue).
61
+
62
+ This example will make use of the Vue framework for building a sidebar tab as this is the official UI framework for Nextcloud apps.
63
+
64
+ The sidebar tab consists of two parts:
65
+ 1. The web component which will be rendered within the sidebar.
66
+ 2. A definition object that provides all information needed by the files app.
67
+
68
+ ##### SidebarTab definition object
69
+
70
+ This object provides the requires information such as:
71
+ - The order (to ensure a consistent tabs order)
72
+ - The display name for the tab navigation
73
+ - An icon, to be used in the tab navigation
74
+ - A callback to check if the sidebar tab is enabled for the current node shown in the sidebar.
75
+ - The web component tag name
76
+
77
+ The registration must happen in an `initScript`.
78
+
79
+ ```ts
80
+ import type { ISidebarTab } from '@nextcloud/files'
81
+
82
+ import { getSidebar } from '@nextcloud/files'
83
+ import { t } from '@nextcloud/l10n'
84
+
85
+ const MyTab: ISidebarTab = {
86
+ // Unique ID of the tab
87
+ id: 'my_app',
88
+
89
+ // The display name in the tab list
90
+ displayName: t('my_app', 'Sharing'),
91
+
92
+ // Pass an SVG (string) to be used as the tab button icon
93
+ iconSvgInline: '<svg>...</svg>',
94
+
95
+ // Lower values mean a more prominent position
96
+ order: 50,
97
+
98
+ // The tag name of the web component
99
+ tagName: 'my_app-files_sidebar_tab',
100
+
101
+ // Optional callback to check if the tab should be shown
102
+ enabled({ node, folder, view }) {
103
+ // you can disable this tab for some cased based on:
104
+ // - node: The node the sidebar was opened for
105
+ // - folder: The folder currently shown in the files app
106
+ // - view: The currently active files view
107
+ return true
108
+ },
109
+
110
+ // Optional, recommended to large tabs
111
+ async onInit() {
112
+ // This is called when the tab is about to be activated the first time.
113
+ // So this can be used to do some initialization or even to define the web component.
114
+ },
115
+ }
116
+
117
+ // the you need to register it in the sidebar
118
+ getSidebar()
119
+ .registerTab(MyTab)
120
+ ```
121
+
122
+ ##### SidebarTab web component
123
+
124
+ The web component needs to have those properties:
125
+ - node of type `INode`
126
+ - folder of type `IFolder`
127
+ - view of type `IView`
128
+ - active of type `boolean`
129
+
130
+ When using Vue you need to first create the Vue component:
131
+
132
+ ```vue
133
+ <script setup lang="ts">
134
+ import type { IFolder, INode, IView } from '@nextcloud/files'
135
+
136
+ defineProps<{
137
+ node: INode
138
+ folder: IFolder
139
+ view: IView
140
+ active: boolean
141
+ }>()
142
+ </script>
143
+
144
+ <template>
145
+ <div>
146
+ <div>Showing node: {{ node.source }}</div>
147
+ <div>... in folder: {{ folder.source }}</div>
148
+ <div>... with view: {{ view.id }}</div>
149
+ </div>
150
+ </template>
151
+ ```
152
+
153
+ Which then can be wrapped in a web component and registered.
154
+
155
+ ```ts
156
+ import { getSidebar } from '@nextcloud/files'
157
+ import { defineAsyncComponent, defineCustomElement } from 'vue'
158
+
159
+ getSidebar().registerTab({
160
+ // ...
161
+
162
+ tagName: `my_app-files_sidebar_tab`,
163
+
164
+ onInit() {
165
+ const MySidebarTab = defineAsyncComponent(() => import('./views/MySidebarTab.vue'))
166
+ // make sure to disable the shadow root to allow theming with Nextcloud provided global styles.
167
+ const MySidebarTabWebComponent = defineCustomElement(MySidebarTab, { shadowRoot: false })
168
+ customElements.define('my_app-files_sidebar_tab', MySidebarTabWebComponent)
169
+ },
170
+ })
171
+ ```
172
+
56
173
  ### WebDAV
57
174
  The `getClient` exported function returns a webDAV client that's a wrapper around [webdav's webDAV client](https://www.npmjs.com/package/webdav).
58
175
  All its methods are available here.
@@ -31,7 +31,7 @@ export interface IHotkeyConfig {
31
31
  */
32
32
  alt?: true;
33
33
  }
34
- export interface FileActionData {
34
+ export interface IFileAction {
35
35
  /** Unique ID */
36
36
  id: string;
37
37
  /** Translatable string displayed in the menu */
@@ -97,32 +97,13 @@ export interface FileActionData {
97
97
  */
98
98
  renderInline?: (context: ActionContextSingle) => Promise<HTMLElement | null>;
99
99
  }
100
- export declare class FileAction {
101
- private _action;
102
- constructor(action: FileActionData);
103
- get id(): string;
104
- get displayName(): (context: ActionContext) => string;
105
- get title(): ((context: ActionContext) => string) | undefined;
106
- get iconSvgInline(): (context: ActionContext) => string;
107
- get enabled(): ((context: ActionContext) => boolean) | undefined;
108
- get exec(): (context: ActionContextSingle) => Promise<boolean | null>;
109
- get execBatch(): ((context: ActionContext) => Promise<(boolean | null)[]>) | undefined;
110
- get hotkey(): IHotkeyConfig | undefined;
111
- get order(): number | undefined;
112
- get parent(): string | undefined;
113
- get default(): TDefaultType | undefined;
114
- get destructive(): boolean | undefined;
115
- get inline(): ((context: ActionContextSingle) => boolean) | undefined;
116
- get renderInline(): ((context: ActionContextSingle) => Promise<HTMLElement | null>) | undefined;
117
- private validateAction;
118
- }
119
100
  /**
120
101
  * Register a new file action.
121
102
  *
122
103
  * @param action - The file list action to register
123
104
  */
124
- export declare function registerFileAction(action: FileAction): void;
105
+ export declare function registerFileAction(action: IFileAction): void;
125
106
  /**
126
- *
107
+ * Get all registered file actions.
127
108
  */
128
- export declare function getFileActions(): FileAction[];
109
+ export declare function getFileActions(): IFileAction[];
@@ -1,5 +1,5 @@
1
1
  import { ViewActionContext } from '../types.ts';
2
- interface FileListActionData {
2
+ export interface IFileListAction {
3
3
  /** Unique ID */
4
4
  id: string;
5
5
  /** Translated name of the action */
@@ -21,25 +21,13 @@ interface FileListActionData {
21
21
  */
22
22
  exec: (context: ViewActionContext) => Promise<boolean | null>;
23
23
  }
24
- export declare class FileListAction {
25
- private _action;
26
- constructor(action: FileListActionData);
27
- get id(): string;
28
- get displayName(): (context: ViewActionContext) => string;
29
- get iconSvgInline(): ((context: ViewActionContext) => string) | undefined;
30
- get order(): number;
31
- get enabled(): ((context: ViewActionContext) => boolean) | undefined;
32
- get exec(): (context: ViewActionContext) => Promise<boolean | null>;
33
- private validateAction;
34
- }
35
24
  /**
36
25
  * Register a new file list action.
37
26
  *
38
27
  * @param action - The file list action to register
39
28
  */
40
- export declare function registerFileListAction(action: FileListAction): void;
29
+ export declare function registerFileListAction(action: IFileListAction): void;
41
30
  /**
42
31
  * Get all currently registered file list actions.
43
32
  */
44
- export declare function getFileListActions(): FileListAction[];
45
- export {};
33
+ export declare function getFileListActions(): IFileListAction[];
@@ -1,3 +1,4 @@
1
- export type { FileActionData, IHotkeyConfig } from './fileAction.ts';
2
- export { DefaultType, FileAction, getFileActions, registerFileAction } from './fileAction.ts';
3
- export { FileListAction, getFileListActions, registerFileListAction } from './fileListAction.ts';
1
+ export type { IFileAction, IHotkeyConfig } from './fileAction.ts';
2
+ export type { IFileListAction } from './fileListAction.ts';
3
+ export { DefaultType, getFileActions, registerFileAction } from './fileAction.ts';
4
+ export { getFileListActions, registerFileListAction } from './fileListAction.ts';
@@ -0,0 +1,20 @@
1
+ import { IFileListFilter } from './listFilters.ts';
2
+ /**
3
+ * Register a new filter on the file list
4
+ *
5
+ * This only must be called once to register the filter,
6
+ * when the filter state changes you need to call `filterUpdated` on the filter instead.
7
+ *
8
+ * @param filter The filter to register on the file list
9
+ */
10
+ export declare function registerFileListFilter(filter: IFileListFilter): void;
11
+ /**
12
+ * Remove a registered filter from the file list
13
+ *
14
+ * @param filterId The unique ID of the filter to remove
15
+ */
16
+ export declare function unregisterFileListFilter(filterId: string): void;
17
+ /**
18
+ * Get all registered file list filters
19
+ */
20
+ export declare function getFileListFilters(): IFileListFilter[];
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3
+ * SPDX-License-Identifier: AGPL-3.0-or-later
4
+ */
5
+ export type * from './listFilters.ts';
6
+ export { getFileListFilters, registerFileListFilter, unregisterFileListFilter, } from './functions.ts';
7
+ export { FileListFilter } from './listFilters.ts';
@@ -1,4 +1,4 @@
1
- import { INode } from './node/index.ts';
1
+ import { INode } from '../node/index.ts';
2
2
  import { TypedEventTarget } from 'typescript-event-target';
3
3
  /**
4
4
  * Active filters can provide one or more "chips" to show the currently active state.
@@ -106,23 +106,4 @@ export declare class FileListFilter extends TypedEventTarget<IFileListFilterEven
106
106
  protected updateChips(chips: IFileListFilterChip[]): void;
107
107
  protected filterUpdated(): void;
108
108
  }
109
- /**
110
- * Register a new filter on the file list
111
- *
112
- * This only must be called once to register the filter,
113
- * when the filter state changes you need to call `filterUpdated` on the filter instead.
114
- *
115
- * @param filter The filter to register on the file list
116
- */
117
- export declare function registerFileListFilter(filter: IFileListFilter): void;
118
- /**
119
- * Remove a registered filter from the file list
120
- *
121
- * @param filterId The unique ID of the filter to remove
122
- */
123
- export declare function unregisterFileListFilter(filterId: string): void;
124
- /**
125
- * Get all registered file list filters
126
- */
127
- export declare function getFileListFilters(): IFileListFilter[];
128
109
  export {};
@@ -0,0 +1,11 @@
1
+ import { Header } from './listHeaders.ts';
2
+ /**
3
+ * Register a new file list header.
4
+ *
5
+ * @param header - The header to register
6
+ */
7
+ export declare function registerFileListHeaders(header: Header): void;
8
+ /**
9
+ * Get all currently registered file list headers.
10
+ */
11
+ export declare function getFileListHeaders(): Header[];
@@ -0,0 +1,3 @@
1
+ export type * from './listHeaders.ts';
2
+ export { Header } from './listHeaders.ts';
3
+ export { getFileListHeaders, registerFileListHeaders } from './functions.ts';
@@ -1,5 +1,5 @@
1
- import { IView } from './navigation/view.ts';
2
- import { IFolder } from './node/folder.ts';
1
+ import { IView } from '../navigation/view.ts';
2
+ import { IFolder } from '../node/folder.ts';
3
3
  export interface HeaderData {
4
4
  /** Unique ID */
5
5
  id: string;
@@ -8,9 +8,9 @@ export interface HeaderData {
8
8
  /** Condition wether this header is shown or not */
9
9
  enabled?: (folder: IFolder, view: IView) => boolean;
10
10
  /** Executed when file list is initialized */
11
- render: (el: HTMLElement, folder: IFolder, view: IView) => void;
11
+ render(el: HTMLElement, folder: IFolder, view: IView): void;
12
12
  /** Executed when root folder changed */
13
- updated(folder: IFolder, view: IView): any;
13
+ updated(folder: IFolder, view: IView): void;
14
14
  }
15
15
  export declare class Header {
16
16
  private _header;
@@ -19,16 +19,6 @@ export declare class Header {
19
19
  get order(): number;
20
20
  get enabled(): ((folder: IFolder, view: IView) => boolean) | undefined;
21
21
  get render(): (el: HTMLElement, folder: IFolder, view: IView) => void;
22
- get updated(): (folder: IFolder, view: IView) => any;
22
+ get updated(): (folder: IFolder, view: IView) => void;
23
23
  private validateHeader;
24
24
  }
25
- /**
26
- * Register a new file list header.
27
- *
28
- * @param header - The header to register
29
- */
30
- export declare function registerFileListHeaders(header: Header): void;
31
- /**
32
- * Get all currently registered file list headers.
33
- */
34
- export declare function getFileListHeaders(): Header[];
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  export type * from './types.ts';
2
2
  export * from './actions/index.ts';
3
- export * from './fileListFilters.ts';
4
- export * from './fileListHeaders.ts';
3
+ export * from './filters/index.ts';
4
+ export * from './headers/index.ts';
5
5
  export * from './navigation/index.ts';
6
6
  export * from './newMenu/index.ts';
7
7
  export * from './node/index.ts';
8
8
  export * from './permissions.ts';
9
9
  export * from './sidebar/index.ts';
10
10
  export * from './utils/index.ts';
11
+ export { getFilesRegistry } from './registry.ts';