@energysage/es-ds-components 3.0.11 → 3.1.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.
@@ -1,113 +1,141 @@
1
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
- });
2
+ import { PopoverArrow, PopoverClose, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from 'reka-ui';
26
3
 
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
-
42
- for (const trigger of triggers) {
43
- targetElement.addEventListener(trigger, showPanel);
44
- }
45
- }
4
+ interface IProps {
5
+ collisionPadding?: number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>;
6
+ show?: boolean | undefined;
7
+ side?: 'top' | 'right' | 'bottom' | 'left';
8
+ triggerClass?: string;
9
+ triggerDescription?: string;
10
+ variant?: 'light' | 'dark';
11
+ }
12
+
13
+ withDefaults(defineProps<IProps>(), {
14
+ collisionPadding: 0,
15
+ show: undefined,
16
+ side: 'top',
17
+ triggerClass: '',
18
+ triggerDescription: 'More information',
19
+ variant: 'dark',
46
20
  });
47
21
 
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
- );
22
+ const emit = defineEmits(['update:show']);
66
23
  </script>
67
24
 
68
25
  <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">
26
+ <popover-root
27
+ :open="show"
28
+ @update:open="(val) => emit('update:show', val)">
29
+ <popover-trigger
30
+ class="es-popover-trigger p-0"
31
+ :class="{ [triggerClass]: true }">
32
+ <span class="sr-only">{{ triggerDescription }}</span>
33
+ <slot name="trigger" />
34
+ </popover-trigger>
35
+ <popover-portal>
36
+ <popover-content
37
+ class="es-popover-content position-relative"
38
+ :class="{
39
+ 'text-white': variant === 'dark',
40
+ 'es-popover-content--light': variant === 'light',
41
+ }"
42
+ :collision-padding="collisionPadding"
43
+ :side="side">
44
+ <popover-close
45
+ class="es-popover-close position-absolute"
46
+ :class="{ 'es-popover-close--light': variant === 'light' }">
47
+ <span class="sr-only">Close</span>
106
48
  <icon-x
107
49
  height="20px"
108
50
  width="20px" />
109
- </button>
110
- </div>
111
- </div>
112
- </overlay-panel>
51
+ </popover-close>
52
+ <popover-arrow
53
+ class="es-popover-arrow"
54
+ :class="{ 'es-popover-arrow--light': variant === 'light' }"
55
+ :height="12"
56
+ rounded
57
+ :width="22" />
58
+ <div class="pr-300">
59
+ <slot />
60
+ </div>
61
+ <slot name="cta" />
62
+ </popover-content>
63
+ </popover-portal>
64
+ </popover-root>
113
65
  </template>
