@globalbrain/sefirot 2.0.0-draft.8 → 2.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.
Files changed (182) hide show
  1. package/README.md +6 -6
  2. package/lib/components/SAvatar.vue +17 -17
  3. package/lib/components/SButton.vue +520 -276
  4. package/lib/components/SButtonGroup.vue +149 -0
  5. package/lib/components/SDropdown.vue +26 -150
  6. package/lib/components/SDropdownSection.vue +48 -0
  7. package/lib/components/SDropdownSectionFilter.vue +190 -0
  8. package/lib/components/SDropdownSectionFilterItem.vue +21 -0
  9. package/lib/components/SDropdownSectionFilterItemAvatar.vue +31 -0
  10. package/lib/components/SDropdownSectionFilterItemText.vue +20 -0
  11. package/lib/components/SDropdownSectionMenu.vue +39 -0
  12. package/lib/components/SIcon.vue +13 -0
  13. package/lib/components/SInputBase.vue +31 -31
  14. package/lib/components/SInputCheckbox.vue +4 -3
  15. package/lib/components/SInputCheckboxes.vue +74 -0
  16. package/lib/components/SInputDate.vue +182 -0
  17. package/lib/components/SInputDropdown.vue +159 -157
  18. package/lib/components/SInputDropdownItem.vue +46 -48
  19. package/lib/components/SInputDropdownItemAvatar.vue +99 -0
  20. package/lib/components/SInputDropdownItemText.vue +79 -16
  21. package/lib/components/SInputFile.vue +56 -60
  22. package/lib/components/SInputHMS.vue +120 -110
  23. package/lib/components/SInputNumber.vue +38 -9
  24. package/lib/components/SInputRadio.vue +39 -36
  25. package/lib/components/SInputRadios.vue +40 -53
  26. package/lib/components/SInputSelect.vue +7 -6
  27. package/lib/components/SInputSwitch.vue +193 -0
  28. package/lib/components/SInputSwitches.vue +88 -0
  29. package/lib/components/SInputText.vue +207 -62
  30. package/lib/components/SInputTextarea.vue +46 -32
  31. package/lib/components/SInputYMD.vue +123 -126
  32. package/lib/components/SMarkdown.vue +52 -0
  33. package/lib/components/SModal.vue +33 -57
  34. package/lib/components/SMount.vue +19 -0
  35. package/lib/components/SSheet.vue +50 -55
  36. package/lib/components/SSheetFooter.vue +1 -1
  37. package/lib/components/SSheetFooterAction.vue +24 -17
  38. package/lib/components/SSheetFooterActions.vue +1 -4
  39. package/lib/components/SSheetForm.vue +15 -0
  40. package/lib/components/SSheetMedium.vue +8 -10
  41. package/lib/components/SSheetTitle.vue +7 -14
  42. package/lib/components/SSnackbar.vue +58 -47
  43. package/lib/components/{SPortalSnackbars.vue → SSnackbars.vue} +17 -20
  44. package/lib/components/{icons/SIconPreloader.vue → SSpinner.vue} +5 -4
  45. package/lib/components/SStep.vue +107 -0
  46. package/lib/components/SSteps.vue +59 -0
  47. package/lib/components/STable.vue +242 -0
  48. package/lib/components/STableCell.vue +82 -0
  49. package/lib/components/STableCellAvatar.vue +69 -0
  50. package/lib/components/STableCellAvatars.vue +93 -0
  51. package/lib/components/STableCellDay.vue +40 -0
  52. package/lib/components/STableCellPill.vue +84 -0
  53. package/lib/components/STableCellText.vue +103 -0
  54. package/lib/components/STableColumn.vue +255 -0
  55. package/lib/components/STableFooter.vue +115 -0
  56. package/lib/components/STableHeader.vue +74 -0
  57. package/lib/components/STableItem.vue +38 -0
  58. package/lib/components/STooltip.vue +112 -0
  59. package/lib/composables/Dropdown.ts +40 -99
  60. package/lib/composables/Form.ts +21 -18
  61. package/lib/composables/Grid.ts +117 -0
  62. package/lib/composables/Markdown.ts +138 -0
  63. package/lib/composables/Step.ts +7 -0
  64. package/lib/composables/Table.ts +103 -0
  65. package/lib/composables/Tooltip.ts +91 -0
  66. package/lib/composables/Validation.ts +5 -9
  67. package/lib/composables/markdown/LinkPlugin.ts +45 -0
  68. package/lib/mixins/Sheet.ts +5 -3
  69. package/lib/stores/Snackbars.ts +48 -0
  70. package/lib/{assets/styles → styles}/base.css +0 -0
  71. package/lib/{assets/styles → styles}/bootstrap.css +1 -0
  72. package/lib/{assets/styles → styles}/variables.css +55 -48
  73. package/lib/support/Day.ts +8 -0
  74. package/lib/support/Num.ts +3 -0
  75. package/lib/support/Time.ts +5 -2
  76. package/lib/support/Utils.ts +4 -3
  77. package/lib/types/shims.d.ts +3 -0
  78. package/lib/validation/validators/requiredYmd.ts +1 -1
  79. package/lib/validation/validators/ymd.ts +4 -4
  80. package/package.json +59 -37
  81. package/CHANGELOG.md +0 -47
  82. package/lib/.DS_Store +0 -0
  83. package/lib/components/.DS_Store +0 -0
  84. package/lib/components/SDialog.vue +0 -140
  85. package/lib/components/SDropdownItem.vue +0 -78
  86. package/lib/components/SDropdownItemText.vue +0 -22
  87. package/lib/components/SDropdownItemUser.vue +0 -40
  88. package/lib/components/SInputDropdownItemTextTag.vue +0 -94
  89. package/lib/components/SInputDropdownItemUser.vue +0 -41
  90. package/lib/components/SInputDropdownItemUserTag.vue +0 -100
  91. package/lib/components/SPortalModals.vue +0 -74
  92. package/lib/components/icons/.DS_Store +0 -0
  93. package/lib/components/icons/SIconActivity.vue +0 -5
  94. package/lib/components/icons/SIconArrowDown.vue +0 -5
  95. package/lib/components/icons/SIconArrowLeft.vue +0 -5
  96. package/lib/components/icons/SIconArrowRight.vue +0 -5
  97. package/lib/components/icons/SIconArrowUp.vue +0 -5
  98. package/lib/components/icons/SIconBarChart.vue +0 -7
  99. package/lib/components/icons/SIconBriefcase.vue +0 -5
  100. package/lib/components/icons/SIconBuilding.vue +0 -5
  101. package/lib/components/icons/SIconCalendar.vue +0 -5
  102. package/lib/components/icons/SIconCheck.vue +0 -5
  103. package/lib/components/icons/SIconCheckCircle.vue +0 -6
  104. package/lib/components/icons/SIconCheckCircleThin.vue +0 -6
  105. package/lib/components/icons/SIconCheckSquare.vue +0 -6
  106. package/lib/components/icons/SIconChevronDown.vue +0 -5
  107. package/lib/components/icons/SIconChevronLeft.vue +0 -5
  108. package/lib/components/icons/SIconChevronRight.vue +0 -5
  109. package/lib/components/icons/SIconChevronUp.vue +0 -5
  110. package/lib/components/icons/SIconClock.vue +0 -6
  111. package/lib/components/icons/SIconCode.vue +0 -6
  112. package/lib/components/icons/SIconDatabase.vue +0 -5
  113. package/lib/components/icons/SIconDollarSign.vue +0 -5
  114. package/lib/components/icons/SIconDownload.vue +0 -6
  115. package/lib/components/icons/SIconDownloadCloud.vue +0 -6
  116. package/lib/components/icons/SIconEdit.vue +0 -6
  117. package/lib/components/icons/SIconEdit2.vue +0 -5
  118. package/lib/components/icons/SIconEdit3.vue +0 -6
  119. package/lib/components/icons/SIconEdit3Off.vue +0 -6
  120. package/lib/components/icons/SIconExternalLink.vue +0 -6
  121. package/lib/components/icons/SIconEye.vue +0 -6
  122. package/lib/components/icons/SIconFile.vue +0 -5
  123. package/lib/components/icons/SIconFilePlus.vue +0 -6
  124. package/lib/components/icons/SIconFileText.vue +0 -8
  125. package/lib/components/icons/SIconFlag.vue +0 -5
  126. package/lib/components/icons/SIconGitBranch.vue +0 -5
  127. package/lib/components/icons/SIconGitCommit.vue +0 -5
  128. package/lib/components/icons/SIconGitPullRequest.vue +0 -6
  129. package/lib/components/icons/SIconGlobe.vue +0 -5
  130. package/lib/components/icons/SIconGrab.vue +0 -10
  131. package/lib/components/icons/SIconGrid.vue +0 -8
  132. package/lib/components/icons/SIconHome.vue +0 -5
  133. package/lib/components/icons/SIconImage.vue +0 -6
  134. package/lib/components/icons/SIconInbox.vue +0 -5
  135. package/lib/components/icons/SIconInfo.vue +0 -7
  136. package/lib/components/icons/SIconLayout.vue +0 -5
  137. package/lib/components/icons/SIconList.vue +0 -10
  138. package/lib/components/icons/SIconLock.vue +0 -5
  139. package/lib/components/icons/SIconLogout.vue +0 -6
  140. package/lib/components/icons/SIconMail.vue +0 -6
  141. package/lib/components/icons/SIconMapPin.vue +0 -6
  142. package/lib/components/icons/SIconMoon.vue +0 -5
  143. package/lib/components/icons/SIconMoreHorizontal.vue +0 -7
  144. package/lib/components/icons/SIconMoreVertical.vue +0 -7
  145. package/lib/components/icons/SIconPauseFill.vue +0 -6
  146. package/lib/components/icons/SIconPlayCircle.vue +0 -6
  147. package/lib/components/icons/SIconPlayFill.vue +0 -5
  148. package/lib/components/icons/SIconPlus.vue +0 -5
  149. package/lib/components/icons/SIconPlusCircle.vue +0 -8
  150. package/lib/components/icons/SIconPlusOff.vue +0 -7
  151. package/lib/components/icons/SIconPreloaderDark.vue +0 -52
  152. package/lib/components/icons/SIconPreloaderLight.vue +0 -52
  153. package/lib/components/icons/SIconProgress.vue +0 -5
  154. package/lib/components/icons/SIconRadio.vue +0 -6
  155. package/lib/components/icons/SIconSave.vue +0 -5
  156. package/lib/components/icons/SIconSearch.vue +0 -5
  157. package/lib/components/icons/SIconSend.vue +0 -5
  158. package/lib/components/icons/SIconSettings.vue +0 -6
  159. package/lib/components/icons/SIconShare2.vue +0 -5
  160. package/lib/components/icons/SIconSkipBackFill.vue +0 -6
  161. package/lib/components/icons/SIconSliders.vue +0 -12
  162. package/lib/components/icons/SIconSun.vue +0 -13
  163. package/lib/components/icons/SIconTelescope.vue +0 -5
  164. package/lib/components/icons/SIconTrash.vue +0 -5
  165. package/lib/components/icons/SIconTrash2.vue +0 -7
  166. package/lib/components/icons/SIconTrash2Off.vue +0 -6
  167. package/lib/components/icons/SIconTrello.vue +0 -7
  168. package/lib/components/icons/SIconUser.vue +0 -6
  169. package/lib/components/icons/SIconUsers.vue +0 -8
  170. package/lib/components/icons/SIconWarning.vue +0 -7
  171. package/lib/components/icons/SIconX.vue +0 -5
  172. package/lib/components/icons/SIconXCircle.vue +0 -6
  173. package/lib/components/icons/SIconXCircleThin.vue +0 -6
  174. package/lib/components/icons/SIconXSquare.vue +0 -6
  175. package/lib/components/icons/SIconZap.vue +0 -5
  176. package/lib/composables/Dialog.ts +0 -38
  177. package/lib/composables/Modal.ts +0 -34
  178. package/lib/composables/Snackbar.ts +0 -18
  179. package/lib/store/Sefirot.ts +0 -17
  180. package/lib/store/dialog/index.ts +0 -42
  181. package/lib/store/modal/index.ts +0 -61
  182. package/lib/store/snackbars/index.ts +0 -70
