Updated Enums in Settings, EditEnum (#4423)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov
2024-01-24 14:39:49 +07:00
committed by GitHub
parent b87bcf2ebe
commit 1024faa46e
30 changed files with 809 additions and 259 deletions
@@ -26,7 +26,17 @@
} from '@hcengineering/core'
import { getEmbeddedLabel } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation'
import { AnyComponent, Component, DropdownLabelsIntl, ModernEditbox, Label, Modal } from '@hcengineering/ui'
import {
AnyComponent,
Component,
DropdownLabelsIntl,
ModernEditbox,
Label,
Modal,
ButtonIcon,
IconDelete,
IconCopy
} from '@hcengineering/ui'
import { DropdownIntlItem } from '@hcengineering/ui/src/types'
import setting from '../plugin'
import view from '@hcengineering/view'
@@ -108,6 +118,10 @@
clearSettingsStore()
}}
>
<svelte:fragment slot="actions">
<ButtonIcon icon={IconDelete} size={'small'} kind={'tertiary'} />
<ButtonIcon icon={IconCopy} size={'small'} kind={'tertiary'} />
</svelte:fragment>
<div class="hulyModal-content__titleGroup">
<div class="hulyChip-item font-medium-12">
<Label label={setting.string.Custom} />
@@ -25,7 +25,10 @@
ModernEditbox,
Label,
themeStore,
Modal
Modal,
ButtonIcon,
IconDelete,
IconCopy
} from '@hcengineering/ui'
import view from '@hcengineering/view-resources/src/plugin'
import { clearSettingsStore } from '../store'
@@ -111,6 +114,10 @@
clearSettingsStore()
}}
>
<svelte:fragment slot="actions">
<ButtonIcon icon={IconDelete} size={'small'} kind={'tertiary'} />
<ButtonIcon icon={IconCopy} size={'small'} kind={'tertiary'} />
</svelte:fragment>
<div class="hulyModal-content__titleGroup">
{#if attribute.isCustom}
<div class="hulyChip-item font-medium-12">
@@ -14,22 +14,37 @@
-->
<script lang="ts">
import core, { Enum } from '@hcengineering/core'
import presentation, { Card, getClient, MessageBox } from '@hcengineering/presentation'
import { ActionIcon, EditBox, IconAdd, IconAttachment, IconDelete, ListView, showPopup } from '@hcengineering/ui'
import view from '@hcengineering/view-resources/src/plugin'
import presentation, { getClient, MessageBox } from '@hcengineering/presentation'
import {
IconAdd,
IconAttachment,
IconDelete,
showPopup,
Modal,
ModernEditbox,
Label,
ButtonIcon,
IconMoreV,
IconMoreV2,
eventToHTMLElement,
ModernPopup
} from '@hcengineering/ui'
import type { DropdownIntlItem } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import setting from '../plugin'
import EnumValuesList from './EnumValuesList.svelte'
import Copy from './icons/Copy.svelte'
import IconBulletList from './icons/BulletList.svelte'
import Report from './icons/Report.svelte'
import { IntlString } from '@hcengineering/platform'
export let value: Enum | undefined
export let name: string = value?.name ?? ''
export let values: string[] = value?.enumValues ?? []
export let title: IntlString = setting.string.EditEnum
const client = getClient()
const dispatch = createEventDispatcher()
let list: ListView
async function save (): Promise<void> {
if (value === undefined) {
await client.createDoc(core.class.Enum, core.space.Model, {
@@ -47,18 +62,29 @@
function add () {
newValue = newValue.trim()
if (newValue.length === 0) return
if (matched) return
if (values.includes(newValue)) return
values.push(newValue)
values = values
newValue = ''
}
function remove (value: string) {
values = values.filter((p) => p !== value)
}
const handleKeydown = (evt: KeyboardEvent) => {
if (evt.key === 'Enter') {
add()
}
if (evt.key === 'Escape') {
newItem = false
newValue = ''
evt.stopPropagation()
}
}
let newValue = ''
let newItem: boolean = false
let opened: boolean = false
let inputFile: HTMLInputElement
function processText (text: string): void {
@@ -89,6 +115,7 @@
}
function fileDrop (e: DragEvent) {
dragover = false
const list = e.dataTransfer?.files
if (list === undefined || list.length === 0) return
for (let index = 0; index < list.length; index++) {
@@ -114,40 +141,78 @@
const text = await navigator.clipboard.readText()
processText(text)
}
let dragover = false
const selection: number = 0
function onKeydown (key: KeyboardEvent): void {
if (key.code === 'ArrowUp') {
key.stopPropagation()
key.preventDefault()
list.select(selection - 1)
// $: filtered = newValue.length > 0 ? values.filter((it) => it.includes(newValue)) : values
$: matched = values.includes(newValue.trim())
// function onDelete () {
// showPopup(
// MessageBox,
// {
// label: view.string.DeleteObject,
// message: view.string.DeleteObjectConfirm,
// params: { count: filtered.length }
// },
// 'top',
// (result?: boolean) => {
// if (result === true) {
// values = values.filter((it) => !filtered.includes(it))
// newValue = ''
// }
// }
// )
// }
const items: (DropdownIntlItem & { action: () => void })[] = [
{
id: 'import',
icon: IconAttachment,
label: setting.string.ImportEnum,
action: () => {
inputFile.click()
}
},
{
id: 'paste',
icon: Report,
label: setting.string.ImportEnumCopy,
action: () => {
handleClipboard()
}
}
if (key.code === 'ArrowDown') {
key.stopPropagation()
key.preventDefault()
list.select(selection + 1)
]
const openPopup = (ev: MouseEvent): void => {
if (!opened) {
opened = true
showPopup(ModernPopup, { items }, eventToHTMLElement(ev), (result) => {
if (result) items.find((it) => it.id === result)?.action()
opened = false
})
}
}
$: filtered = newValue.length > 0 ? values.filter((it) => it.includes(newValue)) : values
async function showConfirmationDialog (): Promise<void> {
const isEnumEmpty = values.length === 0
function onDelete () {
showPopup(
MessageBox,
{
label: view.string.DeleteObject,
message: view.string.DeleteObjectConfirm,
params: { count: filtered.length }
},
'top',
(result?: boolean) => {
if (result === true) {
values = values.filter((it) => !filtered.includes(it))
newValue = ''
if (isEnumEmpty) {
dispatch('close')
} else {
showPopup(
MessageBox,
{
label: setting.string.NewEnumDialogClose,
message: setting.string.NewEnumDialogCloseNote
},
'top',
(result?: boolean) => {
if (result === true) dispatch('close')
}
}
)
)
}
}
</script>
@@ -163,57 +228,22 @@
on:change={fileSelected}
/>
<Card
label={core.string.Enum}
<Modal
label={title}
type={'type-popup'}
okLabel={presentation.string.Save}
okAction={save}
canSave={name.trim().length > 0 && values.length > 0}
on:close={() => {
dispatch('close')
onCancel={() => {
showConfirmationDialog()
}}
on:changeContent
>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="flex-col" on:keydown={onKeydown}>
<EditBox bind:value={name} placeholder={core.string.Name} kind={'large-style'} fullSize />
<div class="flex-between my-4">
<EditBox placeholder={presentation.string.Search} kind={'large-style'} bind:value={newValue} fullSize />
<div class="flex-row-center flex-no-shrink gap-2 ml-4">
<ActionIcon icon={IconAdd} label={presentation.string.Add} action={add} size={'small'} />
<ActionIcon
icon={Copy}
label={setting.string.ImportEnumCopy}
action={() => {
handleClipboard()
}}
size={'small'}
/>
<ActionIcon
icon={IconDelete}
label={setting.string.Delete}
action={() => {
onDelete()
}}
size={'small'}
/>
</div>
</div>
<div class="scroll" style:margin={'0 -.5rem'}>
<div class="box flex max-h-125">
<EnumValuesList
bind:values
bind:filtered
on:remove={(e) => {
remove(e.detail)
}}
/>
</div>
</div>
</div>
<svelte:fragment slot="footer">
<div class="flex-col">
<ModernEditbox bind:value={name} label={setting.string.EnumTitle} kind={'ghost'} size={'large'} width={'100%'} />
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="resume flex-center"
class:solid={dragover}
class="hulyTableAttr-container mt-6"
class:dragDropZone={dragover}
on:dragover|preventDefault={() => {
dragover = true
}}
@@ -222,14 +252,81 @@
}}
on:drop|preventDefault|stopPropagation={fileDrop}
>
<ActionIcon
icon={IconAttachment}
label={setting.string.ImportEnum}
action={() => {
inputFile.click()
}}
size={'small'}
/>
<div class="hulyTableAttr-header font-medium-12">
<IconBulletList size={'small'} />
<span><Label label={setting.string.Options} /></span>
<div class="buttons-group tertiary-textColor">
<ButtonIcon
kind={'tertiary'}
icon={IconMoreV}
size={'small'}
pressed={opened}
inheritColor
hasMenu
on:click={(ev) => {
openPopup(ev)
}}
/>
<ButtonIcon
kind={'primary'}
icon={IconAdd}
size={'small'}
tooltip={{ label: setting.string.Add }}
on:click={() => {
newItem = true
}}
/>
</div>
</div>
{#if values.length > 0 || newItem}
<div class="hulyTableAttr-content options">
<EnumValuesList
bind:values
disableMouseOver={newItem}
on:remove={(e) => {
remove(e.detail)
}}
/>
{#if newItem}
<div class="hulyTableAttr-content__row hovered">
<div class="hulyTableAttr-content__row-dragMenu">
<IconMoreV2 size={'small'} />
</div>
<div class="hulyTableAttr-content__row-label font-regular-14 accent grow">
<ModernEditbox
kind={'ghost'}
size={'small'}
label={setting.string.EnterOptionTitle}
on:keydown={handleKeydown}
bind:value={newValue}
width={'100%'}
autoFocus
/>
</div>
{#if matched}
<div class="hulyChip-item error font-medium-12">
<Label label={presentation.string.Match} />
</div>
{/if}
<ButtonIcon
kind={'tertiary'}
icon={IconDelete}
size={'small'}
on:click={() => {
newValue = ''
newItem = false
}}
/>
</div>
{/if}
</div>
{/if}
</div>
</svelte:fragment>
</Card>
</div>
</Modal>
<style lang="scss">
.dragDropZone {
border: 2px dashed var(--theme-popup-hover);
}
</style>
@@ -15,10 +15,8 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import core, { Enum } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import { createQuery } from '@hcengineering/presentation'
import {
CircleButton,
EditBox,
eventToHTMLElement,
IconAdd,
IconMoreH,
@@ -29,7 +27,10 @@
defineSeparators,
settingsSeparators,
Separator,
Scroller
Scroller,
ButtonIcon,
IconTableOfContents,
ModernButton
} from '@hcengineering/ui'
import { ContextMenu } from '@hcengineering/view-resources'
import setting from '../plugin'
@@ -44,7 +45,6 @@
let enums: Enum[] = []
let selected: Enum | undefined
let hovered: number | null = null
const client = getClient()
query.query(core.class.Enum, {}, (res) => {
enums = res
@@ -54,32 +54,38 @@
})
function create () {
showPopup(setting.component.EditEnum, {}, 'top')
showPopup(setting.component.EditEnum, { title: setting.string.CreateEnum }, 'top')
}
async function update (value: Enum): Promise<void> {
await client.update(value, {
name: value.name
})
}
defineSeparators('workspaceSettings', settingsSeparators)
</script>
<div class="hulyComponent">
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
<Breadcrumb icon={setting.icon.Enums} label={setting.string.Enums} size={'large'} isCurrent />
<svelte:fragment slot="actions">
<ModernButton
kind={'primary'}
icon={IconAdd}
label={setting.string.CreateEnum}
size={'small'}
on:click={create}
/>
</svelte:fragment>
</Header>
<div class="hulyComponent-content__container columns">
<div class="hulyComponent-content__column">
<div class="flex-between trans-title m-3">
<Label label={setting.string.Enums} />
<CircleButton icon={IconAdd} size="medium" on:click={create} />
<div class="hulyComponent-content__navHeader">
<div class="hulyComponent-content__navHeader-menu">
<ButtonIcon kind={'tertiary'} icon={IconTableOfContents} size={'small'} inheritColor />
</div>
<div class="hulyComponent-content__navHeader-hint paragraph-regular-14">
<Label label={setting.string.EnumsSettingHint} />
</div>
</div>
<div class="overflow-y-auto">
<Scroller>
{#each enums as value, i}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
<button
class="enum__list-item"
class:hovered={hovered === i}
class:selected={selected === value}
@@ -87,21 +93,27 @@
selected = value
}}
>
<EditBox bind:value={value.name} on:change={() => update(value)} />
<div
class="hover-trans"
on:click|stopPropagation={(ev) => {
<div class="flex-col">
<span class="font-regular-14 overflow-label">{value.name}</span>
<span class="font-regular-12 secondary-textColor overflow-label">
<Label label={setting.string.EnumsCount} params={{ count: value.enumValues.length }} />
</span>
</div>
<ButtonIcon
kind={'tertiary'}
icon={IconMoreH}
size={'small'}
pressed={hovered === i}
on:click={(ev) => {
hovered = i
showPopup(ContextMenu, { object: value }, eventToHTMLElement(ev), () => {
hovered = null
})
}}
>
<IconMoreH size={'medium'} />
</div>
</div>
/>
</button>
{/each}
</div>
</Scroller>
</div>
<Separator name={'workspaceSettings'} index={0} color={'var(--theme-divider-color)'} />
<div class="hulyComponent-content__column content">
@@ -121,21 +133,27 @@
display: flex;
justify-content: space-between;
align-items: center;
min-height: 2.5rem;
margin: 0 0.75rem;
padding: 0 1.25rem;
border: 1px solid transparent;
border-radius: 12px;
cursor: pointer;
margin: 0 var(--spacing-1_5);
padding: var(--spacing-1) var(--spacing-1_25);
text-align: left;
border: none;
border-radius: var(--small-BorderRadius);
outline: none;
& :global(button.type-button-icon) {
visibility: hidden;
}
&.hovered,
&:hover {
background-color: var(--theme-button-hovered);
& :global(button.type-button-icon) {
visibility: visible;
}
}
&.selected {
background-color: var(--theme-button-default);
border-color: var(--theme-button-border);
cursor: auto;
cursor: default;
}
}
</style>
@@ -15,25 +15,43 @@
<script lang="ts">
import { Enum } from '@hcengineering/core'
import presentation, { getClient, MessageBox } from '@hcengineering/presentation'
import { ActionIcon, EditBox, IconAdd, IconAttachment, IconDelete, showPopup } from '@hcengineering/ui'
import view from '@hcengineering/view-resources/src/plugin'
import {
ModernEditbox,
IconAdd,
IconAttachment,
IconDelete,
showPopup,
ModernButton,
Label,
ButtonIcon,
IconMoreV,
IconMoreV2,
ModernPopup,
eventToHTMLElement
} from '@hcengineering/ui'
import type { DropdownIntlItem } from '@hcengineering/ui'
import setting from '../plugin'
import EnumValuesList from './EnumValuesList.svelte'
import Copy from './icons/Copy.svelte'
import IconCrossedArrows from './icons/CrossedArrows.svelte'
import IconBulletList from './icons/BulletList.svelte'
import Report from './icons/Report.svelte'
export let value: Enum
const client = getClient()
let newValue = ''
let newValue: string = ''
let newItem: boolean = false
let opened: boolean = false
async function add () {
if (newValue.trim().length === 0) return
if (value.enumValues.includes(newValue.trim())) return
if (matched) return
await client.update(value, {
$push: { enumValues: newValue }
})
newValue = ''
newItem = false
}
async function remove (target: string) {
@@ -45,8 +63,13 @@
if (evt.key === 'Enter') {
add()
}
if (evt.key === 'Escape') {
newItem = false
newValue = ''
}
}
$: filtered = newValue.length > 0 ? value.enumValues.filter((it) => it.includes(newValue)) : value.enumValues
// $: filtered = newValue.length > 0 ? value.enumValues.filter((it) => it.includes(newValue)) : []
$: matched = value.enumValues.includes(newValue.trim())
async function handleClipboard (): Promise<void> {
const text = await navigator.clipboard.readText()
@@ -81,31 +104,84 @@
}
inputFile.value = ''
}
function onDelete () {
showPopup(
MessageBox,
{
label: view.string.DeleteObject,
message: view.string.DeleteObjectConfirm,
params: { count: filtered.length }
},
undefined,
(result?: boolean) => {
if (result === true) {
client.update(value, {
$pull: { enumValues: { $in: filtered } }
})
newValue = ''
}
}
)
// function onDelete () {
// showPopup(
// MessageBox,
// {
// label: view.string.DeleteObject,
// message: view.string.DeleteObjectConfirm,
// params: { count: filtered.length }
// },
// undefined,
// (result?: boolean) => {
// if (result === true) {
// client.update(value, {
// $pull: { enumValues: { $in: filtered } }
// })
// newValue = ''
// }
// }
// )
// }
async function update (value: Enum): Promise<void> {
await client.update(value, {
name: value.name
})
}
async function onDrop () {
await client.update(value, { enumValues: value.enumValues })
}
const items: (DropdownIntlItem & { action: () => void })[] = [
{
id: 'import',
icon: IconAttachment,
label: setting.string.ImportEnum,
action: () => {
inputFile.click()
}
},
{
id: 'paste',
icon: Report,
label: setting.string.ImportEnumCopy,
action: () => {
handleClipboard()
}
}
]
const openPopup = (ev: MouseEvent): void => {
if (!opened) {
opened = true
showPopup(ModernPopup, { items }, eventToHTMLElement(ev), (result) => {
if (result) items.find((it) => it.id === result)?.action()
opened = false
})
}
}
</script>
<div class="flex-between flex-gap-2">
<ModernEditbox
bind:value={value.name}
label={setting.string.EnumTitle}
kind={'ghost'}
size={'large'}
on:change={() => update(value)}
/>
<ModernButton
icon={IconCrossedArrows}
label={setting.string.ProjectTypesCount}
labelParams={{ count: 0 }}
disabled
kind={'tertiary'}
size={'medium'}
hasMenu
/>
</div>
<input
bind:this={inputFile}
multiple
@@ -115,56 +191,74 @@
style="display: none"
on:change={fileSelected}
/>
<div class="flex-grow">
<div class="flex-between mb-4">
<EditBox
placeholder={presentation.string.Search}
on:keydown={handleKeydown}
kind="large-style"
bind:value={newValue}
/>
<div class="flex-row-center gap-2">
<ActionIcon
<div class="hulyTableAttr-container mt-6">
<div class="hulyTableAttr-header font-medium-12">
<IconBulletList size={'small'} />
<span><Label label={setting.string.Options} /></span>
<div class="buttons-group tertiary-textColor">
<ButtonIcon
kind={'tertiary'}
icon={IconMoreV}
size={'small'}
pressed={opened}
inheritColor
hasMenu
on:click={(ev) => {
openPopup(ev)
}}
/>
<ButtonIcon
kind={'primary'}
icon={IconAdd}
label={setting.string.Add}
action={add}
size={'small'}
disabled={value.enumValues.includes(newValue.trim())}
/>
<ActionIcon
icon={IconAttachment}
label={setting.string.ImportEnum}
action={() => {
inputFile.click()
tooltip={{ label: setting.string.Add }}
on:click={() => {
newItem = true
}}
size={'small'}
/>
<ActionIcon
icon={Copy}
label={setting.string.ImportEnumCopy}
action={() => {
handleClipboard()
}}
size={'small'}
/>
<ActionIcon
icon={IconDelete}
label={setting.string.Delete}
action={() => {
onDelete()
}}
size={'small'}
/>
</div>
</div>
<div class="scroll">
<div class="box">
{#if value.enumValues.length > 0 || newItem}
<div class="hulyTableAttr-content options">
<EnumValuesList
bind:values={value.enumValues}
bind:filtered
disableMouseOver={newItem}
on:remove={(e) => remove(e.detail)}
on:drop={onDrop}
/>
{#if newItem}
<div class="hulyTableAttr-content__row hovered">
<div class="hulyTableAttr-content__row-dragMenu">
<IconMoreV2 size={'small'} />
</div>
<div class="hulyTableAttr-content__row-label font-regular-14 accent grow">
<ModernEditbox
kind={'ghost'}
size={'small'}
label={setting.string.EnterOptionTitle}
on:keydown={handleKeydown}
bind:value={newValue}
width={'100%'}
autoFocus
/>
</div>
{#if matched}
<div class="hulyChip-item error font-medium-12">
<Label label={presentation.string.Match} />
</div>
{/if}
<ButtonIcon
kind={'tertiary'}
icon={IconDelete}
size={'small'}
on:click={() => {
newValue = ''
newItem = false
}}
/>
</div>
{/if}
</div>
</div>
{/if}
</div>
@@ -13,20 +13,29 @@
// limitations under the License.
-->
<script lang="ts">
import presentation from '@hcengineering/presentation'
import { ActionIcon, IconCircles, IconDelete, Label, Scroller } from '@hcengineering/ui'
import {
ModernPopup,
IconDelete,
ButtonIcon,
IconMoreV,
IconMoreV2,
showPopup,
eventToHTMLElement
} from '@hcengineering/ui'
import type { DropdownIntlItem } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import setting from '../plugin'
export let values: string[]
export let filtered: string[]
export let disableMouseOver: boolean = false
let selected: string | undefined
let opened: number | undefined = undefined
const elements: HTMLElement[] = []
function dragswap (ev: MouseEvent, item: string): boolean {
const s = filtered.findIndex((p) => p === selected)
const i = filtered.findIndex((p) => p === item)
const s = values.findIndex((p) => p === selected)
const i = values.findIndex((p) => p === item)
if (i < s) {
return ev.offsetY < elements[i].offsetHeight / 2
} else if (i > s) {
@@ -52,45 +61,79 @@
async function onDrop () {
dispatch('drop')
}
const items: (DropdownIntlItem & { action: () => void })[] = [
{
id: 'delete',
icon: IconDelete,
label: setting.string.Delete,
action: () => {
if (opened !== undefined) {
remove(values[opened])
opened = undefined
}
}
}
]
function openPopup (ev: MouseEvent, n: number) {
if (opened === undefined) {
opened = n
showPopup(ModernPopup, { items }, eventToHTMLElement(ev), (result) => {
if (result) {
switch (result) {
case 'delete':
remove(values[n])
break
}
}
opened = undefined
})
}
}
</script>
<Scroller>
{#each filtered as item, i}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="flex-between flex-nowrap item step-tb25"
draggable={true}
bind:this={elements[i]}
on:dragover|preventDefault={(ev) => {
dragover(ev, item)
}}
on:drop|preventDefault={onDrop}
on:dragstart={() => {
selected = item
}}
on:dragend={() => {
selected = undefined
}}
>
<div class="flex-row-center">
<div class="circles-mark"><IconCircles size={'small'} /></div>
<span class="overflow-label mx-2">{item}</span>
</div>
<ActionIcon
icon={IconDelete}
label={setting.string.Delete}
action={() => {
remove(item)
}}
size={'small'}
/>
{#each values as item, i}
<button
bind:this={elements[i]}
draggable={!disableMouseOver}
class="hulyTableAttr-content__row"
class:disableMouseOver
class:hovered={opened === i && !disableMouseOver}
class:selected={selected === item}
on:dragover|preventDefault={(ev) => {
dragover(ev, item)
}}
on:drop|preventDefault={onDrop}
on:dragstart={() => {
selected = item
}}
on:dragend={() => {
selected = undefined
}}
>
<button class="hulyTableAttr-content__row-dragMenu" class:drag={!disableMouseOver}>
<IconMoreV2 size={'small'} />
</button>
<div class="hulyTableAttr-content__row-label font-regular-14 accent">
{item}
</div>
{/each}
{#if filtered.length}<div class="antiVSpacer x4" />{/if}
</Scroller>
{#if filtered.length === 0}
<Label label={presentation.string.NoMatchesFound} />
{/if}
<div class="hulyTableAttr-content__row-label grow" />
{#if !disableMouseOver}
<ButtonIcon
kind={'tertiary'}
icon={IconMoreV}
iconProps={{ fill: 'var(--global-tertiary-TextColor)' }}
size={'small'}
pressed={opened === i}
hasMenu
on:click={(ev) => {
openPopup(ev, i)
}}
/>
{/if}
</button>
{/each}
<style lang="scss">
.item {
@@ -0,0 +1,37 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path d="M4 9C5.10457 9 6 8.10457 6 7C6 5.89543 5.10457 5 4 5C2.89543 5 2 5.89543 2 7C2 8.10457 2.89543 9 4 9Z" />
<path
d="M9 7C9 6.44772 9.44772 6 10 6H29C29.5523 6 30 6.44772 30 7C30 7.55228 29.5523 8 29 8H10C9.44772 8 9 7.55228 9 7Z"
/>
<path
d="M9 16C9 15.4477 9.44772 15 10 15H29C29.5523 15 30 15.4477 30 16C30 16.5523 29.5523 17 29 17H10C9.44772 17 9 16.5523 9 16Z"
/>
<path
d="M10 24C9.44772 24 9 24.4477 9 25C9 25.5523 9.44772 26 10 26H29C29.5523 26 30 25.5523 30 25C30 24.4477 29.5523 24 29 24H10Z"
/>
<path
d="M6 16C6 17.1046 5.10457 18 4 18C2.89543 18 2 17.1046 2 16C2 14.8954 2.89543 14 4 14C5.10457 14 6 14.8954 6 16Z"
/>
<path
d="M4 27C5.10457 27 6 26.1046 6 25C6 23.8954 5.10457 23 4 23C2.89543 23 2 23.8954 2 25C2 26.1046 2.89543 27 4 27Z"
/>
</svg>
@@ -0,0 +1,24 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M26.1696 9.00012L22.5898 12.5899L23.9998 13.9999L29.9998 7.99988L23.9998 1.99988L22.5898 3.40988L26.1698 6.99988L21.7712 7.00012C19.7025 7.00012 17.7797 8.06584 16.6832 9.82013L14 14.1133L11.3168 9.82013C10.2203 8.06584 8.2975 7.00012 6.22876 7.00012H3C2.44772 7.00012 2 7.44784 2 8.00012C2 8.55241 2.44772 9.00012 3 9.00012H6.22876C7.60792 9.00012 8.8898 9.7106 9.62075 10.8801L12.8208 16.0001L9.62075 21.1201C8.8898 22.2896 7.60792 23.0001 6.22876 23.0001H3C2.44772 23.0001 2 23.4478 2 24.0001C2 24.5524 2.44772 25.0001 3 25.0001H6.22876C8.2975 25.0001 10.2203 23.9344 11.3168 22.1801L14 17.8869L16.6832 22.1801C17.7797 23.9344 19.7025 25.0001 21.7712 25.0001H26.1696L22.5898 28.5899L23.9998 29.9999L29.9998 23.9999L23.9998 17.9999L22.5898 19.4099L26.1698 22.9999L21.7712 23.0001C20.3921 23.0001 19.1102 22.2896 18.3792 21.1201L15.1792 16.0001L18.3792 10.8801C19.1102 9.7106 20.3921 9.00012 21.7712 9.00012H26.1696Z"
/>
</svg>
@@ -0,0 +1,35 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M10 14.0005C9.44772 14.0005 9 14.4482 9 15.0005C9 15.5528 9.44772 16.0005 10 16.0005H22C22.5523 16.0005 23 15.5528 23 15.0005C23 14.4482 22.5523 14.0005 22 14.0005H10Z"
/>
<path
d="M9 19.0005C9 18.4482 9.44772 18.0005 10 18.0005H18C18.5523 18.0005 19 18.4482 19 19.0005C19 19.5528 18.5523 20.0005 18 20.0005H10C9.44772 20.0005 9 19.5528 9 19.0005Z"
/>
<path
d="M10 22.0005C9.44772 22.0005 9 22.4482 9 23.0005C9 23.5528 9.44772 24.0005 10 24.0005H16C16.5523 24.0005 17 23.5528 17 23.0005C17 22.4482 16.5523 22.0005 16 22.0005H10Z"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M19 2.00049C20.3062 2.00049 21.4175 2.8353 21.8293 4.00049H23C25.2091 4.00049 27 5.79135 27 8.00049V26.0005C27 28.2096 25.2091 30.0005 23 30.0005H9C6.79086 30.0005 5 28.2096 5 26.0005V8.00049C5 5.79135 6.79086 4.00049 9 4.00049H10.1707C10.5825 2.8353 11.6938 2.00049 13 2.00049H19ZM12 5.00049C12 4.4482 12.4477 4.00049 13 4.00049H19C19.5523 4.00049 20 4.4482 20 5.00049C20 5.55277 19.5523 6.00049 19 6.00049H13C12.4477 6.00049 12 5.55277 12 5.00049ZM19 8.00049C20.3062 8.00049 21.4175 7.16568 21.8293 6.00049H23C24.1046 6.00049 25 6.89592 25 8.00049V26.0005C25 27.1051 24.1046 28.0005 23 28.0005H9C7.89543 28.0005 7 27.1051 7 26.0005V8.00049C7 6.89592 7.89543 6.00049 9 6.00049H10.1707C10.5825 7.16568 11.6938 8.00049 13 8.00049H19Z"
/>
</svg>