Skip to content

Commit

Permalink
Implement Popup and List components
Browse files Browse the repository at this point in the history
  • Loading branch information
dk981234 committed Mar 15, 2023
1 parent 4d6a718 commit 08f8ea8
Show file tree
Hide file tree
Showing 6 changed files with 364 additions and 0 deletions.
84 changes: 84 additions & 0 deletions packages/survey-vue-ui/src/components/list/List.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<template>
<div v-bind:class="model.cssClasses.root" ref="listContainerElement">
<div v-bind:class="model.cssClasses.filter" v-if="model.showFilter">
<div v-bind:class="model.cssClasses.filterIcon">
<sv-svg-icon :iconName="'icon-search'" :size="'auto'"> </sv-svg-icon>
</div>
<input
type="text"
v-bind:class="model.cssClasses.filterInput"
:aria-label="model.filterStringPlaceholder"
:placeholder="model.filterStringPlaceholder"
:value="model.filterString"
@change="change"
@keyup="keyup"
/>
<button v-if="model.showSearchClearButton && !!model.filterString" v-on:click="(event) => { model.onClickSearchClearButton(event) }" v-bind:class="model.cssClasses.searchClearButtonIcon">
<sv-svg-icon :iconName="'icon-searchclear'" :size="'auto'"></sv-svg-icon>
</button>
</div>
<div v-bind:class="model.cssClasses.emptyContainer" v-show="model.isEmpty">
<div v-bind:class="model.cssClasses.emptyText" :aria-label="model.emptyMessage">{{ model.emptyMessage }}</div>
</div>
<ul
v-bind:class="model.cssClasses.itemsContainer"
v-show="!model.isEmpty"
role="listbox"
@mousedown="
(event) => {
event.preventDefault();
}
"
@mousemove="mouseMove"
v-on:keydown="
(event) => {
model.onKeyDown(event);
}
"
>
<sv-list-item
v-for="item in model.renderedActions"
:item="item"
:model="model"
:key="item.id"
>
</sv-list-item>
</ul>
</div>
</template>

<script lang="ts">
import { ListModel } from "survey-core";
import { defineSurveyComponent } from "../../base";
export default defineSurveyComponent({
// eslint-disable-next-line
name: "sv-list",
props: {
model: ListModel,
},
methods: {
change(event: any) {
this.model.filterString = event.target.value;
},
keyup(event: any) {
this.model.filterString = event.target.value;
this.model.goToItems(event);
},
mouseMove(event: any) {
this.model.onMouseMove(event);
},
},
mounted() {
const listContainerElement: any = this.$refs["listContainerElement"];
this.model.initListContainerHtmlElement(listContainerElement);
},
data: (vm: any) => {
return {
getModel: () => {
return vm.model;
},
};
},
});
</script>
68 changes: 68 additions & 0 deletions packages/survey-vue-ui/src/components/list/ListItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<li
tabindex="0"
role="option"
:aria-selected="model.isItemSelected(item)"
v-show="model.isItemVisible(item)"
:key="item.id"
v-bind:class="model.getItemClass(item)"
v-on:click="click"
v-on:keyup="keyUp"
>
<div
v-if="item.needSeparator"
v-bind:class="model.cssClasses.itemSeparator"
/>

<div
:style="{ paddingInlineStart: model.getItemIndent(item) }"
v-bind:class="model.cssClasses.itemBody"
>
<sv-svg-icon
v-if="item.iconName && !item.component"
v-bind:class="model.cssClasses.itemIcon"
:iconName="item.iconName"
:size="24"
></sv-svg-icon>
<survey-string v-if="!item.component" :locString="item.locTitle" />
<component v-if="item.component" :is="item.component" :item="item"> </component>
</div>
</li>
</template>

