@proj-airi/ui 0.6.1 → 0.7.0-alpha.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,277 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref, watch } from 'vue'
3
+
4
+ const props = withDefaults(defineProps<{
5
+ min?: number
6
+ max?: number
7
+ step?: number
8
+ disabled?: boolean
9
+ }>(), {
10
+ min: 0,
11
+ max: 100,
12
+ step: 1,
13
+ disabled: false,
14
+ })
15
+
16
+ const modelValue = defineModel<number>({ required: true })
17
+
18
+ const scaledMin = computed(() => props.min * 10000)
19
+ const scaledMax = computed(() => props.max * 10000)
20
+ const scaledStep = computed(() => props.step * 10000)
21
+
22
+ const sliderRef = ref<HTMLInputElement>()
23
+ const sliderValue = computed({
24
+ get: () => modelValue.value * 10000,
25
+ set: (value: number) => {
26
+ modelValue.value = value / 10000
27
+ updateTrackColor()
28
+ },
29
+ })
30
+
31
+ onMounted(() => updateTrackColor())
32
+ watch(sliderValue, () => updateTrackColor(), { immediate: true })
33
+ watch([scaledMin, scaledMax, scaledStep], () => updateTrackColor(), { immediate: true })
34
+
35
+ function updateTrackColor() {
36
+ if (!sliderRef.value) {
37
+ return
38
+ }
39
+
40
+ sliderRef.value.style.setProperty('--value', sliderValue.value.toString())
41
+ sliderRef.value.style.setProperty('--min', !sliderRef.value.min ? props.min.toString() : sliderRef.value.min)
42
+ sliderRef.value.style.setProperty('--max', !sliderRef.value.max ? props.max.toString() : sliderRef.value.max)
43
+ }
44
+
45
+ function handleInput(e: Event) {
46
+ const target = e.target as HTMLInputElement
47
+ target.style.setProperty('--value', target.value)
48
+ }
49
+ </script>
50
+
51
+ <template>
52
+ <input
53
+ ref="sliderRef"
54
+ v-model.number="sliderValue"
55
+ type="range"
56
+ :min="scaledMin"
57
+ :max="scaledMax"
58
+ :step="scaledStep"
59
+ class="slider-progress form_input-round-range"
60
+ @input="handleInput"
61
+ >
62
+ </template>
63
+
64
+ <style scoped>
65
+ /*generated with Input range slider CSS style generator (version 20211225)
66
+ https://toughengineer.github.io/demo/slider-styler*/
67
+ .form_input-round-range {
68
+ --height: 2em;
69
+
70
+ min-height: var(--height);
71
+ appearance: none;
72
+ background: transparent;
73
+ border-radius: 4px;
74
+ transition: background-color 0.2s ease;
75
+
76
+ --thumb-width: var(--height);
77
+ --thumb-height: 0px;
78
+ --thumb-box-shadow: none;
79
+ --thumb-border: none;
80
+ --thumb-border-radius: 0px;
81
+ --thumb-background: rgb(255, 255, 255);
82
+
83
+ --track-height: calc(var(--height) - var(--track-value-padding) * 2);
84
+ --track-box-shadow: 0 0 12px -2px rgb(0 0 0 / 22%);
85
+ --track-border: none;
86
+ --track-border-radius: 10px;
87
+ --track-background: rgba(0, 0, 0, 0.4);
88
+
89
+ --track-value-background: rgb(255, 255, 255);
90
+ --track-value-padding: 0px;
91
+ }
92
+
93
+ [data-direction="vertical"].form_input-round-range {
94
+ transform: rotate(180deg);
95
+ }
96
+
97
+ .dark .form_input-round-range {
98
+ --thumb-background: rgb(238, 238, 238);
99
+
100
+ --track-border: none;
101
+ --track-background: rgba(99, 99, 99, 0.7);
102
+ --track-box-shadow: 0 0 12px -2px rgb(0 0 0 / 22%);
103
+
104
+ --track-value-background: rgb(238, 238, 238);
105
+ }
106
+
107
+ /*progress support*/
108
+ .form_input-round-range.slider-progress {
109
+ --range: calc(var(--max) - var(--min));
110
+ --ratio: calc((var(--value) - var(--min)) / var(--range));
111
+ --sx: calc(0.5 * 0em + var(--ratio) * (100% - 0em));
112
+ }
113
+
114
+ .form_input-round-range:focus {
115
+ outline: none;
116
+ }
117
+
118
+ /*webkit*/
119
+ .form_input-round-range::-webkit-slider-thumb {
120
+ appearance: none;
121
+ width: var(--thumb-width);
122
+ height: var(--thumb-height);
123
+ border-radius: var(--thumb-border-radius);
124
+ background: var(--thumb-background);
125
+ border: var(--thumb-border);
126
+ box-shadow: var(--thumb-box-shadow);
127
+ margin-top: 0px;
128
+ margin-left: calc(0 - var(--track-value-padding));
129
+ cursor: col-resize;
130
+ transition:
131
+ background 0.2s ease-in-out,
132
+ box-shadow 0.2s ease-in-out,
133
+ border-color 0.2s ease-in-out,
134
+ transform 0.2s cubic-bezier(0.165, 0.84, 0.44, 1),
135
+ width 0.2s cubic-bezier(0.165, 0.84, 0.44, 1);
136
+ }
137
+
138
+ [data-direction="vertical"]::-webkit-slider-thumb {
139
+ cursor: ns-resize;
140
+ }
141
+
142
+ .form_input-round-range::-webkit-slider-runnable-track {
143
+ height: var(--track-height);
144
+ border: var(--track-border);
145
+ border-radius: var(--track-border-radius);
146
+ background: var(--track-background);
147
+ backdrop-filter: blur(4px);
148
+ box-shadow: var(--track-box-shadow);
149
+ position: relative;
150
+ cursor: col-resize;
151
+ overflow: hidden;
152
+ transition:
153
+ box-shadow 0.2s ease-in-out,
154
+ border-color 0.2s ease-in-out;
155
+ }
156
+
157
+ [data-direction="vertical"]::-webkit-slider-runnable-track {
158
+ cursor: ns-resize;
159
+ }
160
+
161
+ .form_input-round-range.slider-progress::-webkit-slider-runnable-track {
162
+ background:
163
+ linear-gradient(var(--track-value-background), var(--track-value-background)) 0 / var(--sx) 100% no-repeat,
164
+ var(--track-background);
165
+ }
166
+
167
+ [data-direction="vertical"].form_input-round-range.slider-progress::-webkit-slider-runnable-track {
168
+ background: linear-gradient(var(--track-value-background) var(--sx), var(--track-background) var(--sx)) no-repeat;
169
+ }
170
+
171
+ /*mozilla*/
172
+ .form_input-round-range::-moz-range-thumb {
173
+ width: var(--thumb-width);
174
+ height: var(--thumb-height);
175
+ border-radius: var(--thumb-border-radius);
176
+ background: var(--thumb-background);
177
+ border: none;
178
+ box-shadow: var(--thumb-box-shadow);
179
+ cursor: col-resize;
180
+ margin-left: calc(0 - var(--track-value-padding));
181
+ transition:
182
+ background 0.2s ease-in-out,
183
+ box-shadow 0.2s ease-in-out,
184
+ border-color 0.2s ease-in-out,
185
+ transform 0.2s cubic-bezier(0.165, 0.84, 0.44, 1),
186
+ width 0.2s cubic-bezier(0.165, 0.84, 0.44, 1);
187
+ }
188
+
189
+ [data-direction="vertical"]::-moz-range-thumb {
190
+ cursor: ns-resize;
191
+ }
192
+
193
+ .form_input-round-range::-moz-range-track {
194
+ height: var(--track-height);
195
+ border: var(--track-border);
196
+ border-radius: var(--track-border-radius);
197
+ background: var(--track-background);
198
+ backdrop-filter: blur(4px);
199
+ box-shadow: var(--track-box-shadow);
200
+ cursor: col-resize;
201
+ overflow: hidden;
202
+ /* Trim left and right paddings of track */
203
+ width: calc(100% - var(--track-value-padding) * 2);
204
+ }
205
+
206
+ [data-direction="vertical"]::-moz-range-track {
207
+ cursor: ns-resize;
208
+ }
209
+
210
+ .form_input-round-range.slider-progress::-moz-range-track {
211
+ background:
212
+ linear-gradient(var(--track-value-background), var(--track-value-background)) 0 / var(--sx) 100% no-repeat,
213
+ var(--track-background);
214
+ }
215
+
216
+ [data-direction="vertical"].form_input-round-range.slider-progress::-moz-range-track {
217
+ background: linear-gradient(var(--track-value-background) var(--sx), var(--track-background) var(--sx)) no-repeat;
218
+ }
219
+
220
+ /*ms*/
221
+ .form_input-round-range::-ms-fill-upper {
222
+ background: transparent;
223
+ border-color: transparent;
224
+ }
225
+
226
+ .form_input-round-range::-ms-fill-lower {
227
+ background: transparent;
228
+ border-color: transparent;
229
+ }
230
+
231
+ .form_input-round-range::-ms-thumb {
232
+ width: var(--thumb-width);
233
+ height: var(--thumb-height);
234
+ border-radius: var(--thumb-border-radius);
235
+ background: var(--thumb-background);
236
+ border: var(--thumb-border);
237
+ box-shadow: var(--thumb-box-shadow);
238
+ box-sizing: border-box;
239
+ cursor: col-resize;
240
+
241
+ transition:
242
+ background 0.2s ease-in-out,
243
+ box-shadow 0.2s ease-in-out,
244
+ border-color 0.2s ease-in-out,
245
+ transform 0.2s cubic-bezier(0.165, 0.84, 0.44, 1),
246
+ width 0.2s cubic-bezier(0.165, 0.84, 0.44, 1);
247
+ }
248
+
249
+ [data-direction="vertical"]::-ms-thumb {
250
+ cursor: ns-resize;
251
+ }
252
+
253
+ .form_input-round-range::-ms-track {
254
+ height: var(--track-height);
255
+ border-radius: var(--track-border-radius);
256
+ background: var(--track-background);
257
+ backdrop-filter: blur(4px);
258
+ border: var(--track-border);
259
+ box-shadow: var(--track-box-shadow);
260
+ box-sizing: border-box;
261
+ cursor: col-resize;
262
+ overflow: hidden;
263
+ }
264
+
265
+ [data-direction="vertical"]::-ms-track {
266
+ cursor: ns-resize;
267
+ }
268
+
269
+ .form_input-round-range.slider-progress::-ms-fill-lower {
270
+ height: var(--track-height);
271
+ border-radius: var(--track-border-radius) 0 0 var(--track-border-radius);
272
+ margin: 0;
273
+ background: var(--track-value-background);
274
+ border: none;
275
+ border-right-width: 0;
276
+ }
277
+ </style>
@@ -1,2 +1,3 @@
1
1
  export { default as ColorHueRange } from './ColorHueRange.vue'
