| <script lang="ts"> |
| import type { MenuListEntry } from "@graphite/messages"; |
| import type { IconName } from "@graphite/utility-functions/icons"; |
| |
| import MenuList from "@graphite/components/floating-menus/MenuList.svelte"; |
| import ConditionalWrapper from "@graphite/components/layout/ConditionalWrapper.svelte"; |
| import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte"; |
| import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte"; |
| |
| let self: MenuList; |
| |
| |
| |
| export let label: string; |
| export let icon: IconName | undefined = undefined; |
| export let hoverIcon: IconName | undefined = undefined; |
| export let emphasized = false; |
| export let flush = false; |
| export let minWidth = 0; |
| export let disabled = false; |
| export let tooltip: string | undefined = undefined; |
| export let menuListChildren: MenuListEntry[][] | undefined = undefined; |
| |
| |
| |
| export let action: (() => void) | undefined; |
| |
| $: menuListChildrenExists = (menuListChildren?.length ?? 0) > 0; |
| |
| |
| function onClick(e: MouseEvent) { |
| |
| if ((menuListChildren?.length ?? 0) === 0) { |
| |
| if (action && !disabled) action(); |
| |
| |
| return; |
| } |
| |
| |
| (e.target as HTMLElement | undefined)?.focus(); |
| |
| |
| if (self) self.open = true; |
| else throw new Error("The menu bar floating menu has no reference to `self`"); |
| } |
| </script> |
|
|
| <ConditionalWrapper condition={menuListChildrenExists} wrapperClass="text-button-container"> |
| <button |
| class="text-button" |
| class:open={self?.open} |
| class:hover-icon={hoverIcon && !disabled} |
| class:emphasized |
| class:disabled |
| class:flush |
| style:min-width={minWidth > 0 ? `${minWidth}px` : undefined} |
| title={tooltip} |
| data-emphasized={emphasized || undefined} |
| data-disabled={disabled || undefined} |
| data-text-button |
| tabindex={disabled ? -1 : 0} |
| data-floating-menu-spawner={menuListChildrenExists ? "" : "no-hover-transfer"} |
| on:click={onClick} |
| > |
| {#if icon} |
| <IconLabel {icon} /> |
| {#if hoverIcon && !disabled} |
| <IconLabel icon={hoverIcon} /> |
| {/if} |
| {/if} |
| {#if label} |
| <TextLabel>{label}</TextLabel> |
| {/if} |
| </button> |
| {#if menuListChildrenExists} |
| <MenuList |
| on:open={({ detail }) => self && (self.open = detail)} |
| open={self?.open || false} |
| entries={menuListChildren || []} |
| direction="Bottom" |
| minWidth={240} |
| drawIcon={true} |
| bind:this={self} |
| /> |
| {/if} |
| </ConditionalWrapper> |
|
|
| <style lang="scss" global> |
| .text-button-container { |
| display: flex; |
| position: relative; |
| } |
| |
| .text-button { |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| flex: 0 0 auto; |
| white-space: nowrap; |
| height: 24px; |
| margin: 0; |
| padding: 0 8px; |
| box-sizing: border-box; |
| border: none; |
| border-radius: 2px; |
| background: var(--button-background-color); |
| color: var(--button-text-color); |
| --button-background-color: var(--color-5-dullgray); |
| --button-text-color: var(--color-e-nearwhite); |
| |
| &:hover, |
| &.open { |
| --button-background-color: var(--color-6-lowergray); |
| --button-text-color: var(--color-f-white); |
| } |
| |
| &.hover-icon { |
| &:not(:hover) .icon-label:nth-of-type(2) { |
| display: none; |
| } |
| |
| &:hover .icon-label:nth-of-type(1) { |
| display: none; |
| } |
| } |
| |
| &.disabled { |
| --button-background-color: var(--color-4-dimgray); |
| --button-text-color: var(--color-8-uppergray); |
| } |
| |
| &.emphasized { |
| --button-background-color: var(--color-e-nearwhite); |
| --button-text-color: var(--color-2-mildblack); |
| |
| &:hover, |
| &.open { |
| --button-background-color: var(--color-f-white); |
| } |
| |
| &.disabled { |
| --button-background-color: var(--color-8-uppergray); |
| } |
| } |
| |
| &.flush { |
| --button-background-color: none; |
| --button-text-color: var(--color-e-nearwhite); |
| |
| &:hover, |
| &.open { |
| --button-background-color: var(--color-5-dullgray); |
| } |
| } |
| |
| .icon-label { |
| fill: var(--button-text-color); |
| |
| + .text-label { |
| margin-left: 8px; |
| } |
| } |
| |
| .text-label { |
| overflow: hidden; |
| } |
| |
| // Custom styling for when multiple TextButton widgets are used next to one another in a row or column |
| .widget-span.row > & + .text-button, |
| .layout-row > & + .text-button { |
| margin-left: 8px; |
| } |
| .widget-span.column > & + .text-button, |
| .layout-column > & + .text-button { |
| margin-top: 8px; |
| } |
| } |
| </style> |
|
|