<script lang="ts">
import { ListModel, Action } from "survey-core";
import { defineSurveyComponent } from "../../base";
//todo
function attachKey2click(event: any) {
}
export default defineSurveyComponent({
// eslint-disable-next-line
name: "sv-list-item",
props: {
model: ListModel,
item: Action,
},
methods: {
click(event: any) {
this.model.onItemClick(this.item as any);
event.stopPropagation();
},
keyup(event: any) {
attachKey2click(event);
}
},
data: (vm: any) => {
return {
getModel: () => {
return vm.item;
},
};
},
mounted() {
this.model.onLastItemRended(<any>this.item);
},
});
</script>
51 changes: 51 additions & 0 deletions packages/survey-vue-ui/src/components/popup/Popup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<div>
<Teleport :to="popupViewModel.container">
<sv-popup-container :model="popupViewModel"></sv-popup-container>
</Teleport>
</div>
</template>
<script lang="ts">
import { PopupModel, createPopupViewModel, PopupBaseViewModel } from "survey-core";
import { reactive, ref, watch } from "vue";
import { defineSurveyComponent } from "../../base";
function initializePopupViewModel(model: PopupModel): PopupBaseViewModel {
const res = createPopupViewModel(model);
res.initializePopupContainer();
return res;
}
export default defineSurveyComponent({
// eslint-disable-next-line
name: "sv-popup",
props: {
model: PopupModel,
},
setup(props: any) {
return {
popupViewModel: reactive(initializePopupViewModel(props.model)),
};
},
mounted() {
this.popupViewModel.targetElement = this.$el.parentElement;
},
destroyed() {
this.popupViewModel.dispose();
},
data(vm: any) {
return {
getModel: () => {
return vm.model;
},
};
},
watch: {
model(newValue: PopupModel) {
this.popupViewModel.dispose();
this.popupViewModel = reactive(initializePopupViewModel(newValue));
this.popupViewModel = this.$el.parentElement;
},
},
});
</script>
127 changes: 127 additions & 0 deletions packages/survey-vue-ui/src/components/popup/PopupContainer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<template>
<div
tabindex="-1"
class="sv-popup"
v-bind:class="model.styleClass"
v-show="model.isVisible"
v-on:keydown="
(event) => {
model.onKeyDown(event);
}
"
v-on:click="
() => {
model.clickOutside();
}
"
>
<div
class="sv-popup__container"
v-bind:style="{
left: model.left,
top: model.top,
height: model.height,
width: model.width,
minWidth: model.minWidth,
}"
v-on:click="clickInside"
>
<div class="sv-popup__shadow">
<component
v-show="model.showHeader"
:is="model.popupHeaderTemplate"
:model="model"
></component>
<div class="sv-popup__body-content">
<div class="sv-popup__body-header" v-show="!!model.title">{{ model.title }}</div>
<div class="sv-popup__scrolling-content">
<div class="sv-popup__content">
<component
:is="model.contentComponentName"
v-bind="model.contentComponentData"
></component>
</div>
</div>
<div v-if="model.showFooter" class="sv-popup__body-footer">
<sv-action-bar :model="model.footerToolbar" />
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { PopupBaseViewModel } from "survey-core";
import { defineSurveyComponent } from "../../base";
export default defineSurveyComponent({
// eslint-disable-next-line
name: "sv-popup-container",
props: {
model: PopupBaseViewModel,
},
setup() {
return {
prevIsVisible: false,
};
},
data(vm: any) {
return {
getModel: () => {
return vm.model;
},
};
},
methods: {
clickInside: (event: any) => {
event.stopPropagation();
},
},
updated() {
if (!this.prevIsVisible && this.model.isVisible) {
this.model.updateOnShowing();
}
this.prevIsVisible = this.model.isVisible;
},
});
// replace to showDialog then delete
// export function showModal(
// componentName: string,
// data: any,
// onApply: () => boolean,
// onCancel?: () => void,
// cssClass?: string,
// title?: string,
// displayMode: "popup" | "overlay" = "popup"
// ): PopupBaseViewModel {
// const options = createDialogOptions(
// componentName,
// data,
// onApply,
// onCancel,
// undefined,
// undefined,
// cssClass,
// title,
// displayMode
// );
// return showDialog(options);
// }
// export function showDialog(dialogOptions: IDialogOptions): PopupBaseViewModel {
// dialogOptions.onHide = () => {
// {
// popup.$destroy();
// popupViewModel.dispose();
// }
// };
// const popupViewModel: PopupBaseViewModel = createPopupModalViewModel(dialogOptions);
// const popup = new PopupContainer({
// el: popupViewModel.container.appendChild(document.createElement("div")),
// propsData: { model: popupViewModel },
// });
// popupViewModel.model.isVisible = true;
// return popupViewModel;
// }
// settings.showModal = showModal;
// Vue.component("sv-popup-container", PopupContainer);
</script>
20 changes: 20 additions & 0 deletions packages/survey-vue-ui/src/components/popup/PopupPointer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<span
class="sv-popup__pointer"
v-bind:style="{
left: model.pointerTarget.left,
top: model.pointerTarget.top,
}"
></span>
</template>
<script lang="ts">
import { PopupDropdownViewModel } from 'survey-core';
import { defineComponent } from 'vue';
export default defineComponent({
name: "popup-pointer",
props: {
model: PopupDropdownViewModel,
},
});
</script>
14 changes: 14 additions & 0 deletions packages/survey-vue-ui/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ import ActionBarItem from "./components/action-bar/ActionBarItem.vue";
import ActionBarItemDropdown from "./components/action-bar/ActionBarItemDropdown.vue";
import ActionBarSeparator from "./components/action-bar/ActionBarSeparator.vue";

import List from "./components/list/List.vue";
import ListItem from "./components/list/ListItem.vue";

import Popup from "./components/popup/Popup.vue";
import PopupContainer from "./components/popup/PopupContainer.vue";
import PopupPointer from "./components/popup/PopupPointer.vue";

import "./assets/main.css";
import "survey-core/defaultV2.css";

Expand Down Expand Up @@ -83,4 +90,11 @@ app.component("sv-action-bar-item", ActionBarItem);
app.component("sv-action-bar-item-dropdown", ActionBarItemDropdown);
app.component("sv-action-bar-separator", ActionBarSeparator);

app.component("sv-list", List);
app.component("sv-list-item", ListItem);

app.component("sv-popup", Popup);
app.component("sv-popup-container", PopupContainer);
app.component("popup-pointer", PopupPointer);

const mountedApp = app.mount("#app");

0 comments on commit 08f8ea8

Please sign in to comment.