@fy-/fws-vue 2.1.6 → 2.1.7

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.
Files changed (40) hide show
  1. package/components/fws/CmsArticleBoxed.vue +23 -20
  2. package/components/fws/CmsArticleSingle.vue +74 -68
  3. package/components/fws/DataTable.vue +132 -125
  4. package/components/fws/FilterData.vue +99 -101
  5. package/components/fws/UserData.vue +33 -32
  6. package/components/fws/UserFlow.vue +163 -155
  7. package/components/fws/UserOAuth2.vue +73 -72
  8. package/components/fws/UserProfile.vue +98 -101
  9. package/components/fws/UserProfileStrict.vue +65 -64
  10. package/components/ssr/ClientOnly.ts +7 -7
  11. package/components/ui/DefaultBreadcrumb.vue +13 -13
  12. package/components/ui/DefaultConfirm.vue +35 -34
  13. package/components/ui/DefaultDateSelection.vue +19 -17
  14. package/components/ui/DefaultDropdown.vue +25 -25
  15. package/components/ui/DefaultDropdownLink.vue +15 -14
  16. package/components/ui/DefaultGallery.vue +179 -168
  17. package/components/ui/DefaultInput.vue +121 -126
  18. package/components/ui/DefaultLoader.vue +17 -17
  19. package/components/ui/DefaultModal.vue +35 -33
  20. package/components/ui/DefaultNotif.vue +50 -52
  21. package/components/ui/DefaultPaging.vue +92 -95
  22. package/components/ui/DefaultSidebar.vue +29 -25
  23. package/components/ui/DefaultTagInput.vue +121 -119
  24. package/components/ui/transitions/CollapseTransition.vue +1 -1
  25. package/components/ui/transitions/ExpandTransition.vue +1 -1
  26. package/components/ui/transitions/FadeTransition.vue +1 -1
  27. package/components/ui/transitions/ScaleTransition.vue +1 -1
  28. package/components/ui/transitions/SlideTransition.vue +3 -3
  29. package/composables/event-bus.ts +10 -8
  30. package/composables/rest.ts +59 -56
  31. package/composables/seo.ts +106 -95
  32. package/composables/ssr.ts +64 -62
  33. package/composables/templating.ts +57 -57
  34. package/composables/translations.ts +13 -13
  35. package/env.d.ts +6 -4
  36. package/index.ts +101 -98
  37. package/package.json +7 -7
  38. package/stores/serverRouter.ts +25 -25
  39. package/stores/user.ts +79 -72
  40. package/types.d.ts +65 -65
@@ -1,3 +1,119 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref } from 'vue'
3
+ import { useEventBus } from '../../composables/event-bus'
4
+
5
+ type colorType = 'blue' | 'red' | 'green' | 'purple' | 'orange' | 'neutral'
6
+
7
+ const props = withDefaults(
8
+ defineProps<{
9
+ modelValue: string[]
10
+ color?: colorType
11
+ label?: string
12
+ id: string
13
+ separators?: string[]
14
+ autofocus?: boolean
15
+ help?: string
16
+ maxLenghtPerTag?: number
17
+ error?: string
18
+ copyButton?: boolean
19
+ }>(),
20
+ {
21
+ copyButton: false,
22
+ maxLenghtPerTag: 0,
23
+ color: 'blue',
24
+ label: 'Tags',
25
+ separators: () => [','],
26
+ autofocus: false,
27
+ },
28
+ )
29
+
30
+ const textInput = ref<HTMLElement>()
31
+
32
+ const emit = defineEmits(['update:modelValue'])
33
+ const model = computed({
34
+ get: () => props.modelValue,
35
+ set: (items) => {
36
+ emit('update:modelValue', items)
37
+ },
38
+ })
39
+
40
+ onMounted(() => {
41
+ if (props.autofocus) {
42
+ focusInput()
43
+ }
44
+ })
45
+ const eventBus = useEventBus()
46
+ async function copyText() {
47
+ const text = model.value.join(', ')
48
+ await navigator.clipboard.writeText(text)
49
+ eventBus.emit('SendNotif', {
50
+ title: 'Text copied!',
51
+ type: 'success',
52
+ time: 2500,
53
+ })
54
+ }
55
+
56
+ function handleInput(event: any) {
57
+ const separatorsRegex = new RegExp(props.separators.join('|'))
58
+ if (separatorsRegex.test(event.data)) {
59
+ addTag()
60
+ }
61
+ }
62
+
63
+ function addTag() {
64
+ if (!textInput.value) return
65
+
66
+ const separatorsRegex = new RegExp(props.separators.join('|'))
67
+ if (!textInput.value.textContent) return
68
+ const newTags = textInput.value.textContent
69
+ .split(separatorsRegex)
70
+ .map((tag: string) => tag.trim())
71
+ .filter((tag: string) => tag.length > 0)
72
+ model.value.push(...newTags)
73
+ textInput.value.textContent = ''
74
+ }
75
+
76
+ function removeTag(index: number) {
77
+ model.value.splice(index, 1)
78
+ focusInput()
79
+ }
80
+
81
+ function removeLastTag() {
82
+ if (!textInput.value) return
83
+ if (textInput.value.textContent === '') {
84
+ model.value.pop()
85
+ }
86
+ else {
87
+ if (!textInput.value.textContent) return
88
+ textInput.value.textContent = textInput.value.textContent.slice(0, -1)
89
+
90
+ const range = document.createRange()
91
+ const sel = window.getSelection()
92
+ range.selectNodeContents(textInput.value)
93
+ range.collapse(false)
94
+ if (!sel) return
95
+ sel.removeAllRanges()
96
+ sel.addRange(range)
97
+ }
98
+ }
99
+ function focusInput() {
100
+ if (!textInput.value) return
101
+
102
+ textInput.value.focus()
103
+ }
104
+
105
+ function handlePaste(e: any) {
106
+ if (!textInput.value) return
107
+ // @ts-expect-error: Property 'clipboardData' does not exist on type 'ClipboardEvent'.
108
+ const text = (e.clipboardData || window.clipboardData).getData('text')
109
+ const separatorsRegex = new RegExp(props.separators.join('|'), 'g')
110
+ const pasteText = text.replace(separatorsRegex, ',')
111
+ textInput.value.textContent += pasteText
112
+ e.preventDefault()
113
+ addTag()
114
+ }
115
+ </script>
116
+
1
117
  <template>
