Skip to content

Commit

Permalink
Merge pull request #9398 from surveyjs/bug/9369
Browse files Browse the repository at this point in the history
Move paneldynamic's tabbed menu inside content
  • Loading branch information
andrewtelnov authored Feb 5, 2025
2 parents a97b8f3 + 82150fc commit 9246384
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 206 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<div [class]="model.cssClasses.root" #contentElement>
<div *ngIf="model.hasTabbedMenu" [class]="model.getTabsContainerCss()">
<sv-action-bar [model]="model.tabbedMenu"></sv-action-bar>
</div>
<div *ngIf="model.getShowNoEntriesPlaceholder()" [class]="model.cssClasses.noEntriesPlaceholder">
<span [model]="model.locNoEntriesText" sv-ng-string></span>
<sv-ng-paneldynamic-add-btn *ngIf="model.canAddPanel" [data]="{ question: model }"></sv-ng-paneldynamic-add-btn>
Expand All @@ -14,8 +17,7 @@
<div [class]="model.getPanelWrapperCss(panel)">
<ng-template
[component]="{ name: getPanelComponentName(panel), data: getPanelComponentData(panel) }"></ng-template>
<ng-container
*ngIf="model.canRenderRemovePanelOnRight(panel)">
<ng-container *ngIf="model.canRenderRemovePanelOnRight(panel)">
<ng-template
[component]="{ name: 'sv-paneldynamic-remove-btn', data: { data: { panel, question: model }}}"></ng-template>
</ng-container>
Expand Down
30 changes: 25 additions & 5 deletions packages/survey-core/src/default-theme/blocks/sd-paneldynamic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,28 @@
margin-bottom: calcSize(-1);
}
}