2
2
  export { default as Range } from './Range.vue'
3
+ export { default as RoundRange } from './RoundRange.vue'
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import { inject } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ value: string | number
6
+ label?: string
7
+ active?: boolean
8
+ }>()
9
+
10
+ const selectOption = inject('selectOption') as (value: string | number) => void
11
+ const hide = inject('hide') as () => void
12
+ </script>
13
+
14
+ <template>
15
+ <div
16
+ v-bind="{ ...$attrs, class: null, style: null }"
17
+ class="cursor-pointer rounded px-2 py-1 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-800"
18
+ line-clamp-1 overflow-hidden text-ellipsis whitespace-pre-wrap text="xs sm:sm" transition-colors duration-150 ease-in-out will-change-background-color will-change-color
19
+ :class="{ 'bg-neutral-100 dark:bg-neutral-800': props.active }"
20
+ @click="() => {
21
+ selectOption(props.value)
22
+ hide()
23
+ }"
24
+ >
25
+ <slot>
26
+ {{ props.label }}
27
+ </slot>
28
+ </div>
29
+ </template>
@@ -1,57 +1,76 @@
1
1
  <script setup lang="ts">
2
2
  import { Dropdown as VDropdown } from 'floating-vue'
3
- import { computed } from 'vue'
3
+ import { provide, ref } from 'vue'
4
+
5
+ import UIOption from './Option.vue'
4
6
 
