import { defineComponent } from "vue"; import type { PropType, VNode, HTMLAttributes, InputHTMLAttributes, LabelHTMLAttributes, } from "vue"; import { v4 as uuid } from "uuid"; import { ROUNDING } from "@darwin-studio/ui-codegen/dist/constants/rounding"; import generateClass from "@darwin-studio/vue-ui/src/utils/generate-class"; import generateProp from "@darwin-studio/vue-ui/src/utils/generate-prop"; import { EVENT_NAME } from "@darwin-studio/vue-ui/src/constants/event-name"; import type { DCaptionProps } from "@darwin-studio/vue-ui/src/components/atoms/d-caption/types"; import useCaption from "@darwin-studio/vue-ui/src/compositions/caption"; import config from "./config"; /** * Renders custom input element with type="range" and role="slider".
* Implements ["slider"](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/slider_role). */ export default defineComponent({ name: config.name, props: { /** * Defines id attr of the input element.
* If you don't want to specify it, it will be generated automatically. */ id: generateProp.text(() => uuid()), /** * Defines initial value attr of the input element */ value: generateProp.number(), // TODO: dataset (not just step) // TODO: marks // TODO: mark labels // TODO: range from => to ? /** * Pass any track attrs you want */ trackOptions: generateProp.options(config.trackOptions), /** * Pass any input attrs you want */ inputOptions: generateProp.options( config.inputOptions ), /** * Defines content of the label element. */ label: generateProp.content(), /** * Pass any attrs to customize label, f.e. { class: "someClass" } */ labelOptions: generateProp.options( config.labelOptions ), /** Defines offset of .label */ labelOffset: generateProp.text(config.labelOffset), /** * If not empty renders DCaption below the input element. */ caption: generateProp.content(), /** * Pass any DCaption.props to customize caption, f.e. { type: "error" } */ captionOptions: generateProp.options(config.captionOptions), /** * Defines offset of DCaption */ captionOffset: generateProp.text(config.captionOffset), // TODO: move to captionOptions /** * Defines appearance of the component */ colorScheme: generateProp.colorScheme(), /** * Defines rounding of the component */ rounding: generateProp.rounding(ROUNDING.FULL), /** * Defines size of the component */ size: generateProp.size(), /** * Defines transition type of the component */ transition: generateProp.transition(), /** * Pass true to disable attr of the input element. */ disabled: Boolean, /** * Defines container element type of the component */ tag: generateProp.tag(), /** * Alternative way to catch change event */ whenChange: Function as PropType<(value: string) => void | Promise>, /** * Alternative way to catch input event */ whenInput: Function as PropType<(value: string) => void | Promise>, }, setup(props, { slots }) { return useCaption(props, slots, config.captionOptions); }, emits: [EVENT_NAME.CHANGE, EVENT_NAME.INPUT, EVENT_NAME.UPDATE_VALUE], computed: { classes(): (string | undefined)[] { return [ config.class, generateClass.minControlWidth(this.size), generateClass.size(this.size), ]; }, labelClasses(): (string | undefined)[] { return [generateClass.font(this.size)]; }, renderLabel(): VNode | null { if (!this.$slots.label?.() && !this.label) { return null; } return ( ); }, trackClasses(): (string | undefined)[] { return [ generateClass.colorScheme(this.colorScheme), generateClass.rounding(this.rounding), ]; }, renderTrack(): VNode { return (
{this.$slots.track?.()}
); }, inputClasses(): (string | undefined)[] { return [ generateClass.colorScheme(this.colorScheme), generateClass.outline(this.colorScheme, this.size), generateClass.rounding(this.rounding), generateClass.transition(this.transition), ]; }, renderInput(): VNode { return ( ); }, }, methods: { changeHandler(event: Event) { const value = (event.target as HTMLInputElement).value; /** * Emits on change with value payload * @event change * @type {value: Text} */ this.$emit(EVENT_NAME.CHANGE, value); /** * Emits on change with value payload * @event update:value * @type {value: Text} */ this.$emit(EVENT_NAME.UPDATE_VALUE, value); this.whenChange?.(value); }, inputHandler(event: Event) { const value = (event.target as HTMLInputElement).value; /** * Emits on input with value payload * @event input * @type {value: Text} */ this.$emit(EVENT_NAME.INPUT, value); this.whenInput?.(value); }, }, /** * @slot $slots.label * Use instead of props.label to fully customize label * */ /** * @slot $slots.track * Use instead of props.track to fully customize track * */ /** * @slot $slots.caption * Use instead of props.caption to fully customize caption * */ render(): VNode { const Tag = this.tag; return ( {this.renderLabel} {this.renderTrack} {this.renderInput} {this.renderCaption} ); }, });