@energysage/es-ds-components 0.0.1 → 3.0.0-alpha.10
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/.eslintignore +9 -0
- package/.eslintrc.json +3 -0
- package/.prettierrc.json +10 -0
- package/README.md +0 -3
- package/components/es-accordion-list.vue +117 -0
- package/components/es-accordion.vue +7 -0
- package/components/es-badge.vue +20 -0
- package/components/es-breadcrumbs.vue +73 -0
- package/components/es-button.vue +122 -0
- package/components/es-card.vue +64 -0
- package/components/es-carousel.vue +316 -0
- package/components/es-col.vue +27 -0
- package/components/es-collapse.vue +83 -0
- package/components/es-container.vue +14 -0
- package/components/es-cta-banner.vue +95 -0
- package/components/es-cta-card.vue +60 -0
- package/components/es-data-table-simple.vue +73 -0
- package/components/es-data-table.vue +128 -0
- package/components/es-error-page.vue +120 -0
- package/components/es-file-input.vue +334 -0
- package/components/es-file-preview-modal.vue +61 -0
- package/components/es-footer.vue +163 -0
- package/components/es-form-checkbox.vue +40 -0
- package/components/es-form-input.vue +130 -0
- package/components/es-form-msg.vue +81 -0
- package/components/es-form-radio-card.vue +57 -0
- package/components/es-form-radio-cards.vue +78 -0
- package/components/es-form-textarea.vue +124 -0
- package/components/es-form.vue +16 -0
- package/components/es-modal.vue +103 -0
- package/components/es-nav-bar-account-menu.vue +70 -0
- package/components/es-nav-bar-featured-article.vue +60 -0
- package/components/es-nav-bar-link.vue +27 -0
- package/components/es-nav-bar-product-menu.vue +219 -0
- package/components/es-nav-bar-top-level-menu.vue +194 -0
- package/components/es-nav-bar-topic-menu.vue +197 -0
- package/components/es-nav-bar.vue +411 -0
- package/components/es-pagination.vue +67 -0
- package/components/es-popover.vue +113 -0
- package/components/es-progress-circle.vue +81 -0
- package/components/es-progress.vue +36 -0
- package/components/es-radio-button-group.vue +53 -0
- package/components/es-radio-button.vue +57 -0
- package/components/es-rating.vue +120 -0
- package/components/es-reviews-io-card-carousel.vue +279 -0
- package/components/es-row.vue +5 -0
- package/components/es-skeleton-img.vue +38 -0
- package/components/es-skeleton-wrapper.vue +17 -0
- package/components/es-skeleton.vue +97 -0
- package/components/es-slider.vue +218 -0
- package/components/es-spinner.vue +22 -0
- package/components/es-support-card.vue +150 -0
- package/components/es-support.vue +66 -0
- package/components/es-tab.vue +7 -0
- package/components/es-tabs.vue +70 -0
- package/components/es-verification-code.vue +94 -0
- package/components/es-video.vue +60 -0
- package/components/es-view-more.vue +64 -0
- package/components/es-zip-code-form.vue +204 -0
- package/components/icon/arrow-clockwise.vue +51 -0
- package/components/icon/arrow-counter-clockwise.vue +37 -0
- package/components/icon/arrow-cycle.vue +43 -0
- package/components/icon/arrow-left.vue +39 -0
- package/components/icon/arrow-right.vue +39 -0
- package/components/icon/arrow-up.vue +39 -0
- package/components/icon/arrow.vue +68 -0
- package/components/icon/bank.vue +38 -0
- package/components/icon/battery.vue +40 -0
- package/components/icon/bell.vue +42 -0
- package/components/icon/block.vue +46 -0
- package/components/icon/bolt.vue +38 -0
- package/components/icon/business.vue +42 -0
- package/components/icon/calculator.vue +37 -0
- package/components/icon/calendar.vue +46 -0
- package/components/icon/cart.vue +46 -0
- package/components/icon/chat-add.vue +44 -0
- package/components/icon/chat-approve.vue +42 -0
- package/components/icon/chat-bubble.vue +40 -0
- package/components/icon/chat-dots.vue +42 -0
- package/components/icon/check.vue +39 -0
- package/components/icon/chevron-down.vue +39 -0
- package/components/icon/chevron-horizontal.vue +39 -0
- package/components/icon/chevron-left.vue +39 -0
- package/components/icon/chevron-right.vue +39 -0
- package/components/icon/chevron-up.vue +39 -0
- package/components/icon/circle-alert.vue +46 -0
- package/components/icon/circle-check.vue +46 -0
- package/components/icon/circle-chevron-down.vue +47 -0
- package/components/icon/circle-chevron-left.vue +46 -0
- package/components/icon/circle-chevron-right.vue +46 -0
- package/components/icon/circle-chevron-up.vue +46 -0
- package/components/icon/circle-minus.vue +46 -0
- package/components/icon/circle-plus.vue +46 -0
- package/components/icon/circle-x.vue +46 -0
- package/components/icon/circle.vue +42 -0
- package/components/icon/clock.vue +46 -0
- package/components/icon/community-solar.vue +37 -0
- package/components/icon/companies.vue +43 -0
- package/components/icon/contact-us.vue +37 -0
- package/components/icon/copy.vue +45 -0
- package/components/icon/credit-card.vue +37 -0
- package/components/icon/document.vue +45 -0
- package/components/icon/electric-vehicle.vue +37 -0
- package/components/icon/electricity-circle.vue +39 -0
- package/components/icon/envelope.vue +45 -0
- package/components/icon/es-leaf.vue +39 -0
- package/components/icon/eye.vue +41 -0
- package/components/icon/facebook.vue +41 -0
- package/components/icon/file-doc.vue +72 -0
- package/components/icon/file-docx.vue +72 -0
- package/components/icon/file-pdf.vue +72 -0
- package/components/icon/flag.vue +37 -0
- package/components/icon/folder.vue +41 -0
- package/components/icon/gear.vue +37 -0
- package/components/icon/gift.vue +37 -0
- package/components/icon/hamburger.vue +38 -0
- package/components/icon/heart.vue +39 -0
- package/components/icon/heat-pump.vue +41 -0
- package/components/icon/image.vue +45 -0
- package/components/icon/info-blog-post.vue +47 -0
- package/components/icon/info.vue +45 -0
- package/components/icon/instagram.vue +49 -0
- package/components/icon/light-bulb.vue +36 -0
- package/components/icon/link-out.vue +38 -0
- package/components/icon/linkedin.vue +41 -0
- package/components/icon/location.vue +45 -0
- package/components/icon/lock-off.vue +45 -0
- package/components/icon/lock-on.vue +48 -0
- package/components/icon/marketplace.vue +43 -0
- package/components/icon/minus.vue +38 -0
- package/components/icon/money-bag.vue +37 -0
- package/components/icon/money.vue +35 -0
- package/components/icon/open-envelope.vue +45 -0
- package/components/icon/paper.vue +45 -0
- package/components/icon/payback.vue +37 -0
- package/components/icon/pencil.vue +45 -0
- package/components/icon/person-add.vue +41 -0
- package/components/icon/person-check.vue +41 -0
- package/components/icon/person-cross.vue +41 -0
- package/components/icon/person.vue +41 -0
- package/components/icon/phone.vue +41 -0
- package/components/icon/play.vue +41 -0
- package/components/icon/plus.vue +38 -0
- package/components/icon/roof.vue +37 -0
- package/components/icon/rooftop-solar.vue +37 -0
- package/components/icon/saving.vue +37 -0
- package/components/icon/search.vue +43 -0
- package/components/icon/settings-horizontal.vue +57 -0
- package/components/icon/settings-vertical.vue +57 -0
- package/components/icon/shield-with-check.vue +38 -0
- package/components/icon/shield.vue +41 -0
- package/components/icon/shopping-bag.vue +39 -0
- package/components/icon/solar.vue +37 -0
- package/components/icon/sound-down.vue +45 -0
- package/components/icon/sound-off.vue +41 -0
- package/components/icon/sound-on.vue +41 -0
- package/components/icon/sound-up.vue +41 -0
- package/components/icon/star-empty.vue +38 -0
- package/components/icon/star-full.vue +36 -0
- package/components/icon/star-half.vue +55 -0
- package/components/icon/state-ak.vue +53 -0
- package/components/icon/state-al.vue +38 -0
- package/components/icon/state-ar.vue +38 -0
- package/components/icon/state-az.vue +38 -0
- package/components/icon/state-ca.vue +38 -0
- package/components/icon/state-co.vue +38 -0
- package/components/icon/state-ct.vue +38 -0
- package/components/icon/state-dc.vue +52 -0
- package/components/icon/state-de.vue +38 -0
- package/components/icon/state-fl.vue +38 -0
- package/components/icon/state-ga.vue +38 -0
- package/components/icon/state-hi.vue +59 -0
- package/components/icon/state-ia.vue +38 -0
- package/components/icon/state-id.vue +38 -0
- package/components/icon/state-il.vue +38 -0
- package/components/icon/state-in.vue +38 -0
- package/components/icon/state-ks.vue +38 -0
- package/components/icon/state-ky.vue +38 -0
- package/components/icon/state-la.vue +38 -0
- package/components/icon/state-ma.vue +38 -0
- package/components/icon/state-md.vue +39 -0
- package/components/icon/state-me.vue +38 -0
- package/components/icon/state-mi.vue +38 -0
- package/components/icon/state-mn.vue +38 -0
- package/components/icon/state-mo.vue +38 -0
- package/components/icon/state-ms.vue +38 -0
- package/components/icon/state-mt.vue +38 -0
- package/components/icon/state-nc.vue +38 -0
- package/components/icon/state-nd.vue +38 -0
- package/components/icon/state-ne.vue +38 -0
- package/components/icon/state-nh.vue +38 -0
- package/components/icon/state-nj.vue +37 -0
- package/components/icon/state-nm.vue +38 -0
- package/components/icon/state-nv.vue +38 -0
- package/components/icon/state-ny.vue +41 -0
- package/components/icon/state-oh.vue +38 -0
- package/components/icon/state-ok.vue +38 -0
- package/components/icon/state-or.vue +38 -0
- package/components/icon/state-pa.vue +38 -0
- package/components/icon/state-ri.vue +38 -0
- package/components/icon/state-sc.vue +38 -0
- package/components/icon/state-sd.vue +38 -0
- package/components/icon/state-tn.vue +38 -0
- package/components/icon/state-tx.vue +38 -0
- package/components/icon/state-ut.vue +38 -0
- package/components/icon/state-va.vue +38 -0
- package/components/icon/state-vt.vue +38 -0
- package/components/icon/state-wa.vue +38 -0
- package/components/icon/state-wi.vue +38 -0
- package/components/icon/state-wv.vue +38 -0
- package/components/icon/state-wy.vue +38 -0
- package/components/icon/thumbs-up.vue +39 -0
- package/components/icon/trash-can.vue +41 -0
- package/components/icon/tree.vue +37 -0
- package/components/icon/twitter.vue +43 -0
- package/components/icon/upload.vue +41 -0
- package/components/icon/verified.vue +40 -0
- package/components/icon/video-play.vue +41 -0
- package/components/icon/wifi.vue +38 -0
- package/components/icon/x.vue +38 -0
- package/components/icon/youtube.vue +45 -0
- package/composables/forms.ts +124 -0
- package/nuxt.config.ts +83 -1
- package/package.json +47 -13
- package/tsconfig.json +4 -0
- package/types/es-carousel.ts +12 -0
- package/types/index.ts +1 -0
- package/utils/forms.ts +120 -0
- package/utils/get-es-footer-content.ts +90 -0
- package/utils/get-es-nav-bar-account-content.ts +55 -0
- package/utils/get-es-nav-bar-global-content.ts +482 -0
- package/utils/mime-type-finder.ts +48 -0
- package/utils/vuelidate-keys.ts +39 -0
- package/components/TestComponent.vue +0 -5
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import OverlayPanel from 'primevue/overlaypanel';
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
target: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
},
|
|
9
|
+
triggers: {
|
|
10
|
+
type: String,
|
|
11
|
+
required: false,
|
|
12
|
+
default: 'focus',
|
|
13
|
+
},
|
|
14
|
+
show: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
required: false,
|
|
17
|
+
default: false,
|
|
18
|
+
},
|
|
19
|
+
variant: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: false,
|
|
22
|
+
default: 'dark',
|
|
23
|
+
validator: (val: string) => ['light', 'dark'].includes(val as string),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const op = ref<InstanceType<typeof OverlayPanel> | null>(null);
|
|
28
|
+
const slots = useSlots();
|
|
29
|
+
const hasTitle = computed(() => !!slots.title);
|
|
30
|
+
const closePanel = () => {
|
|
31
|
+
op.value?.hide();
|
|
32
|
+
};
|
|
33
|
+
const showPanel = (event: Event) => {
|
|
34
|
+
op.value?.show(event);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
onMounted(() => {
|
|
38
|
+
const targetElement = document.getElementById(props.target);
|
|
39
|
+
if (targetElement) {
|
|
40
|
+
const triggers = props.triggers.split(' ').map((trigger) => (trigger === 'hover' ? 'mouseover' : trigger));
|
|
41
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
42
|
+
for (const trigger of triggers) {
|
|
43
|
+
targetElement.addEventListener(trigger, showPanel);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
watch(
|
|
49
|
+
() => props.show,
|
|
50
|
+
(newVal) => {
|
|
51
|
+
if (newVal) {
|
|
52
|
+
const targetElement = document.getElementById(props.target);
|
|
53
|
+
if (targetElement) {
|
|
54
|
+
const event = new MouseEvent('click', {
|
|
55
|
+
view: window,
|
|
56
|
+
bubbles: true,
|
|
57
|
+
cancelable: true,
|
|
58
|
+
});
|
|
59
|
+
targetElement.dispatchEvent(event);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
closePanel();
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<template>
|
|
69
|
+
<overlay-panel
|
|
70
|
+
ref="op"
|
|
71
|
+
:dismissable="true"
|
|
72
|
+
append-to="body"
|
|
73
|
+
:pt="{
|
|
74
|
+
root: {
|
|
75
|
+
class: `popover b-popover ${props.variant === 'light' ? 'es-popover-light' : 'es-popover-dark'}`,
|
|
76
|
+
},
|
|
77
|
+
transition: {
|
|
78
|
+
enterFromClass: 'es-popover-enter-from',
|
|
79
|
+
enterActiveClass: 'es-popover-enter-active',
|
|
80
|
+
leaveActiveClass: 'es-popover-leave-active',
|
|
81
|
+
leaveToClass: 'es-popover-leave-to',
|
|
82
|
+
},
|
|
83
|
+
}">
|
|
84
|
+
<div class="arrow"></div>
|
|
85
|
+
<template v-if="hasTitle">
|
|
86
|
+
<!-- Title slot content -->
|
|
87
|
+
<h3 class="popover-header">
|
|
88
|
+
<slot name="title" />
|
|
89
|
+
<button
|
|
90
|
+
class="es-popover-close p-0 float-right bg-transparent"
|
|
91
|
+
@click="closePanel">
|
|
92
|
+
<icon-x
|
|
93
|
+
height="20px"
|
|
94
|
+
width="20px" />
|
|
95
|
+
</button>
|
|
96
|
+
</h3>
|
|
97
|
+
</template>
|
|
98
|
+
<!-- Popover Content -->
|
|
99
|
+
<div class="popover-body">
|
|
100
|
+
<div class="d-flex">
|
|
101
|
+
<slot />
|
|
102
|
+
<button
|
|
103
|
+
v-if="!hasTitle"
|
|
104
|
+
class="es-popover-close p-0 pl-50 mb-auto bg-transparent"
|
|
105
|
+
@click="closePanel">
|
|
106
|
+
<icon-x
|
|
107
|
+
height="20px"
|
|
108
|
+
width="20px" />
|
|
109
|
+
</button>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</overlay-panel>
|
|
113
|
+
</template>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
height: {
|
|
4
|
+
type: String,
|
|
5
|
+
default: '50px',
|
|
6
|
+
},
|
|
7
|
+
value: {
|
|
8
|
+
type: Number,
|
|
9
|
+
required: true,
|
|
10
|
+
},
|
|
11
|
+
showPercentage: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
default: true,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const computedHeight = computed(() => {
|
|
18
|
+
const height = props.height.replace(/[^0-9]/g, '');
|
|
19
|
+
return parseInt(height, 10);
|
|
20
|
+
});
|
|
21
|
+
const fillLength = computed(() => computedHeight.value * Math.PI * (props.value / 100) * (90 / computedHeight.value));
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<div v-bind="$attrs">
|
|
26
|
+
<!-- Based on prior art from es-cdgm codebase -->
|
|
27
|
+
<svg
|
|
28
|
+
viewBox="0 0 100 100"
|
|
29
|
+
:height="height"
|
|
30
|
+
:width="height">
|
|
31
|
+
<circle
|
|
32
|
+
class="inner-circle"
|
|
33
|
+
:cx="50"
|
|
34
|
+
:cy="50"
|
|
35
|
+
stroke-width="8"
|
|
36
|
+
r="45%" />
|
|
37
|
+
<!-- The first argument in `stoke-dasharray` is the amount of the circle we want colored
|
|
38
|
+
The second is the gap before the next stroke starts
|
|
39
|
+
Since we don't want another stroke to start, we use a number greater than the
|
|
40
|
+
circumference of the circle (ex: 300). -->
|
|
41
|
+
<template v-if="fillLength > 0">
|
|
42
|
+
<circle
|
|
43
|
+
class="progress-circle"
|
|
44
|
+
:stroke-dasharray="`${fillLength} 300`"
|
|
45
|
+
:cx="50"
|
|
46
|
+
:cy="50"
|
|
47
|
+
r="45%"
|
|
48
|
+
stroke-width="8"
|
|
49
|
+
stroke-linecap="round"
|
|
50
|
+
transform="rotate(-90, 50, 50)" />
|
|
51
|
+
</template>
|
|
52
|
+
<template v-if="showPercentage">
|
|
53
|
+
<text
|
|
54
|
+
x="50%"
|
|
55
|
+
y="52%"
|
|
56
|
+
class="font-weight-boldest text-gray-700 font-size-base"
|
|
57
|
+
dominant-baseline="middle"
|
|
58
|
+
alignment-baseline="middle"
|
|
59
|
+
text-anchor="middle">
|
|
60
|
+
{{ value }}%
|
|
61
|
+
</text>
|
|
62
|
+
</template>
|
|
63
|
+
</svg>
|
|
64
|
+
</div>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
67
|
+
<style lang="scss" scoped>
|
|
68
|
+
@use '@energysage/es-ds-styles/scss/variables' as variables;
|
|
69
|
+
|
|
70
|
+
.inner-circle {
|
|
71
|
+
// position: relative;
|
|
72
|
+
fill: transparent;
|
|
73
|
+
stroke: variables.$gray-200;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.progress-circle {
|
|
77
|
+
// position: relative;
|
|
78
|
+
fill: transparent;
|
|
79
|
+
stroke: variables.$blue-400;
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ProgressBar from 'primevue/progressbar';
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
value: {
|
|
6
|
+
type: Number,
|
|
7
|
+
required: true,
|
|
8
|
+
},
|
|
9
|
+
height: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: '0.3125rem',
|
|
12
|
+
},
|
|
13
|
+
showValue: {
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: false,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
const progressBarPt = {
|
|
19
|
+
value: {
|
|
20
|
+
class: 'EsProgressValue progress-bar',
|
|
21
|
+
style: {
|
|
22
|
+
height: props.height,
|
|
23
|
+
borderRadius: props.value === 100 ? '0' : '0 0.125rem 0.125rem 0',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
</script>
|
|
28
|
+
<template>
|
|
29
|
+
<progress-bar
|
|
30
|
+
class="bg-gray-200 rounded-0"
|
|
31
|
+
:pt="progressBarPt"
|
|
32
|
+
:show-value="showValue"
|
|
33
|
+
:value="value"
|
|
34
|
+
v-bind="$attrs">
|
|
35
|
+
</progress-bar>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface IOptions {
|
|
3
|
+
id: string;
|
|
4
|
+
text: string;
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
value: any;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface IProps {
|
|
11
|
+
id: string;
|
|
12
|
+
label: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
options?: IOptions[];
|
|
15
|
+
inline?: boolean;
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
modelValue?: any;
|
|
18
|
+
}
|
|
19
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
20
|
+
inline: false,
|
|
21
|
+
name: '',
|
|
22
|
+
options: undefined,
|
|
23
|
+
modelValue: undefined,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
defineEmits(['update:model-value']);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<fieldset
|
|
31
|
+
:id="id"
|
|
32
|
+
class="form-group">
|
|
33
|
+
<legend
|
|
34
|
+
:id="`${props.id}-legend`"
|
|
35
|
+
class="font-size-100"
|
|
36
|
+
tabindex="-1">
|
|
37
|
+
{{ props.label }}
|
|
38
|
+
</legend>
|
|
39
|
+
<slot :options="options">
|
|
40
|
+
<es-radio-button
|
|
41
|
+
v-for="option in options"
|
|
42
|
+
:id="option.id"
|
|
43
|
+
:key="option.value"
|
|
44
|
+
:disabled="option?.disabled || false"
|
|
45
|
+
:name="props.name"
|
|
46
|
+
:value="option.value"
|
|
47
|
+
:model-value="props.modelValue"
|
|
48
|
+
:inline="props.inline || false"
|
|
49
|
+
:display-name="option.text"
|
|
50
|
+
@update:model-value="$emit('update:model-value', option.value)" />
|
|
51
|
+
</slot>
|
|
52
|
+
</fieldset>
|
|
53
|
+
</template>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
interface IProps {
|
|
4
|
+
name: string;
|
|
5
|
+
value: any;
|
|
6
|
+
id: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
inline?: boolean;
|
|
9
|
+
displayName?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
13
|
+
disabled: false,
|
|
14
|
+
inline: false,
|
|
15
|
+
displayName: '',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Need to define the implicit emit from v-model, so that it can also get fired
|
|
19
|
+
// from the label clicks
|
|
20
|
+
const emit = defineEmits(['update:modelValue']);
|
|
21
|
+
function handleRadioButtonClick() {
|
|
22
|
+
if (!props.disabled) {
|
|
23
|
+
emit('update:modelValue', props.value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Similar to the API of https://bootstrap-vue.org/docs/components/form-radio#changing-the-option-field-names
|
|
28
|
+
// the value can be a string, number, or simple object. Avoid using complex types in values.
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
const model = defineModel<any>();
|
|
31
|
+
const isChecked = computed(() => props.value === model.value);
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div
|
|
36
|
+
class="custom-control custom-radio"
|
|
37
|
+
:class="{ 'custom-control-inline': props.inline }">
|
|
38
|
+
<input
|
|
39
|
+
:id="id"
|
|
40
|
+
v-model="model"
|
|
41
|
+
:disabled="props.disabled"
|
|
42
|
+
type="radio"
|
|
43
|
+
:name="props.name"
|
|
44
|
+
class="custom-control-input"
|
|
45
|
+
:value="props.value"
|
|
46
|
+
:checked="isChecked"
|
|
47
|
+
@click="handleRadioButtonClick" />
|
|
48
|
+
<label
|
|
49
|
+
class="custom-control-label"
|
|
50
|
+
:for="id"
|
|
51
|
+
@click="handleRadioButtonClick">
|
|
52
|
+
<slot>
|
|
53
|
+
{{ displayName }}
|
|
54
|
+
</slot>
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import Rating from 'primevue/rating';
|
|
3
|
+
|
|
4
|
+
interface IProps {
|
|
5
|
+
rating?: number;
|
|
6
|
+
readOnly?: boolean;
|
|
7
|
+
width?: string;
|
|
8
|
+
height?: string;
|
|
9
|
+
rounded?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
13
|
+
rating: 0,
|
|
14
|
+
readOnly: true,
|
|
15
|
+
width: '20px',
|
|
16
|
+
height: '20px',
|
|
17
|
+
rounded: true, // Round rating to nearest .5
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const model = defineModel<number>();
|
|
21
|
+
model.value = props.rating;
|
|
22
|
+
|
|
23
|
+
// Rounds to nearest .5
|
|
24
|
+
const round = (value: number) => (value ? Math.round(value * 2) / 2 : 0);
|
|
25
|
+
const localRating = computed(() => (props.rounded ? round(model.value as number) : model.value || 0));
|
|
26
|
+
|
|
27
|
+
const showFocus = ref(false);
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div
|
|
32
|
+
v-if="readOnly"
|
|
33
|
+
:aria-label="`${localRating} out of 5 stars`"
|
|
34
|
+
class="bg-transparent rounded-0 text-orange rating">
|
|
35
|
+
<div
|
|
36
|
+
v-for="i in 5"
|
|
37
|
+
:key="i"
|
|
38
|
+
aria-hidden="true">
|
|
39
|
+
<span v-if="i <= localRating">
|
|
40
|
+
<icon-star-full
|
|
41
|
+
:width="width"
|
|
42
|
+
:height="height" />
|
|
43
|
+
</span>
|
|
44
|
+
<span v-else-if="i - 0.5 === localRating">
|
|
45
|
+
<icon-star-half
|
|
46
|
+
:width="width"
|
|
47
|
+
:height="height" />
|
|
48
|
+
</span>
|
|
49
|
+
<span v-else>
|
|
50
|
+
<icon-star-empty
|
|
51
|
+
:width="width"
|
|
52
|
+
:height="height" />
|
|
53
|
+
</span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div v-else>
|
|
57
|
+
<rating
|
|
58
|
+
v-model="model"
|
|
59
|
+
:cancel="false"
|
|
60
|
+
:readonly="readOnly"
|
|
61
|
+
v-bind="$attrs"
|
|
62
|
+
:pt="{
|
|
63
|
+
root: {
|
|
64
|
+
class: 'bg-transparent rounded-0 text-orange rating reactive',
|
|
65
|
+
},
|
|
66
|
+
item: (options) => {
|
|
67
|
+
return {
|
|
68
|
+
class: [
|
|
69
|
+
{
|
|
70
|
+
reactiveStar: true,
|
|
71
|
+
focused: options.context.focused,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
}"
|
|
77
|
+
@focus="showFocus = true"
|
|
78
|
+
@blur="showFocus = false">
|
|
79
|
+
<template #officon>
|
|
80
|
+
<icon-star-empty
|
|
81
|
+
:width="width"
|
|
82
|
+
:height="height" />
|
|
83
|
+
</template>
|
|
84
|
+
<template #onicon>
|
|
85
|
+
<icon-star-full
|
|
86
|
+
:width="width"
|
|
87
|
+
:height="height" />
|
|
88
|
+
</template>
|
|
89
|
+
</rating>
|
|
90
|
+
</div>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<style lang="scss">
|
|
94
|
+
.rating {
|
|
95
|
+
height: auto !important;
|
|
96
|
+
width: auto;
|
|
97
|
+
padding: 0 !important;
|
|
98
|
+
align-items: center !important;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
display: inline-flex !important;
|
|
101
|
+
text-align: center;
|
|
102
|
+
width: auto;
|
|
103
|
+
display: inline-flex !important;
|
|
104
|
+
outline: 0;
|
|
105
|
+
}
|
|
106
|
+
.reactive {
|
|
107
|
+
cursor: pointer !important;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.reactiveStar {
|
|
111
|
+
transition: all 0.15s ease-in-out;
|
|
112
|
+
|
|
113
|
+
&:hover {
|
|
114
|
+
transform: scale(1.5);
|
|
115
|
+
}
|
|
116
|
+
&.focused {
|
|
117
|
+
transform: scale(1.5);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
</style>
|