5
7
  const props = defineProps<{
6
- options: { label: string, value: string | number }[]
8
+ options?: { label: string, value: string | number }[]
7
9
  placeholder?: string
8
10
  disabled?: boolean
9
11
  title?: string
12
+ layout?: 'horizontal' | 'vertical'
10
13
  }>()
11
14
 
12
- const modelValue = defineModel<string | number>({ required: true })
13
-
14
- const selectedLabel = computed(() => {
15
- const selected = props.options.find(opt => opt.value === modelValue.value)
16
- return selected ? selected.label : props.placeholder
17
- })
15
+ const show = ref(false)
16
+ const modelValue = defineModel<string | number>({ required: false })
18
17
 
19
18
  function selectOption(value: string | number) {
20
19
  modelValue.value = value
21
20
  }
21
+
22
+ function handleHide() {
23
+ show.value = false
24
+ }
25
+
26
+ provide('selectOption', selectOption)
27
+ provide('hide', handleHide)
22
28
  </script>
23
29
 
24
30
  <template>
25
31
  <VDropdown
26
32
  auto-size
27
33
  auto-boundary-max-size
34
+ w-full
28
35
  >
29
36
  <div
30
- class="min-w-[160px] flex cursor-pointer items-center justify-between gap-2 border rounded-lg bg-white p-2.5 text-xs text-neutral-700 shadow-sm outline-none transition-colors disabled:cursor-not-allowed dark:border-neutral-800 dark:bg-neutral-900 disabled:bg-neutral-100 hover:bg-neutral-50 dark:text-neutral-200 disabled:text-neutral-400 focus:ring-2 focus:ring-black/10 dark:disabled:bg-neutral-800 dark:hover:bg-neutral-800 dark:disabled:text-neutral-600"
31
- :class="{ 'pointer-events-none': props.disabled }"
37
+ min-w="[160px]" p="2.5" w-full
38
+ class="focus:ring-2 focus:ring-black/10"
39
+ border="neutral-300 dark:neutral-800 solid 2 focus:neutral-400 dark:focus:neutral-600"
40
+ text="xs sm:sm dark:neutral-200 disabled:neutral-400 dark:disabled:neutral-600 neutral-700"
41
+ bg="white dark:neutral-900 disabled:neutral-100 hover:neutral-50 dark:disabled:neutral-900 dark:hover:neutral-800 "
42
+ cursor="disabled:not-allowed pointer"
43
+ flex items-center gap-2 rounded-lg shadow-sm outline-none transition-colors duration-200 ease-in-out
44
+ :class="[
45
+ props.disabled ? 'pointer-events-none' : '',
46
+ ]"
32
47
  >
