orio-ui 1.7.5 → 1.9.0
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/module.json +1 -1
- package/dist/runtime/assets/css/mixins.css +0 -0
- package/dist/runtime/components/Button.vue +20 -0
- package/dist/runtime/components/ControlElement.vue +5 -0
- package/dist/runtime/components/Input.vue +7 -6
- package/dist/runtime/components/NumberInput/Horizontal.vue +58 -0
- package/dist/runtime/components/NumberInput/Vertical.vue +57 -0
- package/dist/runtime/components/NumberInput/index.vue +126 -0
- package/dist/runtime/composables/index.d.ts +2 -0
- package/dist/runtime/composables/index.js +2 -0
- package/dist/runtime/composables/useDecimalFormatter.d.ts +11 -0
- package/dist/runtime/composables/useDecimalFormatter.js +40 -0
- package/dist/runtime/composables/usePressAndHold.d.ts +4 -0
- package/dist/runtime/composables/usePressAndHold.js +22 -0
- package/dist/runtime/index.d.ts +4 -1
- package/dist/runtime/index.js +4 -1
- package/dist/runtime/utils/icon-registry.js +2 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
File without changes
|
|
@@ -25,12 +25,28 @@ const isIconOnly = computed(() => {
|
|
|
25
25
|
|
|
26
26
|
const emit = defineEmits<{
|
|
27
27
|
(e: "click", event: PointerEvent): void;
|
|
28
|
+
(e: "mousedown", event: MouseEvent): void;
|
|
29
|
+
(e: "mouseup", event: MouseEvent): void;
|
|
30
|
+
(e: "mouseleave", event: MouseEvent): void;
|
|
28
31
|
}>();
|
|
29
32
|
|
|
30
33
|
function click(event: PointerEvent) {
|
|
31
34
|
if (loading.value || disabled.value) return;
|
|
32
35
|
emit("click", event);
|
|
33
36
|
}
|
|
37
|
+
|
|
38
|
+
function onMousedown(event: MouseEvent) {
|
|
39
|
+
if (loading.value || disabled.value) return;
|
|
40
|
+
emit("mousedown", event);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function onMouseup(event: MouseEvent) {
|
|
44
|
+
emit("mouseup", event);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function onMouseleave(event: MouseEvent) {
|
|
48
|
+
emit("mouseleave", event);
|
|
49
|
+
}
|
|
34
50
|
</script>
|
|
35
51
|
|
|
36
52
|
<template>
|
|
@@ -40,6 +56,9 @@ function click(event: PointerEvent) {
|
|
|
40
56
|
:class="[variant, 'gradient-hover', { 'icon-only': isIconOnly }]"
|
|
41
57
|
:disabled
|
|
42
58
|
@click="click"
|
|
59
|
+
@mousedown="onMousedown"
|
|
60
|
+
@mouseup="onMouseup"
|
|
61
|
+
@mouseleave="onMouseleave"
|
|
43
62
|
>
|
|
44
63
|
<orio-loading-spinner v-if="loading" />
|
|
45
64
|
<slot v-else name="icon">
|
|
@@ -68,6 +87,7 @@ button {
|
|
|
68
87
|
button.icon-only {
|
|
69
88
|
padding: 0;
|
|
70
89
|
border-radius: 50%;
|
|
90
|
+
line-height: 0;
|
|
71
91
|
}
|
|
72
92
|
button:disabled, button:disabled:hover {
|
|
73
93
|
background-color: var(--color-accent-soft-base);
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
3
|
-
(e: "input", value: string): void;
|
|
4
|
-
}>();
|
|
5
|
-
|
|
6
|
-
const text = defineModel<string>({ default: "" });
|
|
2
|
+
const modelValue = defineModel<string>({ default: "" });
|
|
7
3
|
</script>
|
|
8
4
|
|
|
9
5
|
<template>
|
|
10
6
|
<orio-control-element v-bind="$attrs">
|
|
11
|
-
<input
|
|
7
|
+
<input
|
|
8
|
+
v-bind="$attrs"
|
|
9
|
+
v-model="modelValue"
|
|
10
|
+
type="text"
|
|
11
|
+
class="text-input"
|
|
12
|
+
/>
|
|
12
13
|
</orio-control-element>
|
|
13
14
|
</template>
|
|
14
15
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { usePressAndHold } from "../../composables/usePressAndHold";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
step?: number;
|
|
8
|
+
decimalPlaces?: number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
withDefaults(defineProps<Props>(), {
|
|
13
|
+
min: undefined,
|
|
14
|
+
max: undefined,
|
|
15
|
+
step: 1,
|
|
16
|
+
decimalPlaces: 0,
|
|
17
|
+
disabled: false,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const modelValue = defineModel<number>({ default: 0 });
|
|
21
|
+
|
|
22
|
+
const { pressAndHold, stop } = usePressAndHold();
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<orio-number-input v-model="modelValue" v-bind="$props" class="horizontal">
|
|
27
|
+
<template #controls="{ increase, decrease, isAtMax, isAtMin }">
|
|
28
|
+
<orio-button
|
|
29
|
+
appearance="minimal"
|
|
30
|
+
icon="minus"
|
|
31
|
+
variant="subdued"
|
|
32
|
+
:disabled="isAtMin || disabled"
|
|
33
|
+
@mousedown="pressAndHold(decrease)"
|
|
34
|
+
@mouseup="stop"
|
|
35
|
+
@mouseleave="stop"
|
|
36
|
+
/>
|
|
37
|
+
<orio-button
|
|
38
|
+
appearance="minimal"
|
|
39
|
+
icon="plus"
|
|
40
|
+
variant="subdued"
|
|
41
|
+
:disabled="isAtMax || disabled"
|
|
42
|
+
@mousedown="pressAndHold(increase)"
|
|
43
|
+
@mouseup="stop"
|
|
44
|
+
@mouseleave="stop"
|
|
45
|
+
/>
|
|
46
|
+
</template>
|
|
47
|
+
</orio-number-input>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<style scoped>
|
|
51
|
+
.horizontal :deep(.number-input) {
|
|
52
|
+
text-align: center;
|
|
53
|
+
}
|
|
54
|
+
.horizontal :deep(.controls) {
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
padding: 0 3px;
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { usePressAndHold } from "../../composables/usePressAndHold";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
step?: number;
|
|
8
|
+
decimalPlaces?: number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
withDefaults(defineProps<Props>(), {
|
|
13
|
+
min: undefined,
|
|
14
|
+
max: undefined,
|
|
15
|
+
step: 1,
|
|
16
|
+
decimalPlaces: 0,
|
|
17
|
+
disabled: false,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const modelValue = defineModel<number>({ default: 0 });
|
|
21
|
+
|
|
22
|
+
const { pressAndHold, stop } = usePressAndHold();
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<orio-number-input v-model="modelValue" v-bind="$props" class="vertical">
|
|
27
|
+
<template #controls="{ increase, decrease, isAtMax, isAtMin }">
|
|
28
|
+
<orio-button
|
|
29
|
+
appearance="minimal"
|
|
30
|
+
icon="chevron-up"
|
|
31
|
+
variant="subdued"
|
|
32
|
+
:disabled="isAtMax || disabled"
|
|
33
|
+
@mousedown="pressAndHold(increase)"
|
|
34
|
+
@mouseup="stop"
|
|
35
|
+
@mouseleave="stop"
|
|
36
|
+
/>
|
|
37
|
+
<orio-button
|
|
38
|
+
appearance="minimal"
|
|
39
|
+
icon="chevron-down"
|
|
40
|
+
variant="subdued"
|
|
41
|
+
:disabled="isAtMin || disabled"
|
|
42
|
+
@mousedown="pressAndHold(decrease)"
|
|
43
|
+
@mouseup="stop"
|
|
44
|
+
@mouseleave="stop"
|
|
45
|
+
/>
|
|
46
|
+
</template>
|
|
47
|
+
</orio-number-input>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<style scoped>
|
|
51
|
+
.vertical :deep(.controls) {
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
justify-content: space-around;
|
|
54
|
+
right: 3px;
|
|
55
|
+
left: auto;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, toRefs } from "vue";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
step?: number;
|
|
8
|
+
decimalPlaces?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
12
|
+
min: undefined,
|
|
13
|
+
max: undefined,
|
|
14
|
+
step: 1,
|
|
15
|
+
decimalPlaces: 0,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const { min, max, step, decimalPlaces } = toRefs(props);
|
|
19
|
+
|
|
20
|
+
const modelValue = defineModel<number>({ default: 0 });
|
|
21
|
+
|
|
22
|
+
function setValidatedValue(value: number) {
|
|
23
|
+
let finalValue = value;
|
|
24
|
+
|
|
25
|
+
if (Number.isFinite(max.value) && finalValue > (max.value as number)) {
|
|
26
|
+
finalValue = max.value as number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (Number.isFinite(min.value) && finalValue < (min.value as number)) {
|
|
30
|
+
finalValue = min.value as number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
finalValue = Number((finalValue ?? 0).toFixed(decimalPlaces.value));
|
|
34
|
+
|
|
35
|
+
modelValue.value = finalValue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function onBlur() {
|
|
39
|
+
setValidatedValue(modelValue.value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function increase() {
|
|
43
|
+
setValidatedValue(modelValue.value + step.value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function decrease() {
|
|
47
|
+
setValidatedValue(modelValue.value - step.value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const isAtMax = computed(
|
|
51
|
+
() => Number.isFinite(max.value) && modelValue.value >= (max.value as number),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const isAtMin = computed(
|
|
55
|
+
() => Number.isFinite(min.value) && modelValue.value <= (min.value as number),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const slotExpose = computed(() => ({
|
|
59
|
+
increase,
|
|
60
|
+
decrease,
|
|
61
|
+
isAtMax: isAtMax.value,
|
|
62
|
+
isAtMin: isAtMin.value,
|
|
63
|
+
}));
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<orio-control-element v-bind="$attrs">
|
|
68
|
+
<div class="wrapper">
|
|
69
|
+
<input
|
|
70
|
+
v-bind="$attrs"
|
|
71
|
+
v-model="modelValue"
|
|
72
|
+
type="number"
|
|
73
|
+
class="number-input"
|
|
74
|
+
@blur="onBlur"
|
|
75
|
+
/>
|
|
76
|
+
<div class="controls">
|
|
77
|
+
<slot name="controls" v-bind="slotExpose" />
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</orio-control-element>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<style scoped>
|
|
84
|
+
.wrapper {
|
|
85
|
+
position: relative;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.number-input {
|
|
89
|
+
width: 100%;
|
|
90
|
+
padding: 0.5rem 0.75rem;
|
|
91
|
+
border: 1px solid var(--color-border);
|
|
92
|
+
border-radius: var(--border-radius-md);
|
|
93
|
+
font-size: 1rem;
|
|
94
|
+
line-height: 1.5;
|
|
95
|
+
color: var(--color-text);
|
|
96
|
+
background-color: var(--color-bg);
|
|
97
|
+
box-sizing: border-box;
|
|
98
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
99
|
+
}
|
|
100
|
+
.number-input::placeholder {
|
|
101
|
+
color: var(--color-muted);
|
|
102
|
+
}
|
|
103
|
+
.number-input:hover {
|
|
104
|
+
border-color: var(--color-accent);
|
|
105
|
+
}
|
|
106
|
+
.number-input:focus {
|
|
107
|
+
border-color: var(--color-accent);
|
|
108
|
+
outline: none;
|
|
109
|
+
}
|
|
110
|
+
.number-input:disabled {
|
|
111
|
+
background-color: var(--color-surface);
|
|
112
|
+
color: var(--color-muted);
|
|
113
|
+
cursor: not-allowed;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.controls {
|
|
117
|
+
position: absolute;
|
|
118
|
+
inset: 0;
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
pointer-events: none;
|
|
122
|
+
}
|
|
123
|
+
.controls :deep(button) {
|
|
124
|
+
pointer-events: auto;
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
@@ -2,3 +2,5 @@ export { useApi, type ApiOptions, type RequestBody, type RequestMethod, } from "
|
|
|
2
2
|
export { useFuzzySearch } from "./useFuzzySearch.js";
|
|
3
3
|
export { useModal, type ModalProps, type OriginRect } from "./useModal.js";
|
|
4
4
|
export { useTheme } from "./useTheme.js";
|
|
5
|
+
export { useDecimalFormatter } from "./useDecimalFormatter.js";
|
|
6
|
+
export { usePressAndHold } from "./usePressAndHold.js";
|
|
@@ -4,3 +4,5 @@ export {
|
|
|
4
4
|
export { useFuzzySearch } from "./useFuzzySearch.js";
|
|
5
5
|
export { useModal } from "./useModal.js";
|
|
6
6
|
export { useTheme } from "./useTheme.js";
|
|
7
|
+
export { useDecimalFormatter } from "./useDecimalFormatter.js";
|
|
8
|
+
export { usePressAndHold } from "./usePressAndHold.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type DecimalFormatOptions = {
|
|
2
|
+
locale?: string;
|
|
3
|
+
decimals?: number;
|
|
4
|
+
minimumFractionDigits?: number;
|
|
5
|
+
maximumFractionDigits?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function useDecimalFormatter(): {
|
|
8
|
+
toNumber: (input: string | number) => number | null;
|
|
9
|
+
formatDecimal: (input: string | number, options?: DecimalFormatOptions) => string | null;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
function getSystemLocale() {
|
|
2
|
+
if (typeof navigator === "undefined") return "de-DE";
|
|
3
|
+
return navigator.languages?.[0] ?? navigator.language;
|
|
4
|
+
}
|
|
5
|
+
export function useDecimalFormatter() {
|
|
6
|
+
function toNumber(input) {
|
|
7
|
+
if (typeof input === "number") {
|
|
8
|
+
return Number.isFinite(input) ? input : null;
|
|
9
|
+
}
|
|
10
|
+
if (typeof input !== "string") return null;
|
|
11
|
+
const cleaned = input.replace(/[^\d.,-]/g, "").trim();
|
|
12
|
+
if (!cleaned) return null;
|
|
13
|
+
const lastComma = cleaned.lastIndexOf(",");
|
|
14
|
+
const lastDot = cleaned.lastIndexOf(".");
|
|
15
|
+
let normalized = cleaned;
|
|
16
|
+
if (lastComma > lastDot) {
|
|
17
|
+
normalized = cleaned.replace(/\./g, "").replace(",", ".");
|
|
18
|
+
} else {
|
|
19
|
+
normalized = cleaned.replace(/,/g, "");
|
|
20
|
+
}
|
|
21
|
+
const result = Number(normalized);
|
|
22
|
+
return Number.isFinite(result) ? result : null;
|
|
23
|
+
}
|
|
24
|
+
function formatDecimal(input, options = {}) {
|
|
25
|
+
const locale = options.locale ?? getSystemLocale();
|
|
26
|
+
const decimals = options.decimals ?? 2;
|
|
27
|
+
const minimumFractionDigits = options.minimumFractionDigits ?? decimals;
|
|
28
|
+
const maximumFractionDigits = options.maximumFractionDigits ?? decimals;
|
|
29
|
+
const value = toNumber(input);
|
|
30
|
+
if (value === null) return null;
|
|
31
|
+
return new Intl.NumberFormat(locale, {
|
|
32
|
+
minimumFractionDigits,
|
|
33
|
+
maximumFractionDigits
|
|
34
|
+
}).format(value);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
toNumber,
|
|
38
|
+
formatDecimal
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
export function usePressAndHold() {
|
|
3
|
+
const interval = ref(null);
|
|
4
|
+
const timeout = ref(null);
|
|
5
|
+
function pressAndHold(callback) {
|
|
6
|
+
callback();
|
|
7
|
+
timeout.value = window.setTimeout(() => {
|
|
8
|
+
interval.value = window.setInterval(callback, 50);
|
|
9
|
+
}, 500);
|
|
10
|
+
}
|
|
11
|
+
function stop() {
|
|
12
|
+
if (timeout.value) {
|
|
13
|
+
window.clearTimeout(timeout.value);
|
|
14
|
+
timeout.value = null;
|
|
15
|
+
}
|
|
16
|
+
if (interval.value) {
|
|
17
|
+
window.clearInterval(interval.value);
|
|
18
|
+
interval.value = null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { pressAndHold, stop };
|
|
22
|
+
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { default as Button } from "./components/Button.vue.js";
|
|
2
2
|
export { default as NavButton } from "./components/NavButton.vue.js";
|
|
3
3
|
export { default as Input } from "./components/Input.vue.js";
|
|
4
|
+
export { default as NumberInput } from "./components/NumberInput/index.vue.js";
|
|
5
|
+
export { default as NumberInputVertical } from "./components/NumberInput/Vertical.vue.js";
|
|
6
|
+
export { default as NumberInputHorizontal } from "./components/NumberInput/Horizontal.vue.js";
|
|
4
7
|
export { default as Textarea } from "./components/Textarea.vue.js";
|
|
5
8
|
export { default as CheckBox } from "./components/CheckBox.vue.js";
|
|
6
9
|
export { default as SwitchButton } from "./components/SwitchButton.vue.js";
|
|
@@ -13,7 +16,7 @@ export { default as LoadingSpinner } from "./components/LoadingSpinner.vue.js";
|
|
|
13
16
|
export { default as Modal } from "./components/Modal.vue.js";
|
|
14
17
|
export { default as Popover } from "./components/Popover.vue.js";
|
|
15
18
|
export { default as Tooltip } from "./components/Tooltip.vue.js";
|
|
16
|
-
export { default as Upload } from "./components/Upload.vue.js";
|
|
19
|
+
export { default as Upload } from "./components/Upload/index.vue.js";
|
|
17
20
|
export { default as EmptyState } from "./components/EmptyState.vue.js";
|
|
18
21
|
export { default as DashedContainer } from "./components/DashedContainer.vue.js";
|
|
19
22
|
export { default as ControlElement } from "./components/ControlElement.vue.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { default as Button } from "./components/Button.vue";
|
|
2
2
|
export { default as NavButton } from "./components/NavButton.vue";
|
|
3
3
|
export { default as Input } from "./components/Input.vue";
|
|
4
|
+
export { default as NumberInput } from "./components/NumberInput/index.vue";
|
|
5
|
+
export { default as NumberInputVertical } from "./components/NumberInput/Vertical.vue";
|
|
6
|
+
export { default as NumberInputHorizontal } from "./components/NumberInput/Horizontal.vue";
|
|
4
7
|
export { default as Textarea } from "./components/Textarea.vue";
|
|
5
8
|
export { default as CheckBox } from "./components/CheckBox.vue";
|
|
6
9
|
export { default as SwitchButton } from "./components/SwitchButton.vue";
|
|
@@ -13,7 +16,7 @@ export { default as LoadingSpinner } from "./components/LoadingSpinner.vue";
|
|
|
13
16
|
export { default as Modal } from "./components/Modal.vue";
|
|
14
17
|
export { default as Popover } from "./components/Popover.vue";
|
|
15
18
|
export { default as Tooltip } from "./components/Tooltip.vue";
|
|
16
|
-
export { default as Upload } from "./components/Upload.vue";
|
|
19
|
+
export { default as Upload } from "./components/Upload/index.vue";
|
|
17
20
|
export { default as EmptyState } from "./components/EmptyState.vue";
|
|
18
21
|
export { default as DashedContainer } from "./components/DashedContainer.vue";
|
|
19
22
|
export { default as ControlElement } from "./components/ControlElement.vue";
|
|
@@ -32,6 +32,8 @@ export const iconRegistry = {
|
|
|
32
32
|
check: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19L21 7l-1.41-1.41z"/></svg>`,
|
|
33
33
|
// Plus / Add
|
|
34
34
|
plus: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>`,
|
|
35
|
+
// Minus / Remove
|
|
36
|
+
minus: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M19 13H5v-2h14v2z"/></svg>`,
|
|
35
37
|
// Calendar
|
|
36
38
|
calendar: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2m0 16H5V10h14zm0-12H5V6h14zM7 12h5v5H7z"/></svg>`,
|
|
37
39
|
// Close / X
|