2
118
  <div>
3
119
  <div
@@ -34,16 +150,16 @@
34
150
  </button>
35
151
  </span>
36
152
  <div
37
- contenteditable
38
- class="input"
39
153
  :id="`tags_${id}`"
40
154
  ref="textInput"
155
+ contenteditable
156
+ class="input"
157
+ placeholder="Add a tag..."
41
158
  @input="handleInput"
42
159
  @paste.prevent="handlePaste"
43
- placeholder="Add a tag..."
44
- ></div>
160
+ />
45
161
  </div>
46
- <div class="flex justify-end mt-1" v-if="copyButton">
162
+ <div v-if="copyButton" class="flex justify-end mt-1">
47
163
  <button class="btn neutral small" type="button" @click.prevent="copyText">
48
164
  Copy tags
49
165
  </button>
@@ -51,120 +167,6 @@
51
167
  </div>
52
168
  </template>
53
169
 
54
- <script setup lang="ts">
55
- import { ref, computed, onMounted } from "vue";
56
- import { useEventBus } from "../../composables/event-bus";
57
- type colorType = "blue" | "red" | "green" | "purple" | "orange" | "neutral";
58
-
59
- const props = withDefaults(
60
- defineProps<{
61
- modelValue: string[];
62
- color?: colorType;
63
- label?: string;
64
- id: string;
65
- separators?: string[];
66
- autofocus?: boolean;
67
- help?: string;
68
- maxLenghtPerTag?: number;
69
- error?: string;
70
- copyButton?: boolean;
71
- }>(),
72
- {
73
- copyButton: false,
74
- maxLenghtPerTag: 0,
75
- color: "blue",
76
- label: "Tags",
77
- separators: () => [","],
78
- autofocus: false,
79
- },
80
- );
81
-
82
- const textInput = ref<HTMLElement>();
83
-
84
- const emit = defineEmits(["update:modelValue"]);
85
- const model = computed({
86
- get: () => props.modelValue,
87
- set: (items) => {
88
- emit("update:modelValue", items);
89
- },
90
- });
91
-
92
- onMounted(() => {
93
- if (props.autofocus) {
94
- focusInput();
95
- }
96
- });
97
- const eventBus = useEventBus();
98
- const copyText = async () => {
99
- const text = model.value.join(", ");
100
- await navigator.clipboard.writeText(text);
101
- eventBus.emit("SendNotif", {
102
- title: "Text copied!",
103
- type: "success",
104
- time: 2500,
105
- });
106
- };
107
-
108
- const handleInput = (event: any) => {
109
- const separatorsRegex = new RegExp(props.separators.join("|"));
110
- if (separatorsRegex.test(event.data)) {
111
- addTag();
112
- }
113
- };
114
-
115
- const addTag = () => {
116
- if (!textInput.value) return;
117
-
118
- const separatorsRegex = new RegExp(props.separators.join("|"));
119
- const newTags = textInput.value.innerText
120
- .split(separatorsRegex)
121
- .map((tag: string) => tag.trim())
122
- .filter((tag: string) => tag.length > 0);
123
- model.value.push(...newTags);
124
- textInput.value.innerText = "";
125
- };
126
-
127
- const removeTag = (index: number) => {
128
- model.value.splice(index, 1);
129
- focusInput();
130
- };
131
-
132
- const removeLastTag = () => {
133
- if (!textInput.value) return;
134
- if (textInput.value.innerText === "") {
135
- model.value.pop();
136
- } else {
137
- const currentLength = textInput.value.innerText.length;
138
- textInput.value.innerText = textInput.value.innerText.slice(0, -1);
139
-
140
- const range = document.createRange();
141
- const sel = window.getSelection();
142
- range.selectNodeContents(textInput.value);
143
- range.collapse(false);
144
- if (!sel) return;
145
- sel.removeAllRanges();
146
- sel.addRange(range);
147
- }
148
- };
149
- const focusInput = () => {
150
- if (!textInput.value) return;
151
-
152
- textInput.value.focus();
153
- };
154
-
155
- const handlePaste = (e: any) => {
156
- if (!textInput.value) return;
157
-
158
- // @ts-ignore
159
- const text = (e.clipboardData || window.clipboardData).getData("text");
160
- const separatorsRegex = new RegExp(props.separators.join("|"), "g");
161
- const pasteText = text.replace(separatorsRegex, ",");
162
- textInput.value.innerText += pasteText;
163
- e.preventDefault();
164
- addTag();
165
- };
166
- </script>
167
-
168
170
  <style scoped>