.sd-paneldynamic__tabs-container {
padding-top: var(--sd-base-padding);
.sd-tabs-toolbar {
margin: 0 0 -1px calcSize(-2);
width: calc(100% + 4 * #{$base-unit});
}
&:after {
content: " ";
display: block;
height: 1px;
position: relative;
background: $border-light;
bottom: 0;
inset-inline-start: calc(-1 * var(--sd-base-padding));
width: calc(100% + 2 * var(--sd-base-padding));
}
}
.sd-paneldynamic__tabs-container--with-header {
padding-top: calcSize(3);
}
.sd-tabs-toolbar.sv-action-bar {
align-items: flex-start;
margin: calcSize(1) 0 -1px calcSize(-2);
width: calc(100% + 4 * #{$base-unit});
z-index: 1;
}

Expand Down Expand Up @@ -277,13 +294,16 @@
.sd-question__title ~ .sd-tabs-toolbar {
margin-top: calcSize(3);
}

.sd-paneldynamic__header.sd-element__header.sd-paneldynamic__header-tab {
padding-bottom: 0;
}

.sd-element--collapsed .sd-paneldynamic__header.sd-element__header.sd-paneldynamic__header-tab {
padding-bottom: calcSize(2);
}

.sd-paneldynamic__header.sd-element__header.sd-paneldynamic__header-tab::after {
bottom: 0;
content: none;
}

.sd-question--paneldynamic.sd-element--with-frame {
Expand Down
2 changes: 2 additions & 0 deletions packages/survey-core/src/defaultCss/defaultCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ export var defaultCss = {
progressBtnIcon: "icon-progressbuttonv2",
noEntriesPlaceholder: "sd-paneldynamic__placeholder sd-question__placeholder",
compact: "sd-element--with-frame sd-element--compact",
tabsContainer: "sd-paneldynamic__tabs-container",
tabsContainerWithHeader: "sd-paneldynamic__tabs-container--with-header",
tabsRoot: "sd-tabs-toolbar",
tabsLeft: "sd-tabs-toolbar--left",
tabsRight: "sd-tabs-toolbar--right",
Expand Down
84 changes: 46 additions & 38 deletions packages/survey-core/src/question_paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ class QuestionPanelDynamicItemTextProcessor extends QuestionTextProcessor {
}
}

interface IPanelDynamicTabbedMenuItem extends IAction {
panelId: string;
}
class PanelDynamicTabbedMenuItem extends Action {
public panelId: string;
constructor(innerItem: IPanelDynamicTabbedMenuItem) {
super(innerItem);
}
}

export class QuestionPanelDynamicItem implements ISurveyData, ISurveyImpl {
public static ItemVariableName = "panel";
public static ParentItemVariableName = "parentpanel";
Expand Down Expand Up @@ -1292,7 +1302,7 @@ export class QuestionPanelDynamicModel extends Question
public set tabAlign(val: "center" | "left" | "right") {
this.setPropertyValue("tabAlign", val);
if (this.isRenderModeTab) {
this.additionalTitleToolbar.containerCss = this.getAdditionalTitleToolbarCss();
this.tabbedMenu.containerCss = this.getTabbedMenuCss();
}
}
public get isRenderModeList(): boolean {
Expand All @@ -1301,12 +1311,6 @@ export class QuestionPanelDynamicModel extends Question
public get isRenderModeTab(): boolean {
return this.displayMode === "tab";
}
get hasTitleOnLeftTop(): boolean {
if (this.isRenderModeTab && this.visiblePanelCount > 0) return true;
if (!this.hasTitle) return false;
const location = this.getTitleLocation();
return location === "left" || location === "top";
}
public setVisibleIndex(value: number): number {
if (!this.isVisible) return 0;
const onSurveyNumbering = this.showQuestionNumbers === "onSurvey";
Expand Down Expand Up @@ -1677,8 +1681,8 @@ export class QuestionPanelDynamicModel extends Question
for (var i = 0; i < panels.length; i++) {
panels[i].locStrsChanged();
}
if (this.additionalTitleToolbar) {
this.additionalTitleToolbar.locStrsChanged();
if (this.tabbedMenu) {
this.tabbedMenu.locStrsChanged();
}
}
public clearIncorrectValues() {
Expand Down Expand Up @@ -2397,11 +2401,13 @@ export class QuestionPanelDynamicModel extends Question
public get cssHeader(): string {
const showTab = this.isRenderModeTab && !!this.visiblePanelCount;
return new CssClassBuilder()
.append(this.cssClasses.header)
.append(this.cssClasses.headerTop, this.hasTitleOnTop || showTab)
.append(this.cssClasses.headerTab, showTab)
.append(super.getCssHeader(this.cssClasses))
.append(this.cssClasses.headerTab, this.hasTitleOnTop && showTab)
.toString();
}
public getTabsContainerCss(): string {
return new CssClassBuilder().append(this.cssClasses.tabsContainer).append(this.cssClasses.tabsContainerWithHeader, this.hasTitleOnTop).toString();
}
public getPanelWrapperCss(panel: PanelModel): string {
return new CssClassBuilder()
.append(this.cssClasses.panelWrapper, !panel || panel.visible)
Expand Down Expand Up @@ -2455,20 +2461,20 @@ export class QuestionPanelDynamicModel extends Question
if (!!panel && panel.needResponsiveWidth()) return true;
return false;
}
private additionalTitleToolbarValue: AdaptiveActionContainer;
public get hasAdditionalTitleToolbar(): boolean {
private tabbedMenuValue: AdaptiveActionContainer<PanelDynamicTabbedMenuItem>;
public get hasTabbedMenu(): boolean {
return this.isRenderModeTab && this.visiblePanels.length > 0;
}
protected getAdditionalTitleToolbar(): AdaptiveActionContainer | null {
public get tabbedMenu(): AdaptiveActionContainer<PanelDynamicTabbedMenuItem> | null {
if (!this.isRenderModeTab) return null;
if (!this.additionalTitleToolbarValue) {
this.additionalTitleToolbarValue = new AdaptiveActionContainer();
this.additionalTitleToolbarValue.dotsItem.popupModel.showPointer = false;
this.additionalTitleToolbarValue.dotsItem.popupModel.verticalPosition = "bottom";
this.additionalTitleToolbarValue.dotsItem.popupModel.horizontalPosition = "center";
if (!this.tabbedMenuValue) {
this.tabbedMenuValue = new AdaptiveActionContainer<PanelDynamicTabbedMenuItem>();
this.tabbedMenuValue.dotsItem.popupModel.showPointer = false;
this.tabbedMenuValue.dotsItem.popupModel.verticalPosition = "bottom";
this.tabbedMenuValue.dotsItem.popupModel.horizontalPosition = "center";
this.updateElementCss(false);
}
return this.additionalTitleToolbarValue;
return this.tabbedMenuValue;
}

private footerToolbarValue: ActionContainer;
Expand Down Expand Up @@ -2563,19 +2569,21 @@ export class QuestionPanelDynamicModel extends Question
return options.title;
};
locTitle.sharedData = this.locTemplateTabTitle;
const isActive = this.getPanelVisibleIndexById(panel.id) === this.currentIndex;
const newItem = new Action({
id: panel.id,
const panelId = panel.id;
const isActive = this.getPanelVisibleIndexById(panelId) === this.currentIndex;
const newItem = new PanelDynamicTabbedMenuItem({
id: `${this.id}_tab_${panelId}`,
panelId: panelId,
pressed: isActive,
locTitle: locTitle,
disableHide: isActive,
action: () => {
this.currentIndex = this.getPanelVisibleIndexById(newItem.id);
this.currentIndex = this.getPanelVisibleIndexById(panelId);
}
});
return newItem;
}
private getAdditionalTitleToolbarCss(cssClasses?: any): string {
private getTabbedMenuCss(cssClasses?: any): string {
const css = cssClasses ?? this.cssClasses;
return new CssClassBuilder()
.append(css.tabsRoot)
Expand All @@ -2588,8 +2596,8 @@ export class QuestionPanelDynamicModel extends Question
if (!this.isRenderModeTab) return;
if (this.currentIndex < 0 || this.currentIndex >= this.visiblePanelCount) return;
const panel = this.visiblePanelsCore[this.currentIndex];
this.additionalTitleToolbar.renderedActions.forEach(action => {
const isActive = action.id === panel.id;
this.tabbedMenu.renderedActions.forEach(action => {
const isActive = action.panelId === panel.id;
action.pressed = isActive;
action.disableHide = isActive;
//should raise update if dimensions are not changed but action is active now
Expand All @@ -2606,20 +2614,20 @@ export class QuestionPanelDynamicModel extends Question
for (let i = 0; i < visPanels.length; i++) {
this.visiblePanelsCore.forEach(panel => items.push(this.createTabByPanel(visPanels[i], i)));
}
this.additionalTitleToolbar.setItems(items);
this.tabbedMenu.setItems(items);
}
private addTabFromToolbar(panel: PanelModel, index: number) {
if (!this.isRenderModeTab) return;

const newItem = this.createTabByPanel(panel, index);
this.additionalTitleToolbar.actions.splice(index, 0, newItem);
this.tabbedMenu.actions.splice(index, 0, newItem);
this.updateTabToolbarItemsPressedState();
}
private removeTabFromToolbar(panel: PanelModel) {
if (!this.isRenderModeTab) return;
const removedItem = this.additionalTitleToolbar.getActionById(panel.id);
const removedItem = this.tabbedMenu.actions.find(a => a.panelId == panel.id);
if (!removedItem) return;
this.additionalTitleToolbar.actions.splice(this.additionalTitleToolbar.actions.indexOf(removedItem), 1);
this.tabbedMenu.actions.splice(this.tabbedMenu.actions.indexOf(removedItem), 1);
this.updateTabToolbarItemsPressedState();
}
get showLegacyNavigation(): boolean {
Expand All @@ -2636,12 +2644,12 @@ export class QuestionPanelDynamicModel extends Question

protected calcCssClasses(css: any): any {
const classes = super.calcCssClasses(css);
const additionalTitleToolbar = <AdaptiveActionContainer>this.additionalTitleToolbar;
if (!!additionalTitleToolbar) {
additionalTitleToolbar.containerCss = this.getAdditionalTitleToolbarCss(classes);
additionalTitleToolbar.cssClasses = classes.tabs;
additionalTitleToolbar.dotsItem.cssClasses = classes.tabs;
additionalTitleToolbar.dotsItem.popupModel.contentComponentData.model.cssClasses = css.list;
const tabbedMenu = <AdaptiveActionContainer>this.tabbedMenu;
if (!!tabbedMenu) {
tabbedMenu.containerCss = this.getTabbedMenuCss(classes);
tabbedMenu.cssClasses = classes.tabs;
tabbedMenu.dotsItem.cssClasses = classes.tabs;
tabbedMenu.dotsItem.popupModel.contentComponentData.model.cssClasses = css.list;
}
return classes;
}
Expand Down
Loading

0 comments on commit 9246384

Please sign in to comment.