chore: merge blocksuite source code (#9213)

This commit is contained in:
Mirone
2024-12-20 15:38:06 +08:00
committed by GitHub
parent 2c9ef916f4
commit 30200ff86d
2031 changed files with 238888 additions and 229 deletions
@@ -0,0 +1,33 @@
import { createUniComponentFromWebComponent } from '../../core/index.js';
import { uniMap } from '../../core/utils/uni-component/operation.js';
import type {
DataViewWidget,
DataViewWidgetProps,
} from '../../core/widget/types.js';
import { DataViewHeaderToolsFilter } from './presets/filter/filter.js';
import { DataViewHeaderToolsSearch } from './presets/search/search.js';
import { DataViewHeaderToolsSort } from './presets/sort/sort.js';
import { DataViewHeaderToolsAddRow } from './presets/table-add-row/add-row.js';
import { DataViewHeaderToolsViewOptions } from './presets/view-options/view-options.js';
import { DataViewHeaderTools } from './tools-view.js';
export const toolsWidgetPresets = {
sort: createUniComponentFromWebComponent(DataViewHeaderToolsSort),
filter: createUniComponentFromWebComponent(DataViewHeaderToolsFilter),
search: createUniComponentFromWebComponent(DataViewHeaderToolsSearch),
viewOptions: createUniComponentFromWebComponent(
DataViewHeaderToolsViewOptions
),
tableAddRow: createUniComponentFromWebComponent(DataViewHeaderToolsAddRow),
};
export const createWidgetTools = (
toolsMap: Record<string, DataViewWidget[]>
) => {
return uniMap(
createUniComponentFromWebComponent(DataViewHeaderTools),
(props: DataViewWidgetProps) => ({
...props,
toolsMap,
})
);
};
@@ -0,0 +1,115 @@
import { popupTargetFromElement } from '@blocksuite/affine-components/context-menu';
import { IS_MOBILE } from '@blocksuite/global/env';
import { FilterIcon } from '@blocksuite/icons/lit';
import { computed } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
import { popCreateFilter } from '../../../../core/filter/add-filter.js';
import { filterTraitKey } from '../../../../core/filter/trait.js';
import type { FilterGroup } from '../../../../core/filter/types.js';
import { emptyFilterGroup } from '../../../../core/filter/utils.js';
import { WidgetBase } from '../../../../core/widget/widget-base.js';
import { ShowQuickSettingBarContextKey } from '../../../quick-setting-bar/context.js';
const styles = css`
.affine-database-filter-button {
display: flex;
align-items: center;
gap: 6px;
line-height: 20px;
padding: 2px;
border-radius: 4px;
cursor: pointer;
font-size: 20px;
}
.affine-database-filter-button:hover,
.affine-database-filter-button.active {
background-color: var(--affine-hover-color);
}
.affine-database-filter-button {
}
`;
export class DataViewHeaderToolsFilter extends WidgetBase {
static override styles = styles;
hasFilter = computed(() => {
return this.filterTrait?.hasFilter$.value ?? false;
});
private get _filter(): FilterGroup {
return this.filterTrait?.filter$.value ?? emptyFilterGroup;
}
private set _filter(filter: FilterGroup) {
this.filterTrait?.filterSet(filter);
}
get filterTrait() {
return this.view.traitGet(filterTraitKey);
}
private get readonly() {
return this.view.readonly$.value;
}
private clickFilter(event: MouseEvent) {
if (this.hasFilter.value) {
this.toggleShowFilter();
return;
}
popCreateFilter(
popupTargetFromElement(event.currentTarget as HTMLElement),
{
vars: this.view.vars$,
onSelect: filter => {
this._filter = {
...this._filter,
conditions: [filter],
};
this.toggleShowFilter(true);
},
}
);
return;
}
override connectedCallback() {
super.connectedCallback();
this.style.display = IS_MOBILE ? 'none' : 'flex';
}
override render() {
if (this.readonly) return nothing;
const style = styleMap({
color: this.hasFilter.value
? cssVarV2('text/emphasis')
: cssVarV2('icon/primary'),
});
return html` <div
@click="${this.clickFilter}"
style="${style}"
class="affine-database-filter-button"
>
${FilterIcon()}
</div>`;
}
toggleShowFilter(show?: boolean) {
const map = this.view.contextGet(ShowQuickSettingBarContextKey);
map.value = {
...map.value,
[this.view.id]: show ?? !map.value[this.view.id],
};
}
}
declare global {
interface HTMLElementTagNameMap {
'data-view-header-tools-filter': DataViewHeaderToolsFilter;
}
}
@@ -0,0 +1,191 @@
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { IS_MOBILE } from '@blocksuite/global/env';
import { CloseIcon, SearchIcon } from '@blocksuite/icons/lit';
import { baseTheme } from '@toeverything/theme';
import { css, html, unsafeCSS } from 'lit';
import { query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { styleMap } from 'lit/directives/style-map.js';
import { stopPropagation } from '../../../../core/utils/event.js';
import { WidgetBase } from '../../../../core/widget/widget-base.js';
import type {
KanbanSingleView,
TableSingleView,
} from '../../../../view-presets/index.js';
const styles = css`
.affine-database-search-container {
position: relative;
display: flex;
align-items: center;
gap: 8px;
width: 24px;
height: 24px;
border-radius: 4px;
transition: width 0.3s ease;
overflow: hidden;
}
.search-container-expand {
overflow: visible;
width: 138px;
background-color: var(--affine-hover-color);
}
.search-input-container {
display: flex;
align-items: center;
}
.close-icon {
display: flex;
align-items: center;
padding-right: 8px;
height: 100%;
cursor: pointer;
}
.affine-database-search-input-icon {
position: absolute;
left: 0;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
cursor: pointer;
padding: 2px;
border-radius: 4px;
color: ${unsafeCSSVarV2('icon/primary')};
}
.affine-database-search-input-icon:hover {
background: var(--affine-hover-color);
}
.search-container-expand .affine-database-search-input-icon {
left: 4px;
pointer-events: none;
}
.affine-database-search-input {
flex: 1;
width: 100%;
padding: 0 2px 0 30px;
border: none;
font-family: ${unsafeCSS(baseTheme.fontSansFamily)};
font-size: var(--affine-font-sm);
box-sizing: border-box;
color: inherit;
background: transparent;
outline: none;
}
.affine-database-search-input::placeholder {
color: var(--affine-placeholder-color);
font-size: var(--affine-font-sm);
}
`;
export class DataViewHeaderToolsSearch extends WidgetBase<
TableSingleView | KanbanSingleView
> {
static override styles = styles;
private _clearSearch = () => {
this._searchInput.value = '';
this.view.setSearch('');
this.preventBlur = true;
setTimeout(() => {
this.preventBlur = false;
});
};
private _clickSearch = (e: MouseEvent) => {
e.stopPropagation();
this.showSearch = true;
};
private _onSearch = (event: InputEvent) => {
const el = event.target as HTMLInputElement;
const inputValue = el.value.trim();
this.view.setSearch(inputValue);
};
private _onSearchBlur = () => {
if (this._searchInput.value || this.preventBlur) {
return;
}
this.showSearch = false;
};
private _onSearchKeydown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
if (this._searchInput.value) {
this._searchInput.value = '';
this.view.setSearch('');
} else {
this.showSearch = false;
}
}
};
preventBlur = false;
override connectedCallback() {
super.connectedCallback();
this.style.display = IS_MOBILE ? 'none' : 'flex';
}
override render() {
const searchToolClassMap = classMap({
'affine-database-search-container': true,
'search-container-expand': this.showSearch,
active: this.showSearch,
});
return html`
<label class="${searchToolClassMap}" @click="${this._clickSearch}">
<div class="affine-database-search-input-icon">${SearchIcon()}</div>
<input
placeholder="Search..."
class="affine-database-search-input"
@input="${this._onSearch}"
@click="${(event: MouseEvent) => event.stopPropagation()}"
@keydown="${this._onSearchKeydown}"
@pointerdown="${stopPropagation}"
@blur="${this._onSearchBlur}"
/>
<div class="close-icon" @mousedown="${this._clearSearch}">
${CloseIcon()}
<affine-tooltip>
<span
style=${styleMap({
display: 'flex',
alignItems: 'center',
boxSizing: 'border-box',
padding: '2px 6px',
borderRadius: '4px',
background: 'var(--affine-white-10)',
})}
>Esc</span
>
to clear all
</affine-tooltip>
</div>
</label>
`;
}
@query('.affine-database-search-input')
private accessor _searchInput!: HTMLInputElement;
@state()
private accessor showSearch = false;
}
declare global {
interface HTMLElementTagNameMap {
'data-view-header-tools-search': DataViewHeaderToolsSearch;
}
}
@@ -0,0 +1,121 @@
import { popupTargetFromElement } from '@blocksuite/affine-components/context-menu';
import { IS_MOBILE } from '@blocksuite/global/env';
import { SortIcon } from '@blocksuite/icons/lit';
import { computed } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
import { popCreateSort } from '../../../../core/sort/add-sort.js';
import { sortTraitKey } from '../../../../core/sort/manager.js';
import { createSortUtils } from '../../../../core/sort/utils.js';
import { WidgetBase } from '../../../../core/widget/widget-base.js';
import { ShowQuickSettingBarContextKey } from '../../../quick-setting-bar/context.js';
import { popSortRoot } from '../../../quick-setting-bar/sort/root-panel.js';
const styles = css`
.affine-database-sort-button {
display: flex;
align-items: center;
gap: 6px;
line-height: 20px;
padding: 2px;
border-radius: 4px;
cursor: pointer;
font-size: 20px;
}
.affine-database-sort-button:hover,
.affine-database-sort-button.active {
background-color: var(--affine-hover-color);
}
.affine-database-sort-button {
}
`;
export class DataViewHeaderToolsSort extends WidgetBase {
static override styles = styles;
sortUtils$ = computed(() => {
const sortTrait = this.view.traitGet(sortTraitKey);
if (sortTrait) {
return createSortUtils(sortTrait, this.dataViewInstance.eventTrace);
}
return;
});
hasSort = computed(() => {
return (this.sortUtils$.value?.sortList$?.value?.length ?? 0) > 0;
});
private get readonly() {
return this.view.readonly$.value;
}
private clickSort(event: MouseEvent) {
const sortUtils = this.sortUtils$.value;
if (!sortUtils) {
return;
}
if (this.hasSort.value) {
this.toggleShowQuickSettingBar();
return;
}
popCreateSort(popupTargetFromElement(event.currentTarget as HTMLElement), {
sortUtils: {
...sortUtils,
add: sort => {
sortUtils.add(sort);
this.toggleShowQuickSettingBar(true);
requestAnimationFrame(() => {
const ele = this.closest(
'affine-data-view-renderer'
)?.querySelector('.data-view-sort-button');
if (ele) {
popSortRoot(popupTargetFromElement(ele as HTMLElement), {
sortUtils: sortUtils,
});
}
});
},
},
});
return;
}
override connectedCallback() {
super.connectedCallback();
this.style.display = IS_MOBILE ? 'none' : 'flex';
}
override render() {
if (this.readonly) return nothing;
const style = styleMap({
color: this.hasSort.value
? cssVarV2('text/emphasis')
: cssVarV2('icon/primary'),
});
return html` <div
@click="${this.clickSort}"
style="${style}"
class="affine-database-sort-button"
>
${SortIcon()}
</div>`;
}
toggleShowQuickSettingBar(show?: boolean) {
const map = this.view.contextGet(ShowQuickSettingBarContextKey);
map.value = {
...map.value,
[this.view.id]: show ?? !map.value[this.view.id],
};
}
}
declare global {
interface HTMLElementTagNameMap {
'data-view-header-tools-sort': DataViewHeaderToolsSort;
}
}
@@ -0,0 +1,51 @@
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { IS_MOBILE } from '@blocksuite/global/env';
import { PlusIcon } from '@blocksuite/icons/lit';
import { css, html } from 'lit';
import { WidgetBase } from '../../../../core/widget/widget-base.js';
const styles = css`
.new-record {
font-weight: 500;
}
.new-record svg {
font-size: 20px;
color: ${unsafeCSSVarV2('icon/primary')};
}
`;
export class DataViewHeaderToolsAddRow extends WidgetBase {
static override styles = styles;
private _onAddNewRecord = () => {
if (this.readonly) return;
this.viewMethods.addRow?.('start');
};
private get readonly() {
return this.view.readonly$.value;
}
override render() {
if (this.readonly) {
return;
}
return html` <data-view-component-button
class="affine-database-toolbar-item new-record"
.onClick="${this._onAddNewRecord}"
.icon="${PlusIcon()}"
.text="${IS_MOBILE
? html`<span style="font-weight: 500">New</span>`
: html`<span style="font-weight: 500">New Record</span>`}"
>
</data-view-component-button>`;
}
}
declare global {
interface HTMLElementTagNameMap {
'data-view-header-tools-add-row': DataViewHeaderToolsAddRow;
}
}
@@ -0,0 +1,43 @@
import { ShadowlessElement } from '@blocksuite/block-std';
import { PlusIcon } from '@blocksuite/icons/lit';
import { html } from 'lit';
export class NewRecordPreview extends ShadowlessElement {
override render() {
return html`
<style>
affine-database-new-record-preview {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
height: 32px;
width: 32px;
border: 1px solid var(--affine-border-color);
border-radius: 50%;
background: var(--affine-blue-100);
box-shadow:
0px 0px 10px rgba(0, 0, 0, 0.05),
0px 0px 0px 0.5px var(--affine-black-10);
cursor: none;
user-select: none;
pointer-events: none;
caret-color: transparent;
z-index: 99999;
}
affine-database-new-record-preview svg {
width: 16px;
height: 16px;
}
affine-database-new-record-preview path {
fill: var(--affine-brand-color);
}
</style>
${PlusIcon()}
`;
}
}
@@ -0,0 +1,379 @@
import {
menu,
type MenuButtonData,
type MenuConfig,
popMenu,
type PopupTarget,
popupTargetFromElement,
} from '@blocksuite/affine-components/context-menu';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import {
ArrowRightSmallIcon,
DeleteIcon,
DuplicateIcon,
FilterIcon,
GroupingIcon,
InfoIcon,
LayoutIcon,
MoreHorizontalIcon,
SortIcon,
} from '@blocksuite/icons/lit';
import { css, html } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
import { popPropertiesSetting } from '../../../../core/common/properties.js';
import { filterTraitKey } from '../../../../core/filter/trait.js';
import {
popGroupSetting,
popSelectGroupByProperty,
} from '../../../../core/group-by/setting.js';
import { groupTraitKey } from '../../../../core/group-by/trait.js';
import {
type DataViewInstance,
emptyFilterGroup,
popCreateFilter,
renderUniLit,
} from '../../../../core/index.js';
import { popCreateSort } from '../../../../core/sort/add-sort.js';
import { sortTraitKey } from '../../../../core/sort/manager.js';
import { createSortUtils } from '../../../../core/sort/utils.js';
import { WidgetBase } from '../../../../core/widget/widget-base.js';
import { popFilterRoot } from '../../../quick-setting-bar/filter/root-panel-view.js';
import { popSortRoot } from '../../../quick-setting-bar/sort/root-panel.js';
const styles = css`
.affine-database-toolbar-item.more-action {
padding: 2px;
border-radius: 4px;
display: flex;
align-items: center;
cursor: pointer;
}
.affine-database-toolbar-item.more-action:hover {
background: var(--affine-hover-color);
}
.affine-database-toolbar-item.more-action {
font-size: 20px;
color: ${unsafeCSSVarV2('icon/primary')};
}
.more-action.active {
background: var(--affine-hover-color);
}
`;
export class DataViewHeaderToolsViewOptions extends WidgetBase {
static override styles = styles;
clickMoreAction = (e: MouseEvent) => {
e.stopPropagation();
this.openMoreAction(popupTargetFromElement(e.currentTarget as HTMLElement));
};
openMoreAction = (target: PopupTarget) => {
popViewOptions(target, this.dataViewInstance);
};
override render() {
if (this.view.readonly$.value) {
return;
}
return html` <div
class="affine-database-toolbar-item more-action"
@click="${this.clickMoreAction}"
>
${MoreHorizontalIcon()}
</div>`;
}
}
declare global {
interface HTMLElementTagNameMap {
'data-view-header-tools-view-options': DataViewHeaderToolsViewOptions;
}
}
const createSettingMenus = (
target: PopupTarget,
dataViewInstance: DataViewInstance,
reopen: () => void
) => {
const view = dataViewInstance.view;
const settingItems: MenuConfig[] = [];
settingItems.push(
menu.action({
name: 'Properties',
prefix: InfoIcon(),
postfix: html` <div style="font-size: 14px;">
${view.properties$.value.length} shown
</div>
${ArrowRightSmallIcon()}`,
select: () => {
popPropertiesSetting(target, {
view: view,
onBack: reopen,
});
},
})
);
const filterTrait = view.traitGet(filterTraitKey);
if (filterTrait) {
const filterCount = filterTrait.filter$.value.conditions.length;
settingItems.push(
menu.action({
name: 'Filter',
prefix: FilterIcon(),
postfix: html` <div style="font-size: 14px;">
${filterCount === 0
? ''
: filterCount === 1
? '1 filter'
: `${filterCount} filters`}
</div>
${ArrowRightSmallIcon()}`,
select: () => {
if (!filterTrait.filter$.value.conditions.length) {
popCreateFilter(target, {
vars: view.vars$,
onBack: reopen,
onSelect: filter => {
filterTrait.filterSet({
...(filterTrait.filter$.value ?? emptyFilterGroup),
conditions: [...filterTrait.filter$.value.conditions, filter],
});
popFilterRoot(target, {
filterTrait: filterTrait,
onBack: reopen,
});
},
});
} else {
popFilterRoot(target, {
filterTrait: filterTrait,
onBack: reopen,
});
}
},
})
);
}
const sortTrait = view.traitGet(sortTraitKey);
if (sortTrait) {
const sortCount = sortTrait.sortList$.value.length;
settingItems.push(
menu.action({
name: 'Sort',
prefix: SortIcon(),
postfix: html` <div style="font-size: 14px;">
${sortCount === 0
? ''
: sortCount === 1
? '1 sort'
: `${sortCount} sorts`}
</div>
${ArrowRightSmallIcon()}`,
select: () => {
const sortList = sortTrait.sortList$.value;
const sortUtils = createSortUtils(
sortTrait,
dataViewInstance.eventTrace
);
if (!sortList.length) {
popCreateSort(target, {
sortUtils: sortUtils,
onBack: reopen,
});
} else {
popSortRoot(target, {
sortUtils: sortUtils,
title: {
text: 'Sort',
onBack: reopen,
},
});
}
},
})
);
}
const groupTrait = view.traitGet(groupTraitKey);
if (groupTrait) {
settingItems.push(
menu.action({
name: 'Group',
prefix: GroupingIcon(),
postfix: html` <div style="font-size: 14px;">
${groupTrait.property$.value?.name$.value ?? ''}
</div>
${ArrowRightSmallIcon()}`,
select: () => {
const groupBy = groupTrait.property$.value;
if (!groupBy) {
popSelectGroupByProperty(target, groupTrait, {
onSelect: () => popGroupSetting(target, groupTrait, reopen),
onBack: reopen,
});
} else {
popGroupSetting(target, groupTrait, reopen);
}
},
})
);
}
return settingItems;
};
export const popViewOptions = (
target: PopupTarget,
dataViewInstance: DataViewInstance,
onClose?: () => void
) => {
const view = dataViewInstance.view;
const reopen = () => {
popViewOptions(target, dataViewInstance);
};
const items: MenuConfig[] = [];
items.push(
menu.input({
initialValue: view.name$.value,
onChange: text => {
view.nameSet(text);
},
})
);
items.push(
menu.group({
items: [
menu.action({
name: 'Layout',
postfix: html` <div
style="font-size: 14px;text-transform: capitalize;"
>
${view.type}
</div>
${ArrowRightSmallIcon()}`,
select: () => {
const viewTypes = view.manager.viewMetas.map<MenuConfig>(meta => {
return menu => {
if (!menu.search(meta.model.defaultName)) {
return;
}
const isSelected =
meta.type === view.manager.currentView$.value.type;
const iconStyle = styleMap({
fontSize: '24px',
color: isSelected
? 'var(--affine-text-emphasis-color)'
: 'var(--affine-icon-secondary)',
});
const textStyle = styleMap({
fontSize: '14px',
lineHeight: '22px',
color: isSelected
? 'var(--affine-text-emphasis-color)'
: 'var(--affine-text-secondary-color)',
});
const data: MenuButtonData = {
content: () => html`
<div
style="color:var(--affine-text-emphasis-color);width:100%;display: flex;flex-direction: column;align-items: center;justify-content: center;padding: 6px 16px;"
>
<div style="${iconStyle}">
${renderUniLit(meta.renderer.icon)}
</div>
<div style="${textStyle}">${meta.model.defaultName}</div>
</div>
`,
select: () => {
view.manager.viewChangeType(
view.manager.currentViewId$.value,
meta.type
);
dataViewInstance.clearSelection();
},
class: {},
};
const containerStyle = styleMap({
flex: '1',
});
return html` <affine-menu-button
style="${containerStyle}"
.data="${data}"
.menu="${menu}"
></affine-menu-button>`;
};
});
popMenu(target, {
options: {
title: {
onBack: reopen,
text: 'Layout',
},
items: [
menu => {
const result = menu.renderItems(viewTypes);
if (result.length) {
return html` <div style="display: flex">${result}</div>`;
}
return html``;
},
// menu.toggleSwitch({
// name: 'Show block icon',
// on: true,
// onChange: value => {
// console.log(value);
// },
// }),
// menu.toggleSwitch({
// name: 'Show Vertical lines',
// on: true,
// onChange: value => {
// console.log(value);
// },
// }),
],
},
});
},
prefix: LayoutIcon(),
}),
],
})
);
items.push(
menu.group({
items: createSettingMenus(target, dataViewInstance, reopen),
})
);
items.push(
menu.group({
items: [
menu.action({
name: 'Duplicate',
prefix: DuplicateIcon(),
select: () => {
view.duplicate();
},
}),
menu.action({
name: 'Delete',
prefix: DeleteIcon(),
select: () => {
view.delete();
},
class: { 'delete-item': true },
}),
],
})
);
popMenu(target, {
options: {
title: {
text: 'View settings',
},
items,
onClose: onClose,
},
});
};
@@ -0,0 +1,83 @@
import { IS_MOBILE } from '@blocksuite/global/env';
import { css, html } from 'lit';
import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { repeat } from 'lit/directives/repeat.js';
import { type DataViewInstance, renderUniLit } from '../../core/index.js';
import type { SingleView } from '../../core/view-manager/single-view.js';
import type { ViewManager } from '../../core/view-manager/view-manager.js';
import type { DataViewWidget } from '../../core/widget/types.js';
import { WidgetBase } from '../../core/widget/widget-base.js';
const styles = css`
.affine-database-toolbar {
display: flex;
align-items: center;
gap: 6px;
opacity: 0;
transition: opacity 150ms cubic-bezier(0.42, 0, 1, 1);
}
.toolbar-hover-container:hover .affine-database-toolbar {
visibility: visible;
opacity: 1;
}
.toolbar-hover-container:has(.active) .affine-database-toolbar {
visibility: visible;
opacity: 1;
}
.show-toolbar {
visibility: visible;
opacity: 1;
}
@media print {
.affine-database-toolbar {
display: none;
}
}
`;
export class DataViewHeaderTools extends WidgetBase {
static override styles = styles;
override render() {
const classList = classMap({
'show-toolbar': IS_MOBILE,
'affine-database-toolbar': true,
});
const tools = this.toolsMap[this.view.type];
return html` <div class="${classList}">
${repeat(tools ?? [], uni => {
return renderUniLit(uni, {
dataViewInstance: this.dataViewInstance,
});
})}
</div>`;
}
@state()
accessor showToolBar = false;
@property({ attribute: false })
accessor toolsMap!: Record<string, DataViewWidget[]>;
}
declare global {
interface HTMLElementTagNameMap {
'data-view-header-tools': DataViewHeaderTools;
}
}
export const renderTools = (
view: SingleView,
viewMethods: DataViewInstance,
viewSource: ViewManager
) => {
return html` <data-view-header-tools
.viewMethods="${viewMethods}"
.view="${view}"
.viewSource="${viewSource}"
></data-view-header-tools>`;
};