66
+
67
+ <style lang="scss" scoped>
68
+ @use '@energysage/es-ds-styles/scss/mixins/border-radius' as border-radius;
69
+ @use '@energysage/es-ds-styles/scss/variables' as variables;
70
+
71
+ @keyframes fadeIn {
72
+ from {
73
+ opacity: 0;
74
+ }
75
+ to {
76
+ opacity: 1;
77
+ }
78
+ }
79
+
80
+ @keyframes fadeOut {
81
+ from {
82
+ opacity: 1;
83
+ }
84
+ to {
85
+ opacity: 0;
86
+ }
87
+ }
88
+
89
+ .es-popover-trigger {
90
+ align-items: center;
91
+ background-color: transparent;
92
+ border: none;
93
+ display: inline-flex;
94
+ justify-content: center;
95
+ vertical-align: middle;
96
+ }
97
+
98
+ :deep(.es-popover-content) {
99
+ background-color: variables.$dark-blue;
100
+ @include border-radius.border-radius(variables.$popover-border-radius);
101
+ box-shadow: variables.$popover-box-shadow;
102
+ padding: variables.$popover-header-padding-y variables.$popover-header-padding-x;
103
+ width: 250px;
104
+ z-index: variables.$zindex-popover;
105
+ }
106
+
107
+ :deep(.es-popover-content[data-state='open']) {
108
+ animation: fadeIn 150ms ease;
109
+ }
110
+
111
+ :deep(.es-popover-content[data-state='closed']) {
112
+ animation: fadeOut 150ms ease;
113
+ }
114
+
115
+ :deep(.es-popover-content--light) {
116
+ background-color: variables.$white;
117
+ }
118
+
119
+ :deep(.es-popover-arrow) {
120
+ fill: variables.$dark-blue;
121
+ }
122
+
123
+ :deep(.es-popover-arrow--light) {
124
+ fill: variables.$white;
125
+ }
126
+
127
+ :deep(.es-popover-close) {
128
+ background-color: transparent;
129
+ border: none;
130
+ color: variables.$white;
131
+ height: 28px;
132
+ right: 1rem;
133
+ padding: 0;
134
+ top: 0.75rem;
135
+ width: 28px;
136
+ }
137
+
138
+ :deep(.es-popover-close--light) {
139
+ color: variables.$blue-600;
140
+ }
141
+ </style>
@@ -0,0 +1,171 @@
1
+ <script setup lang="ts">
2
+ import { TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from 'reka-ui';
3
+
4
+ interface IProps {
5
+ collisionPadding?: number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>;
6
+ delayDuration?: number;
7
+ show?: boolean | undefined;
8
+ side?: 'top' | 'right' | 'bottom' | 'left';
9
+ triggerClass?: string;
10
+ variant?: 'light' | 'dark';
11
+ }
12
+
13
+ withDefaults(defineProps<IProps>(), {
14
+ collisionPadding: 0,
15
+ delayDuration: 0,
16
+ show: undefined,
17
+ side: 'top',
18
+ triggerClass: '',
19
+ variant: 'dark',
20
+ });
21
+
22
+ const emit = defineEmits(['update:show']);
23
+
24
+ const deviceSupportsTouch = ref(false);
25
+ const internalShow = ref(false);
26
+
27
+ // provide a workaround for the case where scroll-flipping causes the tooltip
28
+ // to get in a state where it won't reopen on hover (allow user to click to open)
29
+ const handleClick = () => {
30
+ internalShow.value = true;
31
+ emit('update:show', true);
32
+ };
33
+
34
+ // keep the internal boolean up to date when the state changes
35
+ // and also emit the update event up and out
36
+ const handleUpdateOpen = (val: boolean) => {
37
+ internalShow.value = val;
38
+ emit('update:show', val);
39
+ };
40
+
41
+ onMounted(() => {
42
+ // detect if the device supports touch events or not
43
+ const mediaQueryResult = window.matchMedia('(hover: none)') as MediaQueryList;
44
+ deviceSupportsTouch.value = mediaQueryResult?.matches || false;
45
+ });
46
+ </script>
47
+
48
+ <template>
49
+ <tooltip-provider
50
+ v-if="!deviceSupportsTouch"
51
+ :delay-duration="delayDuration"
52
+ :disable-closing-trigger="true">
53
+ <tooltip-root
54
+ :open="show || internalShow"
55
+ @update:open="handleUpdateOpen">
56
+ <tooltip-trigger
57
+ class="es-tooltip-trigger p-0"
58
+ :class="{ [triggerClass]: true }"
59
+ @click="handleClick">
60
+ <slot name="trigger" />
61
+ </tooltip-trigger>
62
+ <tooltip-portal>
63
+ <tooltip-content
64
+ class="es-tooltip-content"
65
+ :class="{
66
+ 'text-white': variant === 'dark',
67
+ 'es-tooltip-content--light': variant === 'light',
68
+ }"
69
+ :collision-padding="collisionPadding"
70
+ :side="side">
71
+ <tooltip-arrow
72
+ class="es-tooltip-arrow"
73
+ :class="{ 'es-tooltip-arrow--light': variant === 'light' }"
74
+ :height="12"
75
+ rounded
76
+ :width="22" />
77
+ <slot />
78
+ </tooltip-content>
79
+ </tooltip-portal>
80
+ </tooltip-root>
81
+ </tooltip-provider>
82
+ <es-popover
83
+ v-else
84
+ :collision-padding="collisionPadding"
85
+ :show="show"
86
+ :side="side"
87
+ :trigger-class="triggerClass"
88
+ :variant="variant"
89
+ @update:show="(val) => emit('update:show', val)">
90
+ <template #trigger>
91
+ <slot name="trigger" />
92
+ </template>
93
+ <slot />
94
+ </es-popover>
95
+ </template>
96
+
97
+ <style lang="scss" scoped>
98
+ @use '@energysage/es-ds-styles/scss/mixins/border-radius' as border-radius;
99
+ @use '@energysage/es-ds-styles/scss/variables' as variables;
100
+
101
+ @keyframes fadeIn {
102
+ from {
103
+ opacity: 0;
104
+ }
105
+ to {
106
+ opacity: 1;
107
+ }
108
+ }
109
+
110
+ @keyframes fadeOut {
111
+ from {
112
+ opacity: 1;
113
+ }
114
+ to {
115
+ opacity: 0;
116
+ }
117
+ }
118
+
119
+ .es-tooltip-trigger {
120
+ align-items: center;
121
+ background-color: transparent;
122
+ border: none;
123
+ display: inline-flex;
124
+ justify-content: center;
125
+ vertical-align: middle;
126
+ }
127
+
128
+ :deep(.es-tooltip-content) {
129
+ background-color: variables.$dark-blue;
130
+ @include border-radius.border-radius(variables.$popover-border-radius);
131
+ box-shadow: variables.$popover-box-shadow;
132
+ padding: variables.$popover-header-padding-y variables.$popover-header-padding-x;
133
+ width: 250px;
134
+ z-index: variables.$zindex-popover;
135
+ }
136
+
137
+ :deep(.es-tooltip-content[data-state='open']) {
138
+ animation: fadeIn 150ms ease;
139
+ }
140
+
141
+ :deep(.es-tooltip-content[data-state='closed']) {
142
+ animation: fadeOut 150ms ease;
143
+ }
144
+
145
+ :deep(.es-tooltip-content--light) {
146
+ background-color: variables.$white;
147
+ }
148
+
149
+ :deep(.es-tooltip-arrow) {
150
+ fill: variables.$dark-blue;
151
+ }
152
+
153
+ :deep(.es-tooltip-arrow--light) {
154
+ fill: variables.$white;
155
+ }
156
+
157
+ :deep(.es-tooltip-close) {
158
+ background-color: transparent;
159
+ border: none;
160
+ color: variables.$white;
161
+ height: 28px;
162
+ right: 1rem;
163
+ padding: 0;
164
+ top: 0.75rem;
165
+ width: 28px;
166
+ }
167
+
168
+ :deep(.es-tooltip-close--light) {
169
+ color: variables.$blue-600;
170
+ }
171
+ </style>
package/nuxt.config.ts CHANGED
@@ -76,6 +76,7 @@ export default defineNuxtConfig({
76
76
  'primevue/slider',
77
77
  'primevue/tabpanel',
78
78
  'primevue/tabview',
79
+ 'reka-ui',
79
80
  ],
80
81
  },
81
82
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energysage/es-ds-components",
3
- "version": "3.0.11",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "An EnergySage Vue component library",
@@ -17,7 +17,7 @@
17
17
  "author": "EnergySage",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@energysage/es-ds-styles": "^3.0.3",
20
+ "@energysage/es-ds-styles": "^3.1.0",
21
21
  "@nuxt/eslint": "^1.0.1",
22
22
  "@nuxtjs/google-fonts": "^3.2.0",
23
23
  "@vuelidate/core": "^2.0.3",
@@ -28,6 +28,7 @@
28
28
  "nuxt-primevue": "^3.0.0",
29
29
  "primevue": "^3.53.0",
30
30
  "prismjs": "^1.29.0",
31
+ "reka-ui": "^2.2.0",
31
32
  "vue": "^3.5.6"
32
33
  },
33
34
  "devDependencies": {