@@ -1,11 +1,38 @@
1
+ <script setup lang="ts">
2
+ import { Validatable } from '../composables/Validation'
3
+ import SInputBase from './SInputBase.vue'
4
+
5
+ export type Size = 'mini' | 'small' | 'medium'
6
+
7
+ const props = defineProps<{
8
+ size?: Size
9
+ name?: string
10
+ label?: string
11
+ note?: string
12
+ help?: string
13
+ text: string
14
+ hideError?: boolean
15
+ modelValue: boolean
16
+ validation?: Validatable
17
+ }>()
18
+
19
+ const emit = defineEmits<{
20
+ (e: 'update:modelValue', value: boolean): void
21
+ }>()
22
+
23
+ function emitChange() {
24
+ emit('update:modelValue', !props.modelValue)
25
+ }
26
+ </script>
27
+
1
28
  <template>
2
29
  <SInputBase
3
30
  class="SInputRadio"
4
- :class="[size]"
31
+ :class="[size ?? 'small']"
5
32
  :label="label"
6
33
  :note="note"
7
34
  :help="help"
8
- :error-message="errorMessage"
35
+ :hide-error="hideError"
9
36
  :validation="validation"
10
37
  >
11
38
  <div class="container">
@@ -20,31 +47,6 @@
20
47
  </SInputBase>
