diff --git a/README.md b/README.md index 2c97a8a5..4149b09d 100644 --- a/README.md +++ b/README.md @@ -21,15 +21,21 @@ Since version 4.2 this package provides a Vue.js based file picker, so this pack ## Usage +### General +The styles for the components (Toasts and FilePicker) are provided in the `style.css` file. +So make sure that the `@nextcloud/dialogs/style.css` file is included in your app to make sure that the toasts or FilePicker have a proper styling applied. + +```js +import '@nextcloud/dialogs/style.css' +``` + ### Toasts ```js import { showMessage, showInfo, showSuccess, showWarning, showError } from '@nextcloud/dialogs' -import '@nextcloud/dialogs/dist/index.css' +import '@nextcloud/dialogs/style.css' ``` -Make sure that the `@nextcloud/dialogs/dist/index.css` file is included in your app to make sure that the toasts have a proper styling applied. - If you using `@nextcloud/dialogs >= 4.0` you don't need any svg or scss loader in you projects anymore. There are different toast styles available, that are exposed in separate functions: @@ -48,7 +54,56 @@ There are several options that can be passed in as a second parameter, like the showError('This is an error shown without a timeout', { timeout: -1 }) ``` -A full list of available options can be found in the [documentation](https://nextcloud.github.io/nextcloud-dialogs/). +A full list of available options can be found in the [documentation](https://nextcloud-libraries.github.io/nextcloud-dialogs/). + +### FilePicker +There are two ways to spawn a FilePicker provided by the library: + +#### Use the FilePickerBuilder +This way you do not need to use Vue, but can programatically spawn a FilePicker. + +```js +import { getFilePickerBuilder } from '@nextcloud/dialogs' +const filepicker = getFilePickerBuilder('Pick plain text files') + .addMimeTypeFilter('text/plain') + .addButton({ + label: 'Pick', + callback: (nodes) => console.log('Picked', nodes), + }) + .build() + +// You get the file nodes by the button callback, but also the pick yields the paths of the picked files +const paths = await filepicker.pick() +``` + +#### Use the Vue component directly +```vue + + +``` ## Releasing a new version diff --git a/l10n/messages.pot b/l10n/messages.pot index 5235f5d9..fe7ec872 100644 --- a/l10n/messages.pot +++ b/l10n/messages.pot @@ -18,11 +18,11 @@ msgstr "" msgid "All files" msgstr "" -#: lib/filepicker.ts:183 +#: lib/filepicker.ts:178 msgid "Choose" msgstr "" -#: lib/filepicker.ts:171 +#: lib/filepicker.ts:166 msgid "Copy" msgstr "" @@ -43,8 +43,8 @@ msgstr "" msgid "Modified" msgstr "" -#: lib/filepicker.ts:177 -#: lib/filepicker.ts:191 +#: lib/filepicker.ts:172 +#: lib/filepicker.ts:186 msgid "Move" msgstr "" @@ -65,6 +65,6 @@ msgstr "" msgid "Size" msgstr "" -#: lib/toast.ts:229 +#: lib/toast.ts:242 msgid "Undo" msgstr "" diff --git a/lib/components/FilePicker/FilePicker.vue b/lib/components/FilePicker/FilePicker.vue index f96ea6e8..af1da25a 100644 --- a/lib/components/FilePicker/FilePicker.vue +++ b/lib/components/FilePicker/FilePicker.vue @@ -9,7 +9,7 @@ + @create-node="onCreateFolder" />

{{ viewHeadline }}