169
171
  .tags-input {
170
172
  cursor: text;
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <Transition name="collapse">
3
- <slot></slot>
3
+ <slot />
4
4
  </Transition>
5
5
  </template>
6
6
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <Transition name="expand">
3
- <slot></slot>
3
+ <slot />
4
4
  </Transition>
5
5
  </template>
6
6
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <Transition name="fade" mode="out-in">
3
- <slot></slot>
3
+ <slot />
4
4
  </Transition>
5
5
  </template>
6
6
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <Transition name="scale">
3
- <slot></slot>
3
+ <slot />
4
4
  </Transition>
5
5
  </template>
6
6
 
@@ -1,12 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  const props = defineProps<{
3
- animation: string;
4
- }>();
3
+ animation: string
4
+ }>()
5
5
  </script>
6
6
 
7
7
  <template>
8
8
  <Transition :name="props.animation" mode="out-in">
9
- <slot></slot>
9
+ <slot />
10
10
  </Transition>
11
11
  </template>
12
12
 
@@ -1,14 +1,16 @@
1
- import { inject } from "vue";
2
- import type { Emitter } from "mitt";
1
+ import type { Emitter } from 'mitt'
2
+ import { inject } from 'vue'
3
3
 
4
- export type Events = {
5
- [key: string]: any;
6
- };
4
+ export interface Events {
5
+ [key: string]: any
6
+ }
7
7
 
8
+ // @ts-expect-error: Emitter is not exported
8
9
  export function useEventBus(): Emitter<Events> {
9
- const eventBus = inject<Emitter<Events>>("fwsVueEventBus");
10
+ // @ts-expect-error: Emitter is not exported
11
+ const eventBus = inject<Emitter<Events>>('fwsVueEventBus')
10
12
 
11
- if (!eventBus) throw new Error("Did you apply app.use(fwsVue)?");
13
+ if (!eventBus) throw new Error('Did you apply app.use(fwsVue)?')
12
14
 
13
- return eventBus;
15
+ return eventBus
14
16
  }
@@ -1,91 +1,94 @@
1
- import { RestMethod, RestParams, getMode, rest, stringHash } from "@fy-/fws-js";
2
- import { useServerRouter } from "../stores/serverRouter";
3
- import { isServerRendered } from "./ssr";
4
- import { useEventBus } from "./event-bus";
1
+ import type { RestMethod, RestParams } from '@fy-/fws-js'
2
+ import { getMode, rest, stringHash } from '@fy-/fws-js'
3
+ import { useServerRouter } from '../stores/serverRouter'
4
+ import { useEventBus } from './event-bus'
5
+ import { isServerRendered } from './ssr'
5
6
 
6
7
  export interface APIPaging {
7
- page_no: number;
8
- results_per_page: number;
9
- page_max: number;
10
- page_max_relation: string;
11
- count: number;
8
+ page_no: number
9
+ results_per_page: number
10
+ page_max: number
11
+ page_max_relation: string
12
+ count: number
12
13
  }
