fu-kit 0.5.0 → 0.6.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.
@@ -0,0 +1,206 @@
1
+ <template>
2
+ <label
3
+ :class="{'_disabled': isDisabled, '_checked': modelValue }"
4
+ class="ui-check"
5
+ v-bind="{ class: $attrs.class, style: $attrs.style }"
6
+ @mouseup="mouseUp"
7
+ >
8
+ <input
9
+ ref="inputRef"
10
+ :checked="modelValue"
11
+ class="ui-check_input"
12
+ v-bind="{...$attrs, disabled: isDisabled, type: 'checkbox', class: undefined, style: undefined}"
13
+ @input="$emit('update:modelValue', $event.target.checked)"
14
+ >
15
+ <span
16
+ :class="{
17
+ 'ui-check_switch': switchLike,
18
+ 'ui-check_check': !switchLike,
19
+ _loading: isLoading
20
+ }"
21
+ class="ui-check_box"
22
+ >
23
+ <svg v-if="!switchLike" class="ui-check_check-icon" viewBox="0 0 24 24">
24
+ <path d="m7.5 12.5 4 3 5.5-8" stroke="var(--ui-pal, currentColor)" stroke-linecap="round" stroke-width="2" />
25
+ </svg>
26
+ </span>
27
+ <slot />
28
+ </label>
29
+ </template>
30
+
31
+ <script>
32
+ import { computed, defineComponent, ref } from 'vue'
33
+
34
+ export default defineComponent({
35
+ name: 'ui-check',
36
+ props: {
37
+ modelValue: { type: Boolean, default: false },
38
+ switchLike: { type: Boolean, default: false },
39
+ thin: { type: Boolean, default: false },
40
+ isLoading: { type: Boolean, default: false },
41
+ disabled: { type: Boolean, default: false },
42
+ },
43
+ emits: [ 'update:modelValue' ],
44
+ setup (props) {
45
+ const inputRef = ref(null)
46
+ const isDisabled = computed(() => props.disabled || props.disabled === '')
47
+
48
+
49
+ const mouseUp = () => {
50
+ // oof
51
+ setTimeout(() => {
52
+ inputRef.value.blur()
53
+ }, 0)
54
+ }
55
+
56
+ return { isDisabled, inputRef, mouseUp }
57
+ },
58
+ })
59
+ </script>
60
+ <style lang="scss" scoped>
61
+ @import "../../scss";
62
+
63
+ .ui-check {
64
+ @include typo(200);
65
+
66
+ user-select: none;
67
+ display: flex;
68
+ box-sizing: border-box;
69
+ align-items: center;
70
+ justify-content: var(--ui-check-justify-content, stretch);
71
+ height: var(--ui-lt-h);
72
+ position: relative;
73
+ outline: none;
74
+ color: var(--pal-text-dimm);
75
+ font-family: var(--typo-font-text);
76
+ cursor: pointer;
77
+ line-height: 1;
78
+
79
+ &_input {
80
+ opacity: 0; // weird, but it's working inside the label
81
+ position: absolute;
82
+ left: 0;
83
+ top: 0;
84
+ pointer-events: none;
85
+ }
86
+
87
+ &_check {
88
+ border-style: var(--ui-lt-border-style);
89
+ border-width: var(--ui-check-border-w);
90
+ border-color: var(--pal-grey700);
91
+ height: var(--ui-check-size);
92
+ width: var(--ui-check-size);
93
+ border-radius: var(--ui-lt-border-radius);
94
+ display: flex;
95
+ justify-content: stretch;
96
+ align-items: stretch;
97
+ margin-right: spacing(200);
98
+ transition: all var(--ui-transition);
99
+
100
+ &-icon {
101
+ transition: all var(--ui-transition);
102
+ transform: scale(0);
103
+ width: 100%;
104
+ }
105
+ }
106
+
107
+ &._checked &_check {
108
+ border-color: var(--ui-pal);
109
+ }
110
+
111
+ &._checked &_check-icon {
112
+ transform: scale(1.4);
113
+ }
114
+
115
+ &_switch {
116
+ width: var(--ui-switch-w);
117
+ border-radius: var(--ui-switch-h);
118
+ background-color: var(--pal-grey700);
119
+ border: var(--ui-lt-border-width) solid var(--pal-grey700);
120
+ margin-right: spacing(200);
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: flex-start;
124
+ height: var(--ui-switch-h);
125
+
126
+ --switch-left: 0;
127
+
128
+ &:before {
129
+ transform: translateX(var(--switch-left));
130
+ content: "";
131
+ display: block;
132
+ background-color: white;
133
+ border: var(--ui-lt-border-width) solid transparent;
134
+ border-radius: var(--ui-switch-h);
135
+ height: calc(100% - var(--ui-lt-border-width) * 2);
136
+ aspect-ratio: 1;
137
+ transition: all var(--ui-transition);
138
+ }
139
+ }
140
+
141
+ &._checked &_switch {
142
+ background-color: var(--ui-pal);
143
+ border-color: var(--ui-pal);
144
+ }
145
+
146
+ &._checked &_switch:before {
147
+ --switch-left: calc(var(--ui-switch-w) - var(--ui-switch-h));
148
+ transform: translateX(var(--switch-left));
149
+ }
150
+
151
+ &._checked {
152
+ color: var(--pal-text);
153
+ }
154
+
155
+ &:hover:not(&._disabled) &_box {
156
+ box-shadow: 0 5px 12px -4px rgb(var(--rgb-dark), 0.2);
157
+ }
158
+
159
+ &:hover {
160
+ color: var(--pal-text);
161
+ }
162
+
163
+ &:focus-within &_box {
164
+ box-shadow: 0 0 2px 4px rgba(var(--ui-rgb), 0.3);
165
+ }
166
+
167
+ &._disabled {
168
+ color: var(--ui-pal-disabled-border);
169
+ cursor: not-allowed;
170
+ }
171
+
172
+ &._disabled &_check {
173
+ border: var(--ui-lt-border-width) var(--ui-lt-disabled-border-style) var(--ui-pal-disabled-border);
174
+ box-shadow: none;
175
+ }
176
+
177
+ &._disabled &_switch {
178
+ background-color: rgba(var(--rgb-grey700), 0.25);
179
+ border-color: transparent;
180
+ }
181
+
182
+ &._disabled._checked &_switch {
183
+ background-color: rgba(var(--ui-rgb), 0.3);
184
+ }
185
+ }
186
+
187
+ ._loading {
188
+ animation: pulse 1000ms infinite;
189
+ }
190
+
191
+ @keyframes pulse {
192
+ 40% {
193
+ transform: scale(1.1);
194
+ box-shadow: 0 0 0 5px rgba(var(--ui-rgb), 0.3);
195
+ }
196
+
197
+ 80% {
198
+ transform: scale(1);
199
+ box-shadow: 0 0 0 10px rgba(var(--ui-rgb), 0);
200
+ }
201
+
202
+ 100% {
203
+ box-shadow: 0 0 0 0 rgba(var(--ui-rgb), 0)
204
+ }
205
+ }
206
+ </style>
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <div class="code-input">
3
+ <div class="code-input_wrapper">
4
+ <input
5
+ ref="inp"
6
+ :maxlength="$props.length"
7
+ :value="$props.modelValue"
8
+ class="code-input_inp"
9
+ type="text"
10
+ v-bind="{ ...$attrs }"
11
+ @input="handleInput"
12
+ @focus.passive="selectionUpdate"
13
+ @dragend.passive="selectionUpdate"
14
+ @mouseup.passive="selectionUpdate"
15
+ @keydown.passive="selectionUpdate"
16
+ @keyup.passive="selectionUpdate"
17
+ />
18
+ <div
19
+ v-for="i in $props.length"
20
+ :key="'char' + i"
21
+ :class="{
22
+ '_select': i - 1 >= selection.from && i - 1 < selection.to && selection.from !== selection.to,
23
+ '_cursor': i - 1 === selection.to,
24
+ }"
25
+ class="code-input_char"
26
+ >
27
+ <span class="code-input_char-item">{{ chars[i - 1] || '' }}</span>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script>
34
+ import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
35
+
36
+ export default {
37
+ name: 'ui-code-input',
38
+ props: {
39
+ modelValue: {
40
+ type: String,
41
+ },
42
+ length: {
43
+ type: Number,
44
+ default: 6,
45
+ },
46
+ },
47
+ setup (props, { emit }) {
48
+ const selection = reactive({ from: 0, to: 0 })
49
+ const inp = ref(null)
50
+
51
+ const selectionUpdate = (e) => {
52
+ selection.from = e.target.selectionStart
53
+ selection.to = e.target.selectionEnd
54
+ }
55
+
56
+ const handleInput = (e) => {
57
+ emit('update:modelValue', e.target.value)
58
+ }
59
+
60
+ const chars = computed(() => (props.modelValue).split(''))
61
+
62
+ onMounted(() => { })
63
+ onBeforeUnmount(() => { })
64
+
65
+ return { chars, selection, selectionUpdate, inp, handleInput }
66
+ },
67
+ }
68
+ </script>
69
+
70
+ <style lang="scss" scoped>
71
+ .code-input {
72
+ --charbox-width: 34px;
73
+ --chabox-height: 48px;
74
+
75
+ display: flex;
76
+
77
+ &_wrapper {
78
+ position: relative;
79
+ display: flex;
80
+ justify-content: flex-start;
81
+ align-items: center;
82
+ flex-wrap: nowrap;
83
+ gap: spacing(400);
84
+ }
85
+
86
+ &_inp {
87
+ padding: 14px;
88
+ position: absolute;
89
+ width: 100%;
90
+ border: none;
91
+ background: transparent;
92
+ font-family: var(--typo-font-mono);
93
+ font-size: var(--typo-h200);
94
+ letter-spacing: 41px;
95
+ outline: none;
96
+ opacity: 0;
97
+ }
98
+
99
+ &_char {
100
+ width: var(--charbox-width);
101
+ height: var(--ui-lt-h);
102
+ border: 1px solid var(--charbox-border-color, var(--pal-grey300));
103
+ border-radius: var(--ui-lt-border-radius);
104
+ color: var(--charbox-text-color, var(--pal-grey900));
105
+ align-items: center;
106
+ justify-content: center;
107
+ display: flex;
108
+
109
+ &-item {
110
+ border-width: 2px 0;
111
+ border-style: solid;
112
+ border-color: transparent;
113
+ background: transparent;
114
+ min-width: 0.75em;
115
+ min-height: 1.5em;
116
+ text-align: center;
117
+ }
118
+
119
+ &._select &-item {
120
+ color: var(--pal-white);
121
+ background: var(--pal-primary);
122
+ }
123
+
124
+ input:focus ~ &._cursor {
125
+ border-color: var(--ui-pal);
126
+ }
127
+
128
+ input:focus ~ &._cursor &-item {
129
+ border-bottom-color: var(--pal-black);
130
+ }
131
+ }
132
+ }
133
+ </style>
@@ -1,63 +1,63 @@
1
- <template>
2
- <div class="fu-code-view">
3
- <fu-button-link
4
- v-if="collapse"
5
- class="fu-code-view_toggle"
6
- @click="isShown = !isShown"
7
- >
8
- {{ isShown ? 'Hide' : 'Show' }} {{ label }}
9
- </fu-button-link>
10
- <p class="fu-code-view_title" v-else-if="label">{{ label }}</p>
11
- <pre v-if="collapse ? isShown : true" class="fu-code-view_pre"><slot /></pre>
12
- </div>
13
- </template>
14
-
15
- <script>
16
- import { defineComponent, ref, toRaw } from 'vue'
17
-
18
- import FuButtonLink from './FuButtonLink.vue'
19
-
20
- export default defineComponent({
21
- name: 'fu-code-view',
22
- components: { FuButtonLink },
23
- props: {
24
- label: { type: String, default: '' },
25
- collapse: { type: Boolean, default: null },
26
- },
27
- setup (props) {
28
- const collapse = ref(toRaw(props.collapse))
29
- const isShown = ref(false)
30
- const label = props.label
31
- return { isShown, label, collapse }
32
- },
33
- })
34
- </script>
35
-
36
- <style scoped lang="scss">
37
- @import "../../scss";
38
-
39
- .fu-code-view {
40
- @include spacing-margin(200, 0);
41
-
42
- &_title {
43
- @include typo(100);
44
-
45
- font-weight: bold;
46
- margin-bottom: spacing(200);
47
- }
48
-
49
- &_pre {
50
- @include scrollbar-awesome();
51
- @include spacing-padding(300, 200);
52
-
53
- font-family: var(--typo-font-mono);
54
- overflow: auto;
55
- max-width: 100%;
56
- background: var(--pal-block);
57
- border: 1px solid var(--pal-block-border);
58
- border-radius: var(--ui-lt-border-radius);
59
-
60
- --ui-scroll-bg: var(--pal-block);
61
- }
62
- }
1
+ <template>
2
+ <div class="ui-code-view">
3
+ <ui-button-link
4
+ v-if="collapse"
5
+ class="ui-code-view_toggle"
6
+ @click="isShown = !isShown"
7
+ >
8
+ {{ isShown ? 'Hide' : 'Show' }} {{ label }}
9
+ </ui-button-link>
10
+ <p v-else-if="label" class="ui-code-view_title">{{ label }}</p>
11
+ <pre v-if="collapse ? isShown : true" class="ui-code-view_pre"><slot /></pre>
12
+ </div>
13
+ </template>
14
+
15
+ <script>
16
+ import { defineComponent, ref, toRaw } from 'vue'
17
+
18
+ import UiButtonLink from './UiButtonLink.vue'
19
+
20
+ export default defineComponent({
21
+ name: 'ui-code-view',
22
+ components: { UiButtonLink },
23
+ props: {
24
+ label: { type: String, default: '' },
25
+ collapse: { type: Boolean, default: null },
26
+ },
27
+ setup (props) {
28
+ const collapse = ref(toRaw(props.collapse))
29
+ const isShown = ref(false)
30
+ const label = props.label
31
+ return { isShown, label, collapse }
32
+ },
33
+ })
34
+ </script>
35
+
36
+ <style lang="scss" scoped>
37
+ @import "../../scss";
38
+
39
+ .ui-code-view {
40
+ margin: spacing(200, 0);
41
+
42
+ &_title {
43
+ @include typo(100);
44
+
45
+ font-weight: bold;
46
+ margin-bottom: spacing(200);
47
+ }
48
+
49
+ &_pre {
50
+ @include scrollbar-awesome();
51
+ padding: spacing(300, 200);
52
+
53
+ font-family: var(--typo-font-mono);
54
+ overflow: auto;
55
+ max-width: 100%;
56
+ background: var(--pal-block);
57
+ border: 1px solid var(--pal-block-border);
58
+ border-radius: var(--ui-lt-border-radius);
59
+
60
+ --ui-scroll-bg: var(--pal-block);
61
+ }
62
+ }
63
63
  </style>
