Skip to content

Commit

Permalink
Merge pull request #906 from nextcloud-libraries/fix/docs
Browse files Browse the repository at this point in the history
Fix documentation generation
  • Loading branch information
AndyScherzinger authored Aug 17, 2023
2 parents 04a640e + 71d827b commit 845b9a7
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 43 deletions.
63 changes: 59 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
<template>
<FilePicker name="Pick some files" :buttons="buttons" />
</template>
<script setup lang="ts">
import {
FilePickerVue as FilePicker,
type IFilePickerButton,
} from '@nextcloud/dialogs'
import type { Node } from '@nextcloud/files'
import IconShare from 'vue-material-design-icons/Share.vue'
const buttons: IFilePickerButton[] = [
{
label: 'Pick',
callback: (nodes: Node[]) => console.log('Picked', nodes),
type: 'primary'
},
{
label: 'Share',
callback: (nodes: Node[]) => console.log('Share picked files', nodes),
type: 'secondary',
icon: IconShare,
}
]
</script>
```

## Releasing a new version

Expand Down
10 changes: 5 additions & 5 deletions l10n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""

Expand All @@ -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 ""

Expand All @@ -65,6 +65,6 @@ msgstr ""
msgid "Size"
msgstr ""

#: lib/toast.ts:229
#: lib/toast.ts:242
msgid "Undo"
msgstr ""
6 changes: 3 additions & 3 deletions lib/components/FilePicker/FilePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<FilePickerBreadcrumbs v-if="currentView === 'files'"
:path.sync="currentPath"
:show-menu="allowPickDirectory"
@create-node="onCreateFolder"/>
@create-node="onCreateFolder" />
<div v-else class="file-picker__view">
<h3>{{ viewHeadline }}</h3>
</div>
Expand All @@ -28,7 +28,7 @@
</template>

<script setup lang="ts">
import type { IFilePickerButton } from '../types'
import type { IFilePickerButton, IFilePickerFilter } from '../types'
import { davRootPath, type Node } from '@nextcloud/files'
import DialogBase from '../DialogBase.vue'
Expand Down Expand Up @@ -65,7 +65,7 @@ const props = withDefaults(defineProps<{
/**
* Custom filter function used to filter pickable files
*/
filterFn?: (node: Node) => boolean
filterFn?: IFilePickerFilter
/**
* List of allowed mime types
Expand Down
22 changes: 19 additions & 3 deletions lib/components/FilePicker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,26 @@
*
*/

import { defineAsyncComponent, type AsyncComponent } from 'vue'
import type { AsyncComponent } from 'vue'
import type { DefaultComputed, DefaultData, DefaultMethods } from 'vue/types/options.js'
import { defineAsyncComponent } from 'vue'

export type IFilePicker = typeof import('./FilePicker.vue').default
type IFilePickerProps = (typeof import ('./FilePicker.vue').default)['props']

// Async import for module splitting (treeshaking)
export const FilePickerVue = defineAsyncComponent(() => import('./FilePicker.vue')) as AsyncComponent<DefaultData<never>, DefaultMethods<never>, DefaultComputed, IFilePicker['props']>
/**
* FilePicker Vue component (implemented as async component)
* @example
* ```vue
* <template>
* <FilePicker name="Select a file" :buttons="buttons" />
* </template>
* <script setup lang="ts">
* import { FilePickerVue as FilePicker, type IFilePickerButton } from '@nextcloud/dialogs'
* const buttons: IFilePickerButton[] = [{
* label: 'Pick',
* callback: (nodes) => console.log('Picked', nodes)
* }]
* </script>
*/
export const FilePickerVue = defineAsyncComponent(() => import('./FilePicker.vue')) as AsyncComponent<DefaultData<never>, DefaultMethods<never>, DefaultComputed, IFilePickerProps>
31 changes: 30 additions & 1 deletion lib/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IDialogButton, 'callback'> {
/**
* 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
15 changes: 5 additions & 10 deletions lib/filepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -51,15 +46,15 @@ export class FilePicker {
private directoriesAllowed: boolean
private buttons: IFilePickerButton[]
private path?: string
private filter?: FilePickerFilter
private filter?: IFilePickerFilter

public constructor(title: string,
multiSelect: boolean,
mimeTypeFilter: string[],
directoriesAllowed: boolean,
buttons: IFilePickerButton[],
path?: string,
filter?: FilePickerFilter) {
filter?: IFilePickerFilter) {
this.title = title
this.multiSelect = multiSelect
this.mimeTypeFilter = mimeTypeFilter
Expand Down Expand Up @@ -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[] = []

/**
Expand Down Expand Up @@ -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
}
Expand Down
33 changes: 29 additions & 4 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -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'
37 changes: 25 additions & 12 deletions lib/toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof Toastify>

export interface ToastOptions {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 845b9a7

Please sign in to comment.