13
14
 
14
15
  export interface APIResult {
15
- result: "redirect" | "success" | "error";
16
- param?: string;
17
- code?: number;
18
- error?: string;
19
- request?: string;
20
- time?: number;
21
- token?: string;
22
- paging?: APIPaging;
23
- message?: string;
24
- fvReject?: boolean;
25
- data?: any;
26
- status?: number;
16
+ result: 'redirect' | 'success' | 'error'
17
+ param?: string
18
+ code?: number
19
+ error?: string
20
+ request?: string
21
+ time?: number
22
+ token?: string
23
+ paging?: APIPaging
24
+ message?: string
25
+ fvReject?: boolean
26
+ data?: any
27
+ status?: number
27
28
  }
28
29
 
29
30
  export function useRest(): <ResultType extends APIResult>(
30
- url: string,
31
- method: RestMethod,
32
- params?: RestParams,
31
+ url: string,
32
+ method: RestMethod,
33
+ params?: RestParams,
33
34
  ) => Promise<ResultType> {
34
- const serverRouter = useServerRouter();
35
- const eventBus = useEventBus();
35
+ const serverRouter = useServerRouter()
36
+ const eventBus = useEventBus()
36
37
 
37
38
  return async <ResultType extends APIResult>(
38
39
  url: string,
39
40
  method: RestMethod,
40
41
  params?: RestParams,
41
42
  ): Promise<ResultType> => {
42
- let urlForHash: string = url;
43
+ let urlForHash: string = url
43
44
  try {
44
- const urlParse = new URL(url);
45
- urlForHash = urlParse.pathname + urlParse.search;
46
- } catch (error) {
47
- urlForHash = url;
45
+ const urlParse = new URL(url)
46
+ urlForHash = urlParse.pathname + urlParse.search
47
+ }
48
+ catch {
49
+ urlForHash = url
48
50
  }
49
51
 
50
52
  const requestHash = stringHash(
51
53
  urlForHash + method + JSON.stringify(params),
52
- );
54
+ )
53
55
  if (isServerRendered()) {
54
- const hasResult = serverRouter.getResult(requestHash);
56
+ const hasResult = serverRouter.getResult(requestHash)
55
57
  if (hasResult !== undefined) {
56
- const result = hasResult as ResultType;
57
- serverRouter.removeResult(requestHash);
58
- if (result.result === "error") {
59
- eventBus.emit("main-loading", false);
60
- eventBus.emit("rest-error", result);
61
- return Promise.reject(result);
58
+ const result = hasResult as ResultType
59
+ serverRouter.removeResult(requestHash)
60
+ if (result.result === 'error') {
61
+ eventBus.emit('main-loading', false)
62
+ eventBus.emit('rest-error', result)
63
+ return Promise.reject(result)
62
64
  }
63
- return Promise.resolve(result);
65
+ return Promise.resolve(result)
64
66
  }
65
67
  }
66
68
 
67
69
  try {
68
- const restResult: ResultType = await rest(url, method, params);
69
- if (getMode() === "ssr") {
70
+ const restResult: ResultType = await rest(url, method, params)
71
+ if (getMode() === 'ssr') {
70
72
  serverRouter.addResult(
71
73
  requestHash,
72
74
  JSON.parse(JSON.stringify(restResult)),
73
- );
75
+ )
74
76
  }
75
- if (restResult.result === "error") {
76
- eventBus.emit("main-loading", false);
77
- eventBus.emit("rest-error", restResult);
78
- return Promise.reject(restResult);
77
+ if (restResult.result === 'error') {
78
+ eventBus.emit('main-loading', false)
79
+ eventBus.emit('rest-error', restResult)
80
+ return Promise.reject(restResult)
79
81
  }
80
- return Promise.resolve(restResult);
81
- } catch (error) {
82
- const restError: ResultType = error as ResultType;
83
- if (getMode() === "ssr") {
84
- serverRouter.addResult(requestHash, restError);
82
+ return Promise.resolve(restResult)
83
+ }
84
+ catch (error) {
85
+ const restError: ResultType = error as ResultType
86
+ if (getMode() === 'ssr') {
87
+ serverRouter.addResult(requestHash, restError)
85
88
  }
86
- eventBus.emit("main-loading", false);
87
- eventBus.emit("rest-error", restError);
88
- return Promise.resolve(restError);
89
+ eventBus.emit('main-loading', false)
90
+ eventBus.emit('rest-error', restError)
91
+ return Promise.resolve(restError)
89
92
  }
90
- };
93
+ }
91
94
  }