@rancher/shell 0.2.2 → 0.2.3

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 (27) hide show
  1. package/package.json +1 -1
  2. package/rancher-components/BadgeState/BadgeState.spec.ts +12 -0
  3. package/rancher-components/BadgeState/BadgeState.vue +107 -0
  4. package/rancher-components/BadgeState/index.ts +1 -0
  5. package/rancher-components/Banner/Banner.test.ts +13 -0
  6. package/rancher-components/Banner/Banner.vue +163 -0
  7. package/rancher-components/Banner/index.ts +1 -0
  8. package/rancher-components/Card/Card.vue +150 -0
  9. package/rancher-components/Card/index.ts +1 -0
  10. package/rancher-components/Form/Checkbox/Checkbox.test.ts +77 -0
  11. package/rancher-components/Form/Checkbox/Checkbox.vue +395 -0
  12. package/rancher-components/Form/Checkbox/index.ts +1 -0
  13. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +29 -0
  14. package/rancher-components/Form/LabeledInput/LabeledInput.vue +343 -0
  15. package/rancher-components/Form/LabeledInput/index.ts +1 -0
  16. package/rancher-components/Form/Radio/RadioButton.vue +270 -0
  17. package/rancher-components/Form/Radio/RadioGroup.vue +235 -0
  18. package/rancher-components/Form/Radio/index.ts +2 -0
  19. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
  20. package/rancher-components/Form/TextArea/index.ts +1 -0
  21. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
  22. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
  23. package/rancher-components/Form/ToggleSwitch/index.ts +1 -0
  24. package/rancher-components/Form/index.ts +5 -0
  25. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +137 -0
  26. package/rancher-components/LabeledTooltip/index.ts +1 -0
  27. package/scripts/publish-shell.sh +1 -1
