@youcan/celeste 0.23.0 → 0.24.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.
Files changed (36) hide show
  1. package/ai/README.md +1 -1
  2. package/ai/component-registry.json +32 -2
  3. package/ai/icons.json +2 -2
  4. package/ai/tokens.json +2 -2
  5. package/dist/celeste.css +320 -181
  6. package/dist/cjs/chunks/alpha-slider.cjs +2 -2
  7. package/dist/cjs/chunks/button.cjs +9 -3
  8. package/dist/cjs/chunks/color-picker.cjs +3 -3
  9. package/dist/cjs/chunks/compact-button.cjs +1 -1
  10. package/dist/cjs/chunks/fancy-button.cjs +9 -3
  11. package/dist/cjs/chunks/social-button.cjs +1 -1
  12. package/dist/cjs/chunks/text-input-button.cjs +2 -0
  13. package/dist/cjs/chunks/tooltip-content.cjs +1 -1
  14. package/dist/cjs/chunks/tooltip-root.cjs +3 -11
  15. package/dist/components/button/button.d.ts +5 -1
  16. package/dist/components/button/fancy-button.d.ts +5 -1
  17. package/dist/es/chunks/alpha-slider.js +2 -2
  18. package/dist/es/chunks/button.js +10 -4
  19. package/dist/es/chunks/color-picker.js +3 -3
  20. package/dist/es/chunks/compact-button.js +1 -1
  21. package/dist/es/chunks/fancy-button.js +10 -4
  22. package/dist/es/chunks/social-button.js +1 -1
  23. package/dist/es/chunks/text-input-button.js +2 -0
  24. package/dist/es/chunks/tooltip-content.js +1 -1
  25. package/dist/es/chunks/tooltip-root.js +4 -12
  26. package/package.json +3 -3
  27. package/src/components/button/button.vue +59 -5
  28. package/src/components/button/compact-button.vue +1 -0
  29. package/src/components/button/fancy-button.vue +62 -5
  30. package/src/components/button/social-button.vue +1 -0
  31. package/src/components/button/stories/button.stories.ts +28 -0
  32. package/src/components/button/stories/fancy-button.stories.ts +28 -0
  33. package/src/components/color-picker/alpha-slider.vue +2 -2
  34. package/src/components/color-picker/color-picker.vue +1 -1
  35. package/src/components/tooltip/tooltip-content.vue +1 -1
  36. package/src/components/tooltip/tooltip-root.vue +2 -7
@@ -8,6 +8,8 @@ export interface FancyButtonProps extends PrimitiveProps {
8
8
  class?: HTMLAttributes['class'];
9
9
  size?: 'xs' | 'sm' | 'md';
10
10
  intent?: 'primary' | 'neutral' | 'error' | 'basic';
11
+ disabled?: boolean;
12
+ loading?: boolean;
11
13
  }
12
14
 