21
48
  </template>
22
49
 
23
- <script setup lang="ts">
24
- import { PropType } from 'vue'
25
- import { Validation } from '../composables/Validation'
26
- import SInputBase from './SInputBase.vue'
27
-
28
- type Size = 'mini' | 'small' | 'medium'
29
-
30
- const props = defineProps({
31
- size: { type: String as PropType<Size>, default: 'small' },
32
- label: { type: String, default: null },
33
- note: { type: String, default: null },
34
- help: { type: String, default: null },
35
- text: { type: String, required: true },
36
- errorMessage: { type: Boolean, default: true },
37
- modelValue: { type: Boolean, required: true },
38
- validation: { type: Object as PropType<Validation>, default: null }
39
- })
40
-
41
- const emit = defineEmits(['update:modelValue'])
42
-
43
- function emitChange() {
44
- emit('update:modelValue', !props.modelValue)
45
- }
46
- </script>
47
-
48
50
  <style lang="postcss" scoped>
49
51
  .container {
50
52
  display: flex;
@@ -58,14 +60,14 @@ function emitChange() {
58
60
 
59
61
  &:hover {
60
62
  .box {
61
- border-color: var(--c-text-1);
63
+ border-color: var(--c-info);
62
64
  }
63
65
  }
64
66
  }
65
67
 
66
68
  .input.on {
67
69
  .box {
68
- border-color: var(--c-text-1);
70
+ border-color: var(--c-info);
69
71
  box-shadow: var(--shadow-depth-3);
70
72
  }
71
73
 
@@ -77,11 +79,12 @@ function emitChange() {
77
79
 
78
80
  .box {
79
81
  position: relative;
80
- border: 2px solid var(--c-text-3);
82
+ border: 1px solid var(--c-divider);
81
83
  border-radius: 50%;
82
- width: 18px;
83
- height: 18px;
84
- transition: border-color .25s, box-shadow .25s;
84
+ width: 16px;
85
+ height: 16px;
86
+ background-color: var(--c-bg);
87
+ transition: border-color 0.25s, box-shadow 0.25s;
85
88
  }
86
89
 
87
90
  .check {
@@ -95,15 +98,15 @@ function emitChange() {
95
98
  align-items: center;
96
99
  border-radius: 50%;
97
100
  width: 100%;
98
- background-color: var(--c-text-1);
101
+ background-color: var(--c-info);
99
102
  opacity: 0;
100
103
  transform: scale(0);
101
- transition: opacity .25s, transform .1s;
104
+ transition: opacity 0.25s, transform 0.1s;
102
105
  }
103
106
 
104
107
  .text {
105
108
  margin: 0;
106
- padding-left: 12px;
109
+ padding-left: 10px;
107
110
  line-height: 20px;
108
111
  font-size: 14px;
109
112
  font-weight: 500;
@@ -1,54 +1,31 @@
1
- <template>
2
- <SInputBase
3
- class="SInputRadios"
4
- :class="[size]"
5
- :label="label"
6
- :note="note"
7
- :help="help"
8
- :error-message="errorMessage"
9
- :validation="validation"
10
- >
11
- <div class="container">
12
- <div class="row">
13
- <div v-for="(option, index) in options" :key="index" class="col">
14
- <SInputRadio
15
- :text="option.label"
16
- :model-value="isChecked(option.value)"
17
- @update:model-value="handleChange(option.value)"
18
- />
19
- </div>
20
- </div>
21
- </div>
22
- </SInputBase>
23
- </template>
24
-
25
1
  <script setup lang="ts">
26
- import { PropType } from 'vue'
27
2
  import { Validatable } from '../composables/Validation'
28
3
  import SInputBase from './SInputBase.vue'
29
4
  import SInputRadio from './SInputRadio.vue'
30
5
 
31
- type Size = 'mini' | 'small' | 'medium'
6
+ export type Size = 'mini' | 'small' | 'medium'
32
7
 
33
- interface Option {
8
+ export interface Option {
34
9
  label: string
35
10
  value: string | number | boolean
36
11
  }
37
12
 
38
- const props = defineProps({
39
- size: { type: String as PropType<Size>, default: 'small' },
40
- name: { type: String, default: null },
41
- label: { type: String, default: null },
42
- note: { type: String, default: null },
43
- help: { type: String, default: null },
44
- nullable: { type: Boolean, default: true },
45
- options: { type: Array as PropType<any[]>, required: true },
46
- errorMessage: { type: Boolean, default: true },
47
- modelValue: { type: [String, Number, Boolean], default: null },
48
- validation: { type: Object as PropType<Validatable>, default: null }
49
- })
13
+ const props = defineProps<{
14
+ size?: Size
15
+ name?: string
16
+ label?: string
17
+ note?: string
18
+ help?: string
19
+ nullable?: boolean
20
+ options: Option[]
21
+ hideError?: boolean
22
+ modelValue: string | number | boolean | null
23
+ validation?: Validatable
24
+ }>()
50
25
 
51
- const emit = defineEmits(['update:modelValue'])
26
+ const emit = defineEmits<{
27
+ (e: 'update:modelValue', value: string | number | boolean | null): void
28
+ }>()
52
29
 
53
30
  function isChecked(value: string | number | boolean) {
54
31
  return value === props.modelValue
@@ -67,16 +44,26 @@ function handleChange(value: string | number | boolean) {
67
44
  }
68
45
  </script>
69
46
 
70
- <style lang="postcss" scoped>
71
- .container {
72
- display: flex;
73
- }
74
-
75
- .row {
76
- margin: -2px -8px;
77
- }
78
-
79
- .col {
80
- padding: 2px 8px;
81
- }
82
- </style>
47
+ <template>
48
+ <SInputBase
49
+ class="SInputRadios"
50
+ :class="[size ?? 'small']"
51
+ :label="label"
52
+ :note="note"
53
+ :help="help"
54
+ :hide-error="hideError"
55
+ :validation="validation"
56
+ >
57
+ <div class="container">
58
+ <div class="row">
59
+ <div v-for="(option, index) in options" :key="index" class="col">
60
+ <SInputRadio
61
+ :text="option.label"
62
+ :model-value="isChecked(option.value)"
63
+ @update:model-value="handleChange(option.value)"
64
+ />
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </SInputBase>
69
+ </template>
@@ -38,18 +38,19 @@
38
38
  </select>
39
39
 
40
40
  <div class="icon" role="button">
41
- <SIconChevronUp class="icon-svg up" />
42
- <SIconChevronDown class="icon-svg down" />
41
+ <SIcon :icon="IconCaretUp" class="icon-svg up" />
42
+ <SIcon :icon="IconCaretDown" class="icon-svg down" />
43
43
  </div>
44
44
  </div>
45
45
  </SInputBase>
46
46
  </template>
47
47
 
48
48
  <script setup lang="ts">
49
+ import IconCaretDown from '@iconify-icons/ph/caret-down'
50
+ import IconCaretUp from '@iconify-icons/ph/caret-up'
49
51
  import { PropType, ref, computed } from 'vue'
50
- import { Validation, Validatable } from '../composables/Validation'
51
- import SIconChevronUp from './icons/SIconChevronUp.vue'
52
- import SIconChevronDown from './icons/SIconChevronDown.vue'
52
+ import { Validatable } from '../composables/Validation'
53
+ import SIcon from './SIcon.vue'
53
54
  import SInputBase from './SInputBase.vue'
54
55
 
55
56
  type Size = 'mini' | 'small' | 'medium'
@@ -226,7 +227,7 @@ function emitChange(e: any): void {
226
227
  display: block;
227
228
  width: 14px;
228
229
  height: 14px;
229
- fill: var(--input-placeholder);
230
+ color: var(--input-placeholder);
230
231
  }
231
232
 
232
233
  .icon-svg.up {
@@ -0,0 +1,193 @@
1
+ <template>
2
+ <SInputBase
3
+ class="SInputSwitch"
4
+ :class="classes"
5
+ :name="name"
6
+ :label="label"
7
+ :note="note"
8
+ :help="help"
9
+ >
10
+ <div class="SInputSwitch-container">
11
+ <div class="SInputSwitch-input" :class="{ on: modelValue }" role="button" @click="emitChange">
12
+ <p v-if="text" class="SInputSwitch-text" :class="[textMode]">{{ text }}</p>
13
+
14
+ <div class="SInputSwitch-box">
15
+ <div class="SInputSwitch-check" />
16
+ </div>
17
+
18
+ <p v-if="textAfter" class="SInputSwitch-text after" :class="[textMode]">{{ textAfter }}</p>
19
+ </div>
20
+ </div>
21
+ </SInputBase>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { computed, PropType } from 'vue'
26
+ import SInputBase from './SInputBase.vue'
27
+
28
+ type Size = 'mini' | 'small'
29
+ type Mode = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
30
+ type TextMode = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
31
+
32
+ const props = defineProps({
33
+ size: { type: String as PropType<Size>, default: 'small' },
34
+ mode: { type: String as PropType<Mode>, default: 'neutral' },
35
+ name: { type: String, default: null },
36
+ label: { type: String, default: null },
37
+ note: { type: String, default: null },
38
+ text: { type: String, default: null },
39
+ textAfter: { type: String, default: null },
40
+ textMode: { type: String as PropType<TextMode>, default: 'neutral' },
41
+ disabled: { type: Boolean, default: false },
42
+ help: { type: String, default: null },
43
+ modelValue: { type: Boolean, required: true }
44
+ })
45
+
46
+ const emit = defineEmits(['update:modelValue'])
47
+
48
+ const classes = computed(() => ({
49
+ mini: props.size === 'mini',
50
+ small: props.size === 'small',
51
+ neutral: props.mode === 'neutral',
52
+ info: props.mode === 'info',
53
+ success: props.mode === 'success',
54
+ warning: props.mode === 'warning',
55
+ danger: props.mode === 'danger',
56
+ disabled: props.disabled
57
+ }))
58
+
59
+ function emitChange(): void {
60
+ !props.disabled && emit('update:modelValue', !props.modelValue)
61
+ }
62
+ </script>
63
+
64
+ <style lang="postcss" scoped>
65
+ .SInputSwitch.mini {
66
+ .SInputSwitch-box {
67
+ margin: 1px 0 0;
68
+ border-radius: 9px;
69
+ width: 36px;
70
+ height: 18px;
71
+ }
72
+
73
+ .SInputSwitch-check {
74
+ top: 2px;
75
+ left: 2px;
76
+ width: 12px;
77
+ height: 12px;
78
+ transition: background-color .25s, transform .25s;
79
+ }
80
+ }
81
+
82
+ .SInputSwitch.small {
83
+ .SInputSwitch-box {
84
+ margin: -1px 0 -1px;
85
+ border-radius: 11px;
86
+ width: 40px;
87
+ height: 22px;
88
+ }
89
+
90
+ .SInputSwitch-check {
91
+ top: 2px;
92
+ left: 2px;
93
+ width: 16px;
94
+ height: 16px;
95
+ transition: background-color .25s, transform .25s;
96
+ }
97
+ }
98
+
99
+ .SInputSwitch.neutral .SInputSwitch-input.on .SInputSwitch-box {
100
+ border-color: var(--c-black);
101
+ background-color: var(--c-black);
102
+ }
103
+
104
+ .SInputSwitch.info .SInputSwitch-input.on .SInputSwitch-box {
105
+ border-color: var(--c-info);
106
+ background-color: var(--c-info);
107
+ }
108
+
109
+ .SInputSwitch.success .SInputSwitch-input.on .SInputSwitch-box {
110
+ border-color: var(--c-success);
111
+ background-color: var(--c-success);
112
+ }
113
+
114
+ .SInputSwitch.warning .SInputSwitch-input.on .SInputSwitch-box {
115
+ border-color: var(--c-warning);
116
+ background-color: var(--c-warning);
117
+ }
118
+
119
+ .SInputSwitch.danger .SInputSwitch-input.on .SInputSwitch-box {
120
+ border-color: var(--c-danger);
121
+ background-color: var(--c-danger);
122
+ }
123
+
124
+ .SInputSwitch.disabled .SInputSwitch-input {
125
+ .SInputSwitch-box {
126
+ cursor: not-allowed;
127
+ opacity: .6;
128
+ }
129
+
130
+ &:hover .SInputSwitch-box { border-color: var(--c-gray); }
131
+ }
132
+
133
+ .SInputSwitch.disabled .SInputSwitch-input.on {
134
+ &:hover .SInputSwitch-box { border-color: transparent; }
135
+ }
136
+
137
+ .SInputSwitch-container {
138
+ display: flex;
139
+ }
140
+
141
+ .SInputSwitch-input {
142
+ position: relative;
143
+ display: flex;
144
+ justify-content: space-between;
145
+ width: 100%;
146
+
147
+ &:hover {
148
+ .SInputSwitch-box { border-color: var(--c-black); }
149
+ .SInputSwitch-check { background-color: var(--c-black); }
150
+ }
151
+ }
152
+
153
+ .SInputSwitch-input.on .SInputSwitch-check {
154
+ background-color: var(--c-white);
155
+ transform: translateX(18px);
156
+ }
157
+
158
+ .SInputSwitch-text {
159
+ flex-grow: 1;
160
+ margin: 0;
161
+ padding-right: 16px;
162
+ line-height: 20px;
163
+ font-size: 14px;
164
+ }
165
+
166
+ .SInputSwitch-text.mute {
167
+ color: var(--c-text-light-2);
168
+ font-weight: 500;
169
+ }
170
+
171
+ .SInputSwitch-text.info { color: var(--c-info); }
172
+ .SInputSwitch-text.success { color: var(--c-success); }
173
+ .SInputSwitch-text.warning { color: var(--c-warning); }
174
+ .SInputSwitch-text.danger { color: var(--c-danger); }
175
+ .SInputSwitch-text.after {
176
+ padding-left: 12px;
177
+ }
178
+
179
+ .SInputSwitch-box {
180
+ position: relative;
181
+ flex-shrink: 0;
182
+ border: 1px solid var(--c-gray);
183
+ background-color: var(--c-white-mute);
184
+ transition: border-color .25s, background-color .25s, box-shadow .25s;
185
+ }
186
+
187
+ .SInputSwitch-check {
188
+ position: absolute;
189
+ border-radius: 50%;
190
+ background-color: var(--c-black);
191
+ transition: background-color .25s, transform .25s;
192
+ }
193
+ </style>
@@ -0,0 +1,88 @@
1
+ <template>
2
+ <SInputBase
3
+ class="SInputSwitches"
4
+ :class="classes"
5
+ :name="name"
6
+ :label="label"
7
+ :note="note"
8
+ :help="help"
9
+ >
10
+ <div class="SInputSwitches-container">
11
+ <div class="SInputSwitches-row">
12
+ <div v-for="option in options" :key="option.value" class="SInputSwitches-col">
13
+ <SInputSwitch
14
+ :size="size"
15
+ :mode="mode"
16
+ :text="option.label"
17
+ :model-value="isChecked(option.value)"
18
+ @update:model-value="handleChange(option.value)"
19
+ />
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </SInputBase>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed, PropType } from 'vue'
28
+ import SInputBase from './SInputBase.vue'
29
+ import SInputSwitch from './SInputSwitch.vue'
30
+
31
+ type Size = 'mini' | 'small'
32
+ type Mode = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
33
+
34
+
35
+ interface Option {
36
+ label: string
37
+ value: any
38
+ }
39
+
40
+ const props = defineProps({
41
+ size: { type: String as PropType<Size>, default: 'small' },
42
+ mode: { type: String as PropType<Mode>, default: 'neutral' },
43
+ name: { type: String, default: null },
44
+ label: { type: String, default: null },
45
+ note: { type: String, default: null },
46
+ help: { type: String, default: null },
47
+ options: { type: Array as PropType<Option[]>, required: true },
48
+ modelValue: { type: Array as PropType<unknown[]>, required: true }
49
+ })
50
+
51
+ const emit = defineEmits(['update:modelValue'])
52
+
53
+ const classes = computed(() => [
54
+ props.size,
55
+ props.mode
56
+ ])
57
+
58
+ function isChecked(value: unknown): boolean {
59
+ return props.modelValue.includes(value)
60
+ }
61
+
62
+ function handleChange(value: unknown): void {
63
+ const difference = props.modelValue
64
+ .filter(v => v !== value)
65
+ .concat(props.modelValue.includes(value) ? [] : [value])
66
+ emit('update:modelValue', difference)
67
+ }
68
+ </script>
69
+
70
+ <style lang="postcss" scoped>
71
+ .SInputSwitches.mini {
72
+ .SInputSwitches-row { margin: -2px -8px; }
73
+ .SInputSwitches-col { padding: 2px 8px; }
74
+ }
75
+
76
+ .SInputSwitches.small {
77
+ .SInputSwitches-row { margin: -4px -8px; }
78
+ .SInputSwitches-col { padding: 4px 8px; }
79
+ }
80
+
81
+ .SInputSwitches-container {
82
+ display: flex;
83
+ }
84
+
85
+ .SInputSwitches-row {
86
+ width: 100%;
87
+ }
88
+ </style>