@energysage/es-ds-components 4.1.0 → 4.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.1.1](https://github.com/EnergySage/es-ds/compare/es-ds-components-v4.1.0...es-ds-components-v4.1.1) (2026-02-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * EsCollapse animation bug and arrow overlap issue ([#1698](https://github.com/EnergySage/es-ds/issues/1698)) ([a87aba7](https://github.com/EnergySage/es-ds/commit/a87aba7e47b0dffebadfefa43f0a7a3dfa6e074f))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @energysage/es-ds-styles bumped from ^3.3.1 to ^3.3.2
16
+
3
17
  ## [4.1.0](https://github.com/EnergySage/es-ds/compare/es-ds-components-v4.0.3...es-ds-components-v4.1.0) (2026-01-12)
4
18
 
5
19
 
@@ -1,96 +1,144 @@
1
1
  <script setup lang="ts">
2
- import Panel from 'primevue/panel';
2
+ import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'reka-ui';
3
3
 
4
- const emit = defineEmits(['toggled', 'userClick']);
5
-
6
- const model = defineModel<boolean>();
7
- const props = defineProps({
8
- border: {
9
- type: Boolean,
10
- default: true,
11
- },
12
- isProgrammaticUntilUserInput: {
13
- type: Boolean,
14
- default: true,
15
- },
16
- visible: {
17
- type: Boolean,
18
- default: false,
19
- },
4
+ interface Props {
5
+ border?: boolean;
6
+ isProgrammaticUntilUserInput?: boolean;
7
+ triggerClass?: string;
8
+ visible?: boolean;
9
+ }
10
+ const props = withDefaults(defineProps<Props>(), {
11
+ border: true,
12
+ isProgrammaticUntilUserInput: true,
13
+ triggerClass: 'text-body',
14
+ visible: false,
20
15
  });
21
16
 
17
+ const emit = defineEmits(['toggled', 'userClick']);
18
+ const model = defineModel<boolean>();
22
19
  const userDeterminedState: Ref<boolean | null> = ref(null);
23
- const uniqueId = useId();
24
20
 
25
21
  // directly determines the expanded/collapsed state of the panel
26
- const expanded = computed(() => {
22
+ const expanded = computed((oldValue: boolean | undefined) => {
23
+ let newValue = !!oldValue;
24
+
27
25
  // if we are meant to start ignoring the programmatic incoming state as soon as the
28
26
  // user interacts with the collapse, and if the user has interacted with the collapse,
29
27
  // use the value from the user's interaction
30
28
  if (props.isProgrammaticUntilUserInput && userDeterminedState.value !== null) {
31
- return userDeterminedState.value;
29
+ newValue = userDeterminedState.value;
30
+ } else {
31
+ // otherwise, use the one-way visible prop or the two-way v-model value
32
+ newValue = props.visible || !!model.value;
33
+ }
34
+
35
+ // if the truthiness of the value has changed, emit event indicating the state has changed
36
+ if (!!oldValue !== !!newValue) {
37
+ emit('toggled', newValue);
32
38
  }
33
39
 
34
- // otherwise, use the one-way visible prop or the two-way v-model value
35
- return props.visible || model.value;
40
+ return newValue;
36
41
  });
37
42
 
38
- const onClick = ({ value }: { value: boolean }) => {
43
+ const onClick = (value: boolean) => {
39
44
  // save the state toggled by the user
40
45
  // convert from "collapsed" semantics internal to the primevue panel
41
46
  // to the "expanded" semantics exposed by this component
42
- userDeterminedState.value = !value;
47
+ userDeterminedState.value = value;
43
48
 
44
49
  // inform the v-model (if any) that the state has changed
45
- model.value = !value;
50
+ model.value = value;
46
51
 
47
- // emit events indicating the state has changed
48
- emit('toggled', !value);
49
- emit('userClick', !value);
52
+ // emit event indicating the state has changed from a user click
53
+ emit('userClick', value);
50
54
  };
51
55
  </script>
52
56
 
53
57
  <template>
54
- <panel
55
- :collapsed="!expanded"
56
- :toggle-button-props="{ 'aria-labelledby': uniqueId }"
57
- :pt="{
58
- header: 'd-flex flex-column justify-content-center position-relative py-100',
59
- icons: 'h-100 position-absolute w-100',
60
- root: border ? 'border-bottom border-top' : '',
61
- toggler: {
62
- // eslint-disable-next-line max-len
63
- class: 'es-collapse-toggler align-items-center btn btn-link d-flex h-100 inline justify-content-end rounded-0 p-0 position-absolute text-body w-100',
64
- },
65
- // https://vuejs.org/guide/built-ins/transition
66
- transition: {
67
- enterActiveClass: 'es-collapse-enter-active',
68
- enterFromClass: 'es-collapse-enter-from',
69
- enterToClass: 'es-collapse-enter-to',
70
- leaveActiveClass: 'es-collapse-leave-active',
71
- leaveFromClass: 'es-collapse-leave-from',
72
- leaveToClass: 'es-collapse-leave-to',
73
- },
58
+ <collapsible-root
59
+ :class="{
60
+ 'border-bottom border-top': border,
74
61
  }"
75
- toggleable
76
- @toggle="onClick">
77
- <template #header>
78
- <div :id="uniqueId">
62
+ :open="expanded"
63
+ :unmount-on-hide="false"
64
+ @update:open="onClick">
65
+ <collapsible-trigger
66
+ class="es-collapse-trigger d-flex justify-content-between text-left position-relative py-100 w-100"
67
+ :class="triggerClass">
68
+ <div class="pr-200">
79
69
  <slot name="title" />
80
70
  </div>
81
- </template>
82
- <template #togglericon>
83
- <icon-chevron-down />
84
- </template>
85
- <slot />
86
- </panel>
71
+ <div class="es-collapse-icon-container position-absolute">
72
+ <icon-chevron-down class="es-collapse-icon" />
73
+ </div>
74
+ </collapsible-trigger>
75
+ <collapsible-content class="es-collapse-content overflow-hidden">
76
+ <slot />
77
+ </collapsible-content>
78
+ </collapsible-root>
87
79
  </template>
80
+
88
81
  <style lang="scss" scoped>
89
82
  @use '@energysage/es-ds-styles/scss/variables' as variables;
90
83
 
91
- :deep(.es-collapse-toggler:focus-visible) {
92
- outline: 2px auto variables.$blue-600;
93
- outline: 2px auto -webkit-focus-ring-color;
94
- outline-offset: 2px;
84
+ $animation-duration: 0.3s;
85
+ $easing-function: cubic-bezier(0.87, 0, 0.13, 1);
86
+
87
+ @keyframes slideDown {
88
+ 0% {
89
+ height: 0;
90
+ }
91
+ 100% {
92
+ height: var(--reka-collapsible-content-height);
93
+ }
94
+ }
95
+
96
+ @keyframes slideUp {
97
+ 0% {
98
+ height: var(--reka-collapsible-content-height);
99
+ }
100
+ 100% {
101
+ height: 0;
102
+ }
103
+ }
104
+
105
+ .es-collapse-trigger {
106
+ background: none;
107
+ border: 0;
108
+ padding: 0;
109
+
110
+ &:focus-visible {
111
+ outline: 2px auto variables.$blue-600;
112
+ outline: 2px auto -webkit-focus-ring-color;
113
+ outline-offset: 4px;
114
+ }
115
+
116
+ .es-collapse-icon-container {
117
+ right: 0;
118
+ top: 50%;
119
+ transform: translateY(-50%);
120
+ }
121
+
122
+ &[data-state='open'] .es-collapse-icon {
123
+ transform: rotate(180deg);
124
+ }
125
+
126
+ @media not (prefers-reduced-motion) {
127
+ .es-collapse-icon {
128
+ transition: transform $animation-duration $easing-function;
129
+ }
130
+ }
131
+ }
132
+
133
+ .es-collapse-content {
134
+ @media not (prefers-reduced-motion) {
135
+ &[data-state='closed'] {
136
+ animation: slideUp $animation-duration $easing-function;
137
+ }
138
+
139
+ &[data-state='open'] {
140
+ animation: slideDown $animation-duration $easing-function;
141
+ }
142
+ }
95
143
  }
96
144
  </style>
@@ -20,52 +20,47 @@ withDefaults(defineProps<IProps>(), {
20
20
  });
21
21
 
22
22
  const emit = defineEmits(['update:show']);
23
-
24
- // Workaround: Reka UI components don't play nice with the Nuxt 3.16+ dev server side rendering while using NPM link
25
- const wrappingComponent = import.meta.dev ? resolveComponent('ClientOnly') : 'span';
26
23
  </script>
27
24
 
28
25
  <template>
29
- <component :is="wrappingComponent">
30
- <popover-root
31
- :open="show"
32
- @update:open="(val) => emit('update:show', val)">
33
- <popover-trigger
34
- class="es-popover-trigger p-0"
35
- :class="{ [triggerClass]: true }">
36
- <span class="sr-only">{{ triggerDescription }}</span>
37
- <slot name="trigger" />
38
- </popover-trigger>
39
- <popover-portal>
40
- <popover-content
41
- class="es-popover-content position-relative"
42
- :class="{
43
- 'text-white': variant === 'dark',
44
- 'es-popover-content--light': variant === 'light',
45
- }"
46
- :collision-padding="collisionPadding"
47
- :side="side">
48
- <popover-close
49
- class="es-popover-close align-items-center d-flex justify-content-center float-right mb-50 ml-50 position-relative"
50
- :class="{ 'es-popover-close--light': variant === 'light' }">
51
- <span class="sr-only">Close</span>
52
- <icon-x
53
- height="20px"
54
- width="20px" />
55
- </popover-close>
56
- <popover-arrow
57
- class="es-popover-arrow"
58
- :class="{ 'es-popover-arrow--light': variant === 'light' }"
59
- :height="12"
60
- rounded
61
- :width="22" />
62
- <slot />
63
- <!-- the cta slot is kept for backwards compatibility but is deprecated -->
64
- <slot name="cta" />
65
- </popover-content>
66
- </popover-portal>
67
- </popover-root>
68
- </component>
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 align-items-center d-flex justify-content-center float-right mb-50 ml-50 position-relative"
46
+ :class="{ 'es-popover-close--light': variant === 'light' }">
47
+ <span class="sr-only">Close</span>
48
+ <icon-x
49
+ height="20px"
50
+ width="20px" />
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
+ <slot />
59
+ <!-- the cta slot is kept for backwards compatibility but is deprecated -->
60
+ <slot name="cta" />
61
+ </popover-content>
62
+ </popover-portal>
63
+ </popover-root>
69
64
  </template>
70
65
 
71
66
  <style lang="scss" scoped>
@@ -17,34 +17,29 @@ interface Props {
17
17
  withDefaults(defineProps<Props>(), {
18
18
  disabled: false,
19
19
  });
20
-
21
- // Workaround: Reka UI components don't play nice with the Nuxt 3.16+ dev server side rendering while using NPM link
22
- const wrappingComponent = import.meta.dev ? resolveComponent('ClientOnly') : 'div';
23
20
  </script>
24
21
 
25
22
  <template>
26
- <component :is="wrappingComponent">
27
- <div
28
- class="d-flex flex-row"
29
- :class="{
30
- 'has-label': $slots.label,
31
- }"
32
- v-bind="$attrs">
33
- <switch-root
34
- :id="switchId"
35
- v-model="model"
36
- :disabled="disabled"
37
- class="es-toggle">
38
- <switch-thumb class="es-toggle-thumb" />
39
- </switch-root>
40
- <label
41
- v-if="$slots.label"
42
- :for="switchId"
43
- class="es-toggle-label">
44
- <slot name="label" />
45
- </label>
46
- </div>
47
- </component>
23
+ <div
24
+ class="d-flex flex-row"
25
+ :class="{
26
+ 'has-label': $slots.label,
27
+ }"
28
+ v-bind="$attrs">
29
+ <switch-root
30
+ :id="switchId"
31
+ v-model="model"
32
+ :disabled="disabled"
33
+ class="es-toggle">
34
+ <switch-thumb class="es-toggle-thumb" />
35
+ </switch-root>
36
+ <label
37
+ v-if="$slots.label"
38
+ :for="switchId"
39
+ class="es-toggle-label">
40
+ <slot name="label" />
41
+ </label>
42
+ </div>
48
43
  </template>
49
44
 
50
45
  <style lang="scss">
@@ -43,60 +43,55 @@ onMounted(() => {
43
43
  const mediaQueryResult = window.matchMedia('(hover: none)') as MediaQueryList;
44
44
  deviceSupportsTouch.value = mediaQueryResult?.matches || false;
45
45
  });
46
-
47
- // Workaround: Reka UI components don't play nice with the Nuxt 3.16+ dev server side rendering while using NPM link
48
- const wrappingComponent = import.meta.dev ? resolveComponent('ClientOnly') : 'span';
49
46
  </script>
50
47
 
51
48
  <template>
52
- <component :is="wrappingComponent">
53
- <tooltip-provider
54
- v-if="!deviceSupportsTouch"
55
- :delay-duration="delayDuration"
56
- :disable-closing-trigger="true">
57
- <tooltip-root
58
- :open="show || internalShow"
59
- @update:open="handleUpdateOpen">
60
- <tooltip-trigger
61
- class="es-tooltip-trigger p-0"
62
- :class="{ [triggerClass]: true }"
63
- @click="handleClick">
64
- <slot name="trigger" />
65
- </tooltip-trigger>
66
- <tooltip-portal>
67
- <tooltip-content
68
- class="es-tooltip-content"
69
- :class="{
70
- 'text-white': variant === 'dark',
71
- 'es-tooltip-content--light': variant === 'light',
72
- }"
73
- :collision-padding="collisionPadding"
74
- :side="side">
75
- <tooltip-arrow
76
- class="es-tooltip-arrow"
77
- :class="{ 'es-tooltip-arrow--light': variant === 'light' }"
78
- :height="12"
79
- rounded
80
- :width="22" />
81
- <slot />
82
- </tooltip-content>
83
- </tooltip-portal>
84
- </tooltip-root>
85
- </tooltip-provider>
86
- <es-popover
87
- v-else
88
- :collision-padding="collisionPadding"
89
- :show="show"
90
- :side="side"
91
- :trigger-class="triggerClass"
92
- :variant="variant"
93
- @update:show="(val: any) => emit('update:show', val)">
94
- <template #trigger>
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">
95
60
  <slot name="trigger" />
96
- </template>
97
- <slot />
98
- </es-popover>
99
- </component>
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: any) => emit('update:show', val)">
90
+ <template #trigger>
91
+ <slot name="trigger" />
92
+ </template>
93
+ <slot />
94
+ </es-popover>
100
95
  </template>
101
96
 
102
97
  <style lang="scss" scoped>
package/nuxt.config.ts CHANGED
@@ -2,6 +2,11 @@
2
2
  export default defineNuxtConfig({
3
3
  compatibilityDate: '2024-04-03',
4
4
 
5
+ // prevents "Cannot read properties of null (reading 'ce')" in SSR/SSG with reka-ui
6
+ build: {
7
+ transpile: ['reka-ui'],
8
+ },
9
+
5
10
  // https://nuxt.com/docs/getting-started/styling#the-css-property
6
11
  css: ['@energysage/es-ds-styles/scss/bootstrap.scss'],
7
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energysage/es-ds-components",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "An EnergySage Vue component library",
@@ -17,21 +17,21 @@
17
17
  "author": "EnergySage",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@energysage/es-ds-styles": "^3.3.1",
21
- "@nuxt/eslint": "^1.0.1",
20
+ "@energysage/es-ds-styles": "^3.3.2",
22
21
  "@nuxtjs/google-fonts": "^3.2.0",
23
22
  "@vuelidate/core": "^2.0.3",
24
23
  "@vuelidate/validators": "^2.0.4",
25
24
  "@vueuse/core": "^13.9.0",
26
25
  "html-truncate": "^1.2.2",
27
- "nuxt": "^4.1.2",
26
+ "nuxt": "^4.3.1",
28
27
  "nuxt-primevue": "^3.0.0",
29
28
  "primevue": "^3.53.0",
30
29
  "prismjs": "^1.29.0",
31
- "reka-ui": "^2.2.0",
32
- "vue": "^3.5.6"
30
+ "reka-ui": "^2.8.0",
31
+ "vue": "^3.5.28"
33
32
  },
34
33
  "devDependencies": {
34
+ "@nuxt/eslint": "^1.14.0",
35
35
  "eslint": "^9.20.1",
36
36
  "eslint-config-prettier": "^10.0.1",
37
37
  "nuxt-primevue": "^3.0.0",