@youcan/celeste 0.17.2 → 0.19.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.
- package/ai/README.md +1 -1
- package/ai/component-registry.json +206 -3
- package/ai/icons.json +2 -2
- package/ai/tokens.json +2 -2
- package/dist/celeste.css +740 -380
- package/dist/cjs/chunks/ComboboxItem.cjs +6 -0
- package/dist/cjs/chunks/alpha-slider.cjs +1 -1
- package/dist/cjs/chunks/color-area.cjs +1 -1
- package/dist/cjs/chunks/color-picker.cjs +20 -25
- package/dist/cjs/chunks/color-swatch.cjs +4 -3
- package/dist/cjs/chunks/combobox-item.cjs +63 -7
- package/dist/cjs/chunks/combobox-list.cjs +1 -1
- package/dist/cjs/chunks/combobox-trigger.cjs +1 -1
- package/dist/cjs/chunks/combobox.cjs +2 -2
- package/dist/cjs/chunks/components.cjs +7 -5
- package/dist/cjs/chunks/gradient-picker.cjs +635 -0
- package/dist/cjs/chunks/text-input-affix.cjs +1 -1
- package/dist/cjs/chunks/text-input-button.cjs +1 -1
- package/dist/cjs/chunks/text-input.cjs +2 -1
- package/dist/cjs/chunks/textarea.cjs +1 -1
- package/dist/{es/chunks/use-color-model.js → cjs/chunks/tinycolor.cjs} +6 -23
- package/dist/cjs/gradient-picker.cjs +2 -0
- package/dist/cjs/gradient.cjs +71 -0
- package/dist/cjs/index.cjs +10 -5
- package/dist/cjs/use-color-model.cjs +27 -3
- package/dist/components/color-picker/gradient-picker.d.ts +51 -0
- package/dist/components/color-picker/index.d.ts +2 -0
- package/dist/es/chunks/ComboboxItem.js +1 -1
- package/dist/es/chunks/alpha-slider.js +1 -1
- package/dist/es/chunks/color-area.js +1 -1
- package/dist/es/chunks/color-picker.js +12 -17
- package/dist/es/chunks/color-swatch.js +2 -1
- package/dist/es/chunks/combobox-item.js +65 -9
- package/dist/es/chunks/combobox-list.js +1 -1
- package/dist/es/chunks/combobox-trigger.js +1 -1
- package/dist/es/chunks/combobox.js +2 -2
- package/dist/es/chunks/components.js +7 -5
- package/dist/es/chunks/gradient-picker.js +629 -0
- package/dist/es/chunks/text-input-affix.js +1 -1
- package/dist/es/chunks/text-input-button.js +1 -1
- package/dist/es/chunks/text-input.js +2 -1
- package/dist/es/chunks/textarea.js +1 -1
- package/dist/{cjs/chunks/use-color-model.cjs → es/chunks/tinycolor.js} +1 -40
- package/dist/es/gradient-picker.js +2 -0
- package/dist/es/gradient.js +69 -0
- package/dist/es/index.js +8 -6
- package/dist/es/use-color-model.js +25 -1
- package/dist/utils/gradient.d.ts +13 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +3 -3
- package/src/components/color-picker/color-picker.vue +8 -9
- package/src/components/color-picker/composable/use-color-model.ts +5 -0
- package/src/components/color-picker/gradient-picker.vue +944 -0
- package/src/components/color-picker/index.ts +3 -0
- package/src/components/color-picker/stories/gradient-picker.stories.ts +37 -0
- package/src/components/combobox/combobox-item.vue +15 -7
- package/src/components/combobox/combobox-list.vue +2 -2
- package/src/components/combobox/combobox-trigger.vue +38 -0
- package/src/components/combobox/combobox.vue +2 -0
- package/src/components/text-input/stories/text-input.stories.ts +53 -3
- package/src/components/text-input/text-input-affix.vue +7 -3
- package/src/components/text-input/text-input-button.vue +6 -2
- package/src/components/text-input/text-input.vue +45 -34
- package/src/components/textarea/textarea.vue +1 -1
- package/src/utils/gradient.ts +90 -0
- package/src/utils/index.ts +1 -0
|
@@ -10,5 +10,8 @@ export { default as ColorPicker } from './color-picker.vue';
|
|
|
10
10
|
export * from './color-swatch.vue';
|
|
11
11
|
export { default as ColorSwatch } from './color-swatch.vue';
|
|
12
12
|
|
|
13
|
+
export * from './gradient-picker.vue';
|
|
14
|
+
export { default as GradientPicker } from './gradient-picker.vue';
|
|
15
|
+
|
|
13
16
|
export * from './hue-slider.vue';
|
|
14
17
|
export { default as HueSlider } from './hue-slider.vue';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import GradientPicker from '../gradient-picker.vue';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof GradientPicker> = {
|
|
6
|
+
title: 'Components/Gradient Picker',
|
|
7
|
+
component: GradientPicker,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'padded',
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof GradientPicker>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
render: () => ({
|
|
19
|
+
components: { GradientPicker },
|
|
20
|
+
setup() {
|
|
21
|
+
const gradient = ref('linear-gradient(135deg, #3B82F6 0%, #EC4899 100%)');
|
|
22
|
+
return { gradient };
|
|
23
|
+
},
|
|
24
|
+
template: `<div style="display: grid; width: 280px; gap: 8px;"><GradientPicker v-model="gradient" /><code>{{ gradient }}</code></div>`,
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Empty: Story = {
|
|
29
|
+
render: () => ({
|
|
30
|
+
components: { GradientPicker },
|
|
31
|
+
setup() {
|
|
32
|
+
const gradient = ref('');
|
|
33
|
+
return { gradient };
|
|
34
|
+
},
|
|
35
|
+
template: `<div style="display: grid; width: 280px; gap: 8px;"><GradientPicker v-model="gradient" /><code>{{ gradient }}</code></div>`,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { ComboboxItemEmits } from 'reka-ui';
|
|
3
3
|
import type { HTMLAttributes } from 'vue';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
-
import { ComboboxItem, useForwardPropsEmits } from 'reka-ui';
|
|
5
|
+
import { ComboboxItem, ComboboxItemIndicator, useForwardPropsEmits } from 'reka-ui';
|
|
6
6
|
import { computed } from 'vue';
|
|
7
7
|
import Checkbox from '../checkbox/checkbox.vue';
|
|
8
8
|
|
|
@@ -48,7 +48,6 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
48
48
|
props.class,
|
|
49
49
|
'celeste-dropdown-item',
|
|
50
50
|
{ 'celeste-dropdown-item-disabled': disabled },
|
|
51
|
-
{ 'celeste-dropdown-item-selected': selected },
|
|
52
51
|
{ 'celeste-dropdown-item-focused': focused },
|
|
53
52
|
)"
|
|
54
53
|
>
|
|
@@ -83,7 +82,9 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
83
82
|
<div v-if="$slots.suffix" class="celeste-dropdown-item-suffix">
|
|
84
83
|
<slot name="suffix" />
|
|
85
84
|
</div>
|
|
86
|
-
<
|
|
85
|
+
<ComboboxItemIndicator as-child>
|
|
86
|
+
<i class="celeste-dropdown-item-indicator i-celeste-check-line" />
|
|
87
|
+
</ComboboxItemIndicator>
|
|
87
88
|
</div>
|
|
88
89
|
</ComboboxItem>
|
|
89
90
|
</template>
|
|
@@ -91,8 +92,10 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
91
92
|
<style lang="scss" scoped>
|
|
92
93
|
.celeste-dropdown-item {
|
|
93
94
|
display: flex;
|
|
95
|
+
position: relative;
|
|
94
96
|
align-items: center;
|
|
95
97
|
padding: var(--spacing-8);
|
|
98
|
+
padding-inline-end: var(--spacing-36);
|
|
96
99
|
transition-property: background-color;
|
|
97
100
|
transition-duration: var(--animation-fast);
|
|
98
101
|
transition-timing-function: ease-out;
|
|
@@ -159,6 +162,15 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
159
162
|
color: var(--color-icon-sub-600);
|
|
160
163
|
}
|
|
161
164
|
|
|
165
|
+
&-indicator {
|
|
166
|
+
position: absolute;
|
|
167
|
+
top: 50%;
|
|
168
|
+
width: 20px;
|
|
169
|
+
height: 20px;
|
|
170
|
+
transform: translateY(-50%);
|
|
171
|
+
inset-inline-end: var(--spacing-8);
|
|
172
|
+
}
|
|
173
|
+
|
|
162
174
|
&-disabled {
|
|
163
175
|
color: var(--color-text-disabled-300);
|
|
164
176
|
cursor: not-allowed;
|
|
@@ -174,10 +186,6 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
188
|
|
|
177
|
-
&-selected {
|
|
178
|
-
background: var(--color-bg-weak-50);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
189
|
.celeste-dropdown-item-info {
|
|
182
190
|
display: flex;
|
|
183
191
|
flex: 1 0 0;
|
|
@@ -39,14 +39,14 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
|
39
39
|
div:deep(.celeste-dropdown-content) {
|
|
40
40
|
--dropdown-height: 300px;
|
|
41
41
|
--dropdown-min-width: var(--reka-combobox-trigger-width, 300px);
|
|
42
|
-
--dropdown-width: max(var(--reka-popper-anchor-width), 300px);
|
|
43
42
|
|
|
44
43
|
display: flex;
|
|
45
44
|
z-index: 50;
|
|
46
45
|
box-sizing: border-box;
|
|
47
46
|
flex-direction: column;
|
|
48
|
-
width:
|
|
47
|
+
width: max-content;
|
|
49
48
|
min-width: var(--dropdown-min-width);
|
|
49
|
+
max-width: max(var(--reka-popper-anchor-width), 320px);
|
|
50
50
|
max-height: var(--dropdown-height);
|
|
51
51
|
margin-top: var(--spacing-10);
|
|
52
52
|
padding: var(--spacing-8);
|
|
@@ -197,6 +197,19 @@ const forwarded = useForwardProps(delegatedProps);
|
|
|
197
197
|
border: none;
|
|
198
198
|
border-radius: 0;
|
|
199
199
|
box-shadow: none;
|
|
200
|
+
gap: 0;
|
|
201
|
+
|
|
202
|
+
:deep(.celeste-dropdown-anchor-trigger-prefix) {
|
|
203
|
+
margin-inline-end: var(--spacing-8);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
:deep(.celeste-dropdown-trigger) {
|
|
207
|
+
margin-inline-start: var(--spacing-2);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&.celeste-dropdown-anchor-trigger-filled:not([data-disabled]) :deep(.celeste-dropdown-trigger i) {
|
|
211
|
+
color: var(--color-icon-sub-600);
|
|
212
|
+
}
|
|
200
213
|
|
|
201
214
|
&:deep(.celeste-dropdown-trigger-label) {
|
|
202
215
|
flex: inherit;
|
|
@@ -206,6 +219,31 @@ const forwarded = useForwardProps(delegatedProps);
|
|
|
206
219
|
&[data-state='open'] {
|
|
207
220
|
box-shadow: none;
|
|
208
221
|
}
|
|
222
|
+
|
|
223
|
+
&:focus-visible {
|
|
224
|
+
background: var(--color-bg-weak-50);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
&.celeste-dropdown-anchor-trigger-size-md {
|
|
228
|
+
padding-inline: var(--spacing-10) var(--spacing-8);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&.celeste-dropdown-anchor-trigger-size-sm {
|
|
232
|
+
padding-inline: var(--spacing-8);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
&.celeste-dropdown-anchor-trigger-size-xs {
|
|
236
|
+
padding-inline: var(--spacing-8) var(--spacing-6);
|
|
237
|
+
|
|
238
|
+
:deep(.celeste-dropdown-anchor-trigger-prefix) {
|
|
239
|
+
margin-inline-end: var(--spacing-6);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
:deep(.celeste-dropdown-anchor-trigger-prefix :is(i, .selected-dropdown-image)) {
|
|
243
|
+
width: 16px;
|
|
244
|
+
height: 16px;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
209
247
|
}
|
|
210
248
|
|
|
211
249
|
&.celeste-dropdown-anchor-trigger-type-inline {
|
|
@@ -253,6 +253,7 @@ const filteredOptions = computed(() => props.ignoreFilter
|
|
|
253
253
|
align-items: center;
|
|
254
254
|
justify-content: center;
|
|
255
255
|
width: 20px;
|
|
256
|
+
max-width: none;
|
|
256
257
|
height: 20px;
|
|
257
258
|
object-fit: cover;
|
|
258
259
|
border-radius: var(--radius-full);
|
|
@@ -274,6 +275,7 @@ const filteredOptions = computed(() => props.ignoreFilter
|
|
|
274
275
|
overflow: hidden;
|
|
275
276
|
text-overflow: ellipsis;
|
|
276
277
|
white-space: nowrap;
|
|
278
|
+
unicode-bidi: plaintext;
|
|
277
279
|
}
|
|
278
280
|
}
|
|
279
281
|
|
|
@@ -73,15 +73,21 @@ export const Size: Story = {
|
|
|
73
73
|
template: `
|
|
74
74
|
<div style="display: grid; gap: 20px; justify-content: center;">
|
|
75
75
|
<TextInput v-bind="args" style="width: 300px" size="md">
|
|
76
|
-
<
|
|
76
|
+
<template #leadingIcon>
|
|
77
|
+
<i class="i-celeste-user-6-line" />
|
|
78
|
+
</template>
|
|
77
79
|
</TextInput>
|
|
78
80
|
|
|
79
81
|
<TextInput v-bind="args" style="width: 300px" size="sm">
|
|
80
|
-
<
|
|
82
|
+
<template #leadingIcon>
|
|
83
|
+
<i class="i-celeste-user-6-line" />
|
|
84
|
+
</template>
|
|
81
85
|
</TextInput>
|
|
82
86
|
|
|
83
87
|
<TextInput v-bind="args" style="width: 300px" size="xs">
|
|
84
|
-
<
|
|
88
|
+
<template #leadingIcon>
|
|
89
|
+
<i class="i-celeste-user-6-line" />
|
|
90
|
+
</template>
|
|
85
91
|
</TextInput>
|
|
86
92
|
</div>
|
|
87
93
|
`,
|
|
@@ -361,3 +367,47 @@ export const WithTrailingCombobox: Story = {
|
|
|
361
367
|
`,
|
|
362
368
|
}),
|
|
363
369
|
};
|
|
370
|
+
|
|
371
|
+
function flag(color: string): string {
|
|
372
|
+
return `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><circle cx="10" cy="10" r="10" fill="${color}"/></svg>`)}`;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const COUNTRIES = [
|
|
376
|
+
{ value: 'MA', label: 'Morocco (+212)', shortLabel: '+212', image: flag('#c1272d') },
|
|
377
|
+
{ value: 'FR', label: 'France (+33)', shortLabel: '+33', image: flag('#002654') },
|
|
378
|
+
{ value: 'US', label: 'United States (+1)', shortLabel: '+1', image: flag('#3c3b6e') },
|
|
379
|
+
];
|
|
380
|
+
|
|
381
|
+
export const Phone: Story = {
|
|
382
|
+
args: {
|
|
383
|
+
type: 'tel',
|
|
384
|
+
placeholder: '610-101010',
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
render: args => ({
|
|
388
|
+
components: { TextInput, Combobox },
|
|
389
|
+
setup() {
|
|
390
|
+
const country = ref(COUNTRIES[0]);
|
|
391
|
+
const phone = ref('+212610101010');
|
|
392
|
+
|
|
393
|
+
return { args, COUNTRIES, country, phone };
|
|
394
|
+
},
|
|
395
|
+
template: `
|
|
396
|
+
<div style="display: grid; gap: 20px; width: 360px;">
|
|
397
|
+
<TextInput v-for="size in ['md', 'sm', 'xs']" :key="size" v-bind="args" v-model="phone" :size="size">
|
|
398
|
+
<template #leadingNode>
|
|
399
|
+
<Combobox
|
|
400
|
+
v-model="country"
|
|
401
|
+
searchable
|
|
402
|
+
:options="COUNTRIES"
|
|
403
|
+
:size="size"
|
|
404
|
+
value-by="value"
|
|
405
|
+
label-by="shortLabel"
|
|
406
|
+
type="compact-input"
|
|
407
|
+
/>
|
|
408
|
+
</template>
|
|
409
|
+
</TextInput>
|
|
410
|
+
</div>
|
|
411
|
+
`,
|
|
412
|
+
}),
|
|
413
|
+
};
|
|
@@ -27,18 +27,22 @@ const delegatedProps = useDelegatedProps(props, 'class');
|
|
|
27
27
|
flex-shrink: 0;
|
|
28
28
|
align-items: center;
|
|
29
29
|
color: var(--celeste-text-input-affix-color);
|
|
30
|
+
unicode-bidi: plaintext;
|
|
30
31
|
|
|
31
32
|
&[inline='false'] {
|
|
32
|
-
padding-inline: var(--
|
|
33
|
+
padding-inline: var(--input-affix-padding);
|
|
33
34
|
background-color: var(--celeste-text-input-affix-background-color);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
&[askbd='true'] {
|
|
38
|
+
box-sizing: border-box;
|
|
37
39
|
width: fit-content;
|
|
38
|
-
height:
|
|
39
|
-
padding: var(--spacing-
|
|
40
|
+
height: 20px;
|
|
41
|
+
padding-inline: var(--spacing-6);
|
|
40
42
|
border: 1px solid var(--color-stroke-soft-200);
|
|
41
43
|
border-radius: var(--radius-4);
|
|
44
|
+
background-color: var(--color-bg-white-0);
|
|
45
|
+
color: var(--celeste-text-input-muted-color);
|
|
42
46
|
font: var(--subheading-xs);
|
|
43
47
|
}
|
|
44
48
|
}
|
|
@@ -37,10 +37,14 @@ const delegatedProps = useDelegatedProps(props, 'class');
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
&[inline='false'] {
|
|
40
|
-
padding: var(--spacing-
|
|
40
|
+
padding-inline: var(--spacing-14);
|
|
41
41
|
border-end-start-radius: 0;
|
|
42
42
|
border-start-start-radius: 0;
|
|
43
43
|
|
|
44
|
+
&:has(> :only-child:is(i)) {
|
|
45
|
+
padding-inline: var(--spacing-10);
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
&:is(.celeste-button-intent-neutral, .celeste-button-variant-stroke):not(:disabled) {
|
|
45
49
|
background-color: var(--color-bg-white-0);
|
|
46
50
|
|
|
@@ -53,7 +57,7 @@ const delegatedProps = useDelegatedProps(props, 'class');
|
|
|
53
57
|
&[inline='true'] {
|
|
54
58
|
width: 20px;
|
|
55
59
|
height: 20px;
|
|
56
|
-
color: var(--celeste-text-input-
|
|
60
|
+
color: var(--celeste-text-input-muted-color) !important;
|
|
57
61
|
|
|
58
62
|
&:hover {
|
|
59
63
|
background-color: transparent !important;
|
|
@@ -80,6 +80,7 @@ function clearInput() {
|
|
|
80
80
|
>
|
|
81
81
|
<TextInputButton
|
|
82
82
|
v-if="showClearButton"
|
|
83
|
+
inline
|
|
83
84
|
type="button"
|
|
84
85
|
aria-label="Clear search"
|
|
85
86
|
@click="clearInput"
|
|
@@ -97,8 +98,9 @@ function clearInput() {
|
|
|
97
98
|
.celeste-text-input-wrapper {
|
|
98
99
|
--celeste-text-input-border-color: var(--color-stroke-soft-200);
|
|
99
100
|
--celeste-text-input-drop-shadow: var(--shadow-regular-xs);
|
|
100
|
-
--celeste-text-input-icon-color: var(--color-text-
|
|
101
|
-
--celeste-text-input-affix-color: var(--color-text-
|
|
101
|
+
--celeste-text-input-icon-color: var(--color-text-sub-600);
|
|
102
|
+
--celeste-text-input-affix-color: var(--color-text-sub-600);
|
|
103
|
+
--celeste-text-input-muted-color: var(--color-text-soft-400);
|
|
102
104
|
--celeste-text-input-placeholder-color: var(--color-text-soft-400);
|
|
103
105
|
--celeste-text-input-affix-background-color: var(--color-bg-white-0);
|
|
104
106
|
|
|
@@ -106,12 +108,10 @@ function clearInput() {
|
|
|
106
108
|
box-sizing: border-box;
|
|
107
109
|
align-items: center;
|
|
108
110
|
height: var(--input-height);
|
|
109
|
-
padding-inline:
|
|
111
|
+
padding-inline: var(--input-padding);
|
|
110
112
|
transition: all var(--animation-fast) ease-out;
|
|
111
113
|
border: 1px solid var(--celeste-text-input-border-color);
|
|
112
114
|
border-radius: var(--input-radius);
|
|
113
|
-
outline: 2px solid transparent;
|
|
114
|
-
outline-offset: 2px;
|
|
115
115
|
background-color: var(--color-bg-white-0);
|
|
116
116
|
box-shadow: var(--celeste-text-input-drop-shadow);
|
|
117
117
|
color: var(--color-text-strong-950);
|
|
@@ -119,24 +119,27 @@ function clearInput() {
|
|
|
119
119
|
gap: var(--input-gap);
|
|
120
120
|
|
|
121
121
|
&[size='xs'] {
|
|
122
|
-
--input-gap:
|
|
122
|
+
--input-gap: var(--spacing-6);
|
|
123
123
|
--input-height: 32px;
|
|
124
124
|
--input-radius: var(--radius-8);
|
|
125
|
-
--input-padding:
|
|
125
|
+
--input-padding: var(--spacing-8);
|
|
126
|
+
--input-affix-padding: var(--spacing-10);
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
&[size='sm'] {
|
|
129
|
-
--input-gap:
|
|
130
|
+
--input-gap: var(--spacing-8);
|
|
130
131
|
--input-height: 36px;
|
|
131
132
|
--input-radius: var(--radius-8);
|
|
132
|
-
--input-padding: var(--spacing-
|
|
133
|
+
--input-padding: var(--spacing-10);
|
|
134
|
+
--input-affix-padding: var(--spacing-10);
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
&[size='md'] {
|
|
136
|
-
--input-gap:
|
|
138
|
+
--input-gap: var(--spacing-8);
|
|
137
139
|
--input-height: 40px;
|
|
138
140
|
--input-radius: var(--radius-10);
|
|
139
|
-
--input-padding: var(--spacing-
|
|
141
|
+
--input-padding: var(--spacing-12);
|
|
142
|
+
--input-affix-padding: var(--spacing-12);
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
&[has-error='true'] {
|
|
@@ -158,6 +161,12 @@ function clearInput() {
|
|
|
158
161
|
color: var(--celeste-text-input-placeholder-color);
|
|
159
162
|
}
|
|
160
163
|
|
|
164
|
+
&[type='tel'] {
|
|
165
|
+
direction: ltr;
|
|
166
|
+
text-align: -webkit-match-parent;
|
|
167
|
+
text-align: match-parent;
|
|
168
|
+
}
|
|
169
|
+
|
|
161
170
|
// Hide default webkit search cancel button
|
|
162
171
|
&[type='search'] {
|
|
163
172
|
&::-webkit-search-cancel-button {
|
|
@@ -199,18 +208,36 @@ function clearInput() {
|
|
|
199
208
|
padding-inline-end: 0;
|
|
200
209
|
}
|
|
201
210
|
|
|
211
|
+
&:has(.celeste-text-input:placeholder-shown) {
|
|
212
|
+
--celeste-text-input-icon-color: var(--color-text-soft-400);
|
|
213
|
+
--celeste-text-input-affix-color: var(--color-text-soft-400);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
&:hover:not(:has(.celeste-text-input:focus)) {
|
|
217
|
+
--celeste-text-input-drop-shadow: none;
|
|
218
|
+
|
|
219
|
+
&:not([has-error='true'], :has(.celeste-text-input-node)) {
|
|
220
|
+
--celeste-text-input-border-color: transparent;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
&:not(:has(.celeste-text-input-node:hover)) {
|
|
224
|
+
--celeste-text-input-icon-color: var(--color-text-sub-600);
|
|
225
|
+
--celeste-text-input-placeholder-color: var(--color-text-sub-600);
|
|
226
|
+
|
|
227
|
+
background-color: var(--color-bg-weak-50);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
202
231
|
&:has(.celeste-text-input:focus) {
|
|
203
232
|
--celeste-text-input-border-color: var(--color-stroke-strong-950);
|
|
233
|
+
--celeste-text-input-drop-shadow: var(--shadow-buttons-important-focus);
|
|
204
234
|
--celeste-text-input-placeholder-color: var(--color-text-sub-600);
|
|
205
235
|
--celeste-text-input-icon-color: var(--color-text-sub-600);
|
|
206
236
|
--celeste-text-input-affix-color: var(--color-text-sub-600);
|
|
207
237
|
|
|
208
|
-
outline-color: var(--color-stroke-soft-200);
|
|
209
|
-
|
|
210
238
|
&[has-error='true'] {
|
|
211
239
|
--celeste-text-input-border-color: var(--color-state-error-base);
|
|
212
|
-
|
|
213
|
-
outline-color: var(--color-state-error-lighter);
|
|
240
|
+
--celeste-text-input-drop-shadow: var(--shadow-buttons-error-focus);
|
|
214
241
|
}
|
|
215
242
|
}
|
|
216
243
|
|
|
@@ -229,35 +256,17 @@ function clearInput() {
|
|
|
229
256
|
--celeste-text-input-drop-shadow: none;
|
|
230
257
|
--celeste-text-input-affix-background-color: var(--color-bg-weak-50);
|
|
231
258
|
--celeste-text-input-affix-color: var(--color-text-disabled-300);
|
|
259
|
+
--celeste-text-input-muted-color: var(--color-text-disabled-300);
|
|
232
260
|
--celeste-text-input-placeholder-color: var(--color-text-disabled-300);
|
|
233
261
|
--celeste-text-input-icon-color: var(--color-text-disabled-300);
|
|
234
262
|
|
|
235
263
|
background-color: var(--color-bg-weak-50);
|
|
236
|
-
box-shadow: none;
|
|
237
264
|
color: var(--color-text-disabled-300);
|
|
238
265
|
pointer-events: none;
|
|
239
266
|
|
|
240
267
|
.celeste-text-input::placeholder {
|
|
241
268
|
color: currentcolor;
|
|
242
269
|
}
|
|
243
|
-
|
|
244
|
-
.celeste-text-input-clear-button {
|
|
245
|
-
color: var(--color-text-disabled-300);
|
|
246
|
-
pointer-events: none;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
&:has(.celeste-text-input:hover:not(:focus, :disabled)) {
|
|
251
|
-
&:not(:has(.celeste-text-input-node)) {
|
|
252
|
-
--celeste-text-input-border-color: transparent;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
&:not(:has(.celeste-text-input-node:hover)) {
|
|
256
|
-
--celeste-text-input-icon-color: var(--color-text-sub-600);
|
|
257
|
-
--celeste-text-input-placeholder-color: var(--color-text-sub-600);
|
|
258
|
-
|
|
259
|
-
background-color: var(--color-bg-weak-50);
|
|
260
|
-
}
|
|
261
270
|
}
|
|
262
271
|
|
|
263
272
|
.celeste-text-input-icon {
|
|
@@ -274,6 +283,7 @@ function clearInput() {
|
|
|
274
283
|
}
|
|
275
284
|
|
|
276
285
|
:deep(.celeste-text-input-node.celeste-text-input-leading-node) {
|
|
286
|
+
margin-inline-end: calc(var(--input-padding) - var(--input-gap));
|
|
277
287
|
border-inline-end: 1px solid var(--color-stroke-soft-200);
|
|
278
288
|
border-start-start-radius: var(--input-radius);
|
|
279
289
|
border-start-end-radius: 0;
|
|
@@ -282,6 +292,7 @@ function clearInput() {
|
|
|
282
292
|
}
|
|
283
293
|
|
|
284
294
|
:deep(.celeste-text-input-node.celeste-text-input-trailing-node) {
|
|
295
|
+
margin-inline-start: calc(var(--input-padding) - var(--input-gap));
|
|
285
296
|
border-inline-start: 1px solid var(--color-stroke-soft-200);
|
|
286
297
|
border-start-start-radius: 0;
|
|
287
298
|
border-start-end-radius: var(--input-radius);
|
|
@@ -88,7 +88,7 @@ const modelValue = defineModel<string>();
|
|
|
88
88
|
display: flex;
|
|
89
89
|
position: absolute;
|
|
90
90
|
color: var(--color-text-soft-400);
|
|
91
|
-
font: var(--subheading-
|
|
91
|
+
font: var(--subheading-xxs);
|
|
92
92
|
inset-block-end: var(--spacing);
|
|
93
93
|
inset-inline-end: calc(var(--spacing) + var(--resize-handle-offset));
|
|
94
94
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export type GradientType = 'linear' | 'radial';
|
|
2
|
+
|
|
3
|
+
export interface GradientStop {
|
|
4
|
+
color: string;
|
|
5
|
+
position: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Gradient {
|
|
9
|
+
type: GradientType;
|
|
10
|
+
angle: number;
|
|
11
|
+
shape?: string;
|
|
12
|
+
stops: GradientStop[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DIRECTIONS: Record<string, number> = {
|
|
16
|
+
'to top': 0,
|
|
17
|
+
'to top right': 45,
|
|
18
|
+
'to right top': 45,
|
|
19
|
+
'to right': 90,
|
|
20
|
+
'to bottom right': 135,
|
|
21
|
+
'to right bottom': 135,
|
|
22
|
+
'to bottom': 180,
|
|
23
|
+
'to bottom left': 225,
|
|
24
|
+
'to left bottom': 225,
|
|
25
|
+
'to left': 270,
|
|
26
|
+
'to top left': 315,
|
|
27
|
+
'to left top': 315,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const UNITS: Record<string, number> = { deg: 1, grad: 0.9, rad: 180 / Math.PI, turn: 360 };
|
|
31
|
+
|
|
32
|
+
function splitTopLevel(value: string): string[] {
|
|
33
|
+
const parts: string[] = [];
|
|
34
|
+
let depth = 0;
|
|
35
|
+
let current = '';
|
|
36
|
+
|
|
37
|
+
for (const char of value) {
|
|
38
|
+
depth += char === '(' ? 1 : char === ')' ? -1 : 0;
|
|
39
|
+
|
|
40
|
+
if (char === ',' && depth === 0) {
|
|
41
|
+
parts.push(current.trim());
|
|
42
|
+
current = '';
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
current += char;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return [...parts, current.trim()].filter(Boolean);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function parseGradient(value?: string | null): Gradient | null {
|
|
53
|
+
const match = /^\s*(linear|radial)-gradient\(([\s\S]*)\)\s*$/i.exec(value ?? '');
|
|
54
|
+
|
|
55
|
+
if (!match) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const parts = splitTopLevel(match[2]);
|
|
60
|
+
const head = parts[0]?.toLowerCase() ?? '';
|
|
61
|
+
let angle = 180;
|
|
62
|
+
|
|
63
|
+
const unit = /^(-?(?:\d+(?:\.\d+)?|\.\d+))(deg|grad|rad|turn)$/.exec(head);
|
|
64
|
+
|
|
65
|
+
const shape = /circle|ellipse|closest|farthest|^at /.test(head) ? parts[0] : undefined;
|
|
66
|
+
|
|
67
|
+
if (unit || shape || head.startsWith('to ')) {
|
|
68
|
+
parts.shift();
|
|
69
|
+
angle = unit ? Math.round(((Number(unit[1]) * UNITS[unit[2]]) % 360 + 360) % 360) : DIRECTIONS[head] ?? angle;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const stops = parts.map((part, index) => {
|
|
73
|
+
const position = /\s(-?\d+(?:\.\d+)?)%$/.exec(part)?.[1];
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
color: (position === undefined ? part : part.slice(0, part.lastIndexOf(' '))).trim(),
|
|
77
|
+
position: position === undefined ? Math.round((index / Math.max(parts.length - 1, 1)) * 100) : Number(position),
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const type = match[1].toLowerCase() as GradientType;
|
|
82
|
+
|
|
83
|
+
return stops.length > 1 ? { type, angle, ...(type === 'radial' && shape && { shape }), stops } : null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function stringifyGradient({ type, angle, shape, stops }: Gradient): string {
|
|
87
|
+
const list = [...stops].sort((a, b) => a.position - b.position).map(stop => `${stop.color} ${stop.position}%`).join(', ');
|
|
88
|
+
|
|
89
|
+
return type === 'linear' ? `linear-gradient(${angle}deg, ${list})` : `radial-gradient(${shape ? `${shape}, ` : ''}${list})`;
|
|
90
|
+
}
|