@xy-planning-network/trees 0.7.4 → 0.7.5-rc1
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/trees.es.js +3939 -3561
- package/dist/trees.umd.js +10 -10
- package/package.json +2 -2
- package/src/index.css +0 -16
- package/src/lib-components/forms/BaseInput.vue +90 -75
- package/src/lib-components/forms/Checkbox.vue +50 -34
- package/src/lib-components/forms/DateRangePicker.vue +56 -32
- package/src/lib-components/forms/FieldsetLegend.vue +28 -8
- package/src/lib-components/forms/InputHelp.vue +2 -4
- package/src/lib-components/forms/InputLabel.vue +27 -12
- package/src/lib-components/forms/MultiCheckboxes.vue +117 -74
- package/src/lib-components/forms/Radio.vue +79 -66
- package/src/lib-components/forms/RadioCards.vue +72 -70
- package/src/lib-components/forms/Select.vue +59 -56
- package/src/lib-components/forms/TextArea.vue +54 -47
- package/src/lib-components/forms/Toggle.vue +61 -18
- package/src/lib-components/forms/YesOrNoRadio.vue +75 -67
- package/src/lib-components/lists/DynamicTable.vue +43 -20
- package/types/composables/forms.d.ts +118 -0
- package/types/helpers/Debounce.d.ts +1 -1
- package/types/lib-components/forms/BaseInput.vue.d.ts +58 -34
- package/types/lib-components/forms/Checkbox.vue.d.ts +50 -29
- package/types/lib-components/forms/DateRangePicker.vue.d.ts +71 -39
- package/types/lib-components/forms/FieldsetLegend.vue.d.ts +30 -31
- package/types/lib-components/forms/InputHelp.vue.d.ts +19 -27
- package/types/lib-components/forms/InputLabel.vue.d.ts +28 -32
- package/types/lib-components/forms/MultiCheckboxes.vue.d.ts +77 -56
- package/types/lib-components/forms/Radio.vue.d.ts +64 -56
- package/types/lib-components/forms/RadioCards.vue.d.ts +68 -71
- package/types/lib-components/forms/Select.vue.d.ts +55 -44
- package/types/lib-components/forms/TextArea.vue.d.ts +50 -32
- package/types/lib-components/forms/Toggle.vue.d.ts +29 -24
- package/types/lib-components/forms/YesOrNoRadio.vue.d.ts +51 -38
- package/types/lib-components/indicators/XYSpinner.vue.d.ts +1 -1
- package/types/lib-components/layout/DateFilter.vue.d.ts +28 -20
- package/types/lib-components/layout/SidebarLayout.vue.d.ts +38 -32
- package/types/lib-components/layout/StackedLayout.vue.d.ts +45 -33
- package/types/lib-components/lists/Cards.vue.d.ts +14 -17
- package/types/lib-components/lists/DataTable.vue.d.ts +31 -31
- package/types/lib-components/lists/DetailList.vue.d.ts +38 -34
- package/types/lib-components/lists/DownloadCell.vue.d.ts +18 -15
- package/types/lib-components/lists/DynamicTable.vue.d.ts +32 -32
- package/types/lib-components/lists/StaticTable.vue.d.ts +21 -0
- package/types/lib-components/lists/StaticTableActionSlot.vue.d.ts +27 -0
- package/types/lib-components/lists/Table.vue.d.ts +39 -0
- package/types/lib-components/lists/TableActionButtons.vue.d.ts +11 -23
- package/types/lib-components/navigation/ActionsDropdown.vue.d.ts +11 -23
- package/types/lib-components/navigation/ActionsDropdownCallback.vue.d.ts +18 -0
- package/types/lib-components/navigation/ActionsDropdownEmit.vue.d.ts +22 -0
- package/types/lib-components/navigation/Paginator.vue.d.ts +12 -15
- package/types/lib-components/navigation/Steps.vue.d.ts +54 -39
- package/types/lib-components/navigation/Tabs.vue.d.ts +34 -34
- package/types/lib-components/overlays/ContentModal.vue.d.ts +22 -28
- package/types/lib-components/overlays/Modal.vue.d.ts +48 -43
- package/types/lib-components/overlays/Popover/Popover.vue.d.ts +23 -31
- package/types/lib-components/overlays/Popover/PopoverContent.vue.d.ts +1 -1
- package/types/lib-components/overlays/Slideover.vue.d.ts +30 -22
- package/types/lib-components/overlays/Tooltip.vue.d.ts +20 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xy-planning-network/trees",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5-rc1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "github:xy-planning-network/trees",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"tsc-alias": "^1.8.5",
|
|
53
53
|
"typescript": "^5.0.4",
|
|
54
54
|
"vite": "^4.3.9",
|
|
55
|
-
"vue-tsc": "^1.
|
|
55
|
+
"vue-tsc": "^1.8.18"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@floating-ui/vue": "^1.0.1",
|
package/src/index.css
CHANGED
|
@@ -32,17 +32,6 @@
|
|
|
32
32
|
h6 {
|
|
33
33
|
@apply text-xs leading-4 font-semibold;
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
/* Forms: here for backward compatibility. Use <BaseInput> instead. */
|
|
37
|
-
[type="text"],
|
|
38
|
-
[type="email"],
|
|
39
|
-
[type="password"],
|
|
40
|
-
[type="number"],
|
|
41
|
-
[type="search"],
|
|
42
|
-
[type="tel"],
|
|
43
|
-
textarea {
|
|
44
|
-
@apply mt-1 shadow-sm focus:ring-xy-blue-500 focus:border-xy-blue block w-full sm:text-sm border-gray-600 rounded-md;
|
|
45
|
-
}
|
|
46
35
|
}
|
|
47
36
|
|
|
48
37
|
@layer components {
|
|
@@ -131,9 +120,4 @@
|
|
|
131
120
|
.max-h-screen-1\/2 {
|
|
132
121
|
max-height: 50vh;
|
|
133
122
|
}
|
|
134
|
-
|
|
135
|
-
/* Forms */
|
|
136
|
-
.xy-input-error {
|
|
137
|
-
@apply focus:ring-red-700 focus:border-red-700 text-red-900 placeholder-red-700 placeholder-opacity-75 border-red-700;
|
|
138
|
-
}
|
|
139
123
|
}
|
|
@@ -1,87 +1,102 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import Uniques from "@/helpers/Uniques"
|
|
3
2
|
import InputLabel from "./InputLabel.vue"
|
|
4
3
|
import InputHelp from "./InputHelp.vue"
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useInputField,
|
|
6
|
+
defaultInputProps,
|
|
7
|
+
emailPattern,
|
|
8
|
+
looseToNumber,
|
|
9
|
+
passwordPattern,
|
|
10
|
+
phonePattern,
|
|
11
|
+
} from "@/composables/forms"
|
|
12
|
+
import type { TextLikeInput } from "@/composables/forms"
|
|
13
|
+
import { computed, ref } from "vue"
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
defineOptions({
|
|
16
|
+
inheritAttrs: false,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const props = withDefaults(defineProps<TextLikeInput>(), defaultInputProps)
|
|
20
|
+
|
|
21
|
+
defineEmits(["update:modelValue", "update:error"])
|
|
22
|
+
const targetInput = ref<HTMLInputElement | null>(null)
|
|
23
|
+
const {
|
|
24
|
+
errorState,
|
|
25
|
+
modelState,
|
|
26
|
+
inputID,
|
|
27
|
+
isRequired,
|
|
28
|
+
onInvalid,
|
|
29
|
+
inputValidation,
|
|
30
|
+
} = useInputField({ props, targetInput })
|
|
31
|
+
|
|
32
|
+
const typeAttributes = computed(() => {
|
|
33
|
+
switch (props.type) {
|
|
34
|
+
case "number":
|
|
35
|
+
return {
|
|
36
|
+
max: Number.MAX_SAFE_INTEGER,
|
|
37
|
+
min: Number.MIN_SAFE_INTEGER,
|
|
38
|
+
}
|
|
39
|
+
case "email":
|
|
40
|
+
return {
|
|
41
|
+
pattern: emailPattern,
|
|
42
|
+
}
|
|
43
|
+
case "password":
|
|
44
|
+
return {
|
|
45
|
+
pattern: passwordPattern,
|
|
46
|
+
}
|
|
47
|
+
case "tel":
|
|
48
|
+
return {
|
|
49
|
+
pattern: phonePattern,
|
|
50
|
+
}
|
|
51
|
+
default:
|
|
52
|
+
return {}
|
|
19
53
|
}
|
|
20
|
-
)
|
|
54
|
+
})
|
|
21
55
|
|
|
22
|
-
const
|
|
56
|
+
const onInput = (e: Event) => {
|
|
57
|
+
let val = (e.target as HTMLInputElement).value
|
|
23
58
|
|
|
24
|
-
|
|
59
|
+
if (props.type === "number") {
|
|
60
|
+
val = looseToNumber(val)
|
|
61
|
+
}
|
|
25
62
|
|
|
26
|
-
|
|
27
|
-
* common text based inputs
|
|
28
|
-
*/
|
|
29
|
-
const textInputTypes = [
|
|
30
|
-
"date",
|
|
31
|
-
"datetime-local",
|
|
32
|
-
"email",
|
|
33
|
-
"month",
|
|
34
|
-
"number",
|
|
35
|
-
"password",
|
|
36
|
-
"search",
|
|
37
|
-
"tel",
|
|
38
|
-
"text",
|
|
39
|
-
"time",
|
|
40
|
-
"url",
|
|
41
|
-
"week",
|
|
42
|
-
]
|
|
63
|
+
modelState.value = val
|
|
43
64
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*/
|
|
47
|
-
const isTextType = computed((): boolean => {
|
|
48
|
-
return typeof props.type === "string" && textInputTypes.includes(props.type)
|
|
49
|
-
})
|
|
65
|
+
inputValidation(e)
|
|
66
|
+
}
|
|
50
67
|
</script>
|
|
68
|
+
|
|
51
69
|
<template>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
/>
|
|
86
|
-
<InputHelp :id="`${uuid}-help`" :text="help"></InputHelp>
|
|
70
|
+
<div>
|
|
71
|
+
<InputLabel
|
|
72
|
+
:id="`${inputID}-label`"
|
|
73
|
+
class="mb-2"
|
|
74
|
+
:for="inputID"
|
|
75
|
+
:label="label"
|
|
76
|
+
:required="isRequired"
|
|
77
|
+
/>
|
|
78
|
+
<input
|
|
79
|
+
:id="inputID"
|
|
80
|
+
ref="targetInput"
|
|
81
|
+
:aria-labelledby="label ? `${inputID}-label` : undefined"
|
|
82
|
+
:aria-describedby="help ? `${inputID}-help` : undefined"
|
|
83
|
+
:class="[
|
|
84
|
+
'block w-full rounded-md border-0 py-2 shadow-sm ring-1 ring-inset focus:ring-2 sm:text-sm sm:leading-6',
|
|
85
|
+
'disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-700 disabled:ring-gray-200',
|
|
86
|
+
errorState
|
|
87
|
+
? 'text-red-900 ring-red-700 placeholder:text-red-300 focus:ring-red-700'
|
|
88
|
+
: 'text-gray-900 ring-gray-300 placeholder:text-gray-400 focus:ring-xy-blue-500',
|
|
89
|
+
]"
|
|
90
|
+
:placeholder="placeholder"
|
|
91
|
+
:type="type"
|
|
92
|
+
:value="modelState"
|
|
93
|
+
v-bind="{ ...typeAttributes, ...$attrs }"
|
|
94
|
+
@input="onInput"
|
|
95
|
+
@invalid="onInvalid"
|
|
96
|
+
/>
|
|
97
|
+
<InputHelp :id="`${inputID}-help`" class="mt-1" :text="help" />
|
|
98
|
+
<div v-if="errorState" class="mt-0.5">
|
|
99
|
+
<p class="text-sm text-red-700">{{ errorState }}</p>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
87
102
|
</template>
|
|
@@ -1,53 +1,69 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import InputLabel from "./InputLabel.vue"
|
|
3
3
|
import InputHelp from "./InputHelp.vue"
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import { useInputField, defaultInputProps } from "@/composables/forms"
|
|
5
|
+
import type { BooleanInput } from "@/composables/forms"
|
|
6
|
+
import { ref } from "vue"
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
defineOptions({
|
|
9
|
+
inheritAttrs: false,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<BooleanInput>(), defaultInputProps)
|
|
13
|
+
|
|
14
|
+
defineEmits(["update:modelValue", "update:error"])
|
|
15
|
+
const targetInput = ref<HTMLInputElement | null>(null)
|
|
16
|
+
const {
|
|
17
|
+
inputID,
|
|
18
|
+
isDisabled,
|
|
19
|
+
isRequired,
|
|
20
|
+
errorState,
|
|
21
|
+
modelState,
|
|
22
|
+
validate,
|
|
23
|
+
onInvalid,
|
|
24
|
+
} = useInputField({ props, targetInput })
|
|
25
|
+
|
|
26
|
+
const onChange = (e: Event) => {
|
|
27
|
+
modelState.value = (e.target as HTMLInputElement).checked
|
|
28
|
+
validate(e)
|
|
29
|
+
}
|
|
21
30
|
</script>
|
|
31
|
+
|
|
22
32
|
<template>
|
|
23
33
|
<div class="relative flex items-start">
|
|
24
34
|
<div class="flex items-center h-5">
|
|
25
35
|
<input
|
|
26
|
-
:id="
|
|
27
|
-
|
|
28
|
-
:aria-
|
|
29
|
-
:
|
|
30
|
-
|
|
36
|
+
:id="inputID"
|
|
37
|
+
ref="targetInput"
|
|
38
|
+
:aria-labelledby="label ? `${inputID}-label` : undefined"
|
|
39
|
+
:aria-describedby="help ? `${inputID}-help` : undefined"
|
|
40
|
+
:checked="modelState || undefined"
|
|
41
|
+
:class="[
|
|
42
|
+
'h-4 w-4 rounded text-xy-blue cursor-pointer',
|
|
43
|
+
'disabled:bg-gray-100 disabled:border-gray-200 disabled:cursor-not-allowed disabled:opacity-100',
|
|
44
|
+
'checked:disabled:bg-xy-blue checked:disabled:border-xy-blue checked:disabled:opacity-50',
|
|
45
|
+
errorState
|
|
46
|
+
? 'border-red-700 focus:ring-red-700'
|
|
47
|
+
: 'border-gray-300 focus:ring-xy-blue-500',
|
|
48
|
+
]"
|
|
31
49
|
type="checkbox"
|
|
32
|
-
v-bind="
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
...$attrs,
|
|
37
|
-
}"
|
|
50
|
+
v-bind="$attrs"
|
|
51
|
+
@change="onChange"
|
|
52
|
+
@invalid="onInvalid"
|
|
38
53
|
/>
|
|
39
54
|
</div>
|
|
40
55
|
<div class="ml-3">
|
|
41
56
|
<InputLabel
|
|
42
|
-
:id="`${
|
|
43
|
-
|
|
44
|
-
:disabled="
|
|
45
|
-
$attrs.hasOwnProperty('disabled') && $attrs.disabled !== false
|
|
46
|
-
"
|
|
47
|
-
:for="uuid"
|
|
57
|
+
:id="`${inputID}-label`"
|
|
58
|
+
:for="inputID"
|
|
48
59
|
:label="label"
|
|
60
|
+
:class="isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
|
61
|
+
:required="isRequired"
|
|
49
62
|
/>
|
|
50
|
-
<InputHelp :id="`${
|
|
63
|
+
<InputHelp :id="`${inputID}-help`" :text="help"></InputHelp>
|
|
64
|
+
<div v-if="errorState" class="mt-0.5">
|
|
65
|
+
<p class="text-sm text-red-700">{{ errorState }}</p>
|
|
66
|
+
</div>
|
|
51
67
|
</div>
|
|
52
68
|
</div>
|
|
53
69
|
</template>
|
|
@@ -1,39 +1,38 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import Uniques from "@/helpers/Uniques"
|
|
3
2
|
import flatpickr from "flatpickr"
|
|
4
3
|
import "flatpickr/dist/flatpickr.min.css"
|
|
5
|
-
import { onMounted,
|
|
6
|
-
import
|
|
4
|
+
import { onMounted, ref } from "vue"
|
|
5
|
+
import { defaultInputProps, useInputField } from "@/composables/forms"
|
|
6
|
+
import type { DateRangeInput } from "@/composables/forms"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
defineOptions({
|
|
9
|
+
inheritAttrs: false,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<DateRangeInput>(), {
|
|
13
|
+
...defaultInputProps,
|
|
14
|
+
maxRange: 0,
|
|
15
|
+
modelValue: () => {
|
|
16
|
+
return {
|
|
17
|
+
maxDate: 0,
|
|
18
|
+
minDate: 0,
|
|
13
19
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}>(),
|
|
19
|
-
{
|
|
20
|
-
maxRange: 0,
|
|
21
|
-
startDate: 0,
|
|
22
|
-
label: "",
|
|
23
|
-
help: "",
|
|
24
|
-
}
|
|
25
|
-
)
|
|
20
|
+
},
|
|
21
|
+
placeholder: "mm-dd-yyyy range",
|
|
22
|
+
startDate: 0,
|
|
23
|
+
})
|
|
26
24
|
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
25
|
+
const targetInput = ref<HTMLInputElement | null>(null)
|
|
26
|
+
const { errorState, modelState, inputID, isRequired, onInvalid, validate } =
|
|
27
|
+
useInputField({ props, targetInput })
|
|
30
28
|
|
|
31
29
|
const updateModelValue = (value: { minDate: number; maxDate: number }) => {
|
|
32
|
-
|
|
30
|
+
modelState.value = value
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
onMounted(() => {
|
|
36
34
|
const opts: flatpickr.Options.Options = {
|
|
35
|
+
allowInput: true,
|
|
37
36
|
dateFormat: "m-d-Y",
|
|
38
37
|
mode: "range",
|
|
39
38
|
maxDate: new Date(), // So far, we cannot have options past today for ranges
|
|
@@ -84,15 +83,40 @@ onMounted(() => {
|
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
flatpickr(`#${
|
|
86
|
+
flatpickr(`#${inputID.value}`, opts)
|
|
88
87
|
})
|
|
89
88
|
</script>
|
|
89
|
+
|
|
90
90
|
<template>
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
<div>
|
|
92
|
+
<InputLabel
|
|
93
|
+
:id="`${inputID}-label`"
|
|
94
|
+
class="mb-2"
|
|
95
|
+
:for="inputID"
|
|
96
|
+
:label="label"
|
|
97
|
+
:required="isRequired"
|
|
98
|
+
/>
|
|
99
|
+
<input
|
|
100
|
+
:id="inputID"
|
|
101
|
+
ref="targetInput"
|
|
102
|
+
:aria-labelledby="label ? `${inputID}-label` : undefined"
|
|
103
|
+
:aria-describedby="help ? `${inputID}-help` : undefined"
|
|
104
|
+
:class="[
|
|
105
|
+
'block w-full rounded-md border-0 py-2 shadow-sm ring-1 ring-inset focus:ring-2 sm:text-sm sm:leading-6',
|
|
106
|
+
'disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-700 disabled:ring-gray-200',
|
|
107
|
+
errorState
|
|
108
|
+
? 'text-red-900 ring-red-700 placeholder:text-red-300 focus:ring-red-700'
|
|
109
|
+
: 'text-gray-900 ring-gray-300 placeholder:text-gray-400 focus:ring-xy-blue-500',
|
|
110
|
+
]"
|
|
111
|
+
:placeholder="placeholder"
|
|
112
|
+
v-bind="$attrs"
|
|
113
|
+
type="text"
|
|
114
|
+
@input="validate"
|
|
115
|
+
@invalid="onInvalid"
|
|
116
|
+
/>
|
|
117
|
+
<InputHelp :id="`${inputID}-help`" class="mt-1" :text="help" />
|
|
118
|
+
<div v-if="errorState" class="mt-0.5">
|
|
119
|
+
<p class="text-sm text-red-700">{{ errorState }}</p>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
98
122
|
</template>
|
|
@@ -1,23 +1,43 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { computed } from "vue"
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(
|
|
4
5
|
defineProps<{
|
|
6
|
+
label?: string
|
|
7
|
+
required?: boolean
|
|
5
8
|
tag?: string
|
|
6
9
|
}>(),
|
|
7
10
|
{
|
|
11
|
+
label: "",
|
|
12
|
+
required: false,
|
|
8
13
|
tag: "legend",
|
|
9
14
|
}
|
|
10
15
|
)
|
|
16
|
+
|
|
17
|
+
const labelDisplay = computed((): string => {
|
|
18
|
+
if (!props.required) {
|
|
19
|
+
return props.label
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// remove trailing * on the existing label
|
|
23
|
+
const regex = /\*$/gm
|
|
24
|
+
|
|
25
|
+
if (regex.exec(props.label) !== null) {
|
|
26
|
+
return props.label.substring(0, props.label.length - 1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return props.label
|
|
30
|
+
})
|
|
11
31
|
</script>
|
|
32
|
+
|
|
12
33
|
<template>
|
|
13
34
|
<component
|
|
14
35
|
:is="tag"
|
|
15
|
-
v-if="
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class: 'text-sm font-semibold leading-snug text-gray-900',
|
|
19
|
-
}"
|
|
36
|
+
v-if="label"
|
|
37
|
+
class="block text-base leading-snug font-medium text-gray-800"
|
|
38
|
+
v-bind="$attrs"
|
|
20
39
|
>
|
|
21
|
-
|
|
40
|
+
{{ labelDisplay }}
|
|
41
|
+
<span v-if="props.required" class="text-red-700/80">*</span>
|
|
22
42
|
</component>
|
|
23
43
|
</template>
|
|
@@ -14,10 +14,8 @@ withDefaults(
|
|
|
14
14
|
<component
|
|
15
15
|
:is="tag"
|
|
16
16
|
v-if="text"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class: 'mt-1 text-sm leading-snug font-normal text-gray-700',
|
|
20
|
-
}"
|
|
17
|
+
class="text-sm leading-snug font-normal text-gray-600"
|
|
18
|
+
v-bind="$attrs"
|
|
21
19
|
>
|
|
22
20
|
{{ text }}
|
|
23
21
|
</component>
|
|
@@ -1,28 +1,43 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
2
|
+
import { computed } from "vue"
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(
|
|
3
5
|
defineProps<{
|
|
4
|
-
disabled?: boolean
|
|
5
6
|
label?: string
|
|
7
|
+
required?: boolean
|
|
6
8
|
tag?: string
|
|
7
9
|
}>(),
|
|
8
10
|
{
|
|
9
|
-
disabled: false,
|
|
10
11
|
label: "",
|
|
12
|
+
required: false,
|
|
11
13
|
tag: "label",
|
|
12
14
|
}
|
|
13
15
|
)
|
|
16
|
+
|
|
17
|
+
const labelDisplay = computed((): string => {
|
|
18
|
+
if (!props.required) {
|
|
19
|
+
return props.label
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// remove trailing * on the existing label
|
|
23
|
+
const regex = /\*$/gm
|
|
24
|
+
|
|
25
|
+
if (regex.exec(props.label) !== null) {
|
|
26
|
+
return props.label.substring(0, props.label.length - 1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return props.label
|
|
30
|
+
})
|
|
14
31
|
</script>
|
|
32
|
+
|
|
15
33
|
<template>
|
|
16
34
|
<component
|
|
17
35
|
:is="tag"
|
|
18
|
-
v-if="
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'opacity-75': disabled,
|
|
22
|
-
}"
|
|
23
|
-
v-bind="{
|
|
24
|
-
...$attrs,
|
|
25
|
-
}"
|
|
26
|
-
>{{ label }}</component
|
|
36
|
+
v-if="labelDisplay"
|
|
37
|
+
class="block text-sm leading-snug font-medium text-gray-800"
|
|
38
|
+
v-bind="$attrs"
|
|
27
39
|
>
|
|
40
|
+
{{ labelDisplay }}
|
|
41
|
+
<span v-if="props.required" class="text-red-700/80">*</span>
|
|
42
|
+
</component>
|
|
28
43
|
</template>
|