@flux-ui/components 3.0.0-next.71 → 3.0.0-next.73
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/dist/component/FluxFormField.vue.d.ts +2 -2
- package/dist/index.css +303 -303
- package/dist/index.js +1103 -1057
- package/dist/index.js.map +1 -1
- package/dist/util/index.d.ts +1 -0
- package/dist/util/sanitizeUrl.d.ts +7 -0
- package/package.json +7 -7
- package/src/component/FluxColorPicker.vue +1 -1
- package/src/component/FluxFormField.vue +4 -2
- package/src/component/FluxKanbanColumn.vue +1 -1
- package/src/component/FluxPressable.vue +14 -5
- package/src/component/primitive/DialogLayout.vue +3 -3
- package/src/util/index.ts +1 -0
- package/src/util/sanitizeUrl.ts +40 -0
package/dist/util/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export { default as createDialogRenderer } from './createDialogRenderer';
|
|
|
2
2
|
export { default as createLabelForDateRange } from './createLabelForDateRange';
|
|
3
3
|
export { default as defineFilter, type FluxFilterDefinitionFactory } from './defineFilter';
|
|
4
4
|
export { generateMultiOptionsLabel, isFluxFilterOptionHeader, isFluxFilterOptionItem, isResettable, pickFilterCommon } from './filter';
|
|
5
|
+
export { default as sanitizeUrl } from './sanitizeUrl';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitizes a URL intended for an `href` attribute. Returns `undefined` when the
|
|
3
|
+
* URL uses a dangerous scheme (`javascript:`, `vbscript:`, `data:`) so the attribute
|
|
4
|
+
* is omitted instead of becoming a script-execution or data-injection vector.
|
|
5
|
+
* Safe and relative URLs are returned unchanged.
|
|
6
|
+
*/
|
|
7
|
+
export default function (href?: string): string | undefined;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flux-ui/components",
|
|
3
3
|
"description": "A set of opiniated UI components.",
|
|
4
|
-
"version": "3.0.0-next.
|
|
4
|
+
"version": "3.0.0-next.73",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://github.com/sponsors/basmilius",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"**/dist/index.css"
|
|
56
56
|
],
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@basmilius/common": "^3.
|
|
59
|
-
"@basmilius/utils": "^3.
|
|
60
|
-
"@flux-ui/internals": "3.0.0-next.
|
|
61
|
-
"@flux-ui/types": "3.0.0-next.
|
|
58
|
+
"@basmilius/common": "^3.37.0",
|
|
59
|
+
"@basmilius/utils": "^3.37.0",
|
|
60
|
+
"@flux-ui/internals": "3.0.0-next.73",
|
|
61
|
+
"@flux-ui/types": "3.0.0-next.73",
|
|
62
62
|
"@fortawesome/fontawesome-common-types": "^7.2.0",
|
|
63
63
|
"clsx": "^2.1.1",
|
|
64
64
|
"imask": "^7.6.1",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"vue": "^3.6.0-beta.12"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@basmilius/vite-preset": "^3.
|
|
72
|
+
"@basmilius/vite-preset": "^3.37.0",
|
|
73
73
|
"@types/lodash-es": "^4.17.12",
|
|
74
74
|
"@types/luxon": "^3.7.1",
|
|
75
75
|
"@types/node": "^25.9.1",
|
|
@@ -78,6 +78,6 @@
|
|
|
78
78
|
"sass-embedded": "^1.100.0",
|
|
79
79
|
"typescript": "^6.0.3",
|
|
80
80
|
"vite": "^8.0.14",
|
|
81
|
-
"vue-tsc": "^3.3.
|
|
81
|
+
"vue-tsc": "^3.3.2"
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -134,10 +134,10 @@
|
|
|
134
134
|
import { blue500 } from '@flux-ui/internals';
|
|
135
135
|
import { computed, type ComputedRef, ref, unref, watch } from 'vue';
|
|
136
136
|
import { useTranslate } from '~flux/components/composable/private';
|
|
137
|
-
import CoordinatePicker from './primitive/CoordinatePicker.vue';
|
|
138
137
|
import FluxFormField from './FluxFormField.vue';
|
|
139
138
|
import FluxFormInput from './FluxFormInput.vue';
|
|
140
139
|
import FluxFormSlider from './FluxFormSlider.vue';
|
|
140
|
+
import CoordinatePicker from './primitive/CoordinatePicker.vue';
|
|
141
141
|
import $style from '~flux/components/css/component/Color.module.scss';
|
|
142
142
|
|
|
143
143
|
const modelValue = defineModel<string | [number, number, number]>({
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
<label
|
|
4
4
|
:for="id"
|
|
5
5
|
:class="$style.formFieldHeader">
|
|
6
|
-
<span
|
|
6
|
+
<span
|
|
7
|
+
v-if="label"
|
|
8
|
+
:class="$style.formFieldLabel">
|
|
7
9
|
{{ label }}
|
|
8
10
|
</span>
|
|
9
11
|
|
|
@@ -61,7 +63,7 @@
|
|
|
61
63
|
readonly error?: string;
|
|
62
64
|
readonly hint?: string;
|
|
63
65
|
readonly isOptional?: boolean;
|
|
64
|
-
readonly label
|
|
66
|
+
readonly label?: string;
|
|
65
67
|
readonly maxLength?: number;
|
|
66
68
|
}>();
|
|
67
69
|
|
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
import { Comment, computed, onBeforeUnmount, onMounted, provide, Text, toRef, unref, useSlots, useTemplateRef, watch } from 'vue';
|
|
81
81
|
import { useDisabled, useKanbanInjection } from '~flux/components/composable';
|
|
82
82
|
import { FluxDisabledInjectionKey } from '~flux/components/data';
|
|
83
|
-
import $style from '~flux/components/css/component/Kanban.module.scss';
|
|
84
83
|
import FluxBadge from './FluxBadge.vue';
|
|
85
84
|
import FluxIcon from './FluxIcon.vue';
|
|
85
|
+
import $style from '~flux/components/css/component/Kanban.module.scss';
|
|
86
86
|
|
|
87
87
|
const {
|
|
88
88
|
columnId,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
v-if="componentType === 'route'"
|
|
4
4
|
v-bind="$attrs"
|
|
5
5
|
v-on="hoverListeners"
|
|
6
|
-
:rel="
|
|
6
|
+
:rel="resolvedRel"
|
|
7
7
|
:target="target"
|
|
8
8
|
:to="to as any"
|
|
9
9
|
@click="onClick($event)">
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
v-else-if="componentType === 'link'"
|
|
15
15
|
v-bind="$attrs"
|
|
16
16
|
v-on="hoverListeners"
|
|
17
|
-
:href="href"
|
|
18
|
-
:rel="
|
|
17
|
+
:href="sanitizeUrl(href)"
|
|
18
|
+
:rel="resolvedRel"
|
|
19
19
|
:target="target"
|
|
20
20
|
@click="onClick($event)">
|
|
21
21
|
<slot/>
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
lang="ts"
|
|
43
43
|
setup>
|
|
44
44
|
import type { FluxPressableType, FluxTo } from '@flux-ui/types';
|
|
45
|
-
import type
|
|
45
|
+
import { computed, type VNode } from 'vue';
|
|
46
|
+
import { sanitizeUrl } from '~flux/components/util';
|
|
46
47
|
|
|
47
48
|
const emit = defineEmits<{
|
|
48
49
|
click: [MouseEvent];
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
mouseleave: [MouseEvent];
|
|
51
52
|
}>();
|
|
52
53
|
|
|
53
|
-
defineProps<{
|
|
54
|
+
const {rel, target} = defineProps<{
|
|
54
55
|
readonly componentType?: FluxPressableType;
|
|
55
56
|
readonly href?: string;
|
|
56
57
|
readonly rel?: string;
|
|
@@ -62,6 +63,14 @@
|
|
|
62
63
|
default(): VNode[];
|
|
63
64
|
}>();
|
|
64
65
|
|
|
66
|
+
const resolvedRel = computed(() => {
|
|
67
|
+
if (rel) {
|
|
68
|
+
return rel;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return target === '_blank' ? 'noopener noreferrer' : undefined;
|
|
72
|
+
});
|
|
73
|
+
|
|
65
74
|
const hoverListeners = {
|
|
66
75
|
onMouseenter: (evt: MouseEvent) => emit('mouseenter', evt),
|
|
67
76
|
onMouseleave: (evt: MouseEvent) => emit('mouseleave', evt)
|
package/src/util/index.ts
CHANGED
|
@@ -2,3 +2,4 @@ export { default as createDialogRenderer } from './createDialogRenderer';
|
|
|
2
2
|
export { default as createLabelForDateRange } from './createLabelForDateRange';
|
|
3
3
|
export { default as defineFilter, type FluxFilterDefinitionFactory } from './defineFilter';
|
|
4
4
|
export { generateMultiOptionsLabel, isFluxFilterOptionHeader, isFluxFilterOptionItem, isResettable, pickFilterCommon } from './filter';
|
|
5
|
+
export { default as sanitizeUrl } from './sanitizeUrl';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const DANGEROUS_PROTOCOL = /^(javascript|vbscript|data):/i;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Removes control characters (and the Unicode line/paragraph separators) that
|
|
5
|
+
* browsers ignore inside URLs but which can be used to obfuscate the scheme,
|
|
6
|
+
* e.g. `java\tscript:alert(1)`.
|
|
7
|
+
*/
|
|
8
|
+
function stripControlChars(value: string): string {
|
|
9
|
+
let out = '';
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < value.length; i++) {
|
|
12
|
+
const code = value.charCodeAt(i);
|
|
13
|
+
|
|
14
|
+
if (code <= 0x20 || (code >= 0x7f && code <= 0x9f) || code === 0x2028 || code === 0x2029) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
out += value[i];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Sanitizes a URL intended for an `href` attribute. Returns `undefined` when the
|
|
26
|
+
* URL uses a dangerous scheme (`javascript:`, `vbscript:`, `data:`) so the attribute
|
|
27
|
+
* is omitted instead of becoming a script-execution or data-injection vector.
|
|
28
|
+
* Safe and relative URLs are returned unchanged.
|
|
29
|
+
*/
|
|
30
|
+
export default function (href?: string): string | undefined {
|
|
31
|
+
if (!href) {
|
|
32
|
+
return href;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (DANGEROUS_PROTOCOL.test(stripControlChars(href))) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return href;
|
|
40
|
+
}
|