sprintify-ui 0.12.23 → 0.12.25
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 +16 -0
- package/dist/sprintify-ui.es.js +12822 -11862
- package/dist/tailwindcss/theme.js +9 -0
- package/dist/types/composables/layoutHeaderHeight.d.ts +33 -0
- package/dist/types/directives/safeHtml.d.ts +4 -0
- package/dist/types/index.d.ts +6 -0
- package/package.json +2 -1
- package/src/components/BaseButton.vue +2 -1
- package/src/components/BaseDataIteratorSectionColumns.vue +2 -1
- package/src/components/BaseDataTableTemplate.vue +2 -1
- package/src/components/BaseDialog.vue +2 -1
- package/src/components/BaseLayoutNotificationItemContent.vue +2 -1
- package/src/components/BaseLayoutSidebar.vue +18 -2
- package/src/components/BaseLayoutStacked.vue +15 -2
- package/src/components/BaseTableHeader.vue +2 -1
- package/src/components/BaseTooltip.vue +2 -1
- package/src/composables/layoutHeaderHeight.ts +87 -0
- package/src/directives/safeHtml.ts +28 -0
- package/src/index.ts +11 -0
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
extend: {
|
|
3
3
|
spacing: {
|
|
4
|
+
// Measured height of the layout's sticky top header (system
|
|
5
|
+
// alerts + navbar). Kept in sync by the BaseLayout* components
|
|
6
|
+
// through the --app-header-height CSS variable. Use for anything
|
|
7
|
+
// that must clear the header: sticky offsets, scroll margins,
|
|
8
|
+
// 100vh math.
|
|
9
|
+
header: 'var(--app-header-height, 0px)',
|
|
10
|
+
// Header plus the standard content gap, for sticky elements and
|
|
11
|
+
// scroll targets that should sit just below the header.
|
|
12
|
+
'below-header': 'calc(var(--app-header-height, 0px) + 1.25rem)',
|
|
4
13
|
'control-xs': '1.65rem',
|
|
5
14
|
'control-sm': '2rem',
|
|
6
15
|
'control-md': '2.5rem',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Ref, StyleValue } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* The layout's sticky top header (system alerts + navbar) overlaps page
|
|
4
|
+
* content when it scrolls, so anything sticky or scroll-anchored inside the
|
|
5
|
+
* layout needs to know its rendered height. That height cannot be hardcoded:
|
|
6
|
+
* the navbar row depends on the layout `size` prop, and system alerts stack
|
|
7
|
+
* above it dynamically.
|
|
8
|
+
*
|
|
9
|
+
* The layout components measure their own header element and publish the
|
|
10
|
+
* height two ways:
|
|
11
|
+
*
|
|
12
|
+
* - The `--app-header-height` CSS variable, bound on the layout's content
|
|
13
|
+
* wrapper — for Tailwind/CSS (`top-header`, `scroll-mt-below-header`, ...,
|
|
14
|
+
* see the tailwindcss plugin's spacing tokens).
|
|
15
|
+
* - A provided reactive ref, read with `useLayoutHeaderHeight()` — for
|
|
16
|
+
* scripts (scrollspy root margins, canvas math, ...).
|
|
17
|
+
*/
|
|
18
|
+
export declare const LAYOUT_HEADER_HEIGHT_CSS_VARIABLE = "--app-header-height";
|
|
19
|
+
/**
|
|
20
|
+
* Internal — called once by each layout component (BaseLayoutSidebar,
|
|
21
|
+
* BaseLayoutStacked) with a template ref to its sticky header element.
|
|
22
|
+
* Returns the reactive height and a style binding carrying the CSS variable,
|
|
23
|
+
* to spread on the element that wraps the layout's page content.
|
|
24
|
+
*/
|
|
25
|
+
export declare function provideLayoutHeaderHeight(headerElement: Ref<HTMLElement | null>): {
|
|
26
|
+
headerHeight: Readonly<Ref<number>>;
|
|
27
|
+
headerHeightStyle: Readonly<Ref<StyleValue>>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* The rendered height (px) of the layout's sticky top header. Zero when used
|
|
31
|
+
* outside a layout component.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useLayoutHeaderHeight(): Readonly<Ref<number>>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ import { useDialogsStore } from './stores/dialogs';
|
|
|
4
4
|
import { useSnackbarsStore } from './stores/snackbars';
|
|
5
5
|
import { useSystemAlertStore } from './stores/systemAlerts';
|
|
6
6
|
import { useClickOutside } from './composables/clickOutside';
|
|
7
|
+
import { LAYOUT_HEADER_HEIGHT_CSS_VARIABLE, useLayoutHeaderHeight } from './composables/layoutHeaderHeight';
|
|
7
8
|
import { useField } from './composables/field';
|
|
9
|
+
import { vSafeHtml, SAFE_HTML_CONFIG } from './directives/safeHtml';
|
|
8
10
|
declare const messages: {
|
|
9
11
|
en: {
|
|
10
12
|
cancel: string;
|
|
@@ -269,5 +271,9 @@ export { useDialogsStore };
|
|
|
269
271
|
export { useSnackbarsStore };
|
|
270
272
|
export { useSystemAlertStore };
|
|
271
273
|
export { useClickOutside };
|
|
274
|
+
export { useLayoutHeaderHeight };
|
|
275
|
+
export { LAYOUT_HEADER_HEIGHT_CSS_VARIABLE };
|
|
272
276
|
export { useField };
|
|
273
277
|
export { SettingsStorage };
|
|
278
|
+
export { vSafeHtml };
|
|
279
|
+
export { SAFE_HTML_CONFIG };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprintify-ui",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate-llm-txt": "node scripts/generate-llm-txt.js",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"@tiptap/extension-subscript": "^3.20.4",
|
|
45
45
|
"@tiptap/extension-superscript": "^3.20.4",
|
|
46
46
|
"color2k": "^2.0.3",
|
|
47
|
+
"dompurify": "^3.4.14",
|
|
47
48
|
"tailwind-merge": "^2.4.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
name="tooltip"
|
|
70
70
|
>
|
|
71
71
|
<div
|
|
72
|
+
v-safe-html="tooltip"
|
|
72
73
|
class="text-xs max-w-xs leading-snug rounded-md pt-1.5 pb-2 px-3 bg-slate-900 text-white"
|
|
73
|
-
v-html="tooltip"
|
|
74
74
|
/>
|
|
75
75
|
</slot>
|
|
76
76
|
</transition>
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
</template>
|
|
80
80
|
|
|
81
81
|
<script lang="ts" setup>
|
|
82
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
82
83
|
import { ClassNameValue, twMerge } from 'tailwind-merge';
|
|
83
84
|
import { RouteLocationRaw } from 'vue-router';
|
|
84
85
|
import { BaseIcon } from '.';
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
@change="onVisibleColumnChange($event, element.newKey)"
|
|
44
44
|
>
|
|
45
45
|
<div
|
|
46
|
+
v-safe-html="element.label"
|
|
46
47
|
class="text-xs grow leading-tight"
|
|
47
48
|
:class="[element.toggle ? 'text-slate-700' : 'text-slate-400']"
|
|
48
|
-
v-html="element.label"
|
|
49
49
|
>
|
|
50
50
|
</div>
|
|
51
51
|
</label>
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
</template>
|
|
58
58
|
|
|
59
59
|
<script lang="ts" setup>
|
|
60
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
60
61
|
import { cloneDeep } from 'lodash';
|
|
61
62
|
import { PropType } from 'vue';
|
|
62
63
|
import BaseDataTableTemplate from './BaseDataTableTemplate.vue';
|
|
@@ -58,12 +58,12 @@
|
|
|
58
58
|
@click="sort(column, undefined, $event as any)"
|
|
59
59
|
>
|
|
60
60
|
<div
|
|
61
|
+
v-safe-html="column.label"
|
|
61
62
|
class="whitespace-nowrap text-slate-600"
|
|
62
63
|
:class="{
|
|
63
64
|
'text-[12px]': size == 'sm',
|
|
64
65
|
'text-xs': size == 'md',
|
|
65
66
|
}"
|
|
66
|
-
v-html="column.label"
|
|
67
67
|
/>
|
|
68
68
|
<!-- h-4 is used to make sure the tooltip icon is always smaller than label and avoid alignment issues when icon is not present -->
|
|
69
69
|
<div
|
|
@@ -197,6 +197,7 @@
|
|
|
197
197
|
</template>
|
|
198
198
|
|
|
199
199
|
<script lang="ts" setup>
|
|
200
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
200
201
|
import { PropType, ref } from 'vue';
|
|
201
202
|
import { BaseTableColumnData, CollectionItem, Row } from '@/types';
|
|
202
203
|
import SlotComponent from './SlotComponent';
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
<div class="mt-2">
|
|
48
48
|
<div
|
|
49
49
|
v-if="html"
|
|
50
|
+
v-safe-html="message"
|
|
50
51
|
class="text-slate-500 prose-sm prose-p:leading-snug prose-a:text-blue-600 prose-a:underline"
|
|
51
|
-
v-html="message"
|
|
52
52
|
/>
|
|
53
53
|
<p
|
|
54
54
|
v-else
|
|
@@ -118,6 +118,7 @@
|
|
|
118
118
|
</template>
|
|
119
119
|
|
|
120
120
|
<script lang="ts" setup>
|
|
121
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
121
122
|
import { PropType } from 'vue';
|
|
122
123
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
123
124
|
import { t } from '@/i18n';
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
/>
|
|
11
11
|
<div class="min-w-0 flex-1">
|
|
12
12
|
<div
|
|
13
|
+
v-safe-html="notification.text"
|
|
13
14
|
class="text-sm leading-tight"
|
|
14
15
|
:class="textClasses"
|
|
15
|
-
v-html="notification.text"
|
|
16
16
|
/>
|
|
17
17
|
<BaseDisplayRelativeTime
|
|
18
18
|
v-if="notification.created_at"
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
</template>
|
|
33
33
|
|
|
34
34
|
<script lang="ts" setup>
|
|
35
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
35
36
|
import { Notification } from '@/types/Notification';
|
|
36
37
|
import BaseDisplayRelativeTime from './BaseDisplayRelativeTime.vue';
|
|
37
38
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="min-h-full base-layout-sidebar"
|
|
4
|
+
:style="headerHeightStyle"
|
|
5
|
+
>
|
|
3
6
|
<TransitionRoot
|
|
4
7
|
as="template"
|
|
5
8
|
:show="showMobileMenu"
|
|
@@ -95,7 +98,10 @@
|
|
|
95
98
|
class="flex flex-col min-h-full || xl:print:pl-0"
|
|
96
99
|
:class="[collapsed ? 'xl:pl-14' : 'xl:pl-64']"
|
|
97
100
|
>
|
|
98
|
-
<div
|
|
101
|
+
<div
|
|
102
|
+
ref="headerElement"
|
|
103
|
+
class="sticky top-0 left-0 z-10 shadow shrink-0 || print:hidden"
|
|
104
|
+
>
|
|
99
105
|
<BaseSystemAlert
|
|
100
106
|
v-for="systemAlert in systemAlerts"
|
|
101
107
|
:key="systemAlert.id"
|
|
@@ -205,6 +211,7 @@ import {
|
|
|
205
211
|
TransitionRoot,
|
|
206
212
|
} from '@headlessui/vue';
|
|
207
213
|
import { config } from '@/index';
|
|
214
|
+
import { provideLayoutHeaderHeight } from '../composables/layoutHeaderHeight';
|
|
208
215
|
import { useSystemAlertStore } from '../stores/systemAlerts';
|
|
209
216
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
210
217
|
import BaseSystemAlert from './BaseSystemAlert.vue';
|
|
@@ -243,6 +250,15 @@ const systemAlerts = computed(() => {
|
|
|
243
250
|
return systemAlertStore.systemAlerts;
|
|
244
251
|
});
|
|
245
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Header height (sticky system alerts + navbar), published as a CSS variable
|
|
255
|
+
* and via useLayoutHeaderHeight().
|
|
256
|
+
*/
|
|
257
|
+
|
|
258
|
+
const headerElement = ref<HTMLElement | null>(null);
|
|
259
|
+
|
|
260
|
+
const { headerHeightStyle } = provideLayoutHeaderHeight(headerElement);
|
|
261
|
+
|
|
246
262
|
/**
|
|
247
263
|
* Show/Hide sidebar
|
|
248
264
|
*/
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
ref="headerElement"
|
|
4
|
+
:class="classInternal"
|
|
5
|
+
>
|
|
3
6
|
<BaseSystemAlert
|
|
4
7
|
v-for="systemAlert in systemAlerts"
|
|
5
8
|
:key="systemAlert.id"
|
|
@@ -33,13 +36,14 @@
|
|
|
33
36
|
</BaseNavbar>
|
|
34
37
|
</div>
|
|
35
38
|
|
|
36
|
-
<div>
|
|
39
|
+
<div :style="headerHeightStyle">
|
|
37
40
|
<slot />
|
|
38
41
|
</div>
|
|
39
42
|
</template>
|
|
40
43
|
|
|
41
44
|
<script lang="ts" setup>
|
|
42
45
|
import { twMerge } from 'tailwind-merge';
|
|
46
|
+
import { provideLayoutHeaderHeight } from '../composables/layoutHeaderHeight';
|
|
43
47
|
import { useSystemAlertStore } from '../stores/systemAlerts';
|
|
44
48
|
import BaseNavbar from './BaseNavbar.vue';
|
|
45
49
|
import BaseSystemAlert from './BaseSystemAlert.vue';
|
|
@@ -75,4 +79,13 @@ const systemAlertStore = useSystemAlertStore();
|
|
|
75
79
|
const systemAlerts = computed(() => {
|
|
76
80
|
return systemAlertStore.systemAlerts;
|
|
77
81
|
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Header height (sticky system alerts + navbar), published as a CSS variable
|
|
85
|
+
* and via useLayoutHeaderHeight().
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
const headerElement = ref<HTMLElement | null>(null);
|
|
89
|
+
|
|
90
|
+
const { headerHeightStyle } = provideLayoutHeaderHeight(headerElement);
|
|
78
91
|
</script>
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
name="tooltip"
|
|
33
33
|
>
|
|
34
34
|
<div
|
|
35
|
+
v-safe-html="tooltip"
|
|
35
36
|
class="text-xs max-w-xs leading-snug rounded-md pt-1.5 pb-2 px-3 bg-slate-900 text-white"
|
|
36
|
-
v-html="tooltip"
|
|
37
37
|
/>
|
|
38
38
|
</slot>
|
|
39
39
|
</transition>
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
</template>
|
|
43
43
|
|
|
44
44
|
<script lang="ts" setup>
|
|
45
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
45
46
|
import { useTooltip } from '@/composables/tooltip';
|
|
46
47
|
import { cellClasses } from '@/services/table/classes';
|
|
47
48
|
import { CellConfig, TableProps } from '@/services/table/types';
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
>
|
|
29
29
|
<div class="relative filter drop-shadow-[0_1px_2px_rgba(0,0,0,0.1)]">
|
|
30
30
|
<div
|
|
31
|
+
v-safe-html="text"
|
|
31
32
|
class="text-xs max-w-xs leading-snug rounded-md pt-1.5 pb-2 px-3"
|
|
32
33
|
:class="[
|
|
33
34
|
dark ? 'bg-slate-900 text-white' : 'bg-white text-slate-900',
|
|
34
35
|
]"
|
|
35
|
-
v-html="text"
|
|
36
36
|
/>
|
|
37
37
|
<div
|
|
38
38
|
ref="arrowRef"
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
</template>
|
|
52
52
|
|
|
53
53
|
<script lang="ts" setup>
|
|
54
|
+
import { vSafeHtml } from '@/directives/safeHtml';
|
|
54
55
|
import { useTooltip } from '@/composables/tooltip';
|
|
55
56
|
import { unrefElement } from '@vueuse/core';
|
|
56
57
|
import { UseFloatingOptions } from '@floating-ui/vue';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { InjectionKey, Ref, StyleValue } from 'vue';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The layout's sticky top header (system alerts + navbar) overlaps page
|
|
5
|
+
* content when it scrolls, so anything sticky or scroll-anchored inside the
|
|
6
|
+
* layout needs to know its rendered height. That height cannot be hardcoded:
|
|
7
|
+
* the navbar row depends on the layout `size` prop, and system alerts stack
|
|
8
|
+
* above it dynamically.
|
|
9
|
+
*
|
|
10
|
+
* The layout components measure their own header element and publish the
|
|
11
|
+
* height two ways:
|
|
12
|
+
*
|
|
13
|
+
* - The `--app-header-height` CSS variable, bound on the layout's content
|
|
14
|
+
* wrapper — for Tailwind/CSS (`top-header`, `scroll-mt-below-header`, ...,
|
|
15
|
+
* see the tailwindcss plugin's spacing tokens).
|
|
16
|
+
* - A provided reactive ref, read with `useLayoutHeaderHeight()` — for
|
|
17
|
+
* scripts (scrollspy root margins, canvas math, ...).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const LAYOUT_HEADER_HEIGHT_CSS_VARIABLE = '--app-header-height';
|
|
21
|
+
|
|
22
|
+
const layoutHeaderHeightKey: InjectionKey<Readonly<Ref<number>>> = Symbol(
|
|
23
|
+
'layoutHeaderHeight'
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Internal — called once by each layout component (BaseLayoutSidebar,
|
|
28
|
+
* BaseLayoutStacked) with a template ref to its sticky header element.
|
|
29
|
+
* Returns the reactive height and a style binding carrying the CSS variable,
|
|
30
|
+
* to spread on the element that wraps the layout's page content.
|
|
31
|
+
*/
|
|
32
|
+
export function provideLayoutHeaderHeight(
|
|
33
|
+
headerElement: Ref<HTMLElement | null>
|
|
34
|
+
): {
|
|
35
|
+
headerHeight: Readonly<Ref<number>>;
|
|
36
|
+
headerHeightStyle: Readonly<Ref<StyleValue>>;
|
|
37
|
+
} {
|
|
38
|
+
const height = ref(0);
|
|
39
|
+
|
|
40
|
+
let observer: ResizeObserver | null = null;
|
|
41
|
+
|
|
42
|
+
watch(
|
|
43
|
+
headerElement,
|
|
44
|
+
(element) => {
|
|
45
|
+
observer?.disconnect();
|
|
46
|
+
observer = null;
|
|
47
|
+
|
|
48
|
+
if (!element) {
|
|
49
|
+
height.value = 0;
|
|
50
|
+
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
observer = new ResizeObserver(() => {
|
|
55
|
+
height.value = element.getBoundingClientRect().height;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
observer.observe(element);
|
|
59
|
+
|
|
60
|
+
height.value = element.getBoundingClientRect().height;
|
|
61
|
+
},
|
|
62
|
+
{ immediate: true }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
onBeforeUnmount(() => {
|
|
66
|
+
observer?.disconnect();
|
|
67
|
+
observer = null;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const headerHeight = readonly(height);
|
|
71
|
+
|
|
72
|
+
provide(layoutHeaderHeightKey, headerHeight);
|
|
73
|
+
|
|
74
|
+
const headerHeightStyle = computed<StyleValue>(() => ({
|
|
75
|
+
[LAYOUT_HEADER_HEIGHT_CSS_VARIABLE]: `${height.value}px`,
|
|
76
|
+
}));
|
|
77
|
+
|
|
78
|
+
return { headerHeight, headerHeightStyle };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The rendered height (px) of the layout's sticky top header. Zero when used
|
|
83
|
+
* outside a layout component.
|
|
84
|
+
*/
|
|
85
|
+
export function useLayoutHeaderHeight(): Readonly<Ref<number>> {
|
|
86
|
+
return inject(layoutHeaderHeightKey, readonly(ref(0)));
|
|
87
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import DOMPurify from 'dompurify';
|
|
2
|
+
import type { Config } from 'dompurify';
|
|
3
|
+
import type { Directive } from 'vue';
|
|
4
|
+
|
|
5
|
+
// Must keep BaseTipTap output intact: links (href/target), images,
|
|
6
|
+
// highlights (<mark style="background-color">), sub/superscript.
|
|
7
|
+
export const SAFE_HTML_CONFIG: Config = {
|
|
8
|
+
USE_PROFILES: { html: true },
|
|
9
|
+
ADD_ATTR: ['target'],
|
|
10
|
+
FORBID_TAGS: ['style', 'form', 'input', 'textarea', 'select', 'button'],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
DOMPurify.addHook('afterSanitizeAttributes', (node) => {
|
|
14
|
+
if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {
|
|
15
|
+
node.setAttribute('rel', 'noopener noreferrer');
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const vSafeHtml: Directive<HTMLElement, string | null | undefined> = {
|
|
20
|
+
mounted: (el, { value }) => {
|
|
21
|
+
el.innerHTML = DOMPurify.sanitize(value ?? '', SAFE_HTML_CONFIG);
|
|
22
|
+
},
|
|
23
|
+
updated: (el, { value, oldValue }) => {
|
|
24
|
+
if (value !== oldValue) {
|
|
25
|
+
el.innerHTML = DOMPurify.sanitize(value ?? '', SAFE_HTML_CONFIG);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,12 @@ import { useDialogsStore } from './stores/dialogs';
|
|
|
8
8
|
import { useSnackbarsStore } from './stores/snackbars';
|
|
9
9
|
import { useSystemAlertStore } from './stores/systemAlerts';
|
|
10
10
|
import { useClickOutside } from './composables/clickOutside';
|
|
11
|
+
import {
|
|
12
|
+
LAYOUT_HEADER_HEIGHT_CSS_VARIABLE,
|
|
13
|
+
useLayoutHeaderHeight,
|
|
14
|
+
} from './composables/layoutHeaderHeight';
|
|
11
15
|
import { useField } from './composables/field';
|
|
16
|
+
import { vSafeHtml, SAFE_HTML_CONFIG } from './directives/safeHtml';
|
|
12
17
|
|
|
13
18
|
const messages = { en, fr };
|
|
14
19
|
|
|
@@ -72,6 +77,8 @@ function install(app: App, options?: Options) {
|
|
|
72
77
|
app.component(key, components[key]);
|
|
73
78
|
}
|
|
74
79
|
|
|
80
|
+
app.directive('safe-html', vSafeHtml);
|
|
81
|
+
|
|
75
82
|
if (options?.http) {
|
|
76
83
|
config.http = options.http;
|
|
77
84
|
}
|
|
@@ -134,5 +141,9 @@ export { useDialogsStore };
|
|
|
134
141
|
export { useSnackbarsStore };
|
|
135
142
|
export { useSystemAlertStore };
|
|
136
143
|
export { useClickOutside };
|
|
144
|
+
export { useLayoutHeaderHeight };
|
|
145
|
+
export { LAYOUT_HEADER_HEIGHT_CSS_VARIABLE };
|
|
137
146
|
export { useField };
|
|
138
147
|
export { SettingsStorage };
|
|
148
|
+
export { vSafeHtml };
|
|
149
|
+
export { SAFE_HTML_CONFIG };
|