mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
UBERF-7090: Add QMS common components (#5711)
Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
This commit is contained in:
parent
6fcabb9946
commit
f11a7f46c2
@ -308,6 +308,27 @@
|
||||
--theme-clockface-min-arrow: conic-gradient(at 50% -10px, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 49%, #2F2F3A 50%, rgba(0, 0, 0, 0) 51%, rgba(0, 0, 0, 0) 100%);
|
||||
--theme-clockface-arrows-holder: radial-gradient(at top center, #2F2F3A, #555555);
|
||||
--theme-clockface-arrows-shadow: 0 0 1px white;
|
||||
|
||||
--theme-dialog-border-color: rgba(255, 255, 255, 0.1);
|
||||
--theme-dialog-background-color: #2a2938;
|
||||
--theme-dialog-back-color: #848484;
|
||||
--theme-icon-stroke: #e8e9e9;
|
||||
--theme-state-ghost-color: rgba(123, 123, 123, 0.6);
|
||||
--theme-state-ghost-background-color: rgba(123, 123, 123, 0.1);
|
||||
--theme-state-ghost-border-color: transparent;
|
||||
--theme-state-negative-color: #dc5147;
|
||||
--theme-state-negative-background-color: rgba(220, 81, 71, 0.1);
|
||||
--theme-state-negative-border-color: rgba(220, 81, 71, 0.15);
|
||||
--theme-state-positive-color: #139d4a;
|
||||
--theme-state-positive-background-color: rgba(19, 157, 74, 0.1);
|
||||
--theme-state-positive-border-color: rgba(19, 157, 74, 0.15);
|
||||
--theme-state-primary-color: #3070dc;
|
||||
--theme-state-primary-background-color: rgba(48, 112, 220, 0.1);
|
||||
--theme-state-primary-border-color: rgba(48, 112, 220, 0.15);
|
||||
--theme-state-regular-color: #7b7b7b;
|
||||
--theme-state-regular-background-color: rgba(123, 123, 123, 0.1);
|
||||
--theme-state-regular-border-color: rgba(123, 123, 123, 0.15);
|
||||
--theme-wizard-not-visited-color: #34343c;
|
||||
}
|
||||
|
||||
/* Light Theme */
|
||||
@ -536,4 +557,25 @@
|
||||
--theme-clockface-min-arrow: conic-gradient(at 50% -10px, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 49%, white 50%, rgba(255, 255, 255, 0) 51%, rgba(255, 255, 255, 0) 100%);
|
||||
--theme-clockface-arrows-holder: radial-gradient(at top center, #eee, #aaa);
|
||||
--theme-clockface-arrows-shadow: 0 0 1px black;
|
||||
|
||||
--theme-icon-stroke: #1f212b;
|
||||
--theme-dialog-border-color: rgba(0, 0, 0, 0.1);
|
||||
--theme-dialog-background-color: #ffffff;
|
||||
--theme-dialog-back-color: #616161;
|
||||
--theme-state-ghost-color: rgba(123, 123, 123, 0.6);
|
||||
--theme-state-ghost-background-color: rgba(123, 123, 123, 0.1);
|
||||
--theme-state-ghost-border-color: transparent;
|
||||
--theme-state-negative-color: #dc5147;
|
||||
--theme-state-negative-background-color: rgba(220, 81, 71, 0.1);
|
||||
--theme-state-negative-border-color: rgba(220, 81, 71, 0.15);
|
||||
--theme-state-positive-color: #139d4a;
|
||||
--theme-state-positive-background-color: rgba(19, 157, 74, 0.1);
|
||||
--theme-state-positive-border-color: rgba(19, 157, 74, 0.15);
|
||||
--theme-state-primary-color: #3070dc;
|
||||
--theme-state-primary-background-color: rgba(48, 112, 220, 0.1);
|
||||
--theme-state-primary-border-color: rgba(48, 112, 220, 0.15);
|
||||
--theme-state-regular-color: #7b7b7b;
|
||||
--theme-state-regular-background-color: rgba(123, 123, 123, 0.1);
|
||||
--theme-state-regular-border-color: rgba(123, 123, 123, 0.15);
|
||||
--theme-wizard-not-visited-color: #e8e9e9;
|
||||
}
|
||||
|
@ -86,6 +86,9 @@
|
||||
"NoTimeZonesFound": "No time zones found",
|
||||
"Selected": "Selected:",
|
||||
"Spanish": "Spanish",
|
||||
"Portuguese": "Portuguese"
|
||||
"Portuguese": "Portuguese",
|
||||
"Submit": "Submit",
|
||||
"NextStep": "Next step",
|
||||
"TypeHere": "Type here..."
|
||||
}
|
||||
}
|
@ -84,6 +84,9 @@
|
||||
"ThemeDark": "Oscuro",
|
||||
"ThemeSystem": "Sistema",
|
||||
"NoTimeZonesFound": "No se encontraron zonas horarias",
|
||||
"Selected": "Seleccionado:"
|
||||
"Selected": "Seleccionado:",
|
||||
"Submit": "Enviar",
|
||||
"NextStep": "Siguiente paso",
|
||||
"TypeHere": "Escribe aquí..."
|
||||
}
|
||||
}
|
@ -84,6 +84,9 @@
|
||||
"ThemeDark": "Escuro",
|
||||
"ThemeSystem": "Sistema",
|
||||
"NoTimeZonesFound": "Nenhum fuso horário encontrado",
|
||||
"Selected": "Selecionado:"
|
||||
"Selected": "Selecionado:",
|
||||
"Submit": "Enviar",
|
||||
"NextStep": "Seguinte passo",
|
||||
"TypeHere": "Escreva aqui..."
|
||||
}
|
||||
}
|
@ -84,6 +84,9 @@
|
||||
"ThemeDark": "Тёмная",
|
||||
"ThemeSystem": "Системная",
|
||||
"NoTimeZonesFound": "Временные зоны не найдены",
|
||||
"Selected": "Выбрано:"
|
||||
"Selected": "Выбрано:",
|
||||
"Submit": "Отправить",
|
||||
"NextStep": "Следующий шаг",
|
||||
"TypeHere": "Вводите здесь..."
|
||||
}
|
||||
}
|
257
packages/ui/src/components/ModernDialog.svelte
Normal file
257
packages/ui/src/components/ModernDialog.svelte
Normal file
@ -0,0 +1,257 @@
|
||||
<!--
|
||||
// Copyright © 2023 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">
|
||||
// Note: migrated from QMS. Should be unified with the platform solutions eventually.
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { AnySvelteComponent, ButtonKind } from '../types'
|
||||
import Button from './Button.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import Scroller from './Scroller.svelte'
|
||||
import { resizeObserver } from '../resize'
|
||||
import ui from '../plugin'
|
||||
import Close from './icons/Close.svelte'
|
||||
import Left from './icons/Left.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let labelProps: any | undefined = undefined
|
||||
export let submitLabel: IntlString = ui.string.Submit
|
||||
export let submitKind: ButtonKind = 'primary'
|
||||
export let cancelLabel: IntlString = ui.string.Cancel
|
||||
export let canSubmit: boolean = false
|
||||
export let shouldSubmitOnEnter: boolean = false
|
||||
export let shouldCloseOnCancel: boolean = true
|
||||
export let hasBack: boolean = false
|
||||
export let isForm: boolean = true
|
||||
export let embedded: boolean = false
|
||||
export let width: string | undefined = undefined
|
||||
export let isFooterBorderHidden = false
|
||||
export let loading = false
|
||||
export let noContentPadding = false
|
||||
export let scrollableContent = true
|
||||
export let withoutFooter = false
|
||||
export let closeIcon: AnySvelteComponent = Close
|
||||
export let shadow: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function submit (): void {
|
||||
dispatch('submit')
|
||||
}
|
||||
|
||||
function close (): void {
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
function cancel (): void {
|
||||
dispatch('cancel')
|
||||
|
||||
if (shouldCloseOnCancel) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={isForm ? 'form' : 'div'}
|
||||
class="root"
|
||||
class:shadow
|
||||
class:embedded
|
||||
on:submit|preventDefault={isForm && shouldSubmitOnEnter ? submit : undefined}
|
||||
use:resizeObserver={() => {
|
||||
dispatch('changeContent')
|
||||
}}
|
||||
style:width
|
||||
>
|
||||
<div class="header">
|
||||
<slot name="headerLeft">
|
||||
<div class="headerLeft">
|
||||
<div class="flex-row-center flex-gap-2">
|
||||
{#if hasBack}
|
||||
<div class="back">
|
||||
<Button
|
||||
icon={Left}
|
||||
iconProps={{ size: 'small' }}
|
||||
size="small"
|
||||
kind="ghost"
|
||||
label={ui.string.Back}
|
||||
on:click={() => dispatch('back')}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<slot name="headerExtra" />
|
||||
</div>
|
||||
<span class="label"><Label {label} params={labelProps} /></span>
|
||||
</div>
|
||||
</slot>
|
||||
<slot name="headerRight">
|
||||
{#if !embedded}
|
||||
<Button icon={closeIcon} iconProps={{ size: 'medium' }} kind="ghost" size="small" on:click={close} />
|
||||
{/if}
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
{#if scrollableContent}
|
||||
<Scroller>
|
||||
<div class="content" class:noPadding={noContentPadding}>
|
||||
{#if !noContentPadding}
|
||||
<div class="htPadding" />
|
||||
{/if}
|
||||
<slot />
|
||||
{#if !noContentPadding}
|
||||
<div class="hbPadding" />
|
||||
{/if}
|
||||
</div>
|
||||
</Scroller>
|
||||
{:else}
|
||||
<div class="content" class:noPadding={noContentPadding}>
|
||||
{#if !noContentPadding}
|
||||
<div class="htPadding" />
|
||||
{/if}
|
||||
<slot />
|
||||
{#if !noContentPadding}
|
||||
<div class="hbPadding" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !withoutFooter || $$slots.footerExtra || $$slots.footerButtons || $$slots.btnsXtraStart || $$slots.btnsXtraBetween || $$slots.btnsXtraEnd}
|
||||
<div class="footer tweak-buttons" class:footerWithBorder={!isFooterBorderHidden}>
|
||||
<slot name="footerExtra">
|
||||
<div />
|
||||
</slot>
|
||||
|
||||
<div class="footerButtons">
|
||||
<slot name="footerButtons">
|
||||
<slot name="btnsXtraStart" />
|
||||
<Button kind="regular" size="large" label={cancelLabel} on:click={cancel} {loading} />
|
||||
<slot name="btnsXtraBetween" />
|
||||
<Button
|
||||
kind={submitKind}
|
||||
size="large"
|
||||
label={submitLabel}
|
||||
focusIndex={10001}
|
||||
disabled={!canSubmit}
|
||||
on:click={submit}
|
||||
{loading}
|
||||
/>
|
||||
<slot name="btnsXtraEnd" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:element>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 58.25rem;
|
||||
max-height: 80vh;
|
||||
border-radius: 1.25rem;
|
||||
background-color: var(--theme-dialog-background-color);
|
||||
|
||||
&.embedded {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: unset;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow: var(--theme-popup-shadow);
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
padding: 1.25rem 2rem 0.875rem 2.5rem;
|
||||
border-bottom: 1px solid var(--theme-dialog-border-color);
|
||||
}
|
||||
|
||||
.headerLeft {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.back {
|
||||
:global(button) {
|
||||
color: var(--theme-dialog-back-color) !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 1.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
|
||||
// we need these elements as paddings because Scroller doesn't respect css padding
|
||||
.htPadding {
|
||||
width: 100%;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.hbPadding {
|
||||
width: 100%;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
padding: 0 2.5rem 0 2.5rem;
|
||||
|
||||
&.noPadding {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex: 0 0 auto;
|
||||
height: 4.875rem;
|
||||
padding: 1.25rem 2.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&.footerWithBorder {
|
||||
border-top: 1px solid var(--theme-dialog-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.footerButtons {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
// TODO: remove when supported on the platform
|
||||
.tweak-buttons {
|
||||
:global(button) {
|
||||
min-width: 6.25rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
96
packages/ui/src/components/PlainTextEditor.svelte
Normal file
96
packages/ui/src/components/PlainTextEditor.svelte
Normal file
@ -0,0 +1,96 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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">
|
||||
import { afterUpdate, onMount } from 'svelte'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { themeStore } from '@hcengineering/theme'
|
||||
|
||||
import { DelayedCaller } from '../utils'
|
||||
import ui from '../plugin'
|
||||
|
||||
export let value: string | undefined = undefined
|
||||
export let placeholder: IntlString = ui.string.TypeHere
|
||||
export let placeholderParam: any | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
|
||||
let input: HTMLTextAreaElement
|
||||
let phTraslate: string = ''
|
||||
|
||||
$: void translate(placeholder, placeholderParam ?? {}, $themeStore.language).then((res) => {
|
||||
phTraslate = res
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
const throttle = new DelayedCaller(50)
|
||||
const observer = new ResizeObserver(() => {
|
||||
throttle.call(adjustHeight)
|
||||
})
|
||||
observer.observe(input)
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
})
|
||||
|
||||
afterUpdate(adjustHeight)
|
||||
|
||||
function adjustHeight (): void {
|
||||
input.style.height = 'auto'
|
||||
input.style.height = `${input.scrollHeight + 2}px`
|
||||
}
|
||||
|
||||
export function focus (): void {
|
||||
input.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<textarea
|
||||
class="root"
|
||||
bind:value
|
||||
bind:this={input}
|
||||
{disabled}
|
||||
placeholder={phTraslate}
|
||||
on:keydown
|
||||
on:change
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:blur
|
||||
/>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.75rem;
|
||||
min-height: 3.25rem;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: 1.25rem;
|
||||
color: var(--theme-text-primary-color);
|
||||
background-color: var(--theme-button-default);
|
||||
border: 1px solid var(--theme-refinput-border);
|
||||
border-radius: 0.375rem;
|
||||
outline: none;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-button-default);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-text-placeholder-color);
|
||||
}
|
||||
}
|
||||
</style>
|
79
packages/ui/src/components/StateTag.svelte
Normal file
79
packages/ui/src/components/StateTag.svelte
Normal file
@ -0,0 +1,79 @@
|
||||
<!--
|
||||
//
|
||||
// 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">
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
|
||||
import Label from './Label.svelte'
|
||||
import { StateType } from '../types'
|
||||
|
||||
type LabelString = $$Generic<IntlString>
|
||||
type LabelParams = LabelString extends IntlString<infer Params> ? Params : Record<string, any>
|
||||
|
||||
export let type: StateType
|
||||
export let label: LabelString
|
||||
export let params: LabelParams = {} as unknown as LabelParams
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="root"
|
||||
class:ghost={type === StateType.Ghost}
|
||||
class:negative={type === StateType.Negative}
|
||||
class:positive={type === StateType.Positive}
|
||||
class:primary={type === StateType.Primary}
|
||||
class:regular={type === StateType.Regular}
|
||||
>
|
||||
<Label {label} {params} />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
display: flex;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
line-height: 1rem;
|
||||
padding: 0.125rem 0.5rem;
|
||||
width: max-content;
|
||||
|
||||
&.ghost {
|
||||
background: var(--theme-state-ghost-background-color);
|
||||
border-color: var(--theme-state-ghost-border-color);
|
||||
color: var(--theme-state-ghost-color);
|
||||
}
|
||||
&.negative {
|
||||
background: var(--theme-state-negative-background-color);
|
||||
border-color: var(--theme-state-negative-border-color);
|
||||
color: var(--theme-state-negative-color);
|
||||
}
|
||||
&.positive {
|
||||
background: var(--theme-state-positive-background-color);
|
||||
border-color: var(--theme-state-positive-border-color);
|
||||
color: var(--theme-state-positive-color);
|
||||
}
|
||||
&.primary {
|
||||
background: var(--theme-state-primary-background-color);
|
||||
border-color: var(--theme-qms-primary-ghost-border-color);
|
||||
color: var(--theme-state-primary-color);
|
||||
}
|
||||
&.regular {
|
||||
background: var(--theme-state-regular-background-color);
|
||||
border-color: var(--theme-state-regular-border-color);
|
||||
color: var(--theme-state-regular-color);
|
||||
}
|
||||
}
|
||||
</style>
|
26
packages/ui/src/components/icons/Checkmark.svelte
Normal file
26
packages/ui/src/components/icons/Checkmark.svelte
Normal file
@ -0,0 +1,26 @@
|
||||
<!--
|
||||
// Copyright © 2023 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: 'tiny' | 'small' | 'medium' | 'large'
|
||||
export let fill = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" {fill}>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M9.58525 3.53975C9.80492 3.75942 9.80492 4.11558 9.58525 4.33525L5.27275 8.64775C5.05308 8.86742 4.69692 8.86742 4.47725 8.64775L2.41475 6.58525C2.19508 6.36558 2.19508 6.00942 2.41475 5.78975C2.63442 5.57008 2.99058 5.57008 3.21025 5.78975L4.875 7.4545L8.78975 3.53975C9.00942 3.32008 9.36558 3.32008 9.58525 3.53975Z"
|
||||
/>
|
||||
</svg>
|
10
packages/ui/src/components/icons/Left.svelte
Normal file
10
packages/ui/src/components/icons/Left.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2.6665 8L2.31295 7.64645L1.9594 8L2.31295 8.35355L2.6665 8ZM12.6665 8.5C12.9426 8.5 13.1665 8.27614 13.1665 8C13.1665 7.72386 12.9426 7.5 12.6665 7.5V8.5ZM6.31295 3.64645L2.31295 7.64645L3.02006 8.35355L7.02006 4.35355L6.31295 3.64645ZM2.31295 8.35355L6.31295 12.3536L7.02006 11.6464L3.02006 7.64645L2.31295 8.35355ZM2.6665 8.5H12.6665V7.5H2.6665V8.5Z"
|
||||
fill="#616161"
|
||||
/>
|
||||
</svg>
|
105
packages/ui/src/components/wizard/ModernWizardBar.svelte
Normal file
105
packages/ui/src/components/wizard/ModernWizardBar.svelte
Normal file
@ -0,0 +1,105 @@
|
||||
<!--
|
||||
// Copyright © 2023 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">
|
||||
import Label from '../Label.svelte'
|
||||
import { IWizardStep } from '../../types'
|
||||
import Checkmark from '../icons/Checkmark.svelte'
|
||||
|
||||
export let steps: ReadonlyArray<IWizardStep>
|
||||
export let selectedStep: string
|
||||
|
||||
$: selectedIdx = selectedStep !== '' ? steps.findIndex((s) => s.id === selectedStep) : -1
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
{#each steps as step, idx}
|
||||
{@const isCurrent = idx === selectedIdx}
|
||||
{@const isPast = idx < selectedIdx}
|
||||
{#if idx !== 0}
|
||||
<div class="flex-col-center" style:grid-column="1" style:grid-row={3 * idx}>
|
||||
<div class="path" class:highlighted={isPast || isCurrent} />
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="circle"
|
||||
class:filled={!isPast && !isCurrent}
|
||||
class:filledHighlighted={isPast}
|
||||
style:grid-column="1"
|
||||
style:grid-row={3 * idx + 1}
|
||||
>
|
||||
{#if isPast}
|
||||
<div class="checkmark flex-center"><Checkmark size="tiny" /></div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="label" class:highlighted={isCurrent || isPast} style:grid-column="2" style:grid-row={3 * idx + 1}>
|
||||
<div class="overflow-label">{idx + 1}. <Label label={step.title} /></div>
|
||||
</div>
|
||||
{#if idx !== steps.length - 1}
|
||||
<div class="flex-col-center" style:grid-column="1" style:grid-row={3 * idx + 2}>
|
||||
<div class="path" class:highlighted={isPast || isCurrent} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
display: grid;
|
||||
grid-template-columns: 1rem 1fr;
|
||||
grid-auto-rows: auto;
|
||||
grid-column-gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.circle {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--positive-button-default);
|
||||
|
||||
&.filledHighlighted {
|
||||
background: var(--positive-button-default);
|
||||
}
|
||||
|
||||
&.filled {
|
||||
border-color: var(--theme-wizard-not-visited-color);
|
||||
background: var(--theme-wizard-not-visited-color);
|
||||
}
|
||||
}
|
||||
|
||||
.path {
|
||||
width: 2px;
|
||||
height: 0.875rem;
|
||||
border: 1px solid var(--theme-wizard-not-visited-color);
|
||||
|
||||
&.highlighted {
|
||||
border-color: var(--positive-button-default);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1rem;
|
||||
min-width: 0;
|
||||
|
||||
&.highlighted {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
color: var(--theme-button-contrast-color);
|
||||
}
|
||||
</style>
|
144
packages/ui/src/components/wizard/ModernWizardDialog.svelte
Normal file
144
packages/ui/src/components/wizard/ModernWizardDialog.svelte
Normal file
@ -0,0 +1,144 @@
|
||||
<!--
|
||||
// Copyright © 2023 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">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import Button from '../Button.svelte'
|
||||
import Scroller from '../Scroller.svelte'
|
||||
import WizardBar from './ModernWizardBar.svelte'
|
||||
import ModernDialog from '../ModernDialog.svelte'
|
||||
import { IWizardStep } from '../../types'
|
||||
import ui from '../../plugin'
|
||||
import ArrowLeft from '../icons/ArrowLeft.svelte'
|
||||
import ArrowRight from '../icons/ArrowRight.svelte'
|
||||
|
||||
export let loading: boolean = false
|
||||
export let label: IntlString
|
||||
export let canSubmit: boolean = true
|
||||
export let canProceed: boolean = true
|
||||
export let submitLabel: IntlString
|
||||
export let steps: ReadonlyArray<IWizardStep>
|
||||
export let selectedStep: string
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: selectedIdx = hasSelectedStep() ? steps.findIndex((s) => s.id === selectedStep) : -1
|
||||
$: hasBack = selectedIdx > 0
|
||||
$: hasNext = selectedIdx < steps.length - 1
|
||||
$: hasSubmit = selectedIdx === steps.length - 1
|
||||
|
||||
function hasSelectedStep (): boolean {
|
||||
return selectedStep !== undefined && selectedStep !== ''
|
||||
}
|
||||
|
||||
function handleBack (): void {
|
||||
if (!hasSelectedStep()) {
|
||||
return
|
||||
}
|
||||
|
||||
const currIdx = steps.findIndex((s) => s.id === selectedStep)
|
||||
const newIdx = currIdx > 0 ? currIdx - 1 : 0
|
||||
|
||||
dispatch('stepChanged', steps[newIdx].id)
|
||||
}
|
||||
|
||||
function handleNext (): void {
|
||||
if (!hasSelectedStep()) {
|
||||
return
|
||||
}
|
||||
|
||||
const currIdx = steps.findIndex((s) => s.id === selectedStep)
|
||||
const newIdx = currIdx < steps.length - 1 ? currIdx + 1 : steps.length - 1
|
||||
|
||||
dispatch('stepChanged', steps[newIdx].id)
|
||||
}
|
||||
|
||||
function handleSubmit (): void {
|
||||
dispatch('submit')
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModernDialog {loading} {label} {canSubmit} noContentPadding={true} scrollableContent={false} on:submit on:close>
|
||||
<div class="root">
|
||||
<div class="side">
|
||||
<Scroller>
|
||||
<WizardBar {steps} {selectedStep} />
|
||||
</Scroller>
|
||||
</div>
|
||||
<div class="content">
|
||||
<Scroller>
|
||||
<div class="contentBody">
|
||||
<slot />
|
||||
</div>
|
||||
</Scroller>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div slot="footerExtra">
|
||||
{#if hasBack}
|
||||
<Button kind="regular" size="large" label={ui.string.Back} icon={ArrowLeft} on:click={handleBack} {loading} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div slot="footerButtons">
|
||||
{#if hasSubmit}
|
||||
<Button
|
||||
kind="positive"
|
||||
size="large"
|
||||
label={submitLabel}
|
||||
disabled={!canSubmit}
|
||||
{loading}
|
||||
on:click={handleSubmit}
|
||||
/>
|
||||
{/if}
|
||||
{#if hasNext}
|
||||
<Button
|
||||
kind="primary"
|
||||
size="large"
|
||||
label={ui.string.NextStep}
|
||||
iconRight={ArrowRight}
|
||||
iconRightProps={{ size: 'small' }}
|
||||
{loading}
|
||||
disabled={!canProceed}
|
||||
on:click={handleNext}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</ModernDialog>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
color: var(--theme-text-primary-color);
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.side {
|
||||
flex: 0 0 12rem;
|
||||
padding: 1.5rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.contentBody {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
</style>
|
@ -55,6 +55,7 @@ export { default as Button } from './components/Button.svelte'
|
||||
export { default as ButtonWithDropdown } from './components/ButtonWithDropdown.svelte'
|
||||
export { default as ButtonGroup } from './components/ButtonGroup.svelte'
|
||||
export { default as Status } from './components/Status.svelte'
|
||||
export { default as StateTag } from './components/StateTag.svelte'
|
||||
export { default as Component } from './components/Component.svelte'
|
||||
export { default as Icon } from './components/Icon.svelte'
|
||||
export { default as ActionIcon } from './components/ActionIcon.svelte'
|
||||
@ -62,6 +63,7 @@ export { default as Toggle } from './components/Toggle.svelte'
|
||||
export { default as RadioButton } from './components/RadioButton.svelte'
|
||||
export { default as RadioGroup } from './components/RadioGroup.svelte'
|
||||
export { default as Dialog } from './components/Dialog.svelte'
|
||||
export { default as ModernDialog } from './components/ModernDialog.svelte'
|
||||
export { default as ModernToggle } from './components/ModernToggle.svelte'
|
||||
export { default as ToggleWithLabel } from './components/ToggleWithLabel.svelte'
|
||||
export { default as MiniToggle } from './components/MiniToggle.svelte'
|
||||
@ -77,6 +79,7 @@ export { default as SelectPopup } from './components/SelectPopup.svelte'
|
||||
export { default as ColorPopup } from './components/ColorPopup.svelte'
|
||||
export { default as TextArea } from './components/TextArea.svelte'
|
||||
export { default as TextAreaEditor } from './components/TextAreaEditor.svelte'
|
||||
export { default as PlainTextEditor } from './components/PlainTextEditor.svelte'
|
||||
export { default as Section } from './components/Section.svelte'
|
||||
export { default as DatePicker } from './components/calendar/DatePicker.svelte'
|
||||
export { default as DateRangePicker } from './components/calendar/DateRangePicker.svelte'
|
||||
@ -145,6 +148,8 @@ export { default as AccordionItem } from './components/AccordionItem.svelte'
|
||||
export { default as NotificationToast } from './components/NotificationToast.svelte'
|
||||
export { default as Hotkey } from './components/Hotkey.svelte'
|
||||
export { default as HotkeyGroup } from './components/HotkeyGroup.svelte'
|
||||
export { default as ModernWizardDialog } from './components/wizard/ModernWizardDialog.svelte'
|
||||
export { default as ModernWizardBar } from './components/wizard/ModernWizardBar.svelte'
|
||||
|
||||
export { default as IconAdd } from './components/icons/Add.svelte'
|
||||
export { default as IconCircleAdd } from './components/icons/CircleAdd.svelte'
|
||||
@ -167,6 +172,7 @@ export { default as IconExpand } from './components/icons/Expand.svelte'
|
||||
export { default as IconActivity } from './components/icons/Activity.svelte'
|
||||
export { default as IconUp } from './components/icons/Up.svelte'
|
||||
export { default as IconDown } from './components/icons/Down.svelte'
|
||||
export { default as IconLeft } from './components/icons/Left.svelte'
|
||||
export { default as IconUpOutline } from './components/icons/UpOutline.svelte'
|
||||
export { default as IconDownOutline } from './components/icons/DownOutline.svelte'
|
||||
export { default as IconDropdown } from './components/icons/Dropdown.svelte'
|
||||
@ -220,6 +226,7 @@ export { default as IconDropdownRight } from './components/icons/DropdownRight.s
|
||||
export { default as IconKeyCommand } from './components/icons/KeyCommand.svelte'
|
||||
export { default as IconKeyOption } from './components/icons/KeyOption.svelte'
|
||||
export { default as IconKeyShift } from './components/icons/KeyShift.svelte'
|
||||
export { default as IconCheckmark } from './components/icons/Checkmark.svelte'
|
||||
|
||||
export { default as PanelInstance } from './components/PanelInstance.svelte'
|
||||
export { default as Panel } from './components/Panel.svelte'
|
||||
|
@ -110,7 +110,10 @@ export const uis = plugin(uiId, {
|
||||
ThemeDark: '' as IntlString,
|
||||
ThemeSystem: '' as IntlString,
|
||||
NoTimeZonesFound: '' as IntlString,
|
||||
Selected: '' as IntlString
|
||||
Selected: '' as IntlString,
|
||||
Submit: '' as IntlString,
|
||||
NextStep: '' as IntlString,
|
||||
TypeHere: '' as IntlString
|
||||
},
|
||||
metadata: {
|
||||
DefaultApplication: '' as Metadata<AnyComponent>,
|
||||
|
@ -512,3 +512,16 @@ export type MouseTargetEvent = MouseEvent & { currentTarget: EventTarget & HTMLE
|
||||
export interface ScrollParams {
|
||||
autoScrolling: boolean
|
||||
}
|
||||
|
||||
export interface IWizardStep<T = string> {
|
||||
id: T
|
||||
title: IntlString
|
||||
}
|
||||
|
||||
export enum StateType {
|
||||
Ghost,
|
||||
Negative,
|
||||
Positive,
|
||||
Primary,
|
||||
Regular
|
||||
}
|
||||
|
@ -13,20 +13,21 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import contact, { Employee } from '@hcengineering/contact'
|
||||
import type { Class, Doc, DocumentQuery, IdMap, Ref } from '@hcengineering/core'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { Label, showPopup, ActionIcon, IconClose, IconAdd, Icon } from '@hcengineering/ui'
|
||||
import type { IconSize } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
|
||||
import plugin from '../plugin'
|
||||
import { employeeByIdStore } from '../utils'
|
||||
import UserInfo from './UserInfo.svelte'
|
||||
import UsersPopup from './UsersPopup.svelte'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
|
||||
export let items: Ref<Employee>[] = []
|
||||
export let readonlyItems: Ref<Employee>[] = []
|
||||
export let readonlyItems = new Set<Ref<Employee>>()
|
||||
export let _class: Ref<Class<Employee>> = contact.mixin.Employee
|
||||
export let docQuery: DocumentQuery<Employee> | undefined = {}
|
||||
|
||||
@ -36,10 +37,10 @@
|
||||
export let width: string | undefined = undefined
|
||||
export let readonly: boolean = false
|
||||
|
||||
let persons: Employee[] = getPersons(items, $employeeByIdStore)
|
||||
$: persons = getPersons(items, $employeeByIdStore)
|
||||
let readonlyPersons: Employee[] = getPersons(readonlyItems, $employeeByIdStore)
|
||||
$: readonlyPersons = getPersons(readonlyItems, $employeeByIdStore)
|
||||
$: fixedItems = readonly ? items : items.filter((item) => readonlyItems.has(item))
|
||||
$: editableItems = readonly ? [] : items.filter((item) => !readonlyItems.has(item))
|
||||
$: fixedPersons = getPersons(fixedItems, $employeeByIdStore)
|
||||
$: editablePersons = getPersons(editableItems, $employeeByIdStore)
|
||||
|
||||
const client = getClient()
|
||||
|
||||
@ -55,7 +56,7 @@
|
||||
multiSelect: true,
|
||||
allowDeselect: false,
|
||||
selectedUsers: items,
|
||||
ignoreUsers: readonlyItems,
|
||||
ignoreUsers: fixedItems,
|
||||
readonly,
|
||||
filter: (it: Doc) => {
|
||||
if (client.getHierarchy().hasMixin(it, contact.mixin.Employee)) {
|
||||
@ -68,18 +69,17 @@
|
||||
undefined,
|
||||
(result) => {
|
||||
if (result != null) {
|
||||
items = result
|
||||
dispatch('update', items)
|
||||
dispatch('update', fixedItems.concat(result))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getPersons (employees: Ref<Employee>[], employeeById: IdMap<Employee>) {
|
||||
function getPersons (employees: Ref<Employee>[], employeeById: IdMap<Employee>): Employee[] {
|
||||
return employees.map((p) => employeeById.get(p)).filter((p) => p !== undefined) as Employee[]
|
||||
}
|
||||
|
||||
const removePerson = (removed: Employee) => {
|
||||
function removePerson (removed: Employee): void {
|
||||
const newItems = items.filter((it) => it !== removed._id)
|
||||
dispatch('update', newItems)
|
||||
}
|
||||
@ -87,12 +87,12 @@
|
||||
|
||||
<div class="flex-col" style:width={width ?? 'auto'}>
|
||||
<div class="flex-row-center flex-wrap">
|
||||
{#each readonlyPersons as person}
|
||||
{#each fixedPersons as person}
|
||||
<div class="usertag-container gap-1-5">
|
||||
<UserInfo value={person} {size} />
|
||||
</div>
|
||||
{/each}
|
||||
{#each persons as person}
|
||||
{#each editablePersons as person}
|
||||
<div class="usertag-container gap-1-5">
|
||||
<UserInfo value={person} {size} />
|
||||
<ActionIcon
|
||||
@ -110,7 +110,7 @@
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="addButton {size === 'inline' ? 'small' : 'medium'} overflow-label gap-2 cursor-pointer"
|
||||
class:mt-2={persons.length > 0}
|
||||
class:mt-2={editablePersons.length > 0}
|
||||
on:click={addPerson}
|
||||
>
|
||||
<span><Label label={actionLabel} /></span>
|
||||
|
@ -22,7 +22,9 @@
|
||||
let request: Request | undefined = undefined
|
||||
|
||||
const query = createQuery()
|
||||
query.query(value._class, { _id: value._id }, (res) => ([request] = res))
|
||||
query.query(value._class, { _id: value._id }, (res) => {
|
||||
;[request] = res
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if request}
|
||||
|
@ -21,6 +21,9 @@ import RequestPresenter from './components/RequestPresenter.svelte'
|
||||
import RequestView from './components/RequestView.svelte'
|
||||
import NotificationRequestView from './components/NotificationRequestView.svelte'
|
||||
|
||||
export { default as RequestStatusPresenter } from './components/RequestStatusPresenter.svelte'
|
||||
export { default as RequestDetailPopup } from './components/RequestDetailPopup.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
activity: {
|
||||
RequestLabel,
|
||||
|
@ -0,0 +1,65 @@
|
||||
<!--
|
||||
//
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Doc, DocumentQuery, Ref, Space, WithLookup } from '@hcengineering/core'
|
||||
import { IntlString, translate } from '@hcengineering/platform'
|
||||
import { IModeSelector, SearchEdit, ModeSelector, themeStore } from '@hcengineering/ui'
|
||||
import { ViewOptions, Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
|
||||
import FilterBar from './filter/FilterBar.svelte'
|
||||
import FilterButton from './filter/FilterButton.svelte'
|
||||
import ViewletSelector from './ViewletSelector.svelte'
|
||||
import ViewletSettingButton from './ViewletSettingButton.svelte'
|
||||
|
||||
export let viewletQuery: DocumentQuery<Viewlet>
|
||||
export let viewlet: WithLookup<Viewlet> | undefined
|
||||
export let viewOptions: ViewOptions | undefined
|
||||
export let preference: ViewletPreference | undefined
|
||||
export let loading = true
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let title: IntlString
|
||||
export let search: string = ''
|
||||
export let query: DocumentQuery<Doc>
|
||||
export let modeSelectorProps: IModeSelector | undefined = undefined
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
export let resultQuery: DocumentQuery<Doc>
|
||||
|
||||
let label = ''
|
||||
let searchQuery: DocumentQuery<Doc> = { ...query }
|
||||
resultQuery = search === '' ? { ...query } : { ...query, $search: search }
|
||||
|
||||
$: if (!label && title) {
|
||||
translate(title, {}, $themeStore.language).then((res) => {
|
||||
label = res
|
||||
})
|
||||
}
|
||||
$: searchQuery = search === '' ? { ...query } : { ...query, $search: search }
|
||||
</script>
|
||||
|
||||
<div class="ac-header full divide caption-height" class:header-with-mode-selector={modeSelectorProps !== undefined}>
|
||||
<div class="ac-header__wrap-title">
|
||||
<span class="ac-header__title">{label}</span>
|
||||
{#if modeSelectorProps !== undefined}
|
||||
<ModeSelector props={modeSelectorProps} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="clear-mins">
|
||||
<slot name="header-tools" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} />
|
||||
<div class="buttons-divider" />
|
||||
<FilterButton {_class} />
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<ViewletSelector bind:viewlet bind:preference bind:loading {viewletQuery} />
|
||||
<ViewletSettingButton bind:viewlet bind:viewOptions />
|
||||
<slot name="extra" />
|
||||
</div>
|
||||
</div>
|
||||
<FilterBar {_class} query={searchQuery} {space} {viewOptions} on:change={(e) => (resultQuery = { ...e.detail })} />
|
@ -71,6 +71,7 @@ import UpDownNavigator from './components/UpDownNavigator.svelte'
|
||||
import ValueSelector from './components/ValueSelector.svelte'
|
||||
import ViewletContentView from './components/ViewletContentView.svelte'
|
||||
import ViewletSettingButton from './components/ViewletSettingButton.svelte'
|
||||
import ViewletPanelHeader from './components/ViewletPanelHeader.svelte'
|
||||
import ArrayFilter from './components/filter/ArrayFilter.svelte'
|
||||
import DateFilter from './components/filter/DateFilter.svelte'
|
||||
import DateFilterPresenter from './components/filter/DateFilterPresenter.svelte'
|
||||
@ -220,7 +221,8 @@ export {
|
||||
TreeNode,
|
||||
UpDownNavigator,
|
||||
ViewletContentView,
|
||||
ViewletSettingButton
|
||||
ViewletSettingButton,
|
||||
ViewletPanelHeader
|
||||
}
|
||||
|
||||
function PositionElementAlignment (e?: Event): PopupAlignment | undefined {
|
||||
|
Loading…
Reference in New Issue
Block a user