@youcan/celeste 0.23.0 → 0.24.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 +32 -2
- package/ai/icons.json +2 -2
- package/ai/tokens.json +2 -2
- package/dist/celeste.css +256 -117
- package/dist/cjs/chunks/button.cjs +9 -3
- package/dist/cjs/chunks/compact-button.cjs +1 -1
- package/dist/cjs/chunks/fancy-button.cjs +9 -3
- package/dist/cjs/chunks/social-button.cjs +1 -1
- package/dist/cjs/chunks/text-input-button.cjs +2 -0
- package/dist/components/button/button.d.ts +5 -1
- package/dist/components/button/fancy-button.d.ts +5 -1
- package/dist/es/chunks/button.js +10 -4
- package/dist/es/chunks/compact-button.js +1 -1
- package/dist/es/chunks/fancy-button.js +10 -4
- package/dist/es/chunks/social-button.js +1 -1
- package/dist/es/chunks/text-input-button.js +2 -0
- package/package.json +3 -3
- package/src/components/button/button.vue +59 -5
- package/src/components/button/compact-button.vue +1 -0
- package/src/components/button/fancy-button.vue +62 -5
- package/src/components/button/social-button.vue +1 -0
- package/src/components/button/stories/button.stories.ts +28 -0
- package/src/components/button/stories/fancy-button.stories.ts +28 -0
|
@@ -18,6 +18,8 @@ var button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0, vue.d
|
|
|
18
18
|
size: { default: "md" },
|
|
19
19
|
intent: { default: "primary" },
|
|
20
20
|
variant: { default: "fill" },
|
|
21
|
+
disabled: { type: Boolean },
|
|
22
|
+
loading: { type: Boolean },
|
|
21
23
|
asChild: { type: Boolean },
|
|
22
24
|
as: { default: "button" }
|
|
23
25
|
},
|
|
@@ -27,13 +29,17 @@ var button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0, vue.d
|
|
|
27
29
|
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(reka_ui.Primitive), {
|
|
28
30
|
as: __props.as,
|
|
29
31
|
"as-child": __props.asChild,
|
|
30
|
-
|
|
32
|
+
disabled: __props.disabled || __props.loading || void 0,
|
|
33
|
+
"aria-busy": __props.loading || void 0,
|
|
34
|
+
class: (0, vue.normalizeClass)((0, vue.unref)(clsx.default)("celeste-button", `celeste-button-intent-${__props.intent}`, `celeste-button-size-${__props.size}`, `celeste-button-variant-${__props.variant}`, __props.loading && !__props.asChild && "celeste-button-loading", props.class))
|
|
31
35
|
}, {
|
|
32
|
-
default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true)]),
|
|
36
|
+
default: (0, vue.withCtx)(() => [__props.asChild ? (0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true, 0) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true), _cache[0] || (_cache[0] = (0, vue.createElementVNode)("i", { class: "celeste-button-spinner i-celeste-loader-5-line" }, null, -1))], 64))]),
|
|
33
37
|
_: 3
|
|
34
38
|
}, 8, [
|
|
35
39
|
"as",
|
|
36
40
|
"as-child",
|
|
41
|
+
"disabled",
|
|
42
|
+
"aria-busy",
|
|
37
43
|
"class"
|
|
38
44
|
]);
|
|
39
45
|
};
|
|
@@ -41,7 +47,7 @@ var button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0, vue.d
|
|
|
41
47
|
});
|
|
42
48
|
//#endregion
|
|
43
49
|
//#region src/components/button/button.vue
|
|
44
|
-
var button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
50
|
+
var button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-30b82d15"]]);
|
|
45
51
|
//#endregion
|
|
46
52
|
Object.defineProperty(exports, "button_default", {
|
|
47
53
|
enumerable: true,
|
|
@@ -42,7 +42,7 @@ var compact_button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (
|
|
|
42
42
|
});
|
|
43
43
|
//#endregion
|
|
44
44
|
//#region src/components/button/compact-button.vue
|
|
45
|
-
var compact_button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(compact_button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
45
|
+
var compact_button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(compact_button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-0727facf"]]);
|
|
46
46
|
//#endregion
|
|
47
47
|
Object.defineProperty(exports, "compact_button_default", {
|
|
48
48
|
enumerable: true,
|
|
@@ -17,6 +17,8 @@ var fancy_button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0,
|
|
|
17
17
|
] },
|
|
18
18
|
size: { default: "md" },
|
|
19
19
|
intent: { default: "primary" },
|
|
20
|
+
disabled: { type: Boolean },
|
|
21
|
+
loading: { type: Boolean },
|
|
20
22
|
asChild: { type: Boolean },
|
|
21
23
|
as: { default: "button" }
|
|
22
24
|
},
|
|
@@ -26,13 +28,17 @@ var fancy_button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0,
|
|
|
26
28
|
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(reka_ui.Primitive), {
|
|
27
29
|
as: __props.as,
|
|
28
30
|
"as-child": __props.asChild,
|
|
29
|
-
|
|
31
|
+
disabled: __props.disabled || __props.loading || void 0,
|
|
32
|
+
"aria-busy": __props.loading || void 0,
|
|
33
|
+
class: (0, vue.normalizeClass)((0, vue.unref)(clsx.default)("celeste-fbutton", `celeste-fbutton-${__props.intent}`, `celeste-fbutton-${__props.size}`, __props.loading && !__props.asChild && "celeste-fbutton-loading", props.class))
|
|
30
34
|
}, {
|
|
31
|
-
default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true)]),
|
|
35
|
+
default: (0, vue.withCtx)(() => [__props.asChild ? (0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true, 0) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true), _cache[0] || (_cache[0] = (0, vue.createElementVNode)("i", { class: "celeste-fbutton-spinner i-celeste-loader-5-line" }, null, -1))], 64))]),
|
|
32
36
|
_: 3
|
|
33
37
|
}, 8, [
|
|
34
38
|
"as",
|
|
35
39
|
"as-child",
|
|
40
|
+
"disabled",
|
|
41
|
+
"aria-busy",
|
|
36
42
|
"class"
|
|
37
43
|
]);
|
|
38
44
|
};
|
|
@@ -40,7 +46,7 @@ var fancy_button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0,
|
|
|
40
46
|
});
|
|
41
47
|
//#endregion
|
|
42
48
|
//#region src/components/button/fancy-button.vue
|
|
43
|
-
var fancy_button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(fancy_button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
49
|
+
var fancy_button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(fancy_button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-9098298e"]]);
|
|
44
50
|
//#endregion
|
|
45
51
|
Object.defineProperty(exports, "fancy_button_default", {
|
|
46
52
|
enumerable: true,
|
|
@@ -34,7 +34,7 @@ var social_button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0
|
|
|
34
34
|
});
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region src/components/button/social-button.vue
|
|
37
|
-
var social_button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(social_button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
37
|
+
var social_button_default = /*#__PURE__*/ require__plugin_vue_export_helper._plugin_vue_export_helper_default(social_button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-85544f28"]]);
|
|
38
38
|
//#endregion
|
|
39
39
|
Object.defineProperty(exports, "social_button_default", {
|
|
40
40
|
enumerable: true,
|
|
@@ -5,10 +5,14 @@ export interface ButtonProps extends PrimitiveProps {
|
|
|
5
5
|
size?: 'xxs' | 'xs' | 'sm' | 'md';
|
|
6
6
|
intent?: 'primary' | 'neutral' | 'error';
|
|
7
7
|
variant?: 'fill' | 'stroke' | 'lighter' | 'ghost';
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
loading?: boolean;
|
|
8
10
|
}
|
|
9
|
-
declare var __VLS_8: {};
|
|
11
|
+
declare var __VLS_8: {}, __VLS_10: {};
|
|
10
12
|
type __VLS_Slots = {} & {
|
|
11
13
|
default?: (props: typeof __VLS_8) => any;
|
|
14
|
+
} & {
|
|
15
|
+
default?: (props: typeof __VLS_10) => any;
|
|
12
16
|
};
|
|
13
17
|
declare const __VLS_base: import('vue').DefineComponent<ButtonProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ButtonProps> & Readonly<{}>, {
|
|
14
18
|
size: "xxs" | "xs" | "sm" | "md";
|
|
@@ -4,10 +4,14 @@ export interface FancyButtonProps extends PrimitiveProps {
|
|
|
4
4
|
class?: HTMLAttributes['class'];
|
|
5
5
|
size?: 'xs' | 'sm' | 'md';
|
|
6
6
|
intent?: 'primary' | 'neutral' | 'error' | 'basic';
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
loading?: boolean;
|
|
7
9
|
}
|
|
8
|
-
declare var __VLS_8: {};
|
|
10
|
+
declare var __VLS_8: {}, __VLS_10: {};
|
|
9
11
|
type __VLS_Slots = {} & {
|
|
10
12
|
default?: (props: typeof __VLS_8) => any;
|
|
13
|
+
} & {
|
|
14
|
+
default?: (props: typeof __VLS_10) => any;
|
|
11
15
|
};
|
|
12
16
|
declare const __VLS_base: import('vue').DefineComponent<FancyButtonProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<FancyButtonProps> & Readonly<{}>, {
|
|
13
17
|
size: "xs" | "sm" | "md";
|
package/dist/es/chunks/button.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
2
|
-
import { createBlock, defineComponent, normalizeClass, openBlock, renderSlot, unref, withCtx } from "vue";
|
|
2
|
+
import { Fragment, createBlock, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, renderSlot, unref, withCtx } from "vue";
|
|
3
3
|
import clsx$1 from "clsx";
|
|
4
4
|
import { Primitive } from "reka-ui";
|
|
5
5
|
//#endregion
|
|
@@ -17,6 +17,8 @@ var button_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
17
17
|
size: { default: "md" },
|
|
18
18
|
intent: { default: "primary" },
|
|
19
19
|
variant: { default: "fill" },
|
|
20
|
+
disabled: { type: Boolean },
|
|
21
|
+
loading: { type: Boolean },
|
|
20
22
|
asChild: { type: Boolean },
|
|
21
23
|
as: { default: "button" }
|
|
22
24
|
},
|
|
@@ -26,17 +28,21 @@ var button_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
26
28
|
return openBlock(), createBlock(unref(Primitive), {
|
|
27
29
|
as: __props.as,
|
|
28
30
|
"as-child": __props.asChild,
|
|
29
|
-
|
|
31
|
+
disabled: __props.disabled || __props.loading || void 0,
|
|
32
|
+
"aria-busy": __props.loading || void 0,
|
|
33
|
+
class: normalizeClass(unref(clsx$1)("celeste-button", `celeste-button-intent-${__props.intent}`, `celeste-button-size-${__props.size}`, `celeste-button-variant-${__props.variant}`, __props.loading && !__props.asChild && "celeste-button-loading", props.class))
|
|
30
34
|
}, {
|
|
31
|
-
default: withCtx(() => [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
|
|
35
|
+
default: withCtx(() => [__props.asChild ? renderSlot(_ctx.$slots, "default", {}, void 0, true, 0) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [renderSlot(_ctx.$slots, "default", {}, void 0, true), _cache[0] || (_cache[0] = createElementVNode("i", { class: "celeste-button-spinner i-celeste-loader-5-line" }, null, -1))], 64))]),
|
|
32
36
|
_: 3
|
|
33
37
|
}, 8, [
|
|
34
38
|
"as",
|
|
35
39
|
"as-child",
|
|
40
|
+
"disabled",
|
|
41
|
+
"aria-busy",
|
|
36
42
|
"class"
|
|
37
43
|
]);
|
|
38
44
|
};
|
|
39
45
|
}
|
|
40
|
-
}), [["__scopeId", "data-v-
|
|
46
|
+
}), [["__scopeId", "data-v-30b82d15"]]);
|
|
41
47
|
//#endregion
|
|
42
48
|
export { button_default as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
2
|
-
import { createBlock, defineComponent, normalizeClass, openBlock, renderSlot, unref, withCtx } from "vue";
|
|
2
|
+
import { Fragment, createBlock, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, renderSlot, unref, withCtx } from "vue";
|
|
3
3
|
import clsx$1 from "clsx";
|
|
4
4
|
import { Primitive } from "reka-ui";
|
|
5
5
|
//#endregion
|
|
@@ -16,6 +16,8 @@ var fancy_button_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
|
|
|
16
16
|
] },
|
|
17
17
|
size: { default: "md" },
|
|
18
18
|
intent: { default: "primary" },
|
|
19
|
+
disabled: { type: Boolean },
|
|
20
|
+
loading: { type: Boolean },
|
|
19
21
|
asChild: { type: Boolean },
|
|
20
22
|
as: { default: "button" }
|
|
21
23
|
},
|
|
@@ -25,17 +27,21 @@ var fancy_button_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
|
|
|
25
27
|
return openBlock(), createBlock(unref(Primitive), {
|
|
26
28
|
as: __props.as,
|
|
27
29
|
"as-child": __props.asChild,
|
|
28
|
-
|
|
30
|
+
disabled: __props.disabled || __props.loading || void 0,
|
|
31
|
+
"aria-busy": __props.loading || void 0,
|
|
32
|
+
class: normalizeClass(unref(clsx$1)("celeste-fbutton", `celeste-fbutton-${__props.intent}`, `celeste-fbutton-${__props.size}`, __props.loading && !__props.asChild && "celeste-fbutton-loading", props.class))
|
|
29
33
|
}, {
|
|
30
|
-
default: withCtx(() => [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
|
|
34
|
+
default: withCtx(() => [__props.asChild ? renderSlot(_ctx.$slots, "default", {}, void 0, true, 0) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [renderSlot(_ctx.$slots, "default", {}, void 0, true), _cache[0] || (_cache[0] = createElementVNode("i", { class: "celeste-fbutton-spinner i-celeste-loader-5-line" }, null, -1))], 64))]),
|
|
31
35
|
_: 3
|
|
32
36
|
}, 8, [
|
|
33
37
|
"as",
|
|
34
38
|
"as-child",
|
|
39
|
+
"disabled",
|
|
40
|
+
"aria-busy",
|
|
35
41
|
"class"
|
|
36
42
|
]);
|
|
37
43
|
};
|
|
38
44
|
}
|
|
39
|
-
}), [["__scopeId", "data-v-
|
|
45
|
+
}), [["__scopeId", "data-v-9098298e"]]);
|
|
40
46
|
//#endregion
|
|
41
47
|
export { fancy_button_default as t };
|
|
@@ -31,6 +31,6 @@ var social_button_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
|
|
|
31
31
|
}, 8, ["aria-label", "class"]);
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
}), [["__scopeId", "data-v-
|
|
34
|
+
}), [["__scopeId", "data-v-85544f28"]]);
|
|
35
35
|
//#endregion
|
|
36
36
|
export { social_button_default as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youcan/celeste",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.24.0",
|
|
5
5
|
"author": "YouCan <tech@youcan.shop>",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"reka-ui": "~2.10.5",
|
|
53
53
|
"tinycolor2": "^1.6.0",
|
|
54
54
|
"vue-sonner": "^2.0.9",
|
|
55
|
-
"@youcan/celeste-
|
|
56
|
-
"@youcan/celeste-
|
|
55
|
+
"@youcan/celeste-icons": "0.24.0",
|
|
56
|
+
"@youcan/celeste-tokens": "0.24.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@chromatic-com/storybook": "^5.3.0",
|
|
@@ -9,6 +9,8 @@ export interface ButtonProps extends PrimitiveProps {
|
|
|
9
9
|
size?: 'xxs' | 'xs' | 'sm' | 'md';
|
|
10
10
|
intent?: 'primary' | 'neutral' | 'error';
|
|
11
11
|
variant?: 'fill' | 'stroke' | 'lighter' | 'ghost';
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
loading?: boolean;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
const props = withDefaults(defineProps<ButtonProps>(), {
|
|
@@ -23,15 +25,22 @@ const props = withDefaults(defineProps<ButtonProps>(), {
|
|
|
23
25
|
<Primitive
|
|
24
26
|
:as
|
|
25
27
|
:as-child
|
|
28
|
+
:disabled="disabled || loading || undefined"
|
|
29
|
+
:aria-busy="loading || undefined"
|
|
26
30
|
:class="clsx(
|
|
27
31
|
'celeste-button',
|
|
28
32
|
`celeste-button-intent-${intent}`,
|
|
29
33
|
`celeste-button-size-${size}`,
|
|
30
34
|
`celeste-button-variant-${variant}`,
|
|
35
|
+
loading && !asChild && 'celeste-button-loading',
|
|
31
36
|
props.class,
|
|
32
37
|
)"
|
|
33
38
|
>
|
|
34
|
-
<slot />
|
|
39
|
+
<slot v-if="asChild" />
|
|
40
|
+
<template v-else>
|
|
41
|
+
<slot />
|
|
42
|
+
<i class="celeste-button-spinner i-celeste-loader-5-line" />
|
|
43
|
+
</template>
|
|
35
44
|
</Primitive>
|
|
36
45
|
</template>
|
|
37
46
|
|
|
@@ -216,6 +225,7 @@ $hover-map: (
|
|
|
216
225
|
|
|
217
226
|
.celeste-button {
|
|
218
227
|
display: inline-flex;
|
|
228
|
+
position: relative;
|
|
219
229
|
box-sizing: border-box;
|
|
220
230
|
align-items: center;
|
|
221
231
|
justify-content: center;
|
|
@@ -229,8 +239,9 @@ $hover-map: (
|
|
|
229
239
|
text-decoration: none;
|
|
230
240
|
white-space: nowrap;
|
|
231
241
|
cursor: pointer;
|
|
242
|
+
user-select: none;
|
|
232
243
|
|
|
233
|
-
&:disabled {
|
|
244
|
+
&:disabled:not(&-loading) {
|
|
234
245
|
background-color: var(--color-bg-weak-50);
|
|
235
246
|
color: var(--color-text-disabled-300);
|
|
236
247
|
cursor: default;
|
|
@@ -249,7 +260,8 @@ $hover-map: (
|
|
|
249
260
|
padding: map.get($v, padding);
|
|
250
261
|
border-radius: map.get($v, border-radius);
|
|
251
262
|
|
|
252
|
-
&:has(> :only-child:is(i))
|
|
263
|
+
&:has(> :only-child:is(i):not(.celeste-button-spinner)),
|
|
264
|
+
&:has(> i:first-child + .celeste-button-spinner:last-child) {
|
|
253
265
|
padding: list.nth(map.get($v, padding), 1);
|
|
254
266
|
}
|
|
255
267
|
}
|
|
@@ -257,11 +269,17 @@ $hover-map: (
|
|
|
257
269
|
|
|
258
270
|
@each $intent, $sub in $intent-map {
|
|
259
271
|
@each $variant, $values in $sub {
|
|
260
|
-
&-intent-#{$intent}
|
|
272
|
+
&-intent-#{$intent}.celeste-button-variant-#{$variant}:not(:disabled:not(.celeste-button-loading)) {
|
|
273
|
+
--celeste-button-fg: #{map.get($values, fg)};
|
|
274
|
+
|
|
261
275
|
border-color: map.get($values, border);
|
|
262
276
|
background-color: map.get($values, bg);
|
|
263
277
|
box-shadow: map.get($values, shadow);
|
|
264
|
-
color:
|
|
278
|
+
color: var(--celeste-button-fg);
|
|
279
|
+
|
|
280
|
+
&.celeste-button-loading {
|
|
281
|
+
color: transparent;
|
|
282
|
+
}
|
|
265
283
|
|
|
266
284
|
&:hover:not(:disabled) {
|
|
267
285
|
$hover-values: map.get(map.get($hover-map, $intent), $variant);
|
|
@@ -283,4 +301,40 @@ $hover-map: (
|
|
|
283
301
|
}
|
|
284
302
|
}
|
|
285
303
|
}
|
|
304
|
+
|
|
305
|
+
.celeste-button-loading {
|
|
306
|
+
pointer-events: none;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.celeste-button-spinner {
|
|
310
|
+
position: absolute;
|
|
311
|
+
margin: auto;
|
|
312
|
+
transition-property: opacity, scale;
|
|
313
|
+
transition-duration: var(--animation-fast);
|
|
314
|
+
transition-timing-function: ease-out;
|
|
315
|
+
animation: celeste-button-spin 600ms linear infinite paused;
|
|
316
|
+
opacity: 0;
|
|
317
|
+
color: var(--celeste-button-fg);
|
|
318
|
+
inset: 0;
|
|
319
|
+
scale: 0.9;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.celeste-button-loading > .celeste-button-spinner {
|
|
323
|
+
animation-play-state: running;
|
|
324
|
+
opacity: 1;
|
|
325
|
+
scale: 1;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
@media (prefers-reduced-motion: reduce) {
|
|
329
|
+
.celeste-button-spinner {
|
|
330
|
+
animation-duration: 1200ms;
|
|
331
|
+
scale: 1;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
@keyframes celeste-button-spin {
|
|
336
|
+
100% {
|
|
337
|
+
rotate: 360deg;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
286
340
|
</style>
|
|
@@ -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:
|
|
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(--
|
|
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>
|
|
@@ -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
|
+
};
|