@@ -28,7 +28,7 @@ + */ +export const FilePickerVue = defineAsyncComponent(() => import('./FilePicker.vue')) as AsyncComponent, DefaultMethods, DefaultComputed, IFilePickerProps> diff --git a/lib/components/types.ts b/lib/components/types.ts index 0bcac3e4..e48b4f33 100644 --- a/lib/components/types.ts +++ b/lib/components/types.ts @@ -23,13 +23,42 @@ import type { Node } from '@nextcloud/files' import type { AsyncComponent, Component } from 'vue' +/** + * Interface for defining buttons passed to the Dialog component + */ export interface IDialogButton { + /** Label of the button */ label: string, - icon?: Component | AsyncComponent, + + /** Callback on button click */ callback: () => void, + /** + * Optional Icon for the button + * Can be a Vue component or async component + */ + icon?: Component | AsyncComponent, + + /** + * Button type + * @see https://nextcloud-vue-components.netlify.app/#/Components/NcButton + */ type?: 'primary' | 'secondary' | 'error' | 'warning' | 'success' } +/** + * Interface to define buttons of the FilePicker component + * The buttons are based on the Dialog buttons but the callback gets the array of selected nodes + */ export interface IFilePickerButton extends Omit { + /** + * Callback on button click + * + * @param nodes Array of `@nextcloud/files` Nodes that were selected + */ callback: (nodes: Node[]) => void } + +/** +* Type of filter functions to filter the FilePicker's file list +*/ +export type IFilePickerFilter = (node: Node) => boolean diff --git a/lib/filepicker.ts b/lib/filepicker.ts index b34dc56a..81356d41 100644 --- a/lib/filepicker.ts +++ b/lib/filepicker.ts @@ -20,18 +20,13 @@ * */ -import type { IFilePickerButton } from './components/types' +import type { IFilePickerButton, IFilePickerFilter } from './components/types' import type { Node } from '@nextcloud/files' import { spawnDialog } from './utils/dialogs' import { FilePickerVue } from './components/FilePicker/index' import { t } from './utils/l10n' -/** - * Type of filter functions to filter the FilePicker's file list - */ -export type FilePickerFilter = (node: Node) => boolean - /** * @deprecated */ @@ -51,7 +46,7 @@ export class FilePicker { private directoriesAllowed: boolean private buttons: IFilePickerButton[] private path?: string - private filter?: FilePickerFilter + private filter?: IFilePickerFilter public constructor(title: string, multiSelect: boolean, @@ -59,7 +54,7 @@ export class FilePicker { directoriesAllowed: boolean, buttons: IFilePickerButton[], path?: string, - filter?: FilePickerFilter) { + filter?: IFilePickerFilter) { this.title = title this.multiSelect = multiSelect this.mimeTypeFilter = mimeTypeFilter @@ -105,7 +100,7 @@ export class FilePickerBuilder { private mimeTypeFilter: string[] = [] private directoriesAllowed = false private path?: string - private filter?: FilePickerFilter + private filter?: IFilePickerFilter private buttons: IFilePickerButton[] = [] /** @@ -221,7 +216,7 @@ export class FilePickerBuilder { * * @param filter Filter function to apply */ - public setFilter(filter: FilePickerFilter): FilePickerBuilder { + public setFilter(filter: IFilePickerFilter): FilePickerBuilder { this.filter = filter return this } diff --git a/lib/index.ts b/lib/index.ts index d613bc2d..37ccce38 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,7 +1,32 @@ -export { FilePicker, FilePickerType, FilePickerBuilder, getFilePickerBuilder } from './filepicker.js' -export { TOAST_UNDO_TIMEOUT, TOAST_DEFAULT_TIMEOUT, TOAST_PERMANENT_TIMEOUT } from './toast.js' -export { TOAST_ARIA_LIVE_OFF, TOAST_ARIA_LIVE_POLITE, TOAST_ARIA_LIVE_ASSERTIVE } from './toast.js' -export { showMessage, showSuccess, showWarning, showInfo, showError, showUndo } from './toast.js' +export { + FilePicker, + FilePickerType, + FilePickerBuilder, + getFilePickerBuilder, +} from './filepicker.js' + +export { + ToastAriaLive, + ToastType, + TOAST_UNDO_TIMEOUT, + TOAST_DEFAULT_TIMEOUT, + TOAST_PERMANENT_TIMEOUT, + TOAST_ARIA_LIVE_OFF, + TOAST_ARIA_LIVE_POLITE, + TOAST_ARIA_LIVE_ASSERTIVE, + showMessage, + showSuccess, + showWarning, + showInfo, + showError, + showUndo, +} from './toast.js' + +export type { + ToastOptions, +} from './toast.js' export { spawnDialog } from './utils/dialogs.js' + export { FilePickerVue } from './components/FilePicker/index.js' +export type { IFilePickerButton, IFilePickerFilter } from './components/types.js' diff --git a/lib/toast.ts b/lib/toast.ts index 271ae559..fc9a47d5 100644 --- a/lib/toast.ts +++ b/lib/toast.ts @@ -27,30 +27,43 @@ import { t } from './utils/l10n.js' import '../styles/toast.scss' -class ToastType { - - static readonly ERROR = 'toast-error'; - static readonly WARNING = 'toast-warning'; - static readonly INFO = 'toast-info'; - static readonly SUCCESS = 'toast-success'; - static readonly PERMANENT = 'toast-error'; - static readonly UNDO = 'toast-undo'; +/** + * Enum of available Toast types + */ +export enum ToastType { + ERROR = 'toast-error', + WARNING = 'toast-warning', + INFO = 'toast-info', + SUCCESS = 'toast-success', + PERMANENT = 'toast-error', + UNDO = 'toast-undo', } +/** @deprecated Use ToastAriaLive.OFF */ export const TOAST_ARIA_LIVE_OFF = 'off' +/** @deprecated Use ToastAriaLive.POLITE */ export const TOAST_ARIA_LIVE_POLITE = 'polite' +/** @deprecated Use ToastAriaLive.ASSERTIVE */ export const TOAST_ARIA_LIVE_ASSERTIVE = 'assertive' -enum ToastAriaLive { +export enum ToastAriaLive { OFF = TOAST_ARIA_LIVE_OFF, POLITE = TOAST_ARIA_LIVE_POLITE, ASSERTIVE = TOAST_ARIA_LIVE_ASSERTIVE, } +/** Timeout in ms of a undo toast */ export const TOAST_UNDO_TIMEOUT = 10000 +/** Default timeout in ms of toasts */ export const TOAST_DEFAULT_TIMEOUT = 7000 +/** Timeout value to show a toast permanently */ export const TOAST_PERMANENT_TIMEOUT = -1 +/** + * Type of a toast + * @see https://apvarun.github.io/toastify-js/ + * @notExported + */ type Toast = ReturnType export interface ToastOptions { @@ -103,7 +116,7 @@ export interface ToastOptions { /** * Show a toast message * - * @param text Message to be shown in the toast, any HTML is removed by default + * @param data Message to be shown in the toast, any HTML is removed by default * @param options */ export function showMessage(data: string|Node, options?: ToastOptions): Toast { @@ -206,13 +219,13 @@ export function showSuccess(text: string, options?: ToastOptions): Toast { * @param onUndo Function that is called when the undo button is clicked * @param options */ -export function showUndo(text: string, onUndo: Function, options?: ToastOptions): Toast { +export function showUndo(text: string, onUndo: (e: MouseEvent) => void, options?: ToastOptions): Toast { // onUndo callback is mandatory if (!(onUndo instanceof Function)) { throw new Error('Please provide a valid onUndo method') } - let toast + let toast: Toast options = Object.assign(options || {}, { // force 10 seconds of timeout diff --git a/package-lock.json b/package-lock.json index dacee112..b852bbf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@nextcloud/vite-config": "^1.0.0-beta.18", "@types/gettext-parser": "^4.0.2", "@vue/tsconfig": "^0.4.0", + "@zamiell/typedoc-plugin-not-exported": "^0.2.0", "gettext-extractor": "^3.8.0", "gettext-parser": "^7.0.1", "sass": "^1.65.1", @@ -4483,6 +4484,15 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "peer": true }, + "node_modules/@zamiell/typedoc-plugin-not-exported": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@zamiell/typedoc-plugin-not-exported/-/typedoc-plugin-not-exported-0.2.0.tgz", + "integrity": "sha512-R0EOvUfSc7APvBL5ZRkW3J1g/McWnMrVeVaIwrCmz9IiWjQ8LuLumRQxRICuiCz9FEwa3Giz/7SJXbbLf8bQ3A==", + "dev": true, + "peerDependencies": { + "typedoc": ">=0.22.17" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", diff --git a/package.json b/package.json index 8bf9b42f..9bb8ab6d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,10 @@ "import": "./dist/style.css", "require": "./dist/style.css" }, + "./style.css": { + "import": "./dist/style.css", + "require": "./dist/style.css" + }, "./legacy.js": { "types": "./dist/legacy.d.ts", "import": "./dist/legacy.mjs", @@ -24,10 +28,11 @@ }, "scripts": { "prepare": "npm run build", - "build:doc": "typedoc --excludeExternals --out dist/doc lib && touch dist/doc/.nojekyll", + "build:doc": "npm run dev && npm run doc", "build": "vite --mode production build", "dev": "vite --mode development build", "dev:watch": "vite --mode development build --watch", + "doc": "typedoc --tsconfig tsconfig-typedoc.json --plugin @zamiell/typedoc-plugin-not-exported --out dist/doc dist/index.d.ts && touch dist/doc/.nojekyll", "stylelint": "stylelint src", "stylelint:fix": "stylelint src --fix", "check-types": "tsc --noEmit", @@ -67,6 +72,7 @@ "@nextcloud/vite-config": "^1.0.0-beta.18", "@types/gettext-parser": "^4.0.2", "@vue/tsconfig": "^0.4.0", + "@zamiell/typedoc-plugin-not-exported": "^0.2.0", "gettext-extractor": "^3.8.0", "gettext-parser": "^7.0.1", "sass": "^1.65.1", diff --git a/tsconfig-typedoc.json b/tsconfig-typedoc.json new file mode 100644 index 00000000..1846e23d --- /dev/null +++ b/tsconfig-typedoc.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./dist" + }, + "exclude": [ + "node_modules", + "build" + ], + "include": [ + "dist" + ] +}