@cloudron/pankow 4.4.0 → 4.4.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/components/BottomBar.vue +1 -1
- package/components/BreadCrumb.vue +3 -3
- package/components/Button.vue +6 -0
- package/components/ClipboardAction.vue +1 -1
- package/components/DateTimeInput.vue +2 -1
- package/components/Dialog.vue +4 -2
- package/components/DirectoryView.vue +1 -0
- package/components/DirectoryViewGridItem.vue +7 -3
- package/components/DirectoryViewListItem.vue +5 -3
- package/components/EmailInput.vue +2 -1
- package/components/FileUploader.vue +2 -2
- package/components/MaskedInput.vue +2 -1
- package/components/Menu.vue +1 -1
- package/components/MenuItem.vue +1 -1
- package/components/MenuItemLink.vue +1 -1
- package/components/MultiSelect.vue +1 -1
- package/components/Notification.vue +4 -2
- package/components/NumberInput.vue +2 -1
- package/components/OfflineBanner.vue +1 -1
- package/components/PasswordInput.vue +1 -1
- package/components/Popover.vue +1 -1
- package/components/ProgressBar.vue +1 -1
- package/components/SaveIndicator.vue +1 -1
- package/components/SideBar.vue +2 -2
- package/components/SingleSelect.vue +1 -1
- package/components/Spinner.vue +1 -1
- package/components/Switch.vue +1 -1
- package/components/TabView.vue +42 -6
- package/components/TableView.vue +6 -0
- package/components/TagInput.vue +1 -1
- package/components/TextInput.vue +2 -1
- package/components/TextInputRaw.vue +2 -1
- package/components/TreeView.vue +1 -1
- package/components/TreeViewNode.vue +6 -0
- package/package.json +1 -1
- package/viewers/GenericViewer.vue +1 -1
package/components/BottomBar.vue
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<template>
|
|
5
5
|
<div class="pankow-bottom-bar">
|
|
6
6
|
<slot>
|
|
7
|
-
© 2024 <a href="https://cloudron.io" rel="noopener noreferrer" target="_blank">Cloudron</a> <a href="https://forum.cloudron.io" rel="noopener noreferrer" target="_blank">Forum <i class="fa fa-comments"></i></a>
|
|
7
|
+
© 2024 <a href="https://cloudron.io" rel="noopener noreferrer" target="_blank">Cloudron</a> <a href="https://forum.cloudron.io" rel="noopener noreferrer" target="_blank" aria-label="Forum">Forum <i class="fa fa-comments" aria-hidden="true"></i></a>
|
|
8
8
|
</slot>
|
|
9
9
|
</div>
|
|
10
10
|
</template>
|
|
@@ -25,13 +25,13 @@ function onClick() {
|
|
|
25
25
|
</script>
|
|
26
26
|
|
|
27
27
|
<template>
|
|
28
|
-
<div class="pankow-breadcrumb">
|
|
28
|
+
<div class="pankow-breadcrumb" aria-label="Breadcrumb">
|
|
29
29
|
<a class="pankow-breadcrumb-item" :href="home.route" @click="home.action ? home.action(home, $event) : null" @keydown.enter="home.action ? home.action(home, $event) : null" tabindex="0">
|
|
30
30
|
<Icon :class="home.icon"/> {{ home.label }}
|
|
31
31
|
</a>
|
|
32
|
-
<span v-for="item in items">
|
|
32
|
+
<span v-for="(item, index) in items">
|
|
33
33
|
<Icon icon="fa-solid fa-chevron-right" class="pankow-breadcrumb-separator"/>
|
|
34
|
-
<a class="pankow-breadcrumb-item" :href="item.route" @click="item.action ? item.action(home, $event) : null" @keydown.enter="item.action ? item.action(home, $event) : null" tabindex="0">
|
|
34
|
+
<a class="pankow-breadcrumb-item" :href="item.route" @click="item.action ? item.action(home, $event) : null" @keydown.enter="item.action ? item.action(home, $event) : null" tabindex="0" :aria-current="index === items.length - 1 ? 'page' : null">
|
|
35
35
|
<Icon v-if="item.icon" :class="item.icon"/> {{ item.label }}
|
|
36
36
|
</a>
|
|
37
37
|
</span>
|
package/components/Button.vue
CHANGED
|
@@ -53,6 +53,7 @@ function onClick(event) {
|
|
|
53
53
|
<template>
|
|
54
54
|
<component ref="elem" :is="href ? 'a' : 'div'" class="pankow-button" role="button" type="button" :class="{ 'pankow-button-disabled': disabled }"
|
|
55
55
|
@click="onClick" @keydown.enter="onClick" :href="disabled ? null : href" :target="target" tabindex="0"
|
|
56
|
+
:aria-label="!$slots['default'] && icon ? icon : undefined"
|
|
56
57
|
:success="success || undefined" :danger="danger || undefined">
|
|
57
58
|
<Menu ref="menuItem" :model="menu" v-if="menu"></Menu>
|
|
58
59
|
<Spinner v-show="loading" style="stroke: white;" :class="{ 'pankow-button-icon-with-text': $slots['default'] }"/>
|
|
@@ -108,6 +109,11 @@ a.pankow-button:visited {
|
|
|
108
109
|
line-height: inherit;
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
.pankow-button .pankow-spinner {
|
|
113
|
+
width: 1.2em;
|
|
114
|
+
height: 1.2em;
|
|
115
|
+
}
|
|
116
|
+
|
|
111
117
|
.pankow-button-icon-right-with-text {
|
|
112
118
|
padding-left: 7px;
|
|
113
119
|
}
|
|
@@ -19,7 +19,7 @@ function onClipboard() {
|
|
|
19
19
|
</script>
|
|
20
20
|
|
|
21
21
|
<template>
|
|
22
|
-
<i class="pankow-clipboard-action fa-solid fa-copy" @click="onClipboard()"></i>
|
|
22
|
+
<i class="pankow-clipboard-action fa-solid fa-copy" tabindex="0" role="button" aria-label="Copy to clipboard" @click="onClipboard()" @keydown.enter="onClipboard()" @keydown.space.prevent="onClipboard()"></i>
|
|
23
23
|
</template>
|
|
24
24
|
|
|
25
25
|
<style>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const model = defineModel();
|
|
4
4
|
const props = defineProps({
|
|
5
|
+
id: String,
|
|
5
6
|
readonly: {
|
|
6
7
|
type: Boolean,
|
|
7
8
|
default: false
|
|
@@ -15,7 +16,7 @@ const props = defineProps({
|
|
|
15
16
|
</script>
|
|
16
17
|
|
|
17
18
|
<template>
|
|
18
|
-
<input class="pankow-text-input" :type="dateOnly ? 'date' : 'datetime-local'" :readonly="readonly" v-model="model"/>
|
|
19
|
+
<input :id="id" class="pankow-text-input" :type="dateOnly ? 'date' : 'datetime-local'" :readonly="readonly" v-model="model"/>
|
|
19
20
|
</template>
|
|
20
21
|
|
|
21
22
|
<style>
|
package/components/Dialog.vue
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
|
|
3
3
|
import { ref, useTemplateRef, nextTick, computed } from 'vue';
|
|
4
|
+
import { uuidv4 } from '../utils.js';
|
|
4
5
|
import Button from './Button.vue';
|
|
5
6
|
import Icon from './Icon.vue';
|
|
6
7
|
|
|
@@ -60,6 +61,7 @@ const mergedStyle = computed(() => {
|
|
|
60
61
|
})
|
|
61
62
|
|
|
62
63
|
const visible = ref(false);
|
|
64
|
+
const dialogTitleId = ref(uuidv4());
|
|
63
65
|
const dialog = useTemplateRef('dialog');
|
|
64
66
|
const dialogBody = useTemplateRef('dialogBody');
|
|
65
67
|
const confirmButton = useTemplateRef('confirmButton');
|
|
@@ -117,8 +119,8 @@ defineExpose({ open, close });
|
|
|
117
119
|
<div class="pankow-dialog-backdrop" @click="onDismiss" v-show="visible" :style="{ 'z-index': zIndex }"></div>
|
|
118
120
|
</Transition>
|
|
119
121
|
<Transition :name="center ? 'pankow-bounce-center' : 'pankow-bounce-center-top'">
|
|
120
|
-
<div ref="dialog" class="pankow-dialog" v-bind="$attrs" :class="{ 'pankow-dialog-center': center }" v-show="visible" @keydown.esc="onDismiss" tabindex="0" :style="mergedStyle">
|
|
121
|
-
<div class="pankow-dialog-header" v-show="title">
|
|
122
|
+
<div ref="dialog" class="pankow-dialog" role="dialog" aria-modal="true" :aria-labelledby="title ? dialogTitleId : null" v-bind="$attrs" :class="{ 'pankow-dialog-center': center }" v-show="visible" @keydown.esc="onDismiss" tabindex="0" :style="mergedStyle">
|
|
123
|
+
<div :id="dialogTitleId" class="pankow-dialog-header" v-show="title">
|
|
122
124
|
{{ title }}
|
|
123
125
|
</div>
|
|
124
126
|
<div class="pankow-dialog-body" ref="dialogBody" :class="{ 'pankow-dialog-body-no-header': !title, 'pankow-dialog-body-no-buttons': !(rejectLabel || confirmLabel) }">
|
|
@@ -8,15 +8,19 @@
|
|
|
8
8
|
|
|
9
9
|
<div class="grid-item" :class="{ 'focused': item.focused, 'selected': item.selected, 'drop-target-active': dropTargetActive }">
|
|
10
10
|
<div v-if="visible && showStar" class="grid-item-star" @dblclick.stop.prevent @click.stop.prevent="onToggleStar">
|
|
11
|
-
<
|
|
11
|
+
<span tabindex="0" role="button" :aria-label="item.star ? 'Unstar' : 'Star'" @keydown.enter.prevent="onToggleStar" @keydown.space.prevent="onToggleStar">
|
|
12
|
+
<Icon :icon="`${item.star ? 'fa-solid' : 'fa-regular'} fa-star`" class="star-icon" :class="{ 'star-visible': item.star }" />
|
|
13
|
+
</span>
|
|
12
14
|
</div>
|
|
13
15
|
<div v-if="visible" class="grid-item-actions" @mouseup.stop="onActionMenu($event)">
|
|
14
|
-
<
|
|
16
|
+
<span tabindex="0" role="button" aria-label="Actions" @click="onActionMenu($event)" @keydown.enter="onActionMenu($event)" @keydown.space.prevent="onActionMenu($event)">
|
|
17
|
+
<i class="fa-solid fa-ellipsis-vertical"/>
|
|
18
|
+
</span>
|
|
15
19
|
</div>
|
|
16
20
|
|
|
17
21
|
<div class="grid-item-icon">
|
|
18
22
|
<template v-if="visible">
|
|
19
|
-
<img :src="item.previewUrl || item.icon" ref="iconImage" @error="iconError($event)"/>
|
|
23
|
+
<img :src="item.previewUrl || item.icon" ref="iconImage" :alt="item.name" @error="iconError($event)"/>
|
|
20
24
|
<i v-show="shareIndicatorProperty !== '' && !!item[shareIndicatorProperty]" class="fa-solid fa-share-nodes is-shared"></i>
|
|
21
25
|
<i v-show="fileDropIndicatorProperty !== '' && !!item[fileDropIndicatorProperty]" class="fa-solid fa-cloud-arrow-up is-filedrop"></i>
|
|
22
26
|
</template>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<div v-if="!visible" class="col label"></div>
|
|
12
12
|
|
|
13
13
|
<div v-if="visible" class="col icon">
|
|
14
|
-
<img :src="item.previewUrl || item.icon" ref="iconImage" @error="iconError($event)"/>
|
|
14
|
+
<img :src="item.previewUrl || item.icon" ref="iconImage" :alt="item.name" @error="iconError($event)"/>
|
|
15
15
|
<i v-show="shareIndicatorProperty !== '' && !!item[shareIndicatorProperty]" class="fa-solid fa-share-nodes is-shared"></i>
|
|
16
16
|
<i v-show="fileDropIndicatorProperty !== '' && !!item[fileDropIndicatorProperty]" class="fa-solid fa-cloud-arrow-up is-filedrop"></i>
|
|
17
17
|
</div>
|
|
@@ -26,13 +26,15 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
<div v-if="visible && showStar" class="col star">
|
|
29
|
-
<
|
|
29
|
+
<span tabindex="0" role="button" :aria-label="item.star ? 'Unstar' : 'Star'" @dblclick.stop.prevent @click.stop.prevent="onToggleStar" @keydown.enter.prevent="onToggleStar" @keydown.space.prevent="onToggleStar">
|
|
30
|
+
<Icon :icon="`${item.star ? 'fa-solid' : 'fa-regular'} fa-star`" class="star-icon" :class="{ 'star-visible': item.star }" />
|
|
31
|
+
</span>
|
|
30
32
|
</div>
|
|
31
33
|
<div v-if="visible && showOwner" class="col owner">{{ item.owner }}</div>
|
|
32
34
|
<div v-if="visible && showSize" class="col size">{{ prettyFileSize(item.size) }}</div>
|
|
33
35
|
<div v-if="visible && showModified" class="col modified" :title="item.modified.toLocaleString()">{{ prettyDate(item.modified) }}</div>
|
|
34
36
|
<div v-if="visible" class="col actions">
|
|
35
|
-
<div @mouseup.stop="onActionMenu($event)"><i class="fa-solid fa-ellipsis-vertical"/></div>
|
|
37
|
+
<div @mouseup.stop="onActionMenu($event)"><span tabindex="0" role="button" aria-label="Actions" @click="onActionMenu($event)" @keydown.enter="onActionMenu($event)" @keydown.space.prevent="onActionMenu($event)"><i class="fa-solid fa-ellipsis-vertical"/></span></div>
|
|
36
38
|
</div>
|
|
37
39
|
</div>
|
|
38
40
|
</div>
|
|
@@ -4,6 +4,7 @@ import { useTemplateRef } from 'vue';
|
|
|
4
4
|
|
|
5
5
|
const model = defineModel();
|
|
6
6
|
const props = defineProps({
|
|
7
|
+
id: String,
|
|
7
8
|
placeholder: String,
|
|
8
9
|
readonly: {
|
|
9
10
|
type: Boolean,
|
|
@@ -21,7 +22,7 @@ defineExpose({ focus });
|
|
|
21
22
|
</script>
|
|
22
23
|
|
|
23
24
|
<template>
|
|
24
|
-
<input ref="inputElement" class="pankow-text-input" type="email" :placeholder="placeholder" :readonly="readonly" :required="$attrs['required']" v-model.trim="model"/>
|
|
25
|
+
<input :id="id" ref="inputElement" class="pankow-text-input" type="email" :placeholder="placeholder" :readonly="readonly" :required="$attrs['required']" v-model.trim="model"/>
|
|
25
26
|
</template>
|
|
26
27
|
|
|
27
28
|
<style>
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<Button danger small tool @click="onCancelUpload" icon="fa-solid fa-xmark"></Button>
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
|
-
<input type="file" ref="uploadFileInput" style="display: none" multiple/>
|
|
10
|
-
<input type="file" ref="uploadFolderInput" style="display: none" multiple webkitdirectory directory/>
|
|
9
|
+
<input type="file" ref="uploadFileInput" style="display: none" multiple aria-label="Upload files"/>
|
|
10
|
+
<input type="file" ref="uploadFolderInput" style="display: none" multiple webkitdirectory directory aria-label="Upload folder"/>
|
|
11
11
|
|
|
12
12
|
<InputDialog ref="inputDialog" />
|
|
13
13
|
</div>
|
|
@@ -5,6 +5,7 @@ import { computed } from 'vue';
|
|
|
5
5
|
const model = defineModel({ type: [String, null], default: null });
|
|
6
6
|
|
|
7
7
|
const props = defineProps({
|
|
8
|
+
id: String,
|
|
8
9
|
multiline: {
|
|
9
10
|
type: Boolean,
|
|
10
11
|
default: false
|
|
@@ -27,7 +28,7 @@ const displayValue = computed({
|
|
|
27
28
|
|
|
28
29
|
<template>
|
|
29
30
|
<template v-if="!multiline">
|
|
30
|
-
<input class="pankow-masked-input" :value="displayValue" @input="displayValue = $event.target.value" @focus="$event.target.select()" />
|
|
31
|
+
<input :id="id" class="pankow-masked-input" :value="displayValue" @input="displayValue = $event.target.value" @focus="$event.target.select()" />
|
|
31
32
|
</template>
|
|
32
33
|
<template v-else>
|
|
33
34
|
<textarea :value="displayValue" @input="displayValue = $event.target.value" @focus="$event.target.select()"></textarea>
|
package/components/Menu.vue
CHANGED
|
@@ -325,7 +325,7 @@ defineExpose({
|
|
|
325
325
|
<teleport to="#app">
|
|
326
326
|
<div class="pankow-menu-backdrop" @click="onBackdrop($event)" @contextmenu="onBackdrop($event)" v-show="isOpen"></div>
|
|
327
327
|
<Transition :name="rollUp ? 'pankow-roll-up' : 'pankow-roll-down'">
|
|
328
|
-
<div class="pankow-menu" :class="{ 'pankow-menu-keyboard-nav': keyboardNav }" v-show="isOpen" ref="container" tabindex="0" @keydown.up.stop="selectUp()" @keydown.down.stop="selectDown()" @keydown.esc.stop="close()" @keydown="onKeyDown" @mousemove="onMouseMove">
|
|
328
|
+
<div class="pankow-menu" role="menu" :aria-label="searchThreshold < model.length ? 'Filterable menu' : 'Menu'" :class="{ 'pankow-menu-keyboard-nav': keyboardNav }" v-show="isOpen" ref="container" tabindex="0" @keydown.up.stop="selectUp()" @keydown.down.stop="selectDown()" @keydown.esc.stop="close()" @keydown="onKeyDown" @mousemove="onMouseMove">
|
|
329
329
|
<TextInput placeholder="Filter ..." autocomplete="off" @keydown.up.stop="selectUp()" @keydown.down.stop="selectDown()" @keydown.stop @keydown.esc.stop="close()" @click.stop style="width: 100%; border: 0; padding: 8px 12px;" v-model="searchString" v-if="searchThreshold < model.length"/>
|
|
330
330
|
<component v-for="item in visibleItems" ref="itemElements" :is="item.type || (item.href ? MenuItemLink : MenuItem)" @activated="onItemActivated(item)" :item="item" :has-icons="hasIcons" />
|
|
331
331
|
<MenuItem v-if="model.length === 0" :item="emptyItem"/>
|
package/components/MenuItem.vue
CHANGED
|
@@ -42,7 +42,7 @@ function onActivated() {
|
|
|
42
42
|
</script>
|
|
43
43
|
|
|
44
44
|
<template>
|
|
45
|
-
<div class="pankow-menu-item" :class="{'pankow-menu-item-disabled': isDisabled }" @click.stop="onActivated" :separator="item.separator" v-if="isVisible" tabindex="0" @keydown.enter.stop="onActivated" @keydown.space.stop="onActivated">
|
|
45
|
+
<div class="pankow-menu-item" role="menuitem" :aria-checked="item.checkbox ? item.checked : undefined" :class="{'pankow-menu-item-disabled': isDisabled }" @click.stop="onActivated" :separator="item.separator" v-if="isVisible" tabindex="0" @keydown.enter.stop="onActivated" @keydown.space.stop="onActivated">
|
|
46
46
|
<CheckBox v-model="item.checked" v-if="item.checkbox" style="margin-right: 4px; display: inline-flex;"/>
|
|
47
47
|
<span v-if="!item.separator" :style="{ width: (hasIcons && !item.checkbox) ? '29px' : 0 }"><Icon v-show="hasIcons" :icon="item.icon"/></span>{{ item.label }}
|
|
48
48
|
<div class="pankow-menu-item-separator-line" v-if="item.separator"></div>
|
|
@@ -40,7 +40,7 @@ function onActivated() {
|
|
|
40
40
|
</script>
|
|
41
41
|
|
|
42
42
|
<template>
|
|
43
|
-
<a class="pankow-menu-item" style="display: block" :href="isDisabled ? null : item.href" :target="item.target || null" @click="onActivated" :class="{ 'pankow-menu-item-disabled': isDisabled }" v-if="isVisible">
|
|
43
|
+
<a class="pankow-menu-item" role="menuitem" style="display: block" :href="isDisabled ? null : item.href" :target="item.target || null" @click="onActivated" :class="{ 'pankow-menu-item-disabled': isDisabled }" v-if="isVisible">
|
|
44
44
|
<span :style="{ width: hasIcons ? '29px' : 0 }" style="display: inline-block;"><Icon v-show="hasIcons" :icon="item.icon" /></span>{{ item.label }}
|
|
45
45
|
</a>
|
|
46
46
|
</template>
|
|
@@ -162,7 +162,7 @@ onMounted(() => {
|
|
|
162
162
|
</script>
|
|
163
163
|
|
|
164
164
|
<template>
|
|
165
|
-
<div class="pankow-multiselect" :class="{ 'pankow-multiselect-disabled': disabled }" ref="elem" tabindex="0" @click="onClick" @keydown.enter="onOpen" @keydown.down.stop="onOpen" @keydown.up.stop="onOpen" @keydown.esc="onEscape">
|
|
165
|
+
<div class="pankow-multiselect" role="combobox" :aria-expanded="menu?.isOpen ?? false" aria-haspopup="listbox" :class="{ 'pankow-multiselect-disabled': disabled }" ref="elem" tabindex="0" @click="onClick" @keydown.enter="onOpen" @keydown.down.stop="onOpen" @keydown.up.stop="onOpen" @keydown.esc="onEscape">
|
|
166
166
|
<!-- native select for required and accessibility handling -->
|
|
167
167
|
<select ref="nativeSelect" :required="$attrs['required']" multiple style="display: none">
|
|
168
168
|
<option value=""></option>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<TransitionGroup name="pankow-notification-fade" :class="`pankow-notification-container ${position}`" tag="div">
|
|
2
|
+
<TransitionGroup name="pankow-notification-fade" :class="`pankow-notification-container ${position}`" tag="div" role="alert" aria-live="polite">
|
|
3
3
|
<div v-for="message in messages" :key="message.id">
|
|
4
4
|
<div class="pankow-notification" :[message.type]="''">
|
|
5
5
|
{{ message.text }}
|
|
6
|
-
<
|
|
6
|
+
<span tabindex="0" role="button" aria-label="Close notification" @keydown.enter="removeNotify(message.id)" @keydown.space.prevent="removeNotify(message.id)" @click="removeNotify(message.id)" class="pankow-notification-close">
|
|
7
|
+
<Icon icon="fa-solid fa-xmark"/>
|
|
8
|
+
</span>
|
|
7
9
|
</div>
|
|
8
10
|
</div>
|
|
9
11
|
</TransitionGroup>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const model = defineModel();
|
|
4
4
|
const props = defineProps({
|
|
5
|
+
id: String,
|
|
5
6
|
placeholder: String,
|
|
6
7
|
readonly: {
|
|
7
8
|
type: Boolean,
|
|
@@ -21,7 +22,7 @@ const props = defineProps({
|
|
|
21
22
|
</script>
|
|
22
23
|
|
|
23
24
|
<template>
|
|
24
|
-
<input class="pankow-text-input" type="number" :step="step" :min="min" :max="max" :placeholder="placeholder" :readonly="readonly" :value="model" @input="$emit('update:modelValue', parseInt($event.target.value))"/>
|
|
25
|
+
<input :id="id" class="pankow-text-input" type="number" :step="step" :min="min" :max="max" :placeholder="placeholder" :readonly="readonly" :value="model" @input="$emit('update:modelValue', parseInt($event.target.value))"/>
|
|
25
26
|
</template>
|
|
26
27
|
|
|
27
28
|
<style>
|
|
@@ -19,7 +19,7 @@ const props = defineProps({
|
|
|
19
19
|
|
|
20
20
|
<template>
|
|
21
21
|
<Transition name="pankow-roll-down">
|
|
22
|
-
<a class="pankow-offline-banner" v-show="active" :href="href" target="_blank">
|
|
22
|
+
<a class="pankow-offline-banner" role="alert" v-show="active" :href="href" target="_blank">
|
|
23
23
|
<i class="fa fa-solid fa-spin fa-circle-notch"/> {{ label }}
|
|
24
24
|
</a>
|
|
25
25
|
</Transition>
|
|
@@ -30,7 +30,7 @@ function toggleReveal() {
|
|
|
30
30
|
<template>
|
|
31
31
|
<div class="pankow-password">
|
|
32
32
|
<input class="pankow-password-input" :id="id" :type="revealed ? 'text' : 'password'" :disabled="disabled ? true : undefined" :placeholder="placeholder" :autofocus="$attrs['autofocus']" :required="$attrs['required']" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)"/>
|
|
33
|
-
<
|
|
33
|
+
<span class="pankow-password-reveal" tabindex="0" role="button" :aria-label="revealed ? 'Hide password' : 'Show password'" @keydown.enter="toggleReveal" @keydown.space.prevent="toggleReveal" @click="toggleReveal" v-html="revealIcon"></span>
|
|
34
34
|
</div>
|
|
35
35
|
</template>
|
|
36
36
|
|
package/components/Popover.vue
CHANGED
|
@@ -144,7 +144,7 @@ defineExpose({
|
|
|
144
144
|
<teleport to="#app">
|
|
145
145
|
<div class="pankow-popover-backdrop" @click="onBackdrop($event)" @contextmenu="onBackdrop($event)" v-show="isOpen"></div>
|
|
146
146
|
<Transition :name="rollUp ? 'pankow-animation-pop-up' : 'pankow-animation-pop-down'">
|
|
147
|
-
<div v-show="isOpen" class="pankow-popover" ref="container" :style="{ 'max-width': width || null, 'max-height': height || null }">
|
|
147
|
+
<div v-show="isOpen" class="pankow-popover" ref="container" role="dialog" aria-label="Popover" :style="{ 'max-width': width || null, 'max-height': height || null }">
|
|
148
148
|
<slot></slot>
|
|
149
149
|
</div>
|
|
150
150
|
</Transition>
|
|
@@ -35,7 +35,7 @@ const normalizedValue = computed(() => {
|
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
37
|
<template>
|
|
38
|
-
<div class="pankow-progress-bar">
|
|
38
|
+
<div class="pankow-progress-bar" role="progressbar" :aria-valuenow="normalizedValue" aria-valuemin="0" aria-valuemax="100" :aria-label="'Progress: ' + normalizedValue + '%'">
|
|
39
39
|
<div class="pankow-progress-bar-label" v-show="showLabel"><slot>{{ value + ' %' }}</slot></div>
|
|
40
40
|
<div :class="{ 'pankow-progress-bar-background': showTrack }">
|
|
41
41
|
<div v-if="mode !== 'indeterminate'" class="pankow-progress-bar-filled" :style="{ width: normalizedValue+'%', height: slim ? '2px' : '6px' }">
|
|
@@ -42,7 +42,7 @@ defineExpose({ success: showSuccess, error: showError });
|
|
|
42
42
|
<div class="pankow-save-indicator-wrapper">
|
|
43
43
|
<slot />
|
|
44
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>
|
|
45
|
+
<div class="pankow-save-indicator" role="status" aria-live="polite" v-if="visible" :class="{ success: success, error: !success }"><Icon :icon="success ? 'fa-solid fa-check' : 'fa-solid fa-xmark'"/></div>
|
|
46
46
|
</Transition>
|
|
47
47
|
</div>
|
|
48
48
|
</template>
|
package/components/SideBar.vue
CHANGED
|
@@ -38,8 +38,8 @@ defineExpose({ open, close });
|
|
|
38
38
|
</Transition>
|
|
39
39
|
<div class="pankow-sidebar" ref="sideBar" :class="{ 'pankow-sidebar-closed': !isVisible }">
|
|
40
40
|
<Transition name="pankow-scale">
|
|
41
|
-
<div class="pankow-sidebar-close-action" v-if="isVisible" @click="close()"><i class="fa-solid fa-xmark"></i></div>
|
|
42
|
-
<div class="pankow-sidebar-open-action" v-else-if="showOpenAction" @click="open()"><i class="fa-solid fa-bars"></i></div>
|
|
41
|
+
<div class="pankow-sidebar-close-action" v-if="isVisible" tabindex="0" role="button" aria-label="Close sidebar" @click="close()" @keydown.enter="close()" @keydown.space.prevent="close()"><i class="fa-solid fa-xmark"></i></div>
|
|
42
|
+
<div class="pankow-sidebar-open-action" v-else-if="showOpenAction" tabindex="0" role="button" aria-label="Open sidebar" @click="open()" @keydown.enter="open()" @keydown.space.prevent="open()"><i class="fa-solid fa-bars"></i></div>
|
|
43
43
|
</Transition>
|
|
44
44
|
<div class="pankow-sidebar-inner">
|
|
45
45
|
<slot></slot>
|
|
@@ -176,7 +176,7 @@ watchEffect(handleDefaultSelect);
|
|
|
176
176
|
</script>
|
|
177
177
|
|
|
178
178
|
<template>
|
|
179
|
-
<div class="pankow-singleselect" :class="{ 'pankow-singleselect-disabled': disabled }" ref="elem" tabindex="0" @click="onClick" @keydown.enter="onOpen" @keydown.down.stop.prevent="onSelectNext" @keydown.up.stop.prevent="onSelectPrev" @keydown="onKeyDown($event)">
|
|
179
|
+
<div class="pankow-singleselect" role="combobox" :aria-expanded="menu?.isOpen ?? false" aria-haspopup="listbox" :class="{ 'pankow-singleselect-disabled': disabled }" ref="elem" tabindex="0" @click="onClick" @keydown.enter="onOpen" @keydown.down.stop.prevent="onSelectNext" @keydown.up.stop.prevent="onSelectPrev" @keydown="onKeyDown($event)">
|
|
180
180
|
<!-- native select for required and accessibility handling -->
|
|
181
181
|
<select v-model="selectedKey" :id="id" ref="nativeSelect" :required="$attrs['required']" style="display: none">
|
|
182
182
|
<option value=""></option>
|
package/components/Spinner.vue
CHANGED
package/components/Switch.vue
CHANGED
|
@@ -22,7 +22,7 @@ function onChange(event) {
|
|
|
22
22
|
|
|
23
23
|
<template>
|
|
24
24
|
<label :for="id || internalId" class="pankow-switch" :class="{ 'pankow-switch-disabled': disabled }">
|
|
25
|
-
<input :id="id || internalId" class="pankow-switch-input" type="checkbox" v-model="model" :disabled="disabled" @change="onChange"/>
|
|
25
|
+
<input :id="id || internalId" class="pankow-switch-input" type="checkbox" role="switch" :aria-checked="model" v-model="model" :disabled="disabled" @change="onChange"/>
|
|
26
26
|
<span></span>
|
|
27
27
|
<div class="pankow-switch-input-label">
|
|
28
28
|
<slot>{{ label }}</slot>
|
package/components/TabView.vue
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="pankow-tabview" :top="tabPosition === 'top' ? true : null" :left="tabPosition === 'left' ? true : null" :right="tabPosition === 'right' ? true : null" :bottom="tabPosition === 'bottom' ? true : null">
|
|
3
|
-
<div class="pankow-tabview-tabs" v-if="tabPosition === 'top' || tabPosition === 'left'">
|
|
4
|
-
<div class="pankow-tabview-tab" :class="{'active': active === tab }" v-for="tab in Object.keys(tabs)" @click="open(tab)">{{ tabs[tab] }}</div>
|
|
3
|
+
<div class="pankow-tabview-tabs" role="tablist" :aria-label="tabPosition === 'top' || tabPosition === 'bottom' ? 'Tabs' : 'Tabs'" v-if="tabPosition === 'top' || tabPosition === 'left'">
|
|
4
|
+
<div class="pankow-tabview-tab" role="tab" :tabindex="active === tab ? 0 : -1" :aria-selected="active === tab ? 'true' : 'false'" :aria-controls="'tabpanel-'+tab" :class="{'active': active === tab }" v-for="tab in Object.keys(tabs)" @click="open(tab)" @keydown="onTabKeydown($event, tab)">{{ tabs[tab] }}</div>
|
|
5
5
|
</div>
|
|
6
6
|
<div class="pankow-tabview-content">
|
|
7
|
-
<div v-for="tab in Object.keys(tabs)">
|
|
7
|
+
<div v-for="tab in Object.keys(tabs)" :id="'tabpanel-'+tab" role="tabpanel" :aria-labelledby="tab" tabindex="0">
|
|
8
8
|
<slot :name="tab" v-if="active === tab"/>
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
|
-
<div class="pankow-tabview-tabs" v-if="tabPosition === 'bottom' || tabPosition === 'right'">
|
|
12
|
-
<div class="pankow-tabview-tab" :class="{'active': active === tab }" v-for="tab in Object.keys(tabs)" @click="open(tab)">{{ tabs[tab] }}</div>
|
|
11
|
+
<div class="pankow-tabview-tabs" role="tablist" :aria-label="tabPosition === 'top' || tabPosition === 'bottom' ? 'Tabs' : 'Tabs'" v-if="tabPosition === 'bottom' || tabPosition === 'right'">
|
|
12
|
+
<div class="pankow-tabview-tab" role="tab" :tabindex="active === tab ? 0 : -1" :aria-selected="active === tab ? 'true' : 'false'" :aria-controls="'tabpanel-'+tab" :class="{'active': active === tab }" v-for="tab in Object.keys(tabs)" @click="open(tab)" @keydown="onTabKeydown($event, tab)">{{ tabs[tab] }}</div>
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
</template>
|
|
@@ -43,6 +43,42 @@ function open(key) {
|
|
|
43
43
|
emit('changed', key);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function onTabKeydown(event, currentKey) {
|
|
47
|
+
const keys = Object.keys(props.tabs);
|
|
48
|
+
const index = keys.indexOf(currentKey);
|
|
49
|
+
const isVertical = props.tabPosition === 'left' || props.tabPosition === 'right';
|
|
50
|
+
|
|
51
|
+
if (isVertical) {
|
|
52
|
+
if (event.key === 'ArrowDown') {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
const next = index + 1 >= keys.length ? 0 : index + 1;
|
|
55
|
+
open(keys[next]);
|
|
56
|
+
} else if (event.key === 'ArrowUp') {
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
const prev = index <= 0 ? keys.length - 1 : index - 1;
|
|
59
|
+
open(keys[prev]);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
if (event.key === 'ArrowRight') {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
const next = index + 1 >= keys.length ? 0 : index + 1;
|
|
65
|
+
open(keys[next]);
|
|
66
|
+
} else if (event.key === 'ArrowLeft') {
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
const prev = index <= 0 ? keys.length - 1 : index - 1;
|
|
69
|
+
open(keys[prev]);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (event.key === 'Home') {
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
open(keys[0]);
|
|
76
|
+
} else if (event.key === 'End') {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
open(keys[keys.length - 1]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
46
82
|
</script>
|
|
47
83
|
|
|
48
84
|
<style>
|
|
@@ -153,4 +189,4 @@ function open(key) {
|
|
|
153
189
|
margin-right: 10px;
|
|
154
190
|
}
|
|
155
191
|
|
|
156
|
-
</style>
|
|
192
|
+
</style>
|
package/components/TableView.vue
CHANGED
|
@@ -103,7 +103,13 @@ onMounted(() => {
|
|
|
103
103
|
class="pankow-table-header-column"
|
|
104
104
|
:class="{ 'pankow-table-header-column-sortable': columns[column].sort, 'pankow-table-cell-hide-mobile': columns[column].hideMobile }"
|
|
105
105
|
:style="{ 'text-align': columns[column].align || null, width: typeof columns[column].width === 'string' ? columns[column].width : 'auto' }"
|
|
106
|
+
:aria-sort="sortBy === column ? (sortOrder === SORT_ORDER.ASC ? 'ascending' : 'descending') : 'none'"
|
|
107
|
+
scope="col"
|
|
108
|
+
:tabindex="columns[column].sort ? 0 : null"
|
|
109
|
+
:aria-label="columns[column].sort ? 'Sort by ' + columns[column].label : columns[column].label"
|
|
106
110
|
@click="toggleSort(column)"
|
|
111
|
+
@keydown.enter="toggleSort(column)"
|
|
112
|
+
@keydown.space.prevent="toggleSort(column)"
|
|
107
113
|
>
|
|
108
114
|
<Icon v-if="columns[column].icon" :icon="columns[column].icon" />
|
|
109
115
|
{{ columns[column].label }}
|
package/components/TagInput.vue
CHANGED
|
@@ -41,7 +41,7 @@ function onRemoveIndex(index) {
|
|
|
41
41
|
|
|
42
42
|
<template>
|
|
43
43
|
<div class="pankow-tag-input">
|
|
44
|
-
|
|
44
|
+
<div class="pankow-tag-input-tag" v-for="(tag, index) in model" :key="index">{{ tag }} <span tabindex="0" role="button" :aria-label="'Remove ' + tag" class="pankow-tag-input-tag-remove" @click="onRemoveIndex(index)" @keydown.enter="onRemoveIndex(index)" @keydown.space.prevent="onRemoveIndex(index)"><i class="fa-solid fa-xmark"></i></span></div>
|
|
45
45
|
<input class="pankow-tag-input-input" :id="id" :placeholder="placeholder" :autofocus="$attrs['autofocus']" @keydown="onKey($event)" @blur="onBlur"/>
|
|
46
46
|
</div>
|
|
47
47
|
</template>
|
package/components/TextInput.vue
CHANGED
|
@@ -6,6 +6,7 @@ import { useTemplateRef } from 'vue';
|
|
|
6
6
|
|
|
7
7
|
const model = defineModel();
|
|
8
8
|
const props = defineProps({
|
|
9
|
+
id: String,
|
|
9
10
|
placeholder: String,
|
|
10
11
|
readonly: {
|
|
11
12
|
type: Boolean,
|
|
@@ -23,7 +24,7 @@ defineExpose({ focus });
|
|
|
23
24
|
</script>
|
|
24
25
|
|
|
25
26
|
<template>
|
|
26
|
-
<input ref="inputElement" class="pankow-text-input" type="text" :placeholder="placeholder" :readonly="readonly" v-model.trim="model"/>
|
|
27
|
+
<input :id="id" ref="inputElement" class="pankow-text-input" type="text" :placeholder="placeholder" :readonly="readonly" v-model.trim="model"/>
|
|
27
28
|
</template>
|
|
28
29
|
|
|
29
30
|
<style>
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const model = defineModel();
|
|
6
6
|
const props = defineProps({
|
|
7
|
+
id: String,
|
|
7
8
|
placeholder: String,
|
|
8
9
|
readonly: {
|
|
9
10
|
type: Boolean,
|
|
@@ -14,7 +15,7 @@ const props = defineProps({
|
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<template>
|
|
17
|
-
<input class="pankow-text-input" type="text" :placeholder="placeholder" :readonly="readonly" v-model="model"/>
|
|
18
|
+
<input :id="id" class="pankow-text-input" type="text" :placeholder="placeholder" :readonly="readonly" v-model="model"/>
|
|
18
19
|
</template>
|
|
19
20
|
|
|
20
21
|
<style>
|
package/components/TreeView.vue
CHANGED
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
class="tree-view-node-row"
|
|
5
5
|
:class="{ 'active': isActive, 'drop-target': dropTargetActive }"
|
|
6
6
|
:style="{ paddingLeft: (props.depth * 16 + 4) + 'px' }"
|
|
7
|
+
tabindex="0"
|
|
8
|
+
role="treeitem"
|
|
9
|
+
:aria-expanded="expanded"
|
|
10
|
+
:aria-selected="isActive"
|
|
7
11
|
@click="onRowClick"
|
|
12
|
+
@keydown.enter="onRowClick"
|
|
13
|
+
@keydown.space.prevent="onRowClick"
|
|
8
14
|
@dragover.stop.prevent="onDragOver"
|
|
9
15
|
@dragenter.stop.prevent="onDragEnter"
|
|
10
16
|
@dragleave="onDragLeave"
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<template #body>
|
|
14
14
|
<div class="content">
|
|
15
15
|
<div>
|
|
16
|
-
<img class="preview-icon" :src="entry.previewUrl" />
|
|
16
|
+
<img class="preview-icon" :src="entry.previewUrl" :alt="entry.fileName" />
|
|
17
17
|
<h1>{{ entry.fileName }}</h1>
|
|
18
18
|
<Button icon="fa-solid fa-download" :href="entry.downloadFileUrl">Download</Button>
|
|
19
19
|
</div>
|