UNPKG

@sandlada/vue-mdc

Version:

![Vue MDC Logo](https://raw.githubusercontent.com/sandlada/vue-mdc/refs/heads/main/docs/vue-mdc-cover.png)

179 lines (178 loc) 6.3 kB
/** * @license * Copyright 2025 Sandlada & Kai Orion * SPDX-License-Identifier: MIT */ import { defineComponent, ref, computed, onMounted, onBeforeUnmount, watch, createVNode } from "vue"; import { useReflectAttribute } from "../../node_modules/@glare-labs/vue-reflect-attribute/build/vue-reflect-attribute.js"; import { isServer } from "../../utils/is-server.js"; import { generateUuid } from "../../utils/uuid.js"; import { setupDispatchHooks, afterDispatch } from "../../internals/events/dispatch-hooks.js"; import { isActivationClick, dispatchActivationClick } from "../../internals/events/form-label-activation.js"; import { redispatchEvent } from "../../internals/events/redispatch-event.js"; import "../../internals/navigation/render-navigation-destination.js"; import { componentNamePrefix } from "../../internals/component-name-prefix/component-name-prefix.js"; import { FocusRing } from "../focus-ring/focus-ring.js"; import { Ripple } from "../ripple/ripple.js"; import css from "./styles/switch.module.scss.js"; import { props } from "./switch.definition.js"; const SwitchOnIcon = () => createVNode("div", { "class": [css.icon, css["icon--on"]] }, [createVNode("svg", { "viewBox": "0 0 24 24" }, [createVNode("path", { "d": "M9.55 18.2 3.65 12.3 5.275 10.675 9.55 14.95 18.725 5.775 20.35 7.4Z" }, null)])]); const SwitchOffIcon = () => createVNode("div", { "class": [css.icon, css["icon--off"]] }, [createVNode("svg", { "viewBox": "0 0 24 24" }, [createVNode("path", { "d": "M6.4 19.2 4.8 17.6 10.4 12 4.8 6.4 6.4 4.8 12 10.4 17.6 4.8 19.2 6.4 13.6 12 19.2 17.6 17.6 19.2 12 13.6Z" }, null)])]); const Switch = /* @__PURE__ */ defineComponent({ name: `${componentNamePrefix}-switch`, props, slots: {}, emits: ["update:modelValue", "change"], setup(props2, { emit, slots }) { const root = ref(null); const input = ref(null); const ripple = ref(null); const focusRing = ref(null); const _selected = ref(props2.defaultSelected); const selected = computed({ get: () => _selected.value, set: (value) => { _selected.value = value; emit("update:modelValue", value); } }); const _disabled = ref(props2.disabled); const _withIcon = ref(props2.withIcon); const _withIconSelectedOnly = ref(props2.withIconSelectedOnly); const _value = computed(() => selected.value ? "on" : "off"); useReflectAttribute(root, { attributes: [{ attribute: "disabled", ref: _disabled, reflect: true, type: "boolean" }, { attribute: "selected", ref: _selected, reflect: true, type: "boolean" }, { attribute: "with-icon", ref: _withIcon, reflect: true, type: "boolean" }, { attribute: "with-icon-selected-only", ref: _withIconSelectedOnly, reflect: true, type: "boolean" }, { attribute: "value", ref: _value, reflect: false, type: "string" }] }); const handleClick = (event) => { if (!isActivationClick(event) || !input.value) { return; } root.value?.focus(); if (input.value) { dispatchActivationClick(input.value); } }; const handleKeydown = (event) => { afterDispatch(event, () => { const ignoreEvent = event.defaultPrevented || event.key !== "Enter"; if (ignoreEvent || _disabled.value || !input.value) { return; } input.value.click(); }); }; const handleInput = (event) => { const target = event.target; selected.value = target.checked; }; const handleChange = (event) => { redispatchEvent(root.value, event); }; onMounted(() => { if (isServer() || !root.value) { return; } const innerId = `switch-${generateUuid()}`; input.value?.setAttribute("id", innerId); focusRing.value?.$el.setAttribute("for", innerId); ripple.value?.$el.setAttribute("for", innerId); setupDispatchHooks(root.value, "keydown"); root.value.addEventListener("click", handleClick); root.value.addEventListener("keydown", handleKeydown); }); onBeforeUnmount(() => { root.value?.removeEventListener("click", handleClick); root.value?.removeEventListener("keydown", handleKeydown); }); watch(() => props2.modelValue, (newValue, oldValue) => { selected.value = newValue; }, { immediate: false }); return () => { const renderIcon = createVNode("span", { "class": [css.handle, (_withIconSelectedOnly.value || _withIcon.value) && css["with-icon"]] }, [(_withIconSelectedOnly.value || _withIcon.value) && createVNode("div", { "class": css.icons }, [_selected.value && (slots["on-icon"] ? slots["on-icon"]() : createVNode(SwitchOnIcon, null, null)), !_withIconSelectedOnly.value && !_selected.value && (slots["off-icon"] ? slots["off-icon"]() : createVNode(SwitchOffIcon, null, null))])]); return createVNode("div", { "class": [css.switch, _disabled.value && css.disabled, _selected.value ? css.selected : css.unselected], "role": "switch", "aria-disabled": _disabled.value, "data-component": "switch", "ref": root }, [createVNode(FocusRing, { "ref": focusRing, "shapeInherit": false }, null), createVNode("input", { "type": "checkbox", "role": "switch", "checked": _selected.value, "disabled": _disabled.value, "aria-disabled": _disabled.value, "class": "need-inner-id", "onInput": handleInput, "onChange": handleChange, "ref": input }, null), createVNode("span", { "aria-hidden": "true", "class": css.background }, null), createVNode("span", { "aria-hidden": "true", "class": css.outline }, null), createVNode("span", { "class": css.track, "aria-hidden": "true" }, [createVNode("span", { "class": css["handle-container"] }, [createVNode(Ripple, { "ref": ripple }, null), renderIcon])])]); }; }, inheritAttrs: true }); export { Switch }; //# sourceMappingURL=switch.js.map