@@ -0,0 +1,395 @@
1
+ <script lang="ts">
2
+ import Vue, { PropType } from 'vue';
3
+ import { _EDIT, _VIEW } from '@shell/config/query-params';
4
+ import { addObject, removeObject } from '@shell/utils/array';
5
+
6
+ export default Vue.extend({
7
+ props: {
8
+ /**
9
+ * The checkbox value.
10
+ */
11
+ value: {
12
+ type: [Boolean, Array, String] as PropType<boolean | boolean[] | string>,
13
+ default: false
14
+ },
15
+
16
+ /**
17
+ * The checkbox label.
18
+ */
19
+ label: {
20
+ type: String,
21
+ default: null
22
+ },
23
+
24
+ /**
25
+ * The i18n key to use for the checkbox label.
26
+ */
27
+ labelKey: {
28
+ type: String,
29
+ default: null
30
+ },
31
+
32
+ /**
33
+ * Random ID generated for binding label to input.
34
+ */
35
+ id: {
36
+ type: String,
37
+ default: String(Math.random() * 1000)
38
+ },
39
+
40
+ /**
41
+ * Disable the checkbox.
42
+ */
43
+ disabled: {
44
+ type: Boolean,
45
+ default: false
46
+ },
47
+
48
+ /**
49
+ * Display an indeterminate state. Useful for cases where a checkbox might
50
+ * be the parent to child checkboxes, and we need to show that a subset of
51
+ * children are checked.
52
+ */
53
+ indeterminate: {
54
+ type: Boolean,
55
+ default: false
56
+ },
57
+
58
+ /**
59
+ * The checkbox editing mode.
60
+ * @values _EDIT, _VIEW
61
+ */
62
+ mode: {
63
+ type: String,
64
+ default: _EDIT
65
+ },
66
+
67
+ /**
68
+ * The contents of the checkbox tooltip.
69
+ */
70
+ tooltip: {
71
+ type: [String, Object],
72
+ default: null
73
+ },
74
+
75
+ /**
76
+ * The i18n key to use for the checkbox tooltip.
77
+ */
78
+ tooltipKey: {
79
+ type: String,
80
+ default: null
81
+ },
82
+
83
+ /**
84
+ * A custom value to use when the checkbox is checked.
85
+ */
86
+ valueWhenTrue: {
87
+ type: [Boolean, String, Number],
88
+ default: true
89
+ },
90
+
91
+ /**
92
+ * The i18n key to use for the checkbox description.
93
+ */
94
+ descriptionKey: {
95
+ type: String,
96
+ default: null
97
+ },
98
+
99
+ /**
100
+ * The checkbox description.
101
+ */
102
+ description: {
103
+ type: String,
104
+ default: null
105
+ },
106
+
107
+ /**
108
+ * Primary checkbox displays label so that it stands out more
109
+ */
110
+ primary: {
111
+ type: Boolean,
112
+ default: false
113
+ },
114
+ },
115
+
116
+ computed: {
117
+ /**
118
+ * Determines if the checkbox is disabled.
119
+ * @returns boolean: True when the disabled prop is true or when mode is
120
+ * View.
121
+ */
122
+ isDisabled(): boolean {
123
+ return (this.disabled || this.mode === _VIEW);
124
+ },
125
+ /**
126
+ * Determines if the checkbox is checked when using custom values or
127
+ * multiple values.
128
+ * @returns boolean: True when at least one value is true in a collection or
129
+ * when value matches `this.valueWhenTrue`.
130
+ */
131
+ isChecked(): boolean {
132
+ return this.isMulti(this.value) ? this.findTrueValues(this.value) : this.value === this.valueWhenTrue;
133
+ }
134
+ },
135
+
136
+ methods: {
137
+ /**
138
+ * Toggles the checked state for the checkbox and emits an 'input' event.
139
+ */
140
+ clicked(event: MouseEvent): boolean | void {
141
+ if ((event.target as HTMLLinkElement).tagName === 'A' && (event.target as HTMLLinkElement).href) {
142
+ // Ignore links inside the checkbox label so you can click them
143
+ return true;
144
+ }
145
+
146
+ event.stopPropagation();
147
+ event.preventDefault();
148
+
149
+ if (this.isDisabled) {
150
+ return;
151
+ }
152
+
153
+ const customEvent = {
154
+ bubbles: true,
155
+ cancelable: false,
156
+ shiftKey: event.shiftKey,
157
+ altKey: event.altKey,
158
+ ctrlKey: event.ctrlKey,
159
+ metaKey: event.metaKey
160
+ };
161
+
162
+ const click = new CustomEvent('click', customEvent);
163
+
164
+ // Flip the value
165
+ if (this.isMulti(this.value)) {
166
+ if (this.isChecked) {
167
+ removeObject(this.value, this.valueWhenTrue);
168
+ } else {
169
+ addObject(this.value, this.valueWhenTrue);
170
+ }
171
+ this.$emit('input', this.value);
172
+ } else if (this.isString(this.valueWhenTrue)) {
173
+ if (this.isChecked) {
174
+ this.$emit('input', null);
175
+ } else {
176
+ this.$emit('input', this.valueWhenTrue);
177
+ }
178
+ } else {
179
+ this.$emit('input', !this.value);
180
+ this.$el.dispatchEvent(click);
181
+ }
182
+ },
183
+
184
+ /**
185
+ * Determines if there are multiple values for the checkbox.
186
+ */
187
+ isMulti(value: boolean | boolean[] | string): value is boolean[] {
188
+ return Array.isArray(value);
189
+ },
190
+
191
+ isString(value: boolean | number | string): value is boolean {
192
+ return typeof value === 'string';
193
+ },
194
+
195
+ /**
196
+ * Finds the first true value for multiple checkboxes.
197
+ * @param value A collection of values for the checkbox.
198
+ */
199
+ findTrueValues(value: boolean[]): boolean {
200
+ return value.find(v => v === this.valueWhenTrue) || false;
201
+ }
202
+ }
203
+ });
204
+ </script>
205
+
206
+ <template>
207
+ <div class="checkbox-outer-container" data-checkbox-ctrl>
208
+ <label
209
+ class="checkbox-container"
210
+ :class="{ 'disabled': isDisabled}"
211
+ :for="id"
212
+ @keydown.enter.prevent="clicked($event)"
213
+ @keydown.space.prevent="clicked($event)"
214
+ @click="clicked($event)"
215
+ >
216
+ <input
217
+ v-model="value"
218
+ :checked="isChecked"
219
+ :value="valueWhenTrue"
220
+ type="checkbox"
221
+ :tabindex="-1"
222
+ :name="id"
223
+ @click.stop.prevent
224
+ />
225
+ <span
226
+ class="checkbox-custom"
227
+ :class="{indeterminate: indeterminate}"
228
+ :tabindex="isDisabled ? -1 : 0"
229
+ :aria-label="label"
230
+ :aria-checked="!!value"
231
+ role="checkbox"
232
+ />
233
+ <span
234
+ v-if="$slots.label || label || labelKey || tooltipKey || tooltip"
235
+ class="checkbox-label"
236
+ :class="{ 'checkbox-primary': primary }"
237
+ >
238
+ <slot name="label">
239
+ <t v-if="labelKey" :k="labelKey" :raw="true" />
240
+ <template v-else-if="label">{{ label }}</template>
241
+ <i v-if="tooltipKey" v-tooltip="t(tooltipKey)" class="checkbox-info icon icon-info icon-lg" />
242
+ <i v-else-if="tooltip" v-tooltip="tooltip" class="checkbox-info icon icon-info icon-lg" />
243
+ </slot>
244
+ </span>
245
+ </label>
246
+ <div v-if="descriptionKey || description" class="checkbox-outer-container-description">
247
+ <t v-if="descriptionKey" :k="descriptionKey" />
248
+ <template v-else-if="description">
249
+ {{ description }}
250
+ </template>
251
+ </div>
252
+ </div>
253
+ </template>
254
+
255
+ <style lang='scss'>
256
+ $fontColor: var(--input-label);
257
+
258
+ .checkbox-outer-container {
259
+ display: inline-flex;
260
+ flex-direction: column;
261
+ &-description {
262
+ color: $fontColor;
263
+ font-size: 14px;
264
+ margin-left: 19px;
265
+ margin-top: 5px;
266
+ opacity: 0.8;
267
+ }
268
+ }
269
+
270
+ // NOTE: SortableTable depends on the names of this class, do not arbitrarily change.
271
+ .checkbox-container {
272
+ position: relative;
273
+ display: inline-flex;
274
+ align-items: center;
275
+ margin: 0;
276
+ cursor: pointer;
277
+ user-select: none;
278
+ border-radius: var(--border-radius);
279
+
280
+ .checkbox-label {
281
+ color: var(--input-label);
282
+ display: inline-flex;
283
+ margin: 0px 10px 0px 5px;
284
+
285
+ &.checkbox-primary {
286
+ color: inherit;
287
+ font-weight: 600;
288
+ }
289
+ }
290
+
291
+ .checkbox-info {
292
+ line-height: normal;
293
+ margin-left: 2px;
294
+ }
295
+
296
+ .checkbox-custom {
297
+ height: 14px;
298
+ width: 14px;
299
+ background-color: var(--body-bg);
300
+ border-radius: var(--border-radius);
301
+ transition: all 0.3s ease-out;
302
+ border: 1px solid var(--border);
303
+ }
304
+
305
+ input {
306
+ // display: none;
307
+ opacity: 0;
308
+ position: absolute;
309
+ z-index: -1;
310
+ }
311
+
312
+ input:checked ~ .checkbox-custom {
313
+ background-color:var(--primary);
314
+ -webkit-transform: rotate(0deg) scale(1);
315
+ -ms-transform: rotate(0deg) scale(1);
316
+ transform: rotate(0deg) scale(1);
317
+ opacity:1;
318
+ border: 1px solid var(--primary);
319
+ }
320
+
321
+ // Custom Checkbox tick
322
+ .checkbox-custom::after {
323
+ position: absolute;
324
+ content: "";
325
+ left: 0px;
326
+ top: 0px;
327
+ height: 0px;
328
+ width: 0px;
329
+ border-radius: var(--border-radius);
330
+ border: solid;
331
+ border-color: var(--input-text);
332
+ border-width: 0 3px 3px 0;
333
+ -webkit-transform: rotate(0deg) scale(0);
334
+ -ms-transform: rotate(0deg) scale(0);
335
+ transform: rotate(0deg) scale(0);
336
+ opacity:1;
337
+ }
338
+
339
+ input:checked ~ .checkbox-custom::after {
340
+ -webkit-transform: rotate(45deg) scale(1);
341
+ -ms-transform: rotate(45deg) scale(1);
342
+ transform: rotate(45deg) scale(1);
343
+ opacity:1;
344
+ left: 4px;
345
+ width: 4px;
346
+ height: 10px;
347
+ border: solid;
348
+ border-color: var(--checkbox-tick);
349
+ border-width: 0 2px 2px 0;
350
+ background-color: transparent;
351
+ }
352
+
353
+ input:checked ~ .checkbox-custom.indeterminate::after {
354
+ -webkit-transform: scale(1);
355
+ -ms-transform: scale(1);
356
+ transform: scale(1);
357
+ opacity:1;
358
+ left: 3px;
359
+ top:2px;
360
+ width: 6px;
361
+ height: 5px;
362
+ border: solid;
363
+ border-color: var(--checkbox-tick);
364
+ border-width: 0 0 2px 0;
365
+ background-color: transparent;
366
+ }
367
+
368
+ // Disabled styles
369
+ &.disabled {
370
+ .checkbox-custom {
371
+ background-color: var(--checkbox-disabled-bg);
372
+ border-color: var(--checkbox-disabled-bg);
373
+ }
374
+ input:checked ~ .checkbox-custom {
375
+ background-color: var(--checkbox-disabled-bg);
376
+ border-color: var(--checkbox-disabled-bg);
377
+ &::after {
378
+ border-color: var(--checkbox-tick-disabled);
379
+ }
380
+ }
381
+ }
382
+
383
+ &.disabled {
384
+ cursor: not-allowed;
385
+ }
386
+
387
+ .checkbox-view {
388
+ display: flex;
389
+ flex-direction: column;
390
+ LABEL {
391
+ color: $fontColor;
392
+ }
393
+ }
394
+ }
395
+ </style>
@@ -0,0 +1 @@
1
+ export { default as Checkbox } from './Checkbox.vue';
@@ -0,0 +1,29 @@
1
+
2
+ import { mount } from '@vue/test-utils';
3
+ import { LabeledInput } from './index';
4
+
5
+ describe('component: LabeledInput', () => {
6
+ it('should emit input only once', () => {
7
+ const value = '2';
8
+ const delay = 1;
9
+ const wrapper = mount(LabeledInput, {
10
+ propsData: { delay },
11
+ mocks: {
12
+ $store: {
13
+ getters: {
14
+ 'i18n/t': jest.fn()
15
+ }
16
+ }
17
+ }
18
+ });
19
+
20
+ jest.useFakeTimers();
21
+ wrapper.find('input').setValue('1');
22
+ wrapper.find('input').setValue(value);
23
+ jest.advanceTimersByTime(delay);
24
+ jest.useRealTimers();
25
+
26
+ expect(wrapper.emitted('input')).toHaveLength(1);
27
+ expect(wrapper.emitted('input')![0][0]).toBe(value);
28
+ });
29
+ });