Fixed #4646 - Add custom wrapper support for helper components

pull/4992/head
mertsincan 2023-12-21 23:41:41 +00:00
parent 7618f8ba7a
commit f16bd6ab2e
14 changed files with 196 additions and 157 deletions

View File

@ -57,7 +57,7 @@
import ChevronDownIcon from 'primevue/icons/chevrondown'; import ChevronDownIcon from 'primevue/icons/chevrondown';
import ChevronRightIcon from 'primevue/icons/chevronright'; import ChevronRightIcon from 'primevue/icons/chevronright';
import Ripple from 'primevue/ripple'; import Ripple from 'primevue/ripple';
import { DomHandler, UniqueComponentId } from 'primevue/utils'; import { DomHandler, HelperSet, UniqueComponentId } from 'primevue/utils';
import { mergeProps } from 'vue'; import { mergeProps } from 'vue';
import BaseAccordion from './BaseAccordion.vue'; import BaseAccordion from './BaseAccordion.vue';
@ -65,10 +65,16 @@ export default {
name: 'Accordion', name: 'Accordion',
extends: BaseAccordion, extends: BaseAccordion,
emits: ['update:activeIndex', 'tab-open', 'tab-close', 'tab-click'], emits: ['update:activeIndex', 'tab-open', 'tab-close', 'tab-click'],
provide() {
return {
$accordionTabs: this.d_accordionTabs
};
},
data() { data() {
return { return {
id: this.$attrs.id, id: this.$attrs.id,
d_activeIndex: this.activeIndex d_activeIndex: this.activeIndex,
d_accordionTabs: new HelperSet({ type: 'AccordionTab' })
}; };
}, },
watch: { watch: {
@ -82,10 +88,10 @@ export default {
mounted() { mounted() {
this.id = this.id || UniqueComponentId(); this.id = this.id || UniqueComponentId();
}, },
methods: { beforeUnmount() {
isAccordionTab(child) { this.d_accordionTabs.clear();
return child.type.name === 'AccordionTab';
}, },
methods: {
isTabActive(index) { isTabActive(index) {
return this.multiple ? this.d_activeIndex && this.d_activeIndex.includes(index) : this.d_activeIndex === index; return this.multiple ? this.d_activeIndex && this.d_activeIndex.includes(index) : this.d_activeIndex === index;
}, },
@ -235,19 +241,7 @@ export default {
}, },
computed: { computed: {
tabs() { tabs() {
return this.$slots.default().reduce((tabs, child) => { return this.d_accordionTabs.get(this);
if (this.isAccordionTab(child)) {
tabs.push(child);
} else if (child.children && child.children instanceof Array) {
child.children.forEach((nestedChild) => {
if (this.isAccordionTab(nestedChild)) {
tabs.push(nestedChild);
}
});
}
return tabs;
}, []);
} }
}, },
components: { components: {

View File

@ -7,6 +7,13 @@ import BaseAccordionTab from './BaseAccordionTab.vue';
export default { export default {
name: 'AccordionTab', name: 'AccordionTab',
extends: BaseAccordionTab extends: BaseAccordionTab,
inject: ['$accordionTabs'],
mounted() {
this.$accordionTabs?.add(this.$);
},
unmounted() {
this.$accordionTabs?.delete(this.$);
}
}; };
</script> </script>

View File

@ -4,6 +4,13 @@ import BaseColumn from './BaseColumn.vue';
export default { export default {
name: 'Column', name: 'Column',
extends: BaseColumn, extends: BaseColumn,
inject: ['$columns'],
mounted() {
this.$columns?.add(this.$);
},
unmounted() {
this.$columns?.delete(this.$);
},
render() { render() {
return null; return null;
} }

View File

@ -4,6 +4,13 @@ import BaseColumnGroup from './BaseColumnGroup.vue';
export default { export default {
name: 'ColumnGroup', name: 'ColumnGroup',
extends: BaseColumnGroup, extends: BaseColumnGroup,
inject: ['$columnGroups'],
mounted() {
this.$columnGroups?.add(this.$);
},
unmounted() {
this.$columnGroups?.delete(this.$);
},
render() { render() {
return null; return null;
} }

View File

@ -283,7 +283,7 @@ import ArrowDownIcon from 'primevue/icons/arrowdown';
import ArrowUpIcon from 'primevue/icons/arrowup'; import ArrowUpIcon from 'primevue/icons/arrowup';
import SpinnerIcon from 'primevue/icons/spinner'; import SpinnerIcon from 'primevue/icons/spinner';
import Paginator from 'primevue/paginator'; import Paginator from 'primevue/paginator';
import { DomHandler, ObjectUtils, UniqueComponentId } from 'primevue/utils'; import { DomHandler, HelperSet, ObjectUtils, UniqueComponentId } from 'primevue/utils';
import VirtualScroller from 'primevue/virtualscroller'; import VirtualScroller from 'primevue/virtualscroller';
import BaseDataTable from './BaseDataTable.vue'; import BaseDataTable from './BaseDataTable.vue';
import TableBody from './TableBody.vue'; import TableBody from './TableBody.vue';
@ -333,6 +333,12 @@ export default {
'row-edit-save', 'row-edit-save',
'row-edit-cancel' 'row-edit-cancel'
], ],
provide() {
return {
$columns: this.d_columns,
$columnGroups: this.d_columnGroups
};
},
data() { data() {
return { return {
d_first: this.first, d_first: this.first,
@ -346,7 +352,9 @@ export default {
d_columnOrder: null, d_columnOrder: null,
d_editingRowKeys: null, d_editingRowKeys: null,
d_editingMeta: {}, d_editingMeta: {},
d_filters: this.cloneFilters(this.filters) d_filters: this.cloneFilters(this.filters),
d_columns: new HelperSet({ type: 'Column' }),
d_columnGroups: new HelperSet({ type: 'ColumnGroup' })
}; };
}, },
rowTouched: false, rowTouched: false,
@ -430,6 +438,9 @@ export default {
this.unbindColumnResizeEvents(); this.unbindColumnResizeEvents();
this.destroyStyleElement(); this.destroyStyleElement();
this.destroyResponsiveStyle(); this.destroyResponsiveStyle();
this.d_columns.clear();
this.d_columnGroups.clear();
}, },
updated() { updated() {
if (this.isStateful()) { if (this.isStateful()) {
@ -1852,9 +1863,6 @@ export default {
hasGlobalFilter() { hasGlobalFilter() {
return this.filters && Object.prototype.hasOwnProperty.call(this.filters, 'global'); return this.filters && Object.prototype.hasOwnProperty.call(this.filters, 'global');
}, },
getChildren() {
return this.$slots.default ? this.$slots.default() : null;
},
onFilterChange(filters) { onFilterChange(filters) {
this.d_filters = filters; this.d_filters = filters;
}, },
@ -1952,23 +1960,6 @@ export default {
this.styleElement = null; this.styleElement = null;
} }
}, },
recursiveGetChildren(children, results) {
if (!results) {
results = [];
}
if (children && children.length) {
children.forEach((child) => {
if (child.children instanceof Array) {
results.concat(this.recursiveGetChildren(child.children, results));
} else if (child.type.name == 'Column') {
results.push(child);
}
});
}
return results;
},
dataToRender(data) { dataToRender(data) {
const _data = data || this.processedData; const _data = data || this.processedData;
@ -1989,13 +1980,7 @@ export default {
}, },
computed: { computed: {
columns() { columns() {
let children = this.getChildren(); const cols = this.d_columns.get(this);
if (!children) {
return;
}
const cols = this.recursiveGetChildren(children, []);
if (this.reorderableColumns && this.d_columnOrder) { if (this.reorderableColumns && this.d_columnOrder) {
let orderedColumns = []; let orderedColumns = [];
@ -2013,31 +1998,14 @@ export default {
return cols; return cols;
}, },
columnGroups() {
return this.d_columnGroups.get(this);
},
headerColumnGroup() { headerColumnGroup() {
const children = this.getChildren(); return this.columnGroups?.find((group) => this.columnProp(group, 'type') === 'header');
if (children) {
for (let child of children) {
if (child.type.name === 'ColumnGroup' && this.columnProp(child, 'type') === 'header') {
return child;
}
}
}
return null;
}, },
footerColumnGroup() { footerColumnGroup() {
const children = this.getChildren(); return this.columnGroups?.find((group) => this.columnProp(group, 'type') === 'footer');
if (children) {
for (let child of children) {
if (child.type.name === 'ColumnGroup' && this.columnProp(child, 'type') === 'footer') {
return child;
}
}
}
return null;
}, },
hasFilters() { hasFilters() {
return this.filters && Object.keys(this.filters).length > 0 && this.filters.constructor === Object; return this.filters && Object.keys(this.filters).length > 0 && this.filters.constructor === Object;

View File

@ -17,7 +17,7 @@
<script> <script>
import BaseComponent from 'primevue/basecomponent'; import BaseComponent from 'primevue/basecomponent';
import { ObjectUtils } from 'primevue/utils'; import { HelperSet, ObjectUtils } from 'primevue/utils';
import { mergeProps } from 'vue'; import { mergeProps } from 'vue';
import FooterCell from './FooterCell.vue'; import FooterCell from './FooterCell.vue';
@ -35,6 +35,22 @@ export default {
default: null default: null
} }
}, },
provide() {
return {
$rows: this.d_footerRows,
$columns: this.d_footerColumns
};
},
data() {
return {
d_footerRows: new HelperSet({ type: 'Row' }),
d_footerColumns: new HelperSet({ type: 'Column' })
};
},
beforeUnmount() {
this.d_footerRows.clear();
this.d_footerColumns.clear();
},
methods: { methods: {
columnProp(col, prop) { columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop); return ObjectUtils.getVNodeProp(col, prop);
@ -77,33 +93,10 @@ export default {
return row.props && row.props.pt ? row.props.pt : undefined; //@todo return row.props && row.props.pt ? row.props.pt : undefined; //@todo
}, },
getFooterRows() { getFooterRows() {
let rows = []; return this.d_footerRows?.get(this.columnGroup, this.columnGroup.children);
let columnGroup = this.columnGroup;
if (columnGroup.children && columnGroup.children.default) {
for (let child of columnGroup.children.default()) {
if (child.type.name === 'Row') {
rows.push(child);
} else if (child.children && child.children instanceof Array) {
rows = child.children;
}
}
return rows;
}
}, },
getFooterColumns(row) { getFooterColumns(row) {
let cols = []; return this.d_footerColumns?.get(row, row.children);
if (row.children && row.children.default) {
row.children.default().forEach((child) => {
if (child.children && child.children instanceof Array) cols = [...cols, ...child.children];
else if (child.type.name === 'Column') cols.push(child);
});
return cols;
}
} }
}, },
computed: { computed: {

View File

@ -128,7 +128,7 @@
<script> <script>
import BaseComponent from 'primevue/basecomponent'; import BaseComponent from 'primevue/basecomponent';
import { ObjectUtils } from 'primevue/utils'; import { HelperSet, ObjectUtils } from 'primevue/utils';
import { mergeProps } from 'vue'; import { mergeProps } from 'vue';
import ColumnFilter from './ColumnFilter.vue'; import ColumnFilter from './ColumnFilter.vue';
import HeaderCell from './HeaderCell.vue'; import HeaderCell from './HeaderCell.vue';
@ -226,6 +226,22 @@ export default {
default: null default: null
} }
}, },
provide() {
return {
$rows: this.d_headerRows,
$columns: this.d_headerColumns
};
},
data() {
return {
d_headerRows: new HelperSet({ type: 'Row' }),
d_headerColumns: new HelperSet({ type: 'Column' })
};
},
beforeUnmount() {
this.d_headerRows.clear();
this.d_headerColumns.clear();
},
methods: { methods: {
columnProp(col, prop) { columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop); return ObjectUtils.getVNodeProp(col, prop);
@ -292,33 +308,10 @@ export default {
return [this.columnProp(column, 'filterHeaderStyle'), this.columnProp(column, 'style')]; return [this.columnProp(column, 'filterHeaderStyle'), this.columnProp(column, 'style')];
}, },
getHeaderRows() { getHeaderRows() {
let rows = []; return this.d_headerRows?.get(this.columnGroup, this.columnGroup.children);
let columnGroup = this.columnGroup;
if (columnGroup.children && columnGroup.children.default) {
for (let child of columnGroup.children.default()) {
if (child.type.name === 'Row') {
rows.push(child);
} else if (child.children && child.children instanceof Array) {
rows = child.children;
}
}
return rows;
}
}, },
getHeaderColumns(row) { getHeaderColumns(row) {
let cols = []; return this.d_headerColumns?.get(row, row.children);
if (row.children && row.children.default) {
row.children.default().forEach((child) => {
if (child.children && child.children instanceof Array) cols = [...cols, ...child.children];
else if (child.type.name === 'Column') cols.push(child);
});
return cols;
}
} }
}, },
computed: { computed: {

View File

@ -4,6 +4,13 @@ import BaseComponent from 'primevue/basecomponent';
export default { export default {
name: 'Row', name: 'Row',
extends: BaseComponent, extends: BaseComponent,
inject: ['$rows'],
mounted() {
this.$rows?.add(this.$);
},
unmounted() {
this.$rows?.delete(this.$);
},
render() { render() {
return null; return null;
} }

View File

@ -7,6 +7,13 @@ import BaseTabPanel from './BaseTabPanel.vue';
export default { export default {
name: 'TabPanel', name: 'TabPanel',
extends: BaseTabPanel extends: BaseTabPanel,
inject: ['$tabPanels'],
mounted() {
this.$tabPanels?.add(this.$);
},
unmounted() {
this.$tabPanels?.delete(this.$);
}
}; };
</script> </script>

View File

@ -95,7 +95,7 @@
import ChevronLeftIcon from 'primevue/icons/chevronleft'; import ChevronLeftIcon from 'primevue/icons/chevronleft';
import ChevronRightIcon from 'primevue/icons/chevronright'; import ChevronRightIcon from 'primevue/icons/chevronright';
import Ripple from 'primevue/ripple'; import Ripple from 'primevue/ripple';
import { DomHandler, UniqueComponentId } from 'primevue/utils'; import { DomHandler, HelperSet, UniqueComponentId } from 'primevue/utils';
import { mergeProps } from 'vue'; import { mergeProps } from 'vue';
import BaseTabView from './BaseTabView.vue'; import BaseTabView from './BaseTabView.vue';
@ -103,12 +103,18 @@ export default {
name: 'TabView', name: 'TabView',
extends: BaseTabView, extends: BaseTabView,
emits: ['update:activeIndex', 'tab-change', 'tab-click'], emits: ['update:activeIndex', 'tab-change', 'tab-click'],
provide() {
return {
$tabPanels: this.d_tabPanels
};
},
data() { data() {
return { return {
id: this.$attrs.id, id: this.$attrs.id,
d_activeIndex: this.activeIndex, d_activeIndex: this.activeIndex,
isPrevButtonDisabled: true, isPrevButtonDisabled: true,
isNextButtonDisabled: false isNextButtonDisabled: false,
d_tabPanels: new HelperSet({ type: 'TabPanel' })
}; };
}, },
watch: { watch: {
@ -130,10 +136,10 @@ export default {
updated() { updated() {
this.updateInkBar(); this.updateInkBar();
}, },
methods: { beforeUnmount() {
isTabPanel(child) { this.d_tabPanels.clear();
return child.type.name === 'TabPanel';
}, },
methods: {
isTabActive(index) { isTabActive(index) {
return this.d_activeIndex === index; return this.d_activeIndex === index;
}, },
@ -342,19 +348,7 @@ export default {
}, },
computed: { computed: {
tabs() { tabs() {
return this.$slots.default().reduce((tabs, child) => { return this.d_tabPanels.get(this);
if (this.isTabPanel(child)) {
tabs.push(child);
} else if (child.children && child.children instanceof Array) {
child.children.forEach((nestedChild) => {
if (this.isTabPanel(nestedChild)) {
tabs.push(nestedChild);
}
});
}
return tabs;
}, []);
}, },
prevButtonAriaLabel() { prevButtonAriaLabel() {
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.previous : undefined; return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.previous : undefined;

View File

@ -170,7 +170,7 @@
import { FilterService } from 'primevue/api'; import { FilterService } from 'primevue/api';
import SpinnerIcon from 'primevue/icons/spinner'; import SpinnerIcon from 'primevue/icons/spinner';
import Paginator from 'primevue/paginator'; import Paginator from 'primevue/paginator';
import { DomHandler, ObjectUtils } from 'primevue/utils'; import { DomHandler, HelperSet, ObjectUtils } from 'primevue/utils';
import BaseTreeTable from './BaseTreeTable.vue'; import BaseTreeTable from './BaseTreeTable.vue';
import FooterCell from './FooterCell.vue'; import FooterCell from './FooterCell.vue';
import HeaderCell from './HeaderCell.vue'; import HeaderCell from './HeaderCell.vue';
@ -196,10 +196,11 @@ export default {
'filter', 'filter',
'column-resize-end' 'column-resize-end'
], ],
documentColumnResizeListener: null, provide() {
documentColumnResizeEndListener: null, return {
lastResizeHelperX: null, $columns: this.d_columns
resizeColumnElement: null, };
},
data() { data() {
return { return {
d_expandedKeys: this.expandedKeys || {}, d_expandedKeys: this.expandedKeys || {},
@ -208,9 +209,14 @@ export default {
d_sortField: this.sortField, d_sortField: this.sortField,
d_sortOrder: this.sortOrder, d_sortOrder: this.sortOrder,
d_multiSortMeta: this.multiSortMeta ? [...this.multiSortMeta] : [], d_multiSortMeta: this.multiSortMeta ? [...this.multiSortMeta] : [],
hasASelectedNode: false hasASelectedNode: false,
d_columns: new HelperSet({ type: 'Column' })
}; };
}, },
documentColumnResizeListener: null,
documentColumnResizeEndListener: null,
lastResizeHelperX: null,
resizeColumnElement: null,
watch: { watch: {
expandedKeys(newValue) { expandedKeys(newValue) {
this.d_expandedKeys = newValue; this.d_expandedKeys = newValue;
@ -241,6 +247,9 @@ export default {
this.updateScrollWidth(); this.updateScrollWidth();
} }
}, },
beforeUnmount() {
this.d_columns.clear();
},
methods: { methods: {
columnProp(col, prop) { columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop); return ObjectUtils.getVNodeProp(col, prop);
@ -763,15 +772,7 @@ export default {
}, },
computed: { computed: {
columns() { columns() {
let cols = []; return this.d_columns.get(this);
let children = this.$slots.default();
children.forEach((child) => {
if (child.children && child.children instanceof Array) cols = [...cols, ...child.children];
else if (child.type.name === 'Column') cols.push(child);
});
return cols;
}, },
processedData() { processedData() {
if (this.lazy) { if (this.lazy) {

View File

@ -0,0 +1,51 @@
import ObjectUtils from './ObjectUtils';
export default class {
helpers;
type;
constructor({ init, type }) {
this.helpers = new Set(init);
this.type = type;
}
add(instance) {
this.helpers.add(instance);
}
update() {
// @todo
}
delete(instance) {
this.helpers.delete(instance);
}
clear() {
this.helpers.clear();
}
get(parentInstance, slots) {
const children = this._get(parentInstance, slots);
const computed = children ? this._recursive([...this.helpers], children) : null;
return ObjectUtils.isNotEmpty(computed) ? computed : null;
}
_isMatched(instance, key) {
const parent = instance?.parent;
return parent?.vnode?.key === key || (parent && this._isMatched(parent, key)) || false;
}
_get(parentInstance, slots) {
return (slots || parentInstance?.$slots)?.default?.() || null;
}
_recursive(helpers = [], children = []) {
let components = [];
children.forEach((child) => {
if (child.children instanceof Array) {
components = components.concat(this._recursive(components, child.children));
} else if (child.type.name === this.type) {
components.push(child);
} else if (ObjectUtils.isNotEmpty(child.key)) {
components = components.concat(helpers.filter((c) => this._isMatched(c, child.key)).map((c) => c.vnode));
}
});
return components;
}
}

View File

@ -102,6 +102,15 @@ export declare class ObjectUtils {
static stringify(value: any, indent?: number, currentIndent?: number): string; static stringify(value: any, indent?: number, currentIndent?: number): string;
} }
export declare class HelperSet {
constructor(options: { init?: any; type?: string });
add(instance: any): void;
update(): void;
delete(instance: any): void;
clear(): void;
get(parentInstance?: any, slots?: any): any[] | null | undefined;
}
export declare namespace ZIndexUtils { export declare namespace ZIndexUtils {
export function get(el?: HTMLElement): number; export function get(el?: HTMLElement): number;
export function set(key: string, el: HTMLElement, baseZIndex?: number): void; export function set(key: string, el: HTMLElement, baseZIndex?: number): void;

View File

@ -1,8 +1,9 @@
import ConnectedOverlayScrollHandler from './ConnectedOverlayScrollHandler'; import ConnectedOverlayScrollHandler from './ConnectedOverlayScrollHandler';
import DomHandler from './DomHandler'; import DomHandler from './DomHandler';
import EventBus from './EventBus'; import EventBus from './EventBus';
import HelperSet from './HelperSet';
import ObjectUtils from './ObjectUtils'; import ObjectUtils from './ObjectUtils';
import UniqueComponentId from './UniqueComponentId'; import UniqueComponentId from './UniqueComponentId';
import ZIndexUtils from './ZIndexUtils'; import ZIndexUtils from './ZIndexUtils';
export { ConnectedOverlayScrollHandler, DomHandler, EventBus, ObjectUtils, UniqueComponentId, ZIndexUtils }; export { ConnectedOverlayScrollHandler, DomHandler, EventBus, HelperSet, ObjectUtils, UniqueComponentId, ZIndexUtils };