@energysage/es-ds-components 5.0.0 → 5.0.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,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.0.1](https://github.com/EnergySage/es-ds/compare/es-ds-components-v5.0.0...es-ds-components-v5.0.1) (2026-03-04)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * EsFormRadioCards focus state is no longer applied on select/click ([#1711](https://github.com/EnergySage/es-ds/issues/1711)) ([c1ff4eb](https://github.com/EnergySage/es-ds/commit/c1ff4eb951d06d5de38ad35127adf4e7b8ca47c7))
9
+ * security vulnerabilities in serialize-javascript and minimatch ([#1713](https://github.com/EnergySage/es-ds/issues/1713)) ([3a5e859](https://github.com/EnergySage/es-ds/commit/3a5e85954ca208a7e3a7f510ec04eca6a71ba92f))
10
+
11
+
12
+ ### Dependencies
13
+
14
+ * The following workspace dependencies were updated
15
+ * dependencies
16
+ * @energysage/es-ds-styles bumped from ^3.3.2 to ^3.3.3
17
+
3
18
  ## [5.0.0](https://github.com/EnergySage/es-ds/compare/es-ds-components-v4.2.0...es-ds-components-v5.0.0) (2026-02-23)
4
19
 
5
20
 
@@ -1,9 +1,4 @@
1
1
  <script setup lang="ts">
2
- import { useFocus } from '@vueuse/core';
3
-
4
- const inputElem = useTemplateRef('input-elem');
5
- const { focused: inputFocused } = useFocus(inputElem);
6
-
7
2
  interface IProps {
8
3
  id: string;
9
4
  name: string;
@@ -35,8 +30,8 @@ const isChecked = computed(() => props.value === model.value);
35
30
 
36
31
  <template>
37
32
  <label
38
- class="es-form-radio-card es-card interactive w-100 btn btn-outline-primary"
39
- :class="{ active: isChecked, disabled: props.disabled, focus: isChecked || inputFocused }"
33
+ class="es-form-radio-card user-select-none w-100"
34
+ :class="{ active: isChecked, disabled: props.disabled }"
40
35
  @click="handleRadioButtonClick">
41
36
  <input
42
37
  :id="id"
@@ -53,3 +48,196 @@ const isChecked = computed(() => props.value === model.value);
53
48
  </slot>
54
49
  </label>
55
50
  </template>
51
+
52
+ <style lang="scss" scoped>
53
+ @use '@energysage/es-ds-styles/scss/mixins/breakpoints' as breakpoints;
54
+ @use '@energysage/es-ds-styles/scss/variables' as variables;
55
+ @use 'sass:math';
56
+
57
+ /* padding */
58
+
59
+ $padding-x-mobile: 1rem;
60
+ $padding-y-mobile: 1.5rem;
61
+ $padding-for-radio-mobile: 3rem;
62
+
63
+ $padding-x-desktop: 1.5rem;
64
+ $padding-y-desktop: 1.5rem;
65
+ $padding-for-radio-desktop: 4.5rem;
66
+
67
+ /* sizing */
68
+
69
+ $inner-circle-size-mobile: 11px;
70
+ $outer-circle-size-mobile: 22px;
71
+
72
+ $inner-circle-size-desktop: 15px;
73
+ $outer-circle-size-desktop: 28px;
74
+
75
+ /* calculated positioning */
76
+
77
+ $additional-translate-y-for-vertical-centering: 2px;
78
+
79
+ $inner-circle-translate-x-from-left-mobile: math.div($outer-circle-size-mobile, 2) - math.div(
80
+ $inner-circle-size-mobile,
81
+ 2
82
+ );
83
+ $inner-circle-translate-y-from-top-mobile: $inner-circle-translate-x-from-left-mobile +
84
+ $additional-translate-y-for-vertical-centering;
85
+
86
+ $inner-circle-half-of-dimension-desktop: math.div($inner-circle-size-desktop, 2);
87
+ $outer-circle-half-of-dimension-desktop: math.div($outer-circle-size-desktop, 2);
88
+
89
+ $inner-circle-translate-x-from-left-desktop: $outer-circle-half-of-dimension-desktop -
90
+ $inner-circle-half-of-dimension-desktop;
91
+ $inner-circle-translate-y-from-top-desktop: $inner-circle-translate-x-from-left-desktop +
92
+ $additional-translate-y-for-vertical-centering;
93
+
94
+ .es-form-radio-card {
95
+ /* keep these styles here instead of applying via utility classes so they can be easily overridden by utility classes downstream */
96
+ align-items: center;
97
+ background-color: variables.$white;
98
+ border: 2px solid variables.$gray-200;
99
+ border-radius: 1rem;
100
+ box-shadow:
101
+ 0 0 0 1px transparent,
102
+ 0 4px 12px variables.$gray-50;
103
+ color: variables.$gray-800;
104
+ cursor: pointer;
105
+ font-size: variables.$font-size-300;
106
+ font-weight: variables.$font-weight-bold;
107
+ line-height: 1.2;
108
+ margin-bottom: 1rem;
109
+ padding: $padding-y-mobile $padding-x-mobile $padding-y-mobile $padding-for-radio-mobile;
110
+ position: relative;
111
+ text-align: left;
112
+ transform: translateZ(0);
113
+ transition:
114
+ color 0.15s ease-in-out,
115
+ background-color 0.15s ease-in-out,
116
+ border-color 0.15s ease-in-out,
117
+ box-shadow 0.15s ease-in-out,
118
+ outline 0.15s ease-in-out;
119
+
120
+ @include breakpoints.media-breakpoint-up(lg) {
121
+ font-size: variables.$font-size-400;
122
+ padding: $padding-y-desktop $padding-x-desktop $padding-y-desktop $padding-for-radio-desktop;
123
+ }
124
+
125
+ &::before,
126
+ &::after {
127
+ border-radius: 50%;
128
+ content: '';
129
+ left: $padding-x-mobile;
130
+ position: absolute;
131
+ top: $padding-y-mobile;
132
+
133
+ @include breakpoints.media-breakpoint-up(lg) {
134
+ left: $padding-x-desktop;
135
+ }
136
+ }
137
+
138
+ /* outer circle of radio button */
139
+ &::before {
140
+ border: 2.5px solid variables.$blue-900;
141
+ height: $outer-circle-size-mobile;
142
+ transform: translateY($additional-translate-y-for-vertical-centering);
143
+ width: $outer-circle-size-mobile;
144
+
145
+ @include breakpoints.media-breakpoint-up(lg) {
146
+ height: $outer-circle-size-desktop;
147
+ width: $outer-circle-size-desktop;
148
+ }
149
+ }
150
+
151
+ /* selected state */
152
+ &:not(:disabled):not(.disabled).active {
153
+ border-color: variables.$warm-orange;
154
+ box-shadow:
155
+ 0 0 0 1px transparent,
156
+ variables.$card-interactive-selected-shadow;
157
+ transform: none;
158
+
159
+ /* inner circle of radio button */
160
+ &::after {
161
+ background-color: variables.$blue-900;
162
+ height: $inner-circle-size-mobile;
163
+ transform: translateX($inner-circle-translate-x-from-left-mobile)
164
+ translateY($inner-circle-translate-y-from-top-mobile);
165
+ width: $inner-circle-size-mobile;
166
+
167
+ @include breakpoints.media-breakpoint-up(lg) {
168
+ height: $inner-circle-size-desktop;
169
+ transform: translateX($inner-circle-translate-x-from-left-desktop)
170
+ translateY($inner-circle-translate-y-from-top-desktop);
171
+ width: $inner-circle-size-desktop;
172
+ }
173
+ }
174
+ }
175
+
176
+ &:has(input:focus-visible) {
177
+ outline: 2px solid variables.$blue-600;
178
+ outline-offset: 2px;
179
+ }
180
+
181
+ /* mousedown/touchstart state */
182
+ &:not(:disabled):not(.disabled):active,
183
+ &:not(:disabled):not(.disabled).active:active {
184
+ border-color: variables.$card-interactive-active-border-color;
185
+ box-shadow:
186
+ 0 0 0 1px variables.$card-interactive-active-border-color,
187
+ variables.$card-interactive-selected-active-shadow;
188
+ transform: variables.$btn-active-transform;
189
+ }
190
+
191
+ &.disabled {
192
+ background: variables.$gray-50;
193
+ border-color: variables.$gray-200;
194
+ color: variables.$gray-500;
195
+
196
+ &::before {
197
+ border: 2.5px solid variables.$gray-500;
198
+ }
199
+ }
200
+
201
+ input {
202
+ /**
203
+ * hide the radio button input elements the same way bootstrap vue does.
204
+ * bootstrap vue's styles only work on items directly nested under b-form-radio-group, and we want
205
+ * to enable users to put any elements (e.g. <es-col> and <es-row>) between the EsFormRadioCards and
206
+ * EsFormRadioCard elements.
207
+ */
208
+ clip: rect(0, 0, 0, 0);
209
+ pointer-events: none;
210
+ position: absolute;
211
+ }
212
+ }
213
+
214
+ /* desktop has-icon styling (move radio button to bottom center) */
215
+ @include breakpoints.media-breakpoint-up(lg) {
216
+ .es-form-radio-cards.has-icon {
217
+ .es-form-radio-card {
218
+ padding: $padding-y-desktop $padding-x-desktop $padding-for-radio-desktop $padding-x-desktop;
219
+
220
+ &::before,
221
+ &::after {
222
+ bottom: $padding-y-desktop;
223
+ left: 50%;
224
+ top: auto;
225
+ }
226
+
227
+ /* outer circle of radio button */
228
+ &::before {
229
+ transform: translateX(-$outer-circle-half-of-dimension-desktop);
230
+ }
231
+
232
+ /* selected state */
233
+ &:not(:disabled):not(.disabled).active {
234
+ /* inner circle of radio button */
235
+ &::after {
236
+ transform: translateX(-$inner-circle-half-of-dimension-desktop)
237
+ translateY(-$inner-circle-translate-x-from-left-desktop);
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ </style>
@@ -1,33 +1,31 @@
1
1
  <script setup lang="ts">
2
2
  interface Option {
3
+ disabled?: boolean;
3
4
  id: string;
5
+ inline?: boolean;
4
6
  text: string;
5
-
6
7
  value: any;
7
- disabled?: boolean;
8
- inline?: boolean;
9
8
  }
10
9
 
11
10
  interface Props {
11
+ hasIcon?: boolean;
12
12
  id: string;
13
13
  label: string;
14
+ labelClass?: string;
15
+ labelSrOnly?: boolean;
16
+ modelValue?: any;
14
17
  name?: string;
15
18
  options?: Option[];
16
19
  inline?: boolean;
17
-
18
- modelValue?: any;
19
- hasIcon?: boolean;
20
- labelClass?: string;
21
- labelSrOnly?: boolean;
22
20
  }
23
21
  const props = withDefaults(defineProps<Props>(), {
24
- name: '',
25
- options: undefined,
26
- inline: false,
27
- modelValue: undefined,
28
22
  hasIcon: false,
23
+ inline: false,
29
24
  labelClass: 'font-size-h3',
30
25
  labelSrOnly: false,
26
+ modelValue: undefined,
27
+ name: '',
28
+ options: undefined,
31
29
  });
32
30
 
33
31
  const emit = defineEmits(['update:model-value']);
@@ -40,7 +38,7 @@ function handleUpdate(value: any) {
40
38
  <template>
41
39
  <fieldset
42
40
  :id="`${props.id}-fieldset`"
43
- class="form-group">
41
+ class="mb-100">
44
42
  <legend
45
43
  :id="`${props.id}-legend`"
46
44
  class="font-size-h1 font-weight-bolder mb-200 pb-0 text-dark"
@@ -53,7 +51,7 @@ function handleUpdate(value: any) {
53
51
  :id="`${props.id}-radiogroup`"
54
52
  role="radiogroup"
55
53
  tabindex="-1"
56
- class="es-form-radio-cards d-flex justify-content-center btn-group-vertical"
54
+ class="es-form-radio-cards align-items-stretch d-flex flex-column justify-content-center position-relative"
57
55
  :class="{ 'has-icon': props.hasIcon }">
58
56
  <slot :options="options">
59
57
  <es-form-radio-card
@@ -24,8 +24,10 @@ export default {
24
24
 
25
25
  <template>
26
26
  <svg
27
- width="32"
28
- height="32"
27
+ :style="{
28
+ height: height,
29
+ width: width,
30
+ }"
29
31
  viewBox="0 0 32 32"
30
32
  fill="currentColor"
31
33
  xmlns="http://www.w3.org/2000/svg">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energysage/es-ds-components",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
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.3.2",
20
+ "@energysage/es-ds-styles": "^3.3.3",
21
21
  "@nuxtjs/google-fonts": "^3.2.0",
22
22
  "@vuelidate/core": "^2.0.3",
23
23
  "@vuelidate/validators": "^2.0.4",
@@ -43,6 +43,7 @@
43
43
  },
44
44
  "overrides": {
45
45
  "chokidar": "==3.6.0",
46
- "minimatch": "==10.2.1"
46
+ "minimatch": "==10.2.3",
47
+ "serialize-javascript": "==7.0.3"
47
48
  }
48
49
  }