Files
windmill/frontend/src/lib/components/common/toggleButton-v2/ToggleButton.svelte
T
a9a9335a34 fix: keep the instance users table's actions and header in view (#11145)
* fix: keep the instance users table's actions and header in view

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pMjimm9tUMXtD8rkWB62w

* fix: lock only the User option for group-granted roles and keep pinned cells opaque

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pMjimm9tUMXtD8rkWB62w

* fix: close the instance settings drawer from the manage-in-workspace menu item

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pMjimm9tUMXtD8rkWB62w

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-09-16 00:26:56 +02:00

126 lines
3.8 KiB
Svelte

<script lang="ts">
import { twMerge } from 'tailwind-merge'
import Tooltip from '$lib/components/meltComponents/Tooltip.svelte'
import { type ToggleGroupElements, type ToggleGroupItemProps, melt } from '@melt-ui/svelte'
import { Info } from 'lucide-svelte'
import { ButtonType } from '$lib/components/common/button/model'
interface Props {
label?: string | undefined
/** Shown instead of `label` below the `xl` breakpoint, for groups that must keep
* their width inside a narrow table cell. The full label stays the accessible name. */
shortLabel?: string | undefined
iconOnly?: boolean
tooltip?: string | undefined
icon?: any | undefined
disabled?: boolean
selectedColor?: string | undefined
small?: boolean
size?: 'sm' | 'md' | 'lg'
iconProps?: Record<string, any>
showTooltipIcon?: boolean
documentationLink?: string | undefined
id?: string | undefined
item: ToggleGroupElements['item']
value: ToggleGroupItemProps
class?: string
// Fires on activation, including on the already-selected button — which the
// group's onSelected never reports (melt treats it as a deselection and the
// group keeps the current value). Keyboard activation needs its own keydown
// branch below: melt preventDefaults Enter/Space, so no click is synthesized.
onActivate?: (e: Event) => void
}
let {
label = undefined,
shortLabel = undefined,
iconOnly = false,
tooltip = undefined,
icon = undefined,
disabled = false,
selectedColor = undefined,
small = false,
size = undefined,
iconProps = {},
showTooltipIcon = false,
documentationLink = undefined,
id = undefined,
item,
value,
class: className = '',
onActivate
}: Props = $props()
// Handle backward compatibility: small prop maps to size="sm"
const actualSize = $derived(size ?? (small ? 'sm' : 'md'))
// Direct access to unified sizing
const horizontalPadding = $derived(
iconOnly
? ButtonType.UnifiedIconOnlySizingClasses[actualSize]
: ButtonType.UnifiedSizingClasses[actualSize]
)
const height = $derived(ButtonType.UnifiedHeightClasses[actualSize])
const iconSize = $derived(ButtonType.UnifiedIconSizes[actualSize])
</script>
<Tooltip
class={twMerge('flex', disabled ? 'cursor-not-allowed' : 'cursor-pointer')}
disablePopup={tooltip === undefined}
{documentationLink}
>
<button
{id}
{disabled}
aria-label={shortLabel ? label : undefined}
class={twMerge(
'group rounded-md transition-all font-normal flex gap-1 flex-row items-center justify-center border text-xs',
horizontalPadding,
height,
'text-primary data-[state=on]:text-primary',
'data-[state=on]:bg-surface-tertiary data-[state=off]:border-transparent data-[state=on]:border-border-normal/30',
'bg-surface-transparent hover:bg-surface-hover',
disabled ? '!shadow-none !text-disabled' : '',
className
)}
use:melt={$item(value)}
style={selectedColor ? `--selected-color: ${selectedColor}` : ''}
onclick={onActivate}
onkeydown={(e) => {
// `repeat` filtered out: a held key keeps firing keydown, and one activation
// must mean one call however the consumer's side effect behaves.
if (!e.repeat && (e.key === 'Enter' || e.key === ' ')) onActivate?.(e)
}}
>
{#if icon}
{@const SvelteComponent = icon}
<SvelteComponent
size={iconSize}
{...iconProps}
class={twMerge(
'text-primary',
selectedColor
? 'group-data-[state=on]:text-[var(--selected-color)]'
: 'group-data-[state=on]:text-blue-500 dark:group-data-[state=on]:text-nord-800',
iconProps.class
)}
/>
{/if}
{#if label && !iconOnly}
{#if shortLabel}
<span class="hidden xl:inline">{label}</span>
<span class="xl:hidden" aria-hidden="true">{shortLabel}</span>
{:else}
{label}
{/if}
{/if}
{#if showTooltipIcon}
<Info size={iconSize} class="text-gray-400" />
{/if}
</button>
{#snippet text()}
{tooltip}
{/snippet}
</Tooltip>