import { defineComponent } from "vue";
import type { ButtonHTMLAttributes, PropType, VNode } from "vue";
import colorSchemeStyles from "@darwin-studio/ui-codegen/dist/styles/color-scheme.css?module"; // TODO: shorter path, default export ??? TODO: make it module ???
import { DLoaderAsync as DLoader } from "@darwin-studio/vue-ui/src/components/atoms/d-loader/async";
import type { DLoaderProps } from "@darwin-studio/vue-ui/src/components/atoms/d-loader/types";
import { EVENT_NAME } from "@darwin-studio/vue-ui/src/constants/event-name";
import generateProp from "@darwin-studio/vue-ui/src/utils/generate-prop";
import generateClass from "@darwin-studio/vue-ui/src/utils/generate-class";
import type { Tag } from "./types";
import config from "./config";
import styles from "./index.css?module";
/**
* A clickable component which renders as button element, router-link component or a element depending on props.
*/
export default defineComponent({
name: config.name,
props: {
/**
* Plain string or VNode
*/
content: generateProp.content(),
/**
* Defines appearance of the component
*/
colorScheme: generateProp.colorScheme(), // TODO: gent defaults base on actual values, not hardcoded
/**
* Defines padding type of the component, use 'equal' if the component contains only an icon
*/
padding: generateProp.padding(), // TODO: gent defaults base on actual values, not hardcoded
/**
* Defines corner rounding of the component
*/
rounding: generateProp.rounding(), // TODO: gent defaults base on actual values, not hardcoded
/**
* Defines size of the component
*/
// TODO: fontSize and size separately ???
size: generateProp.size(), // TODO: gent defaults base on actual values, not hardcoded
/**
* Defines transition type of the component
*/
transition: generateProp.transition(), // TODO: gent defaults base on actual values, not hardcoded
/**
* Pass true to prevent default click behaviour
*/
preventDefault: Boolean,
/**
* Pass true to make the button disabled // TODO: test, story
*/
disabled: Boolean,
/**
* Defines if DLoader element should be displayed.
*/
loading: Boolean,
/**
* Pass any DLoader.props to customize it, f.e. { class: "someClass" }
*/
loaderOptions: generateProp.options(config.loaderOptions),
/**
* Pass true to make the button active // TODO: test, story
*/
active: Boolean,
/**
* Alternative way to catch click event
*/
whenClick: Function as PropType<
(event: MouseEvent) => void | Promise
>,
},
emits: [EVENT_NAME.CLICK],
computed: {
classes(): (string | undefined)[] {
const classes = [
config.class,
generateClass.border(this.colorScheme, this.size),
generateClass.colorScheme(this.colorScheme),
generateClass.font(this.size),
generateClass.outline(this.colorScheme, this.size),
...generateClass.padding(this.padding, this.size),
generateClass.rounding(this.rounding),
generateClass.size(this.size),
generateClass.transition(this.transition),
];
if (this.disabled) {
// TODO: use css custom props instead?
classes.push(styles["__disabled"]); // TODO: const
classes.push(colorSchemeStyles["__disabled"]); // TODO: const
}
if (this.loading) {
classes.push(styles["__loading"]); // TODO: const, test
}
if (this.active) {
classes.push(colorSchemeStyles["__active"]); // TODO: const
}
return classes;
},
tag(): Tag {
if (this.$attrs["href"]) {
return config.linkTag;
}
if (this.$attrs["to"]) {
return config.routerLinkTag;
}
return config.buttonTag;
},
bindings(): ButtonHTMLAttributes {
return {
class: this.classes,
onClick: this.clickHandler,
};
},
},
methods: {
clickHandler(event: MouseEvent): void | Promise {
if (this.preventDefault) {
event.preventDefault();
}
if (!this.disabled && !this.loading) {
/**
* Emits on click with MouseEvent payload
* @event click
* @type {event: MouseEvent}
*/
this.$emit(EVENT_NAME.CLICK, event);
this.whenClick?.(event);
}
},
},
render(): VNode {
const Tag = this.tag;
/** @slot Use instead of props.content to fully customize content */
return (
{this.$slots.default?.() || this.content}
{this.loading && (
)}
);
},
});