13
15
  const props = withDefaults(defineProps<FancyButtonProps>(), {
@@ -21,14 +23,21 @@ const props = withDefaults(defineProps<FancyButtonProps>(), {
21
23
  <Primitive
22
24
  :as
23
25
  :as-child
26
+ :disabled="disabled || loading || undefined"
27
+ :aria-busy="loading || undefined"
24
28
  :class="clsx(
25
29
  'celeste-fbutton',
26
30
  `celeste-fbutton-${intent}`,
27
31
  `celeste-fbutton-${size}`,
32
+ loading && !asChild && 'celeste-fbutton-loading',
28
33
  props.class,
29
34
  )"
30
35
  >
31
- <slot />
36
+ <slot v-if="asChild" />
37
+ <template v-else>
38
+ <slot />
39
+ <i class="celeste-fbutton-spinner i-celeste-loader-5-line" />
40
+ </template>
32
41
  </Primitive>
33
42
  </template>
34
43
 
@@ -95,8 +104,9 @@ $intent-map: (
95
104
  text-decoration: none;
96
105
  white-space: nowrap;
97
106
  cursor: pointer;
107
+ user-select: none;
98
108
 
99
- &:disabled {
109
+ &:disabled:not(&-loading) {
100
110
  background-color: var(--color-bg-weak-50);
101
111
  color: var(--color-text-disabled-300);
102
112
  cursor: default;
@@ -122,7 +132,8 @@ $intent-map: (
122
132
  }
123
133
 
124
134
  @each $k, $v in $intent-map {
125
- &-#{$k}:not(&-basic, :disabled) {
135
+ &-#{$k}:not(&-basic, :disabled:not(&-loading)) {
136
+ --celeste-fbutton-fg: #{if($k == 'neutral', var(--color-text-white-0), var(--color-static-white))};
126
137
  --celeste-fbutton-bg-start: rgb(255 255 255 / 16%);
127
138
  --celeste-fbutton-bg-end: rgb(255 255 255 / 0%);
128
139
 
@@ -130,7 +141,11 @@ $intent-map: (
130
141
  linear-gradient(180deg, var(--celeste-fbutton-bg-start) 0%, var(--celeste-fbutton-bg-end) 100%),
131
142
  #{map.get($v, bg)};
132
143
  box-shadow: var(--shadow-fancy-buttons-#{$k});
133
- color: if($k == 'neutral', var(--color-text-white-0), var(--color-static-white));
144
+ color: var(--celeste-fbutton-fg);
145
+
146
+ &.celeste-fbutton-loading {
147
+ color: transparent;
148
+ }
134
149
 
135
150
  &::before {
136
151
  content: '';
@@ -161,9 +176,15 @@ $intent-map: (
161
176
  }
162
177
 
163
178
  &-basic {
179
+ --celeste-fbutton-fg: var(--color-text-sub-600);
180
+
164
181
  background: var(--color-bg-white-0);
165
182
  box-shadow: var(--shadow-fancy-buttons-stroke);
166
- color: var(--color-text-sub-600);
183
+ color: var(--celeste-fbutton-fg);
184
+
185
+ &.celeste-fbutton-loading {
186
+ color: transparent;
187
+ }
167
188
 
168
189
  &:hover {
169
190
  background: var(--color-bg-weak-50);
@@ -178,4 +199,40 @@ $intent-map: (
178
199
  }
179
200
  }
180
201
  }
202
+
203
+ .celeste-fbutton-loading {
204
+ pointer-events: none;
205
+ }
206
+
207
+ .celeste-fbutton-spinner {
208
+ position: absolute;
209
+ margin: auto;
210
+ transition-property: opacity, scale;
211
+ transition-duration: var(--animation-fast);
212
+ transition-timing-function: ease-out;
213
+ animation: celeste-fbutton-spin 600ms linear infinite paused;
214
+ opacity: 0;
215
+ color: var(--celeste-fbutton-fg);
216
+ inset: 0;
217
+ scale: 0.9;
218
+ }
219
+
220
+ .celeste-fbutton-loading > .celeste-fbutton-spinner {
221
+ animation-play-state: running;
222
+ opacity: 1;
223
+ scale: 1;
224
+ }
225
+
226
+ @media (prefers-reduced-motion: reduce) {
227
+ .celeste-fbutton-spinner {
228
+ animation-duration: 1200ms;
229
+ scale: 1;
230
+ }
231
+ }
232
+
233
+ @keyframes celeste-fbutton-spin {
234
+ 100% {
235
+ rotate: 360deg;
236
+ }
237
+ }
181
238
  </style>
@@ -82,6 +82,7 @@ $brand-map: (
82
82
  text-decoration: none;
83
83
  white-space: nowrap;
84
84
  cursor: pointer;
85
+ user-select: none;
85
86
  gap: var(--spacing-8);
86
87
 
87
88
  span {
@@ -1,4 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { ref } from 'vue';
2
3
  import Button from '../button.vue';
3
4
 
4
5
  const meta: Meta<typeof Button> = {
@@ -49,3 +50,30 @@ export const IconOnly: Story = {
49
50
  `,
50
51
  }),
51
52
  };
53
+
54
+ export const Loading: Story = {
55
+ args: {
56
+ size: 'md',
57
+ intent: 'primary',
58
+ },
59
+
60
+ render: args => ({
61
+ components: { Button },
62
+ setup() {
63
+ const loading = ref(false);
64
+
65
+ function save(): void {
66
+ loading.value = true;
67
+ setTimeout(() => loading.value = false, 3000);
68
+ }
69
+
70
+ return { args, loading, save };
71
+ },
72
+ template: `
73
+ <Button v-bind="args" :loading="loading" @click="save">
74
+ Save changes
75
+ <i class="i-celeste-check-line"></i>
76
+ </Button>
77
+ `,
78
+ }),
79
+ };
@@ -1,4 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { ref } from 'vue';
2
3
  import FancyButton from '../fancy-button.vue';
3
4
 
4
5
  const meta: Meta<typeof FancyButton> = {
@@ -29,3 +30,30 @@ export const Default: Story = {
29
30
  `,
30
31
  }),
31
32
  };
33
+
34
+ export const Loading: Story = {
35
+ args: {
36
+ size: 'md',
37
+ intent: 'primary',
38
+ },
39
+
40
+ render: args => ({
41
+ components: { FancyButton },
42
+ setup() {
43
+ const loading = ref(false);
44
+
45
+ function save(): void {
46
+ loading.value = true;
47
+ setTimeout(() => loading.value = false, 3000);
48
+ }
49
+
50
+ return { args, loading, save };
51
+ },
52
+ template: `
53
+ <FancyButton v-bind="args" :loading="loading" @click="save">
54
+ Save changes
55
+ <i class="i-celeste-check-line"></i>
56
+ </FancyButton>
57
+ `,
58
+ }),
59
+ };
@@ -71,7 +71,7 @@ function handleChange(e: MouseEvent | TouchEvent, skip = false) {
71
71
  }
72
72
 
73
73
  if (alpha.value !== a) {
74
- tinyColorRef.value = tinyColorRef.value.setAlpha(a).clone();
74
+ tinyColorRef.value = tinyColorRef.value.clone().setAlpha(a);
75
75
  }
76
76
  }
77
77
 
@@ -115,7 +115,7 @@ function handleKeydown(e: KeyboardEvent) {
115
115
  }
116
116
  }
117
117
  if (typeof newValue !== 'undefined') {
118
- tinyColorRef.value = tinyColorRef.value.setAlpha(newValue).clone();
118
+ tinyColorRef.value = tinyColorRef.value.clone().setAlpha(newValue);
119
119
  }
120
120
  }
121
121
 
@@ -235,7 +235,7 @@ function inputChangeAlpha(event: Event) {
235
235
  return;
236
236
  }
237
237
 
238
- tinyColorRef.value = tinyColorRef.value.setAlpha(Math.max(0, Math.min(1, alphaValue)));
238
+ tinyColorRef.value = tinyColorRef.value.clone().setAlpha(Math.max(0, Math.min(1, alphaValue)));
239
239
  }
240
240
 
241
241
  function handleColorValueKeyDown(event: KeyboardEvent, key: ColorKey) {
@@ -88,7 +88,7 @@ function handleDismiss() {
88
88
  gap: var(--spacing-12);
89
89
  scale: 0.98;
90
90
 
91
- &[data-state='delayed-open'] {
91
+ &[data-state$='open'] {
92
92
  animation-name: open;
93
93
  }
94
94
 
@@ -1,22 +1,17 @@
1
1
  <script setup lang="ts">
2
2
  import type { TooltipRootProps as PrimitiveProps, TooltipRootEmits } from 'reka-ui';
3
3
  import { TooltipRoot, useForwardPropsEmits } from 'reka-ui';
4
- import { ref } from 'vue';
5
- import { useDelegatedProps } from '@/composables/use-delegated-props';
6
4
 
7
5
  export interface TooltipRootProps extends PrimitiveProps {}
8
6
 
9
7
  const props = defineProps<TooltipRootProps>();
10
8
  const emits = defineEmits<TooltipRootEmits>();
11
9
 
12
- const delegatedProps = useDelegatedProps(props, 'open');
13
- const forwarded = useForwardPropsEmits(delegatedProps, emits);
14
-
15
- const open = ref(false);
10
+ const forwarded = useForwardPropsEmits(props, emits);
16
11
  </script>
17
12
 
18
13
  <template>
19
- <TooltipRoot v-bind="forwarded" v-model:open="open">
14
+ <TooltipRoot v-bind="forwarded">
20
15
  <slot />
21
16
  </TooltipRoot>
22
17
  </template>