@rancher/shell 0.3.17 → 0.3.18

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.
Files changed (110) hide show
  1. package/assets/translations/en-us.yaml +8 -4
  2. package/assets/translations/zh-hans.yaml +64 -8
  3. package/components/AsyncButton.vue +1 -1
  4. package/components/Inactivity.vue +10 -0
  5. package/components/LazyImage.vue +2 -2
  6. package/components/PromptRestore.vue +7 -5
  7. package/components/ResourceDetail/Masthead.vue +1 -1
  8. package/components/ResourceDetail/index.vue +4 -2
  9. package/components/__tests__/PromptRestore.test.ts +72 -0
  10. package/components/auth/AzureWarning.vue +1 -1
  11. package/components/fleet/FleetResources.vue +3 -64
  12. package/components/form/FileImageSelector.vue +9 -0
  13. package/components/form/FileSelector.vue +2 -1
  14. package/components/form/MatchExpressions.vue +1 -3
  15. package/components/form/__tests__/FileImageSelector.test.ts +42 -0
  16. package/components/form/__tests__/FileSelector.test.ts +76 -0
  17. package/components/formatter/ClusterProvider.vue +3 -1
  18. package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
  19. package/components/nav/WindowManager/ContainerShell.vue +60 -36
  20. package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
  21. package/config/labels-annotations.js +2 -1
  22. package/config/persistentVolume.ts +108 -0
  23. package/config/product/manager.js +5 -1
  24. package/config/types.js +2 -0
  25. package/core/plugin-helpers.js +19 -3
  26. package/core/types.ts +4 -0
  27. package/detail/fleet.cattle.io.gitrepo.vue +10 -2
  28. package/detail/pod.vue +36 -3
  29. package/detail/workload/index.vue +40 -9
  30. package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
  31. package/edit/fleet.cattle.io.clustergroup.vue +14 -3
  32. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
  33. package/edit/persistentvolume/index.vue +2 -1
  34. package/edit/persistentvolume/plugins/csi.vue +3 -1
  35. package/edit/persistentvolume/plugins/longhorn.vue +12 -12
  36. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
  37. package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
  38. package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -1
  39. package/edit/storage.k8s.io.storageclass/index.vue +1 -2
  40. package/edit/ui.cattle.io.navlink.vue +213 -187
  41. package/layouts/default.vue +1 -1
  42. package/list/group.principal.vue +1 -1
  43. package/middleware/authenticated.js +12 -4
  44. package/mixins/create-edit-view/impl.js +2 -2
  45. package/models/chart.js +1 -1
  46. package/models/fleet.cattle.io.cluster.js +33 -4
  47. package/models/fleet.cattle.io.gitrepo.js +112 -38
  48. package/models/management.cattle.io.kontainerdriver.js +14 -0
  49. package/models/persistentvolume.js +2 -111
  50. package/models/pod.js +30 -0
  51. package/models/rke.cattle.io.etcdsnapshot.js +10 -7
  52. package/package.json +1 -1
  53. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  54. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  55. package/pages/c/_cluster/explorer/index.vue +1 -1
  56. package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
  57. package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
  58. package/pages/c/_cluster/settings/brand.vue +11 -8
  59. package/pages/c/_cluster/uiplugins/index.vue +9 -4
  60. package/pages/home.vue +1 -1
  61. package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
  62. package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
  63. package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
  64. package/plugins/dashboard-store/actions.js +1 -1
  65. package/plugins/dashboard-store/resource-class.js +4 -0
  66. package/plugins/steve/__tests__/getters.spec.ts +93 -0
  67. package/plugins/steve/getters.js +21 -1
  68. package/plugins/steve/subscribe.js +1 -3
  69. package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
  70. package/rancher-components/components/BadgeState/BadgeState.vue +111 -0
  71. package/rancher-components/components/BadgeState/index.ts +1 -0
  72. package/rancher-components/components/Banner/Banner.test.ts +63 -0
  73. package/rancher-components/components/Banner/Banner.vue +244 -0
  74. package/rancher-components/components/Banner/index.ts +1 -0
  75. package/rancher-components/components/Card/Card.test.ts +37 -0
  76. package/rancher-components/components/Card/Card.vue +167 -0
  77. package/rancher-components/components/Card/index.ts +1 -0
  78. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +68 -0
  79. package/rancher-components/components/Form/Checkbox/Checkbox.vue +420 -0
  80. package/rancher-components/components/Form/Checkbox/index.ts +1 -0
  81. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +23 -0
  82. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +355 -0
  83. package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
  84. package/rancher-components/components/Form/Radio/RadioButton.test.ts +31 -0
  85. package/rancher-components/components/Form/Radio/RadioButton.vue +287 -0
  86. package/rancher-components/components/Form/Radio/RadioGroup.vue +254 -0
  87. package/rancher-components/components/Form/Radio/index.ts +2 -0
  88. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +170 -0
  89. package/rancher-components/components/Form/TextArea/index.ts +1 -0
  90. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +94 -0
  91. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +149 -0
  92. package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
  93. package/rancher-components/components/Form/index.ts +5 -0
  94. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +151 -0
  95. package/rancher-components/components/LabeledTooltip/index.ts +1 -0
  96. package/rancher-components/components/StringList/StringList.test.ts +484 -0
  97. package/rancher-components/components/StringList/StringList.vue +611 -0
  98. package/rancher-components/components/StringList/index.ts +1 -0
  99. package/scripts/typegen.sh +10 -2
  100. package/store/index.js +1 -3
  101. package/store/store-types.js +2 -0
  102. package/types/api.d.ts +1 -0
  103. package/types/fleet.d.ts +1 -0
  104. package/types/shell/index.d.ts +695 -2
  105. package/types/userPreferences.d.ts +1 -1
  106. package/utils/__mocks__/socket.js +21 -0
  107. package/utils/grafana.js +23 -11
  108. package/utils/selector.js +2 -1
  109. package/utils/validators/formRules/index.ts +3 -3
  110. package/plugins/steve/urloptions.js +0 -47
