| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| <script lang="ts"> |
| import { createBubbler, handlers } from 'svelte/legacy'; |
| |
| const bubble = createBubbler(); |
| import { twMerge } from 'tailwind-merge'; |
| |
| let isMouseDown = $state(false); |
| interface Props { |
| checked?: boolean | undefined; |
| value: string; |
| id?: string; |
| name?: string | undefined; |
| bindGroup?: string[] | undefined; |
| disabled?: boolean; |
| onclick?: (_event: Event) => void; |
| } |
| |
| let { |
| checked = $bindable(undefined), |
| value, |
| id = '', |
| name = undefined, |
| bindGroup = $bindable(undefined), |
| disabled = false, |
| onclick |
| }: Props = $props(); |
| |
| function onChange(e: Event) { |
| const { value: checkboxValue, checked: checkboxChecked } = e.target as HTMLInputElement; |
| if (bindGroup) { |
| if (checkboxChecked) { |
| bindGroup = [...bindGroup, checkboxValue]; |
| } else { |
| bindGroup = bindGroup.filter((item) => item !== value); |
| checked = checkboxChecked; |
| } |
| } else { |
| checked = checkboxChecked; |
| } |
| } |
| </script> |
| |
| <div class="relative w-8 h-8"> |
| <input |
| type="checkbox" |
| checked={bindGroup?.includes(value) || checked} |
| {name} |
| {value} |
| {id} |
| {disabled} |
| onchange={handlers(onChange, bubble('change'))} |
| {onclick} |
| onmousedown={() => (isMouseDown = true)} |
| onmouseup={() => (isMouseDown = false)} |
| onmouseleave={() => (isMouseDown = false)} |
| onmouseout={() => (isMouseDown = false)} |
| onblur={() => (isMouseDown = false)} |
| /> |
| |
| <div |
| role="checkbox" |
| tabindex="0" |
| aria-checked={checked} |
| class={twMerge( |
| 'w-[18px] h-[18px] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 border-neutral-300 border-2 rounded-sm transition-all pointer-events-none', |
| isMouseDown && 'scale-90' |
| )} |
| ></div> |
| |
| <svg |
| class="w-[18px] h-[18px] pointer-events-none transition-all scale-75 opacity-0 absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" |
| viewBox="0 0 24 24" |
| fill="none" |
| xmlns="http://www.w3.org/2000/svg" |
| > |
| <path |
| id="Vector" |
| d="M6 12L10.2426 16.2426L18.727 7.75732" |
| stroke-width="2.4" |
| stroke-linecap="round" |
| stroke-linejoin="round" |
| /> |
| </svg> |
| </div> |
| |
| <style lang="postcss"> |
| @reference "../../styles/app.css"; |
| |
| input[type='checkbox'] { |
| @apply cursor-pointer appearance-none m-0 absolute inset-0; |
| } |
| |
| input[type='checkbox'] + div { |
| @apply bg-shade-l100; |
| } |
| |
| input[type='checkbox']:hover:not(:checked):not(:disabled) + div { |
| @apply border-neutral-400; |
| } |
| |
| input[type='checkbox']:checked + div { |
| @apply bg-[#32AD84]; |
| } |
| |
| input[type='checkbox']:checked + div + svg { |
| @apply opacity-100 stroke-white; |
| } |
| |
| input[type='checkbox']:checked:disabled + div { |
| @apply opacity-50; |
| } |
| |
| input[type='checkbox']:disabled { |
| @apply cursor-not-allowed; |
| } |
| </style> |