33
48
  <div class="flex-1 truncate">
34
- <slot :label="selectedLabel">
35
- {{ selectedLabel }}
49
+ <slot :value="modelValue">
50
+ {{ props.options?.find(item => item.value === modelValue)?.label || modelValue }}
36
51
  </slot>
37
52
  </div>
38
- <div i-solar:alt-arrow-down-bold-duotone class="h-3.5 w-3.5 text-neutral-500 dark:text-neutral-400" />
53
+ <div i-solar:alt-arrow-down-linear class="h-3.5 w-3.5 text-neutral-500 dark:text-neutral-400" />
39
54
  </div>
40
55
 
41
56
  <template #popper="{ hide }">
42
- <div class="min-w-[160px] flex flex-col gap-0.5 border border-neutral-200 rounded-lg bg-white p-1 shadow-lg dark:border-neutral-800 dark:bg-neutral-900">
43
- <div
44
- v-for="option of props.options"
45
- v-bind="{ ...$attrs, class: null, style: null }"
46
- :key="option.value"
47
- class="cursor-pointer rounded px-2 py-1.5 text-sm text-neutral-700 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-800"
48
- :class="{
49
- 'bg-neutral-100 dark:bg-neutral-800': modelValue === option.value,
50
- }"
51
- @click="selectOption(option.value); hide()"
52
- >
53
- {{ option.label }}
54
- </div>
57
+ <div class="min-w-[160px] flex flex-col gap-0.5 border border-neutral-200 rounded-lg bg-white p-1 shadow-lg dark:border-neutral-800 dark:bg-neutral-900 dark:bg-neutral-900">
58
+ <slot name="options" :hide="hide">
59
+ <template v-if="props.options && props.options.length">
60
+ <UIOption
61
+ v-for="option of props.options"
62
+ :key="option.value"
63
+ :value="option.value"
64
+ :label="option.label"
65
+ :active="modelValue === option.value"
66
+ @click="selectOption(option.value); hide()"
67
+ />
68
+ </template>
69
+
70
+ <p v-else class="my-3 text-center text-neutral-500 dark:text-neutral-400">
71
+ No data
72
+ </p>
73
+ </slot>
55
74
  </div>