@@ -0,0 +1,355 @@
1
+ <script lang="ts">
2
+ import Vue, { VueConstructor } from 'vue';
3
+ import CompactInput from '@shell/mixins/compact-input';
4
+ import LabeledFormElement from '@shell/mixins/labeled-form-element';
5
+ import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow.vue';
6
+ import LabeledTooltip from '@components/LabeledTooltip/LabeledTooltip.vue';
7
+ import { escapeHtml } from '@shell/utils/string';
8
+ import cronstrue from 'cronstrue';
9
+ import { isValidCron } from 'cron-validator';
10
+ import { debounce } from 'lodash';
11
+
12
+ export default (
13
+ Vue as VueConstructor<Vue & InstanceType<typeof LabeledFormElement> & InstanceType<typeof CompactInput>>
14
+ ).extend({
15
+ components: { LabeledTooltip, TextAreaAutoGrow },
16
+ mixins: [LabeledFormElement, CompactInput],
17
+
18
+ props: {
19
+ /**
20
+ * The type of the Labeled Input.
21
+ * @values text, cron, multiline, multiline-password
22
+ */
23
+ type: {
24
+ type: String,
25
+ default: 'text'
26
+ },
27
+
28
+ /**
29
+ * The status class of the Labeled Input and tooltip.
30
+ * @values info, success, warning, error
31
+ */
32
+ status: {
33
+ type: String,
34
+ default: null
35
+ },
36
+
37
+ /**
38
+ * The sub-label for the Labeled Input.
39
+ */
40
+ subLabel: {
41
+ type: String,
42
+ default: null
43
+ },
44
+
45
+ /**
46
+ * The tooltip to display for the Labeled Input.
47
+ */
48
+ tooltip: {
49
+ default: null,
50
+ type: [String, Object]
51
+ },
52
+
53
+ /**
54
+ * Renders the tooltip when hovering the cursor over the Labeled Input.
55
+ */
56
+ hoverTooltip: {
57
+ type: Boolean,
58
+ default: true
59
+ },
60
+
61
+ /**
62
+ * Disables the password manager prompt to save the contents of the Labeled
63
+ * Input.
64
+ */
65
+ ignorePasswordManagers: {
66
+ default: false,
67
+ type: Boolean
68
+ },
69
+
70
+ /**
71
+ * The max length of the Labeled Input.
72
+ */
73
+ maxlength: {
74
+ type: Number,
75
+ default: null
76
+ },
77
+
78
+ /**
79
+ * Hides arrows on the Labeled Input.
80
+ * @deprecated This doesn't appear to be in use for Labeled Input.
81
+ */
82
+ hideArrows: {
83
+ type: Boolean,
84
+ default: false
85
+ },
86
+
87
+ /**
88
+ * Optionally delay on input while typing.
89
+ */
90
+ delay: {
91
+ type: Number,
92
+ default: 0
93
+ }
94
+ },
95
+
96
+ data() {
97
+ return {
98
+ updated: false,
99
+ validationErrors: ''
100
+ };
101
+ },
102
+
103
+ computed: {
104
+ /**
105
+ * Determines if the Labeled Input @input event should be debounced.
106
+ */
107
+ onInput(): ((value: string) => void) | void {
108
+ return this.delay ? debounce(this.delayInput, this.delay) : this.delayInput;
109
+ },
110
+
111
+ /**
112
+ * Determines if the Labeled Input should display a label.
113
+ */
114
+ hasLabel(): boolean {
115
+ return this.isCompact ? false : !!this.label || !!this.labelKey || !!this.$slots.label;
116
+ },
117
+
118
+ /**
119
+ * Determines if the Labeled Input should display a tooltip.
120
+ */
121
+ hasTooltip(): boolean {
122
+ return !!this.tooltip || !!this.tooltipKey;
123
+ },
124
+
125
+ tooltipValue(): string | undefined {
126
+ if (this.hasTooltip) {
127
+ return this.tooltipKey ? this.t(this.tooltipKey) : this.tooltip;
128
+ }
129
+
130
+ return undefined;
131
+ },
132
+
133
+ /**
134
+ * Determines if the Labeled Input makes use of the suffix slot.
135
+ */
136
+ hasSuffix(): boolean {
137
+ return !!this.$slots.suffix;
138
+ },
139
+
140
+ /**
141
+ * Determines if the Labeled Input should display a cron hint.
142
+ */
143
+ cronHint(): string | undefined {
144
+ if (this.type !== 'cron' || !this.value) {
145
+ return;
146
+ }
147
+ if (!isValidCron(this.value)) {
148
+ return this.t('generic.invalidCron');
149
+ }
150
+ try {
151
+ const hint = cronstrue.toString(this.value);
152
+
153
+ return hint;
154
+ } catch (e) {
155
+ return this.t('generic.invalidCron');
156
+ }
157
+ },
158
+
159
+ /**
160
+ * The placeholder value for the Labeled Input.
161
+ */
162
+ _placeholder(): string {
163
+ if (this.placeholder) {
164
+ return this.placeholder.toString();
165
+ }
166
+ if (this.placeholderKey) {
167
+ return this.t(this.placeholderKey);
168
+ }
169
+
170
+ return '';
171
+ },
172
+
173
+ /**
174
+ * The max length for the Labeled Input.
175
+ */
176
+ _maxlength(): number | null {
177
+ if (this.type === 'text' && this.maxlength) {
178
+ return this.maxlength;
179
+ }
180
+
181
+ return null;
182
+ },
183
+ },
184
+
185
+ methods: {
186
+ /**
187
+ * Attempts to give the Labeled Input focus.
188
+ */
189
+ focus(): void {
190
+ const comp = this.$refs.value as HTMLInputElement;
191
+
192
+ if (comp) {
193
+ comp.focus();
194
+ }
195
+ },
196
+
197
+ /**
198
+ * Attempts to select the Labeled Input.
199
+ * @deprecated
200
+ */
201
+ select(): void {
202
+ const comp = this.$refs.value as HTMLInputElement;
203
+
204
+ if (comp) {
205
+ comp.select();
206
+ }
207
+ },
208
+
209
+ /**
210
+ * Emit on input with delay. Note: Arrow function is avoided due context
211
+ * binding.
212
+ */
213
+ delayInput(value: string): void {
214
+ this.$emit('input', value);
215
+ },
216
+
217
+ /**
218
+ * Handles the behavior of the Labeled Input when given focus.
219
+ * @see labeled-form-element.ts mixin for onFocusLabeled()
220
+ */
221
+ onFocus(): void {
222
+ this.onFocusLabeled();
223
+ },
224
+
225
+ /**
226
+ * Handles the behavior of the Labeled Input when blurred and emits the blur
227
+ * event.
228
+ * @see labeled-form-element.ts mixin for onBlurLabeled()
229
+ */
230
+ onBlur(event: string): void {
231
+ this.$emit('blur', event);
232
+ this.onBlurLabeled();
233
+ },
234
+
235
+ escapeHtml
236
+ }
237
+ });
238
+ </script>
239
+
240
+ <template>
241
+ <div
242
+ :class="{
243
+ 'labeled-input': true,
244
+ focused,
245
+ [mode]: true,
246
+ disabled: isDisabled,
247
+ [status]: status,
248
+ suffix: hasSuffix,
249
+ 'has-tooltip': hasTooltip,
250
+ 'compact-input': isCompact,
251
+ hideArrows
252
+ }"
253
+ >
254
+ <slot name="label">
255
+ <label v-if="hasLabel">
256
+ <t
257
+ v-if="labelKey"
258
+ :k="labelKey"
259
+ />
260
+ <template v-else-if="label">{{ label }}</template>
261
+
262
+ <span
263
+ v-if="requiredField"
264
+ class="required"
265
+ >*</span>
266
+ </label>
267
+ </slot>
268
+
269
+ <slot name="prefix" />
270
+
271
+ <slot name="field">
272
+ <TextAreaAutoGrow
273
+ v-if="type === 'multiline' || type === 'multiline-password'"
274
+ ref="value"
275
+ v-bind="$attrs"
276
+ :maxlength="_maxlength"
277
+ :disabled="isDisabled"
278
+ :value="value"
279
+ :placeholder="_placeholder"
280
+ autocapitalize="off"
281
+ :class="{ conceal: type === 'multiline-password' }"
282
+ @input="onInput($event)"
283
+ @focus="onFocus"
284
+ @blur="onBlur"
285
+ />
286
+ <input
287
+ v-else
288
+ ref="value"
289
+ :class="{ 'no-label': !hasLabel }"
290
+ v-bind="$attrs"
291
+ :maxlength="_maxlength"
292
+ :disabled="isDisabled"
293
+ :type="type === 'cron' ? 'text' : type"
294
+ :value="value"
295
+ :placeholder="_placeholder"
296
+ autocomplete="off"
297
+ autocapitalize="off"
298
+ :data-lpignore="ignorePasswordManagers"
299
+ @input="onInput($event.target.value)"
300
+ @focus="onFocus"
301
+ @blur="onBlur"
302
+ >
303
+ </slot>
304
+
305
+ <slot name="suffix" />
306
+ <LabeledTooltip
307
+ v-if="hasTooltip && !focused"
308
+ :hover="hoverTooltip"
309
+ :value="tooltipValue"
310
+ :status="status"
311
+ />
312
+ <LabeledTooltip
313
+ v-if="!!validationMessage"
314
+ :hover="hoverTooltip"
315
+ :value="validationMessage"
316
+ />
317
+ <label
318
+ v-if="cronHint"
319
+ class="cron-label"
320
+ >{{ cronHint }}</label>
321
+ <label
322
+ v-if="subLabel"
323
+ class="sub-label"
324
+ >{{ subLabel }}</label>
325
+ </div>
326
+ </template>
327
+ <style scoped lang="scss">
328
+ .labeled-input.view {
329
+ input {
330
+ text-overflow: ellipsis;
331
+ }
332
+ }
333
+
334
+ .hideArrows {
335
+ /* Hide arrows on number input when it overlaps with the unit */
336
+ /* Chrome, Safari, Edge, Opera */
337
+ input::-webkit-outer-spin-button,
338
+ input::-webkit-inner-spin-button {
339
+ -webkit-appearance: none;
340
+ margin: 0;
341
+ }
342
+
343
+ /* Firefox */
344
+ input[type=number] {
345
+ -moz-appearance: textfield;
346
+ }
347
+ }
348
+ </style>
349
+ <style>
350
+ .validation-message {
351
+ padding: 5px;
352
+ position: absolute;
353
+ bottom: -35px;
354
+ }
355
+ </style>
@@ -0,0 +1 @@
1
+ export { default as LabeledInput } from './LabeledInput.vue';
@@ -0,0 +1,31 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { RadioButton } from './index';
3
+ import { cleanHtmlDirective } from '@shell/plugins/clean-html-directive';
4
+
5
+ describe('radioButton.vue', () => {
6
+ it('renders label slot contents', () => {
7
+ const wrapper = shallowMount(RadioButton, { slots: { label: 'Test Label' } });
8
+
9
+ expect(wrapper.find('.radio-label').text()).toBe('Test Label');
10
+ });
11
+
12
+ it('renders label prop contents', () => {
13
+ const wrapper = shallowMount(
14
+ RadioButton,
15
+ {
16
+ directives: { cleanHtmlDirective },
17
+ propsData: { label: 'Test Label' }
18
+ });
19
+
20
+ expect(wrapper.find('.radio-label').text()).toBe('Test Label');
21
+ });
22
+
23
+ it('renders slot contents when both slot and label prop are provided', () => {
24
+ const wrapper = shallowMount(RadioButton, {
25
+ slots: { label: 'Test Label - Slot' },
26
+ propsData: { label: 'Test Label - Props' },
27
+ });
28
+
29
+ expect(wrapper.find('.radio-label').text()).toBe('Test Label - Slot');
30
+ });
31
+ });
@@ -0,0 +1,287 @@
1
+ <script lang="ts">
2
+ import Vue from 'vue';
3
+ import { _VIEW } from '@shell/config/query-params';
4
+
5
+ export default Vue.extend({
6
+ props: {
7
+ /**
8
+ * The name of the input, for grouping.
9
+ */
10
+ name: {
11
+ type: String,
12
+ default: ''
13
+ },
14
+
15
+ /**
16
+ * The value for this option.
17
+ */
18
+ val: {
19
+ required: true,
20
+ validator: () => true
21
+ },
22
+
23
+ /**
24
+ * The selected value.
25
+ */
26
+ value: {
27
+ required: true,
28
+ validator: () => true
29
+ },
30
+
31
+ /**
32
+ * The label shown next to the radio.
33
+ */
34
+ label: {
35
+ type: String,
36
+ default: ''
37
+ },
38
+
39
+ /**
40
+ * Disable the radio.
41
+ */
42
+ disabled: {
43
+ type: Boolean,
44
+ default: false
45
+ },
46
+
47
+ /**
48
+ * The radio editing mode.
49
+ * @values _EDIT, _VIEW
50
+ */
51
+ mode: {
52
+ type: String,
53
+ default: 'edit'
54
+ },
55
+
56
+ /**
57
+ * The i18n key to use for the radio description.
58
+ */
59
+ descriptionKey: {
60
+ type: String,
61
+ default: null
62
+ },
63
+
64
+ /**
65
+ * The radio description.
66
+ */
67
+ description: {
68
+ type: String,
69
+ default: null
70
+ }
71
+ },
72
+
73
+ data() {
74
+ return { isChecked: this.value === this.val };
75
+ },
76
+
77
+ computed: {
78
+ /**
79
+ * Determines if the radio is disabled.
80
+ */
81
+ isDisabled(): boolean {
82
+ return this.mode === _VIEW || this.disabled;
83
+ },
84
+
85
+ /**
86
+ * Determines if the label for the radio should be muted.
87
+ */
88
+ muteLabel(): boolean {
89
+ // Don't mute the label if the mode is view and the button is checked
90
+ return this.disabled && !(this.mode === _VIEW && this.isChecked);
91
+ },
92
+
93
+ /**
94
+ * Determines if the description slot is in use.
95
+ */
96
+ hasDescriptionSlot(): boolean {
97
+ return !!this.$slots.description;
98
+ },
99
+
100
+ hasLabelSlot(): boolean {
101
+ return !!this.$slots.label || !!this.$scopedSlots.label;
102
+ }
103
+ },
104
+
105
+ watch: {
106
+ value(neu) {
107
+ this.isChecked = this.val === neu;
108
+ if (this.isChecked) {
109
+ (this.$refs.custom as HTMLElement).focus();
110
+ }
111
+ }
112
+ },
113
+
114
+ methods: {
115
+ /**
116
+ * Emits the input event.
117
+ */
118
+ clicked({ target }: { target?: HTMLElement }) {
119
+ if (this.isDisabled || target?.tagName === 'A') {
120
+ return;
121
+ }
122
+
123
+ this.$emit('input', this.val);
124
+ }
125
+ }
126
+ });
127
+ </script>
128
+
129
+ <template>
130
+ <label
131
+ :class="{'disabled': isDisabled, 'radio-container': true}"
132
+ @keydown.enter="clicked($event)"
133
+ @keydown.space="clicked($event)"
134
+ @click.stop="clicked($event)"
135
+ >
136
+ <input
137
+ :id="_uid+'-radio'"
138
+ :disabled="isDisabled"
139
+ :name="name"
140
+ :value="''+val"
141
+ :checked="isChecked"
142
+ type="radio"
143
+ :tabindex="-1"
144
+ @click.stop.prevent
145
+ >
146
+ <span
147
+ ref="custom"
148
+ :class="[ isDisabled ? 'text-muted' : '', 'radio-custom']"
149
+ :tabindex="isDisabled ? -1 : 0"
150
+ :aria-label="label"
151
+ :aria-checked="isChecked"
152
+ role="radio"
153
+ />
154
+ <div class="labeling">
155
+ <label
156
+ :class="[ muteLabel ? 'text-muted' : '', 'radio-label', 'm-0']"
157
+ :for="name"
158
+ >
159
+ <slot
160
+ v-if="hasLabelSlot"
161
+ name="label"
162
+ >
163
+ <!-- slot content -->
164
+ </slot>
165
+ <span
166
+ v-else-if="label"
167
+ v-clean-html="label"
168
+ />
169
+ </label>
170
+ <div
171
+ v-if="descriptionKey || description"
172
+ class="radio-button-outer-container-description"
173
+ >
174
+ <t
175
+ v-if="descriptionKey"
176
+ :k="descriptionKey"
177
+ />
178
+ <template v-else-if="description">
179
+ {{ description }}
180
+ </template>
181
+ </div>
182
+ <div
183
+ v-else-if="hasDescriptionSlot"
184
+ class="radio-button-outer-container-description"
185
+ >
186
+ <slot name="description" />
187
+ </div>
188
+ </div>
189
+ </label>
190
+ </template>
191
+
192
+ <style lang='scss'>
193
+ $fontColor: var(--input-label);
194
+
195
+ .radio-view {
196
+ display: flex;
197
+ flex-direction: column;
198
+ LABEL {
199
+ color: var(--input-label);
200
+ }
201
+ }
202
+
203
+ .radio-group {
204
+ .text-label {
205
+ display: block;
206
+ padding-bottom: 5px;
207
+ }
208
+ }
209
+
210
+ .radio-container {
211
+ position: relative;
212
+ display: inline-flex;
213
+ align-items: flex-start;
214
+ margin: 0;
215
+ user-select: none;
216
+ border-radius: var(--border-radius);
217
+ padding-bottom: 5px;
218
+
219
+ &,
220
+ .radio-label,
221
+ .radio-button-outer-container-description {
222
+ cursor: pointer;
223
+ }
224
+
225
+ &.disabled,
226
+ &.disabled .radio-label,
227
+ &.disabled .radio-button-outer-container-description {
228
+ cursor: not-allowed
229
+ }
230
+
231
+ .radio-custom {
232
+ height: 14px;
233
+ width: 14px;
234
+ min-height: 14px;
235
+ min-width: 14px;
236
+ background-color: var(--input-bg);
237
+ border-radius: 50%;
238
+ transition: all 0.3s ease-out;
239
+ border: 1.5px solid var(--border);
240
+ margin-top: 5px;
241
+
242
+ &:focus {
243
+ outline: none;
244
+ border-radius: 50%;
245
+ }
246
+ }
247
+
248
+ input {
249
+ display: none;
250
+ }
251
+
252
+ .radio-custom {
253
+ &[aria-checked="true"] {
254
+ background-color: var(--primary);
255
+ -webkit-transform: rotate(0deg) scale(1);
256
+ -ms-transform: rotate(0deg) scale(1);
257
+ transform: rotate(0deg) scale(1);
258
+ opacity:1;
259
+ border: 1.5px solid var(--primary);
260
+
261
+ // Ensure that checked radio buttons are muted but still visibly selected when muted
262
+ &.text-muted {
263
+ opacity: .25;
264
+ }
265
+ }
266
+ }
267
+
268
+ input:disabled ~ .radio-custom:not([aria-checked="true"]) {
269
+ background-color: var(--disabled-bg);
270
+ opacity: .25;
271
+ }
272
+
273
+ .radio-button-outer-container-description {
274
+ color: $fontColor;
275
+ font-size: 11px;
276
+ margin-top: 5px;
277
+ }
278
+
279
+ .labeling {
280
+ display: inline-flex;
281
+ flex-direction: column;
282
+
283
+ margin: 3px 10px 0px 5px;
284
+ }
285
+ }
286
+
287
+ </style>