UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

249 lines (248 loc) 7.46 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const core_scroller = require("./core_scroller.vue.cjs"); const scroller_item = require("./scroller_item.vue.cjs"); const common_utils = require("../../../common/utils.cjs"); const vue = require("vue"); const _pluginVue_exportHelper = require("../../../_virtual/_plugin-vue_export-helper.cjs"); const _sfc_main = { name: "DynamicScroller", components: { CoreScroller: core_scroller.default, DtScrollerItem: scroller_item.default }, provide() { if (typeof ResizeObserver !== "undefined") { this.$_resizeObserver = new ResizeObserver((entries) => { requestAnimationFrame(() => { if (!Array.isArray(entries)) { return; } for (const entry of entries) { if (entry.target && entry.target.$_vs_onResize) { let width, height; if (entry.borderBoxSize) { const resizeObserverSize = entry.borderBoxSize[0]; width = resizeObserverSize.inlineSize; height = resizeObserverSize.blockSize; } else { width = entry.contentRect.width; height = entry.contentRect.height; } entry.target.$_vs_onResize(entry.target.$_vs_id, width, height); } } }); }); } return { vscrollData: this.vscrollData, vscrollParent: this, vscrollResizeObserver: this.$_resizeObserver }; }, inheritAttrs: false, props: { /* * The items to render. * If the items are simple arrays, the index will be used as the key. * If the items are objects, the keyField will be used as the key. */ items: { type: Array, required: true }, /* * Indicates if the items are dynamic. * If true, the items will be wrapped in a DtScrollerItem component. * This is required for dynamic items to be able to react to changes in their size. */ dynamic: { type: Boolean, default: false }, /* * The key field to use for the items. * Only used if the items are objects. */ keyField: { type: String, default: "id" }, /* * The direction of the scroller. * Can be either 'vertical' or 'horizontal'. */ direction: { type: String, default: "vertical", validator: (value) => ["vertical", "horizontal"].includes(value) }, /* * The tag to use for the list. */ listTag: { type: String, default: "div" }, /* * The tag to use for the items. */ itemTag: { type: String, default: "div" }, /* * Display height (or width in horizontal mode) of the items in pixels * used to calculate the scroll size and position. * Is required for the initial render of items in DYNAMIC size mode. */ minItemSize: { type: [Number, String] } }, data() { return { vscrollData: { active: true, sizes: {}, keyField: this.keyField, simpleArray: false } }; }, computed: { simpleArray() { return this.items.length && typeof this.items[0] !== "object"; }, itemsWithSize() { const result = []; const { items, keyField, simpleArray } = this; const sizes = this.vscrollData.sizes; const l = items.length; for (let i = 0; i < l; i++) { const item = items[i]; const id = simpleArray ? i : item[keyField]; let size = sizes[id]; if (typeof size === "undefined" && !this.$_undefinedMap[id]) { size = 0; } result.push({ item, [keyField]: id, size }); } return result; } }, watch: { simpleArray: { handler(value) { this.vscrollData.simpleArray = value; }, immediate: true }, itemsWithSize(next, prev) { const scrollTop = common_utils.returnFirstEl(this.$el).scrollTop; let prevActiveTop = 0; let activeTop = 0; const length = Math.min(next.length, prev.length); for (let i = 0; i < length; i++) { if (prevActiveTop >= scrollTop) { break; } prevActiveTop += prev[i].size || this.minItemSize; activeTop += next[i].size || this.minItemSize; } const offset = activeTop - prevActiveTop; if (offset === 0) { return; } common_utils.returnFirstEl(this.$el).scrollTop += offset; } }, beforeCreate() { this.$_updates = []; this.$_undefinedSizes = 0; this.$_undefinedMap = {}; }, activated() { this.vscrollData.active = true; }, deactivated() { this.vscrollData.active = false; }, methods: { dynamicScrollerUpdateItems() { const scroller = this.$refs.scroller; if (scroller) scroller._updateVisibleItems(true); }, dynamicScrollerUpdateItemsFromBottom() { const scroller = this.$refs.scroller; if (scroller) scroller._updateVisibleItems(false, true); }, scrollToItem(index) { const scroller = this.$refs.scroller; if (scroller) scroller.scrollToItem(index); }, scrollToBottom() { if (this.$_scrollingToBottom) return; this.$_scrollingToBottom = true; const el = common_utils.returnFirstEl(this.$el); this.$nextTick(() => { el.scrollTop = el.scrollHeight + 5e3; const cb = () => { el.scrollTop = el.scrollHeight + 5e3; requestAnimationFrame(() => { el.scrollTop = el.scrollHeight + 5e3; if (this.$_undefinedSizes === 0) { this.$_scrollingToBottom = false; } else { requestAnimationFrame(cb); } }); }; requestAnimationFrame(cb); }); } } }; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_dt_scroller_item = vue.resolveComponent("dt-scroller-item"); const _component_core_scroller = vue.resolveComponent("core-scroller"); return vue.openBlock(), vue.createBlock(_component_core_scroller, vue.mergeProps({ ref: "scroller", items: $options.itemsWithSize, "min-item-size": $props.minItemSize, direction: $props.direction, "key-field": $props.keyField, "list-tag": $props.listTag, "item-tag": $props.itemTag }, _ctx.$attrs), { default: vue.withCtx(({ item: itemWithSize, index, active }) => [ vue.createVNode(_component_dt_scroller_item, { item: itemWithSize, active, "size-dependencies": [ itemWithSize.message ], "data-index": index }, { default: vue.withCtx(() => [ vue.renderSlot(_ctx.$slots, "default", vue.normalizeProps(vue.guardReactiveProps({ item: itemWithSize.item, index, active, itemWithSize }))) ]), _: 2 }, 1032, ["item", "active", "size-dependencies", "data-index"]) ]), _: 3 }, 16, ["items", "min-item-size", "direction", "key-field", "list-tag", "item-tag"]); } const DynamicScroller = /* @__PURE__ */ _pluginVue_exportHelper.default(_sfc_main, [["render", _sfc_render]]); exports.default = DynamicScroller; //# sourceMappingURL=dynamic_scroller.vue.cjs.map