Files
EasyFlow/easyflow-ui-admin/packages/tinyflow-ui/src/components/base/collapse.svelte

187 lines
5.5 KiB
Svelte

<svelte:options customElement={{ props: {} }} />
<script lang="ts">
import type {Snippet} from 'svelte';
import {Render} from './index';
interface Item {
key: string;
icon?: string | Snippet;
title: string | Snippet;
badge?: string | Snippet;
titleHelp?: string;
description?: string | Snippet;
content: string | Snippet;
}
let { items, onChange, activeKeys = $bindable([]), ...rest }: {
items: Item[],
onChange?: (item: Item, activeKeys: string[]) => void,
activeKeys?: string[],
[key: string]: any
} = $props();
function handlerOnChange(item: Item) {
if (activeKeys.includes(item.key)) {
activeKeys = activeKeys.filter(key => key !== item.key);
} else {
activeKeys.push(item.key);
activeKeys = activeKeys;
}
onChange?.(item, activeKeys);
}
</script>
<div style={rest.style} class="tf-collapse {rest.class}">
{#each items as item, index}
<div class="tf-collapse-item">
<div class="tf-collapse-item-title tf-node-drag-handle" role="button" tabindex={index}
onclick={() => handlerOnChange(item)}
onkeydown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
handlerOnChange(item);
}
}}
>
{#if item.icon}
<span class="tf-collapse-item-title-icon">
<Render target={item.icon} />
</span>
{/if}
<Render target={item.title} />
{#if item.badge}
<span class="tf-collapse-item-title-badge">
<Render target={item.badge} />
</span>
{/if}
{#if item.titleHelp}
<span
class="tf-collapse-item-title-help"
data-help={item.titleHelp}
aria-label="节点使用说明"
>
?
</span>
{/if}
<span class="tf-collapse-item-title-arrow {activeKeys.includes(item.key) ? 'rotate-90' : ''}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path
d="M13.1717 12.0007L8.22192 7.05093L9.63614 5.63672L16.0001 12.0007L9.63614 18.3646L8.22192 16.9504L13.1717 12.0007Z"></path></svg>
</span>
</div>
{#if item.description}
<div class="tf-collapse-item-description">
<Render target={item.description} />
</div>
{/if}
{#if activeKeys.includes(item.key)}
<div class="tf-collapse-item-content">
<Render target={item.content} />
</div>
{/if}
</div>
{/each}
</div>
<style>
/* 定义旋转的 CSS 类 */
.rotate-90 {
transform: rotate(90deg);
transition: transform 0.3s ease;
}
.tf-collapse-item-title-help {
margin-left: 6px;
width: 16px;
height: 16px;
border-radius: 50%;
border: 1px solid var(--tf-border-color-strong);
color: var(--tf-text-secondary);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 11px;
line-height: 1;
cursor: default;
user-select: none;
background: var(--tf-bg-surface);
position: relative;
}
.tf-collapse-item-title-badge {
display: inline-flex;
align-items: center;
min-height: 18px;
padding: 1px 6px;
margin-left: 8px;
font-size: 10px;
font-weight: 500;
line-height: 1.2;
color: var(--tf-primary-color);
white-space: nowrap;
background: var(--tf-primary-soft-bg);
border: 1px solid var(--tf-primary-soft-border);
border-radius: 999px;
}
.tf-collapse-item-title-help:hover {
border-color: var(--tf-border-color-strong);
color: var(--tf-text-primary);
background: var(--tf-bg-hover);
}
.tf-node-drag-handle {
cursor: grab;
}
:global(.svelte-flow__node.dragging) .tf-node-drag-handle {
cursor: grabbing;
}
.tf-collapse-item-title-help::after {
content: attr(data-help);
position: absolute;
left: calc(100% + 10px);
top: 50%;
transform: translateY(-50%);
min-width: 260px;
max-width: 420px;
white-space: pre-line;
background: var(--tf-tip-bg);
color: var(--tf-tip-text);
border-radius: 8px;
padding: 10px 12px;
font-size: 12px;
line-height: 1.45;
box-shadow: var(--tf-shadow-medium);
opacity: 0;
visibility: hidden;
pointer-events: none;
z-index: 120;
}
.tf-collapse-item-title-help::before {
content: "";
position: absolute;
left: calc(100% + 4px);
top: 50%;
transform: translateY(-50%);
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-right: 6px solid var(--tf-tip-bg);
opacity: 0;
visibility: hidden;
z-index: 121;
}
.tf-collapse-item-title-help:hover::after,
.tf-collapse-item-title-help:hover::before {
opacity: 1;
visibility: visible;
}
</style>