56
75
  </template>
57
76
  </VDropdown>
@@ -1 +1,2 @@
1
+ export { default as Option } from './Option.vue'
1
2
  export { default as Select } from './Select.vue'
@@ -1,6 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, watch } from 'vue'
3
3
 
4
+ const props = defineProps<{
5
+ defaultHeight?: string
6
+ }>()
7
+
4
8
  const events = defineEmits<{
5
9
  (event: 'submit', message: string): void
6
10
  }>()
@@ -26,6 +30,10 @@ watch(input, () => {
26
30
  requestAnimationFrame(() => {
27
31
  if (!textareaRef.value)
28
32
  return
33
+ if (input.value === '') {
34
+ textareaHeight.value = props.defaultHeight || 'fit-content'
35
+ return
36
+ }
29
37
 
30
38
  textareaHeight.value = `${textareaRef.value.scrollHeight}px`
31
39
  })
@@ -1,153 +0,0 @@
1
- import { export_helper_default } from "./export-helper-WDd986Km.mjs";
2
- import { Transition, createBlock, defineComponent, openBlock, renderSlot, withCtx } from "vue";
3
-
4
- //#region src/components/Animations/TransitionVertical.vue?vue&type=script&setup=true&lang.ts
5
- const closed = "0px";
6
- var TransitionVertical_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
7
- __name: "TransitionVertical",
8
- props: {
9
- duration: {
10
- type: Number,
11
- required: false,
12
- default: 250
13
- },
14
- easingEnter: {
15
- type: String,
16
- required: false,
17
- default: "ease-in-out"
18
- },
19
- easingLeave: {
20
- type: String,
21
- required: false,
22
- default: "ease-in-out"
23
- },
24
- opacityClosed: {
25
- type: Number,
26
- required: false,
27
- default: 0
28
- },
29
- opacityOpened: {
30
- type: Number,
31
- required: false,
32
- default: 1
33
- }
34
- },
35
- setup(__props, { expose: __expose }) {
36
- __expose();
37
- const props = __props;
38
- function getElementStyle(element) {
39
- return {
40
- height: element.style.height,
41
- width: element.style.width,
42
- position: element.style.position,
43
- visibility: element.style.visibility,
44
- overflow: element.style.overflow,
45
- paddingTop: element.style.paddingTop,
46
- paddingBottom: element.style.paddingBottom,
47
- borderTopWidth: element.style.borderTopWidth,
48
- borderBottomWidth: element.style.borderBottomWidth,
49
- marginTop: element.style.marginTop,
50
- marginBottom: element.style.marginBottom
51
- };
52
- }
53
- function prepareElement(element, initialStyle) {
54
- const { width } = getComputedStyle(element);
55
- element.style.width = width;
56
- element.style.position = "absolute";
57
- element.style.visibility = "hidden";
58
- element.style.height = "";
59
- const { height } = getComputedStyle(element);
60
- element.style.width = initialStyle.width;
61
- element.style.position = initialStyle.position;
62
- element.style.visibility = initialStyle.visibility;
63
- element.style.height = closed;
64
- element.style.overflow = "hidden";
65
- return initialStyle.height && initialStyle.height !== closed ? initialStyle.height : height;
66
- }
67
- function animateTransition(element, initialStyle, done, keyframes, options) {
68
- const animation = element.animate(keyframes, options);
69
- element.style.height = initialStyle.height;
70
- animation.onfinish = () => {
71
- element.style.overflow = initialStyle.overflow;
72
- done();
73
- };
74
- }
75
- function getEnterKeyframes(height, initialStyle) {
76
- return [{
77
- height: closed,
78
- opacity: props.opacityClosed,
79
- paddingTop: closed,
80
- paddingBottom: closed,
81
- borderTopWidth: closed,
82
- borderBottomWidth: closed,
83
- marginTop: closed,
84
- marginBottom: closed
85
- }, {
86
- height,
87
- opacity: props.opacityOpened,
88
- paddingTop: initialStyle.paddingTop,
89
- paddingBottom: initialStyle.paddingBottom,
90
- borderTopWidth: initialStyle.borderTopWidth,
91
- borderBottomWidth: initialStyle.borderBottomWidth,
92
- marginTop: initialStyle.marginTop,
93
- marginBottom: initialStyle.marginBottom
94
- }];
95
- }
96
- function enterTransition(element, done) {
97
- const HTMLElement = element;
98
- const initialStyle = getElementStyle(HTMLElement);
99
- const height = prepareElement(HTMLElement, initialStyle);
100
- const keyframes = getEnterKeyframes(height, initialStyle);
101
- const options = {
102
- duration: props.duration,
103
- easing: props.easingEnter
104
- };
105
- animateTransition(HTMLElement, initialStyle, done, keyframes, options);
106
- }
107
- function leaveTransition(element, done) {
108
- const HTMLElement = element;
109
- const initialStyle = getElementStyle(HTMLElement);
110
- const { height } = getComputedStyle(HTMLElement);
111
- HTMLElement.style.height = height;
112
- HTMLElement.style.overflow = "hidden";
113
- const keyframes = getEnterKeyframes(height, initialStyle).reverse();
114
- const options = {
115
- duration: props.duration,
116
- easing: props.easingLeave
117
- };
118
- animateTransition(HTMLElement, initialStyle, done, keyframes, options);
119
- }
120
- const __returned__ = {
121
- props,
122
- closed,
123
- getElementStyle,
124
- prepareElement,
125
- animateTransition,
126
- getEnterKeyframes,
127
- enterTransition,
128
- leaveTransition
129
- };
130
- Object.defineProperty(__returned__, "__isScriptSetup", {
131
- enumerable: false,
132
- value: true
133
- });
134
- return __returned__;
135
- }
136
- });
137
-
138
- //#endregion
139
- //#region src/components/Animations/TransitionVertical.vue
140
- function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
141
- return openBlock(), createBlock(Transition, {
142
- css: false,
143
- onEnter: $setup.enterTransition,
144
- onLeave: $setup.leaveTransition
145
- }, {
146
- default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
147
- _: 3
148
- });
149
- }
150
- var TransitionVertical_default = /* @__PURE__ */ export_helper_default(TransitionVertical_vue_vue_type_script_setup_true_lang_default, [["render", _sfc_render], ["__file", "/home/runner/work/airi/airi/packages/ui/src/components/Animations/TransitionVertical.vue"]]);
151
-
152
- //#endregion
153
- export { TransitionVertical_default };