@youcan/celeste 0.18.0 → 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 +573 -274
- 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/components.cjs +6 -4
- package/dist/cjs/chunks/gradient-picker.cjs +635 -0
- 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 +9 -4
- 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/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/components.js +6 -4
- package/dist/es/chunks/gradient-picker.js +629 -0
- 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 +7 -5
- 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/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
|
+
};
|
|
@@ -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
|
+
}
|