@@ -1,24 +1,24 @@
1
1
  <template>
2
- <fu-button
3
- hollow
2
+ <ui-button
3
+ :class="{'_hot': isCopied}"
4
+ :hollow="!isCopied"
5
+ class="ui-copy"
4
6
  v-bind="$attrs"
5
- class="fu-copy"
6
7
  @click="handleCopyToClipboard"
7
- :class="{'_hot': isCopied}"
8
8
  >
9
9
  <slot />
10
- </fu-button>
10
+ </ui-button>
11
11
  </template>
12
12
 
13
13
  <script>
14
14
  import { defineComponent, onBeforeUnmount, ref } from 'vue'
15
- import FuButton from './FuButton.vue'
15
+ import UiButton from './UiButton.vue'
16
16
 
17
17
  export default defineComponent({
18
- name: 'fu-copy',
19
- components: { FuButton },
18
+ name: 'ui-copy',
19
+ components: { UiButton },
20
20
  props: {
21
- value: { type: String, required: true },
21
+ value: { type: [ String, null ], required: true },
22
22
  },
23
23
  setup (props) {
24
24
  const isCopied = ref(false)
@@ -74,36 +74,15 @@ export default defineComponent({
74
74
  <style lang="scss" scoped>
75
75
  @import "../../scss";
76
76
 
77
- .fu-copy {
78
- @include spacing-padding(0, 200);
77
+ .ui-copy {
78
+ padding: spacing(0, 200);
79
79
  @include ellipsis();
80
80
 
81
- // todo: replace on vanilla button to get rid of !important maybe?
82
81
  --ui-lt-h: 2em;
83
- --ui-pal: var(--pal-block-border);
84
- color: var(--pal-text) !important;
85
- overflow: hidden;
86
-
87
- &._hollow {
88
- font-weight: normal;
82
+ --ui-pal: var(--pal-light);
89
83
 
90
- &:active {
91
- box-shadow: none;
92
- }
93
-
94
- &:hover {
95
- box-shadow: none;
96
- }
97
-
98
- &:focus {
99
- box-shadow: none;
100
- }
101
-
102
- &._hot {
103
- transition: none;
104
- border-color: var(--pal-positive);
105
- }
84
+ &._hot {
85
+ color: var(--pal-positive);
106
86
  }
107
-
108
87
  }
109
88
  </style>
@@ -1,15 +1,15 @@
1
1
  <template>
2
2
  <div
3
- class="fu-dropdown"
4
- :class="{ '_is-open': !disabled && isOpen }"
5
3
  v-click-away="isOpen && handleClickaway"
4
+ :class="{ '_is-open': !disabled && isOpen }"
5
+ class="ui-dropdown"
6
6
  >
7
- <div class="fu-dropdown_trigger" @click="toggle">
8
- <slot />
7
+ <div class="ui-dropdown_trigger" @click="toggle">
8
+ <slot :isOpen="!disabled && isOpen" />
9
9
  </div>
10
10
 
11
- <div v-if="!disabled && isOpen" class="fu-dropdown_content" ref="slotWrap">
12
- <slot name="content" :dropdownClose="close" />
11
+ <div v-if="!disabled && isOpen" ref="slotWrap" :class="{ _right: snapToRight }" class="ui-dropdown_content">
12
+ <slot :dropdownClose="close" name="content" />
13
13
  </div>
14
14
  </div>
15
15
  </template>
@@ -22,10 +22,11 @@ import { directive as clickAway } from 'vue3-click-away'
22
22
  import { defineComponent } from 'vue'
23
23
 
24
24
  export default defineComponent({
25
- name: 'fu-dropdown',
25
+ name: 'ui-dropdown',
26
26
  directives: { clickAway },
27
27
  props: {
28
28
  clickaway: { type: Boolean, default: true },
29
+ snapToRight: { type: Boolean, default: false },
29
30
  disabled: { type: Boolean, default: false },
30
31
  },
31
32
  emits: [ 'open', 'close' ],
@@ -65,7 +66,7 @@ export default defineComponent({
65
66
  <style lang="scss" scoped>
66
67
  @import "../../scss";
67
68
 
68
- .fu-dropdown {
69
+ .ui-dropdown {
69
70
  @include typo(200);
70
71
 
71
72
  padding: 0;
@@ -80,24 +81,29 @@ export default defineComponent({
80
81
 
81
82
  &_content {
82
83
  @include scrollbar-awesome();
83
- @include spacing-padding(300, 0);
84
84
 
85
85
  overflow: auto;
86
- max-height: 30vh;
86
+ min-width: 100%;
87
87
  max-width: 100vw;
88
+ max-height: var(--ui-dropdown-max-height);
88
89
  flex-direction: column;
89
90
  justify-content: stretch;
90
- border-width: var(--ui-lt-border-width);
91
91
  border-radius: var(--ui-lt-border-radius);
92
- border-color: var(--ui-pal);
93
- border-style: solid;
94
92
  position: absolute;
95
- left: 0;
96
93
  top: 100%;
97
- min-width: 100%;
98
94
  background: var(--ui-pal-bg);
99
95
  margin-top: spacing(200);
100
96
  z-index: var(--lt-z-pop);
97
+ background: var(--pal-white);
98
+ box-shadow: 0 3px 11px rgba(var(--rgb-black), 0.2);
99
+
100
+ &:not(._right) {
101
+ left: 0;
102
+ }
103
+
104
+ &._right {
105
+ right: 0;
106
+ }
101
107
  }
102
108
  }
103
109
  </style>
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <div
3
- class="fu-dropdown-item"
4
3
  :class="{
5
4
  '_interactive': interactive || autoClose,
6
5
  '_active': active,
7
6
  }"
7
+ class="ui-dropdown-item"
8
8
  @click="handleClick"
9
9
  >
10
10
  <slot />
@@ -15,7 +15,7 @@
15
15
  import { defineComponent } from 'vue'
16
16
 
17
17
  export default defineComponent({
18
- name: 'fu-dropdown-item',
18
+ name: 'ui-dropdown-item',
19
19
  props: {
20
20
  autoClose: { type: Boolean, default: false },
21
21
  interactive: { type: Boolean, default: false },
@@ -35,26 +35,18 @@ export default defineComponent({
35
35
  <style lang="scss" scoped>
36
36
  @import "../../scss";
37
37
 
38
- .fu-dropdown-item {
39
- &:first-child {
40
- margin-top: spacing(200);
41
- }
42
-
43
- &:last-child {
44
- margin-bottom: spacing(200);
45
- }
46
-
47
- padding: spacing(200) calc(#{spacing(200)} + 1px);
38
+ .ui-dropdown-item {
39
+ padding: spacing(200) spacing(400);
48
40
  display: flex;
49
41
  align-items: center;
42
+ min-height: var(--ui-lt-h);
50
43
 
51
44
  &._interactive {
52
45
  color: var(--ui-pal-text);
53
46
  cursor: pointer;
54
47
 
55
48
  &:hover {
56
- color: var(--ui-pal-acc);
57
- background-color: var(--ui-pal);
49
+ color: var(--ui-pal);
58
50
  }
59
51
 
60
52
  &:focus,
@@ -70,10 +62,5 @@ export default defineComponent({
70
62
  &:hover {
71
63
  }
72
64
  }
73
-
74
- &._selected {
75
- color: black;
76
- background-color: orange;
77
- }
78
65
  }
79
66
  </style>