Compare commits

..

1 Commits

Author SHA1 Message Date
Paulus Schoutsen
0ec7973e95 Exclude viz network from babel 2021-05-31 13:36:24 -07:00
108 changed files with 322 additions and 4842 deletions

View File

@@ -104,6 +104,5 @@
"lit/attribute-value-entities": 0
},
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
"processor": "disable/disable",
"ignorePatterns": ["src/resources/lit-virtualizer/*"]
"processor": "disable/disable"
}

21
.gitignore vendored
View File

@@ -1,17 +1,10 @@
.DS_Store
.reify-cache
# build
build
build-translations/*
hass_frontend/*
dist
# yarn
.yarn
yarn-error.log
node_modules/*
npm-debug.log
.DS_Store
hass_frontend/*
.reify-cache
# Python stuff
*.py[cod]
@@ -21,8 +14,11 @@ npm-debug.log
# venv stuff
pyvenv.cfg
pip-selfcheck.json
venv/*
venv
.venv
lib
bin
dist
# vscode
.vscode/*
@@ -35,8 +31,9 @@ src/cast/dev_const.ts
# Secrets
.lokalise_token
yarn-error.log
# asdf
#asdf
.tool-versions
# Home Assistant config

View File

@@ -83,6 +83,7 @@ module.exports.babelOptions = ({ latestBuild }) => ({
module.exports.babelExclude = () => [
require.resolve("@mdi/js/mdi.js"),
require.resolve("hls.js"),
require.resolve("vis-network/peer/esm/vis-network.js"),
];
const outputPath = (outputRoot, latestBuild) =>

View File

@@ -116,9 +116,8 @@ const createWebpackConfig = ({
// We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one
new webpack.NormalModuleReplacementPlugin(
new RegExp(
path.resolve(
paths.polymer_dir,
"src/resources/lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
require.resolve(
"@lit-labs/virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
)
),
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")

View File

@@ -28,11 +28,10 @@ const createConfigEntry = (
title,
source: "zeroconf",
state: "loaded",
connection_class: "local_push",
supports_options: false,
supports_unload: true,
disabled_by: null,
pref_disable_new_entities: false,
pref_disable_polling: false,
reason: null,
...override,
});
@@ -65,9 +64,6 @@ const configPanelEntry = createConfigEntry("Config Panel", {
const optionsFlowEntry = createConfigEntry("Options Flow", {
supports_options: true,
});
const disabledPollingEntry = createConfigEntry("Disabled Polling", {
pref_disable_polling: true,
});
const setupErrorEntry = createConfigEntry("Setup Error", {
state: "setup_error",
});
@@ -140,7 +136,6 @@ const configEntries: Array<{
{ items: [loadedEntry] },
{ items: [configPanelEntry] },
{ items: [optionsFlowEntry] },
{ items: [disabledPollingEntry] },
{ items: [nameAsDomainEntry] },
{ items: [longNameEntry] },
{ items: [longNonBreakingNameEntry] },

View File

@@ -44,9 +44,6 @@ const _computeFolders = (folders): CheckboxItem[] => {
if (folders.includes("share")) {
list.push({ slug: "share", name: "Share", checked: false });
}
if (folders.includes("media")) {
list.push({ slug: "media", name: "Media", checked: false });
}
if (folders.includes("addons/local")) {
list.push({ slug: "addons/local", name: "Local add-ons", checked: false });
}

View File

@@ -339,21 +339,6 @@ export class DialogHassioNetwork
>
</ha-radio>
</ha-formfield>
${version === "ipv6"
? html` <ha-formfield
.label=${this.supervisor.localize("dialog.network.link-local")}
class="warning"
>
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
value="link-local"
name="${version}method"
.checked=${this._interface![version]?.method === "link-local"}
>
</ha-radio>
</ha-formfield>`
: ""}
</div>
${this._interface![version].method === "static"
? html`
@@ -573,7 +558,7 @@ export class DialogHassioNetwork
@media all and (min-width: 451px) and (min-height: 501px) {
.container {
width: 500px;
width: 400px;
}
}

View File

@@ -108,7 +108,7 @@
"fecha": "^4.2.0",
"fuse.js": "^6.0.0",
"google-timezones-json": "^1.0.2",
"hls.js": "^1.0.5",
"hls.js": "^1.0.4",
"home-assistant-js-websocket": "^5.10.0",
"idb-keyval": "^5.0.5",
"intl-messageformat": "^9.6.16",

View File

@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20210601.1",
version="20210531.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",

View File

@@ -89,6 +89,8 @@ export const domainIcon = (
}
// eslint-disable-next-line
console.warn(`Unable to find icon for domain ${domain}`);
console.warn(
"Unable to find icon for domain " + domain + " (" + stateObj + ")"
);
return DEFAULT_DOMAIN_ICON;
};

View File

@@ -1,16 +1,9 @@
import "@material/mwc-icon-button/mwc-icon-button";
import { mdiClose, mdiMagnify } from "@mdi/js";
import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, query } from "lit/decorators";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import "../../components/ha-svg-icon";
import { fireEvent } from "../dom/fire_event";
@@ -34,11 +27,18 @@ class SearchInput extends LitElement {
this.shadowRoot!.querySelector("paper-input")!.focus();
}
@query("paper-input", true) private _input!: PaperInputElement;
protected render(): TemplateResult {
return html`
<style>
.no-underline:not(.focused) {
--paper-input-container-underline: {
display: none;
height: 0;
}
}
</style>
<paper-input
class=${classMap({ "no-underline": this.noUnderline })}
.autofocus=${this.autofocus}
.label=${this.label || "Search"}
.value=${this.filter}
@@ -62,17 +62,6 @@ class SearchInput extends LitElement {
`;
}
protected updated(changedProps: PropertyValues) {
if (
changedProps.has("noUnderline") &&
(this.noUnderline || changedProps.get("noUnderline") !== undefined)
) {
(this._input.inputElement!.parentElement!.shadowRoot!.querySelector(
"div.unfocused-line"
) as HTMLElement).style.display = this.noUnderline ? "none" : "block";
}
}
private async _filterChanged(value: string) {
fireEvent(this, "value-changed", { value: String(value) });
}

View File

@@ -4,25 +4,29 @@
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
export const debounce = <T extends any[]>(
func: (...args: T) => void,
wait: number,
// eslint-disable-next-line: ban-types
export const debounce = <T extends (...args) => unknown>(
func: T,
wait,
immediate = false
) => {
let timeout: number | undefined;
return (...args: T): void => {
): T => {
let timeout;
// @ts-ignore
return function (...args) {
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-this-alias
const context = this;
const later = () => {
timeout = undefined;
timeout = null;
if (!immediate) {
func(...args);
func.apply(context, args);
}
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = window.setTimeout(later, wait);
timeout = setTimeout(later, wait);
if (callNow) {
func(...args);
func.apply(context, args);
}
};
};

View File

@@ -1,4 +1,4 @@
import { Layout1d, scroll } from "../../resources/lit-virtualizer";
import { Layout1d, scroll } from "@lit-labs/virtualizer";
import deepClone from "deep-clone-simple";
import {
css,
@@ -246,7 +246,7 @@ export class HaDataTable extends LitElement {
aria-rowcount=${this._filteredData.length + 1}
style=${styleMap({
height: this.autoHeight
? `${(this._filteredData.length || 1) * 53 + 53}px`
? `${(this._filteredData.length || 1) * 53 + 57}px`
: `calc(100% - ${this._headerHeight}px)`,
})}
>
@@ -340,10 +340,11 @@ export class HaDataTable extends LitElement {
${scroll({
items: this._items,
layout: Layout1d,
// @ts-expect-error
renderItem: (row: DataTableRowData, index) => {
// not sure how this happens...
if (!row) {
return html``;
return "";
}
if (row.append) {
return html`
@@ -919,11 +920,13 @@ export class HaDataTable extends LitElement {
color: var(--secondary-text-color);
}
.scroller {
display: flex;
position: relative;
contain: strict;
height: calc(100% - 57px);
}
.mdc-data-table__table.auto-height .scroller {
overflow-y: hidden !important;
.mdc-data-table__table:not(.auto-height) .scroller {
overflow: auto;
}
.grows {
flex-grow: 1;

View File

@@ -13,11 +13,6 @@ import { nextRender } from "../common/util/render-status";
import { getExternalConfig } from "../external_app/external_config";
import type { HomeAssistant } from "../types";
type HlsLite = Omit<
HlsType,
"subtitleTrackController" | "audioTrackController" | "emeController"
>;
@customElement("ha-hls-player")
class HaHLSPlayer extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -44,7 +39,7 @@ class HaHLSPlayer extends LitElement {
@state() private _attached = false;
private _hlsPolyfillInstance?: HlsLite;
private _hlsPolyfillInstance?: HlsType;
private _useExoPlayer = false;
@@ -108,8 +103,7 @@ class HaHLSPlayer extends LitElement {
const useExoPlayerPromise = this._getUseExoPlayer();
const masterPlaylistPromise = fetch(this.url);
const Hls: typeof HlsType = (await import("hls.js/dist/hls.light.min.js"))
.default;
const Hls = (await import("hls.js")).default;
let hlsSupported = Hls.isSupported();
if (!hlsSupported) {
@@ -188,7 +182,7 @@ class HaHLSPlayer extends LitElement {
url: string
) {
const hls = new Hls({
backBufferLength: 60,
liveBackBufferLength: 60,
fragLoadingTimeOut: 30000,
manifestLoadingTimeOut: 30000,
levelLoadingTimeOut: 30000,

View File

@@ -1,12 +1,5 @@
import "@polymer/paper-tooltip/paper-tooltip";
import {
css,
CSSResultGroup,
html,
nothing,
LitElement,
TemplateResult,
} from "lit";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, state, property } from "lit/decorators";
import {
Adapter,
@@ -24,19 +17,18 @@ import "./ha-icon";
const format_addresses = (
addresses: IPv6ConfiguredAddress[] | IPv4ConfiguredAddress[]
): TemplateResult =>
html`${addresses.map((address, i) => [
html`<span>${address.address}/${address.network_prefix}</span>`,
i < addresses.length - 1 ? ", " : nothing,
])}`;
): TemplateResult[] =>
addresses.map(
(address) => html`<span>${address.address}/${address.network_prefix}</span>`
);
const format_auto_detected_interfaces = (
adapters: Adapter[]
): Array<TemplateResult | string> =>
adapters.map((adapter) =>
adapter.auto
? html`${adapter.name}
(${format_addresses([...adapter.ipv4, ...adapter.ipv6])})`
? html`${adapter.name} (${format_addresses(adapter.ipv4)}
${format_addresses(adapter.ipv6)} )`
: ""
);
@@ -96,7 +88,8 @@ export class HaNetwork extends LitElement {
: ""}
</span>
<span slot="description">
${format_addresses([...adapter.ipv4, ...adapter.ipv6])}
${format_addresses(adapter.ipv4)}
${format_addresses(adapter.ipv6)}
</span>
</ha-settings-row>`
)

View File

@@ -377,10 +377,7 @@ class StateHistoryChartLine extends LocalizeMixin(PolymerElement) {
major: {
fontStyle: "bold",
},
source: "auto",
sampleSize: 5,
autoSkipPadding: 20,
maxRotation: 0,
},
},
],

View File

@@ -236,9 +236,7 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) {
major: {
fontStyle: "bold",
},
sampleSize: 5,
autoSkipPadding: 50,
maxRotation: 0,
},
categoryPercentage: undefined,
barPercentage: undefined,

View File

@@ -12,20 +12,20 @@ export interface ConfigEntry {
| "setup_retry"
| "not_loaded"
| "failed_unload";
connection_class: string;
supports_options: boolean;
supports_unload: boolean;
pref_disable_new_entities: boolean;
pref_disable_polling: boolean;
disabled_by: "user" | null;
reason: string | null;
}
export type ConfigEntryMutableParams = Partial<
Pick<
ConfigEntry,
"title" | "pref_disable_new_entities" | "pref_disable_polling"
>
>;
export interface ConfigEntryMutableParams {
title: string;
}
export interface ConfigEntrySystemOptions {
disable_new_entities: boolean;
}
export const getConfigEntries = (hass: HomeAssistant) =>
hass.callApi<ConfigEntry[]>("GET", "config/config_entries/entry");
@@ -33,9 +33,9 @@ export const getConfigEntries = (hass: HomeAssistant) =>
export const updateConfigEntry = (
hass: HomeAssistant,
configEntryId: string,
updatedValues: ConfigEntryMutableParams
updatedValues: Partial<ConfigEntryMutableParams>
) =>
hass.callWS<{ require_restart: boolean; config_entry: ConfigEntry }>({
hass.callWS<ConfigEntry>({
type: "config_entries/update",
entry_id: configEntryId,
...updatedValues,
@@ -51,15 +51,13 @@ export const reloadConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
require_restart: boolean;
}>("POST", `config/config_entries/entry/${configEntryId}/reload`);
export interface DisableConfigEntryResult {
require_restart: boolean;
}
export const disableConfigEntry = (
hass: HomeAssistant,
configEntryId: string
) =>
hass.callWS<DisableConfigEntryResult>({
hass.callWS<{
require_restart: boolean;
}>({
type: "config_entries/disable",
entry_id: configEntryId,
disabled_by: "user",
@@ -73,3 +71,23 @@ export const enableConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
entry_id: configEntryId,
disabled_by: null,
});
export const getConfigEntrySystemOptions = (
hass: HomeAssistant,
configEntryId: string
) =>
hass.callWS<ConfigEntrySystemOptions>({
type: "config_entries/system_options/list",
entry_id: configEntryId,
});
export const updateConfigEntrySystemOptions = (
hass: HomeAssistant,
configEntryId: string,
params: Partial<ConfigEntrySystemOptions>
) =>
hass.callWS({
type: "config_entries/system_options/update",
entry_id: configEntryId,
...params,
});

View File

@@ -5,7 +5,7 @@ import { hassioApiResultExtractor, HassioResponse } from "./common";
interface IpConfiguration {
address: string[];
gateway: string;
method: "disabled" | "static" | "auto" | "link-local";
method: "disabled" | "static" | "auto";
nameservers: string[];
}

View File

@@ -3,17 +3,17 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { computeRTLDirection } from "../../common/util/compute_rtl";
import "../../components/ha-circular-progress";
import "../../components/ha-dialog";
import "../../components/ha-formfield";
import "../../components/ha-switch";
import type { HaSwitch } from "../../components/ha-switch";
import {
ConfigEntryMutableParams,
updateConfigEntry,
getConfigEntrySystemOptions,
updateConfigEntrySystemOptions,
} from "../../data/config_entries";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { showAlertDialog } from "../generic/show-dialog-box";
import { ConfigEntrySystemOptionsDialogParams } from "./show-dialog-config-entry-system-options";
@customElement("dialog-config-entry-system-options")
@@ -22,12 +22,12 @@ class DialogConfigEntrySystemOptions extends LitElement {
@state() private _disableNewEntities!: boolean;
@state() private _disablePolling!: boolean;
@state() private _error?: string;
@state() private _params?: ConfigEntrySystemOptionsDialogParams;
@state() private _loading = false;
@state() private _submitting = false;
public async showDialog(
@@ -35,8 +35,13 @@ class DialogConfigEntrySystemOptions extends LitElement {
): Promise<void> {
this._params = params;
this._error = undefined;
this._disableNewEntities = params.entry.pref_disable_new_entities;
this._disablePolling = params.entry.pref_disable_polling;
this._loading = true;
const systemOptions = await getConfigEntrySystemOptions(
this.hass,
params.entry.entry_id
);
this._loading = false;
this._disableNewEntities = systemOptions.disable_new_entities;
}
public closeDialog(): void {
@@ -61,57 +66,45 @@ class DialogConfigEntrySystemOptions extends LitElement {
this._params.entry.domain
)}
>
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
<ha-formfield
.label=${html`<p>
${this.hass.localize(
"ui.dialogs.config_entry_system_options.enable_new_entities_label"
)}
</p>
<p class="secondary">
${this.hass.localize(
"ui.dialogs.config_entry_system_options.enable_new_entities_description",
"integration",
this.hass.localize(
`component.${this._params.entry.domain}.title`
) || this._params.entry.domain
)}
</p>`}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.checked=${!this._disableNewEntities}
@change=${this._disableNewEntitiesChanged}
.disabled=${this._submitting}
></ha-switch>
</ha-formfield>
${this._allowUpdatePolling()
? html`
<ha-formfield
.label=${html`<p>
${this.hass.localize(
"ui.dialogs.config_entry_system_options.enable_polling_label"
)}
</p>
<p class="secondary">
${this.hass.localize(
"ui.dialogs.config_entry_system_options.enable_polling_description",
"integration",
this.hass.localize(
`component.${this._params.entry.domain}.title`
) || this._params.entry.domain
)}
</p>`}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.checked=${!this._disablePolling}
@change=${this._disablePollingChanged}
.disabled=${this._submitting}
></ha-switch>
</ha-formfield>
`
: ""}
<div>
${this._loading
? html`
<div class="init-spinner">
<ha-circular-progress active></ha-circular-progress>
</div>
`
: html`
${this._error
? html` <div class="error">${this._error}</div> `
: ""}
<div class="form">
<ha-formfield
.label=${html`<p>
${this.hass.localize(
"ui.dialogs.config_entry_system_options.enable_new_entities_label"
)}
</p>
<p class="secondary">
${this.hass.localize(
"ui.dialogs.config_entry_system_options.enable_new_entities_description",
"integration",
this.hass.localize(
`component.${this._params.entry.domain}.title`
) || this._params.entry.domain
)}
</p>`}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.checked=${!this._disableNewEntities}
@change=${this._disableNewEntitiesChanged}
.disabled=${this._submitting}
>
</ha-switch>
</ha-formfield>
</div>
`}
</div>
<mwc-button
slot="secondaryAction"
@click=${this.closeDialog}
@@ -122,7 +115,7 @@ class DialogConfigEntrySystemOptions extends LitElement {
<mwc-button
slot="primaryAction"
@click="${this._updateEntry}"
.disabled=${this._submitting}
.disabled=${this._submitting || this._loading}
>
${this.hass.localize("ui.dialogs.config_entry_system_options.update")}
</mwc-button>
@@ -130,47 +123,22 @@ class DialogConfigEntrySystemOptions extends LitElement {
`;
}
private _allowUpdatePolling() {
return (
this._params!.manifest &&
(this._params!.manifest.iot_class === "local_polling" ||
this._params!.manifest.iot_class === "cloud_polling")
);
}
private _disableNewEntitiesChanged(ev: Event): void {
this._error = undefined;
this._disableNewEntities = !(ev.target as HaSwitch).checked;
}
private _disablePollingChanged(ev: Event): void {
this._error = undefined;
this._disablePolling = !(ev.target as HaSwitch).checked;
}
private async _updateEntry(): Promise<void> {
this._submitting = true;
const data: ConfigEntryMutableParams = {
pref_disable_new_entities: this._disableNewEntities,
};
if (this._allowUpdatePolling()) {
data.pref_disable_polling = this._disablePolling;
}
try {
const result = await updateConfigEntry(
await updateConfigEntrySystemOptions(
this.hass,
this._params!.entry.entry_id,
data
{
disable_new_entities: this._disableNewEntities,
}
);
if (result.require_restart) {
await showAlertDialog(this, {
text: this.hass.localize(
"ui.dialogs.config_entry_system_options.restart_home_assistant"
),
});
}
this._params!.entryUpdated(result.config_entry);
this.closeDialog();
this._params = undefined;
} catch (err) {
this._error = err.message || "Unknown error";
} finally {
@@ -182,6 +150,20 @@ class DialogConfigEntrySystemOptions extends LitElement {
return [
haStyleDialog,
css`
.init-spinner {
padding: 50px 100px;
text-align: center;
}
.form {
padding-top: 6px;
padding-bottom: 24px;
color: var(--primary-text-color);
}
.secondary {
color: var(--secondary-text-color);
}
.error {
color: var(--error-color);
}

View File

@@ -1,11 +1,12 @@
import { fireEvent } from "../../common/dom/fire_event";
import { ConfigEntry } from "../../data/config_entries";
import { IntegrationManifest } from "../../data/integration";
export interface ConfigEntrySystemOptionsDialogParams {
entry: ConfigEntry;
manifest?: IntegrationManifest;
entryUpdated(entry: ConfigEntry): void;
// updateEntry: (
// updates: Partial<EntityRegistryEntryUpdateParams>
// ) => Promise<unknown>;
// removeEntry: () => Promise<boolean>;
}
export const loadConfigEntrySystemOptionsDialog = () =>

View File

@@ -50,9 +50,6 @@ class HaStoreAuth extends LitElement {
bottom: 16px;
right: 16px;
transition: bottom 0.25s;
--ha-card-box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
0px 6px 10px 0px rgba(0, 0, 0, 0.14),
0px 1px 18px 0px rgba(0, 0, 0, 0.12);
}
.card-actions {

View File

@@ -108,7 +108,7 @@ class MoreInfoWeather extends LitElement {
this.stateObj.attributes.pressure,
this.hass.locale
)}
${getWeatherUnit(this.hass, "pressure")}
${getWeatherUnit(this.hass, "air_pressure")}
</div>
</div>
`

View File

@@ -1,4 +1,4 @@
import { Layout1d, scroll } from "../../resources/lit-virtualizer";
import { Layout1d, scroll } from "@lit-labs/virtualizer";
import "@material/mwc-list/mwc-list";
import type { List } from "@material/mwc-list/mwc-list";
import { SingleSelectedEvent } from "@material/mwc-list/mwc-list-foundation";
@@ -188,6 +188,7 @@ export class QuickBar extends LitElement {
${scroll({
items,
layout: Layout1d,
// @ts-expect-error
renderItem: (item: QuickBarItem, index) =>
this._renderItem(item, index),
})}
@@ -223,7 +224,7 @@ export class QuickBar extends LitElement {
private _renderItem(item: QuickBarItem, index?: number) {
if (!item) {
return html``;
return undefined;
}
return isCommandItem(item)
? this._renderCommandItem(item, index)
@@ -638,6 +639,18 @@ export class QuickBar extends LitElement {
margin-left: 8px;
}
.uni-virtualizer-host {
display: block;
position: relative;
contain: strict;
overflow: auto;
height: 100%;
}
.uni-virtualizer-host > * {
box-sizing: border-box;
}
mwc-list-item {
width: 100%;
}

View File

@@ -229,7 +229,7 @@ class HassTabsSubpage extends LitElement {
color: var(--sidebar-text-color);
text-decoration: none;
}
.bottom-bar a {
:host([narrow]) .toolbar a {
width: 25%;
}

View File

@@ -9,14 +9,13 @@ import {
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import "../../../components/ha-network";
import "../../../components/ha-card";
import "../../../components/ha-checkbox";
import "../../../components/ha-network";
import "../../../components/ha-settings-row";
import { fetchNetworkInfo } from "../../../data/hassio/network";
import {
getNetworkConfig,
NetworkConfig,
getNetworkConfig,
setNetworkConfig,
} from "../../../data/network";
import { haStyle } from "../../../resources/styles";
@@ -74,19 +73,7 @@ class ConfigNetwork extends LitElement {
private async _load() {
this._error = undefined;
try {
const coreNetwork = await getNetworkConfig(this.hass);
if (isComponentLoaded(this.hass, "hassio")) {
const supervisorNetwork = await fetchNetworkInfo(this.hass);
const interfaces = new Set(
supervisorNetwork.interfaces.map((int) => int.interface)
);
if (interfaces.size) {
coreNetwork.adapters = coreNetwork.adapters.filter((adapter) =>
interfaces.has(adapter.name)
);
}
}
this._networkConfig = coreNetwork;
this._networkConfig = await getNetworkConfig(this.hass);
} catch (err) {
this._error = err.message || err;
}

View File

@@ -11,11 +11,7 @@ import { slugify } from "../../../common/string/slugify";
import "../../../components/entity/ha-battery-icon";
import "../../../components/ha-icon-next";
import { AreaRegistryEntry } from "../../../data/area_registry";
import {
ConfigEntry,
disableConfigEntry,
DisableConfigEntryResult,
} from "../../../data/config_entries";
import { ConfigEntry, disableConfigEntry } from "../../../data/config_entries";
import {
computeDeviceName,
DeviceRegistryEntry,
@@ -29,10 +25,7 @@ import {
} from "../../../data/entity_registry";
import { SceneEntities, showSceneEditor } from "../../../data/scene";
import { findRelated, RelatedResult } from "../../../data/search";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-error-screen";
import "../../../layouts/hass-tabs-subpage";
import { haStyle } from "../../../resources/styles";
@@ -678,41 +671,13 @@ export class HaConfigDevicePage extends LitElement {
dismissText: this.hass.localize("ui.common.no"),
}))
) {
let result: DisableConfigEntryResult;
try {
// eslint-disable-next-line no-await-in-loop
result = await disableConfigEntry(this.hass, cnfg_entry);
} catch (err) {
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_entry.disable_error"
),
text: err.message,
});
return;
}
if (result.require_restart) {
showAlertDialog(this, {
text: this.hass.localize(
"ui.panel.config.integrations.config_entry.disable_restart_confirm"
),
});
}
disableConfigEntry(this.hass, cnfg_entry);
delete updates.disabled_by;
}
}
}
}
try {
await updateDeviceRegistryEntry(this.hass, this.deviceId, updates);
} catch (err) {
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.devices.update_device_error"
),
text: err.message,
});
}
await updateDeviceRegistryEntry(this.hass, this.deviceId, updates);
if (
!oldDeviceName ||

View File

@@ -18,7 +18,6 @@ import {
ConfigEntry,
deleteConfigEntry,
disableConfigEntry,
DisableConfigEntryResult,
enableConfigEntry,
reloadConfigEntry,
updateConfigEntry,
@@ -111,7 +110,6 @@ export class HaIntegrationCard extends LitElement {
: undefined}
.localizedDomainName=${item ? item.localized_domain_name : undefined}
.manifest=${this.manifest}
.configEntry=${item}
>
${this.items.length > 1
? html`
@@ -468,11 +466,6 @@ export class HaIntegrationCard extends LitElement {
private _showSystemOptions(configEntry: ConfigEntry) {
showConfigEntrySystemOptionsDialog(this, {
entry: configEntry,
manifest: this.manifest,
entryUpdated: (entry) =>
fireEvent(this, "entry-updated", {
entry,
}),
});
}
@@ -488,18 +481,7 @@ export class HaIntegrationCard extends LitElement {
if (!confirmed) {
return;
}
let result: DisableConfigEntryResult;
try {
result = await disableConfigEntry(this.hass, entryId);
} catch (err) {
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_entry.disable_error"
),
text: err.message,
});
return;
}
const result = await disableConfigEntry(this.hass, entryId);
if (result.require_restart) {
showAlertDialog(this, {
text: this.hass.localize(
@@ -515,18 +497,7 @@ export class HaIntegrationCard extends LitElement {
private async _enableIntegration(configEntry: ConfigEntry) {
const entryId = configEntry.entry_id;
let result: DisableConfigEntryResult;
try {
result = await enableConfigEntry(this.hass, entryId);
} catch (err) {
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_entry.disable_error"
),
text: err.message,
});
return;
}
const result = await enableConfigEntry(this.hass, entryId);
if (result.require_restart) {
showAlertDialog(this, {
@@ -590,10 +561,10 @@ export class HaIntegrationCard extends LitElement {
if (newName === null) {
return;
}
const result = await updateConfigEntry(this.hass, configEntry.entry_id, {
const newEntry = await updateConfigEntry(this.hass, configEntry.entry_id, {
title: newName,
});
fireEvent(this, "entry-updated", { entry: result.config_entry });
fireEvent(this, "entry-updated", { entry: newEntry });
}
static get styles(): CSSResultGroup {

View File

@@ -1,9 +1,8 @@
import { mdiCloud, mdiPackageVariant, mdiSyncOff } from "@mdi/js";
import { mdiCloud, mdiPackageVariant } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-svg-icon";
import { ConfigEntry } from "../../../data/config_entries";
import { domainToName, IntegrationManifest } from "../../../data/integration";
import { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
@@ -22,8 +21,6 @@ export class HaIntegrationHeader extends LitElement {
@property({ attribute: false }) public manifest?: IntegrationManifest;
@property({ attribute: false }) public configEntry?: ConfigEntry;
protected render(): TemplateResult {
let primary: string;
let secondary: string | undefined;
@@ -62,15 +59,6 @@ export class HaIntegrationHeader extends LitElement {
),
]);
}
if (this.configEntry?.pref_disable_polling) {
icons.push([
mdiSyncOff,
this.hass.localize(
"ui.panel.config.integrations.config_entry.disabled_polling"
),
]);
}
}
return html`

View File

@@ -9,12 +9,7 @@ import {
} from "../../../../../data/zha";
import "../../../../../layouts/hass-tabs-subpage";
import type { HomeAssistant, Route } from "../../../../../types";
import {
Network,
Edge,
Node,
EdgeOptions,
} from "vis-network/peer/esm/vis-network";
import { Network, Edge, Node, EdgeOptions } from "vis-network/peer";
import "../../../../../common/search/search-input";
import "../../../../../components/device/ha-device-picker";
import "../../../../../components/ha-button-menu";
@@ -26,7 +21,6 @@ import "../../../../../components/ha-checkbox";
import type { HaCheckbox } from "../../../../../components/ha-checkbox";
import { zhaTabs } from "./zha-config-dashboard";
import { customElement, property, query, state } from "lit/decorators";
import "../../../../../components/ha-formfield";
@customElement("zha-network-visualization-page")
export class ZHANetworkVisualizationPage extends LitElement {
@@ -34,7 +28,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public isWide!: boolean;
@@ -73,6 +67,8 @@ export class ZHANetworkVisualizationPage extends LitElement {
{},
{
autoResize: true,
height: window.innerHeight + "px",
width: window.innerWidth + "px",
layout: {
improvedLayout: true,
},
@@ -139,35 +135,17 @@ export class ZHANetworkVisualizationPage extends LitElement {
"ui.panel.config.zha.visualization.header"
)}
>
${this.narrow
? html`
<div slot="header">
<search-input
no-label-float
no-underline
class="header"
@value-changed=${this._handleSearchChange}
.filter=${this._filter}
.label=${this.hass.localize(
"ui.panel.config.zha.visualization.highlight_label"
)}
>
</search-input>
</div>
`
: ""}
<div class="header">
${!this.narrow
? html`<search-input
no-label-float
no-underline
@value-changed=${this._handleSearchChange}
.filter=${this._filter}
.label=${this.hass.localize(
"ui.panel.config.zha.visualization.highlight_label"
)}
></search-input>`
: ""}
<div class="table-header">
<search-input
no-label-float
no-underline
@value-changed=${this._handleSearchChange}
.filter=${this._filter}
.label=${this.hass.localize(
"ui.panel.config.zha.visualization.highlight_label"
)}
>
</search-input>
<ha-device-picker
.hass=${this.hass}
.value=${this.zoomedDeviceId}
@@ -177,24 +155,16 @@ export class ZHANetworkVisualizationPage extends LitElement {
.deviceFilter=${(device) => this._filterDevices(device)}
@value-changed=${this._onZoomToDevice}
></ha-device-picker>
<div class="controls">
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.zha.visualization.auto_zoom"
)}
>
<ha-checkbox
@change=${this._handleCheckboxChange}
.checked=${this._autoZoom}
>
</ha-checkbox>
</ha-formfield>
<mwc-button @click=${this._refreshTopology}>
${this.hass!.localize(
"ui.panel.config.zha.visualization.refresh_topology"
)}
</mwc-button>
</div>
<ha-checkbox
@change=${this._handleCheckboxChange}
.checked=${this._autoZoom}
></ha-checkbox
>${this.hass!.localize("ui.panel.config.zha.visualization.auto_zoom")}
<mwc-button @click=${this._refreshTopology}
>${this.hass!.localize(
"ui.panel.config.zha.visualization.refresh_topology"
)}</mwc-button
>
</div>
<div id="visualization"></div>
</hass-tabs-subpage>
@@ -382,23 +352,30 @@ export class ZHANetworkVisualizationPage extends LitElement {
return [
css`
.header {
border-bottom: 1px solid var(--divider-color);
padding: 0 8px;
font-family: var(--paper-font-display1_-_font-family);
-webkit-font-smoothing: var(
--paper-font-display1_-_-webkit-font-smoothing
);
font-size: var(--paper-font-display1_-_font-size);
font-weight: var(--paper-font-display1_-_font-weight);
letter-spacing: var(--paper-font-display1_-_letter-spacing);
line-height: var(--paper-font-display1_-_line-height);
opacity: var(--dark-primary-opacity);
}
.table-header {
border-bottom: 1px solid --divider-color;
padding: 0 16px;
display: flex;
align-items: center;
justify-content: space-between;
flex-direction: row;
height: var(--header-height);
box-sizing: border-box;
}
.header > * {
padding: 0 8px;
}
:host([narrow]) .header {
:host([narrow]) .table-header {
flex-direction: column;
align-items: stretch;
height: var(--header-height) * 2;
height: var(--header-height) * 3;
}
.search-toolbar {
@@ -409,34 +386,34 @@ export class ZHANetworkVisualizationPage extends LitElement {
}
search-input {
position: relative;
top: 2px;
flex: 1;
}
:host(:not([narrow])) search-input {
margin: 5px;
}
search-input.header {
display: block;
position: relative;
top: -2px;
color: var(--secondary-text-color);
left: -8px;
}
ha-device-picker {
flex: 1;
position: relative;
top: -4px;
}
.controls {
display: flex;
align-items: center;
justify-content: space-between;
:host(:not([narrow])) ha-device-picker {
margin: 5px;
}
#visualization {
height: calc(100% - var(--header-height));
width: 100%;
mwc-button {
font-weight: 500;
color: var(--primary-color);
}
:host([narrow]) #visualization {
height: calc(100% - (var(--header-height) * 2));
:host(:not([narrow])) mwc-button {
margin: 5px;
}
`,
];

View File

@@ -1,4 +1,4 @@
import { Layout1d, scroll } from "../../resources/lit-virtualizer";
import { Layout1d, scroll } from "@lit-labs/virtualizer";
import {
css,
CSSResultGroup,
@@ -100,6 +100,7 @@ class HaLogbook extends LitElement {
? scroll({
items: this.entries,
layout: Layout1d,
// @ts-expect-error
renderItem: (item: LogbookEntry, index) =>
this._renderLogbookItem(item, index),
})
@@ -353,7 +354,15 @@ class HaLogbook extends LitElement {
}
:host([virtualize]) .container {
display: block;
position: relative;
contain: strict;
height: 100%;
overflow: auto;
}
.container > * {
box-sizing: border-box;
}
.narrow .entry {

View File

@@ -1,106 +0,0 @@
import "@material/mwc-button";
import "@polymer/paper-input/paper-input";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { createCloseHeading } from "../../components/ha-dialog";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { LongLivedAccessTokenDialogParams } from "./show-long-lived-access-token-dialog";
const QR_LOGO_URL = "/static/icons/favicon-192x192.png";
@customElement("ha-long-lived-access-token-dialog")
export class HaLongLivedAccessTokenDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _params?: LongLivedAccessTokenDialogParams;
@state() private _qrCode?: TemplateResult;
public showDialog(params: LongLivedAccessTokenDialogParams): void {
this._params = params;
}
public closeDialog() {
this._params = undefined;
this._qrCode = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult {
if (!this._params || !this._params.token) {
return html``;
}
return html`
<ha-dialog
open
hideActions
.heading=${createCloseHeading(this.hass, this._params.name)}
@closed=${this.closeDialog}
>
<div>
<paper-input
dialogInitialFocus
.value=${this._params.token}
.label=${this.hass.localize(
"ui.panel.profile.long_lived_access_tokens.prompt_copy_token"
)}
type="text"
></paper-input>
<div id="qr">
${this._qrCode
? this._qrCode
: html`
<mwc-button @click=${this._generateQR}>
Generate QR code
</mwc-button>
`}
</div>
</div>
</ha-dialog>
`;
}
private async _generateQR() {
const qrcode = await import("qrcode");
const canvas = await qrcode.toCanvas(this._params?.token, {
width: 180,
errorCorrectionLevel: "Q",
});
const context = canvas.getContext("2d");
const imageObj = new Image();
imageObj.src = QR_LOGO_URL;
await new Promise((resolve) => {
imageObj.onload = resolve;
});
context.drawImage(
imageObj,
canvas.width / 3,
canvas.height / 3,
canvas.width / 3,
canvas.height / 3
);
this._qrCode = html`<img src=${canvas.toDataURL()}></img>`;
}
static get styles(): CSSResultGroup {
return [
haStyleDialog,
css`
#qr {
text-align: center;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-long-lived-access-token-dialog": HaLongLivedAccessTokenDialog;
}
}

View File

@@ -18,7 +18,6 @@ import {
import { haStyle } from "../../resources/styles";
import "../../styles/polymer-ha-style";
import { HomeAssistant } from "../../types";
import { showLongLivedAccessTokenDialog } from "./show-long-lived-access-token-dialog";
@customElement("ha-long-lived-access-tokens-card")
class HaLongLivedTokens extends LitElement {
@@ -119,7 +118,13 @@ class HaLongLivedTokens extends LitElement {
client_name: name,
});
showLongLivedAccessTokenDialog(this, { token, name });
showPromptDialog(this, {
title: name,
text: this.hass.localize(
"ui.panel.profile.long_lived_access_tokens.prompt_copy_token"
),
defaultValue: token,
});
fireEvent(this, "hass-refresh-tokens");
} catch (err) {

View File

@@ -1,17 +0,0 @@
import { fireEvent } from "../../common/dom/fire_event";
export interface LongLivedAccessTokenDialogParams {
token: string;
name: string;
}
export const showLongLivedAccessTokenDialog = (
element: HTMLElement,
longLivedAccessTokenDialogParams: LongLivedAccessTokenDialogParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "ha-long-lived-access-token-dialog",
dialogImport: () => import("./ha-long-lived-access-token-dialog"),
dialogParams: longLivedAccessTokenDialogParams,
});
};

View File

@@ -1,39 +0,0 @@
import { LitElement, TemplateResult } from "lit";
import {
LayoutSpecifier,
Layout,
LayoutConstructor,
} from "./uni-virtualizer/lib/layouts/Layout.js";
/**
* A LitElement wrapper of the scroll directive.
*
* Import this module to declare the lit-virtualizer custom element.
* Pass an items array, renderItem method, and scroll target as properties
* to the <lit-virtualizer> element.
*/
export declare class LitVirtualizer extends LitElement {
renderItem?: (item: any, index?: number) => TemplateResult;
items: Array<unknown>;
scrollTarget: Element | Window;
keyFunction: ((item: unknown) => unknown) | undefined;
private _layout;
private _scrollToIndex;
createRenderRoot(): this;
/**
* The method used for rendering each item.
*/
set layout(layout: Layout | LayoutConstructor | LayoutSpecifier | null);
get layout(): Layout | LayoutConstructor | LayoutSpecifier | null;
/**
* Scroll to the specified index, placing that item at the given position
* in the scroll view.
*/
scrollToIndex(index: number, position?: string): Promise<void>;
render(): TemplateResult;
}
declare global {
interface HTMLElementTagNameMap {
"lit-virtualizer": LitVirtualizer;
}
}
//# sourceMappingURL=lit-virtualizer.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"lit-virtualizer.d.ts","sourceRoot":"","sources":["../src/lib/lit-virtualizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAKvD,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAErG;;;;;;GAMG;AACH,qBACa,cAAe,SAAQ,UAAU;IAE1C,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC;IAG7D,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAM;IAG3B,YAAY,EAAE,OAAO,GAAG,MAAM,CAAQ;IAGtC,WAAW,EAAE,CAAC,CAAC,IAAI,EAAC,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS,CAAa;IAEjE,OAAO,CAAC,OAAO,CAA6D;IAE5E,OAAO,CAAC,cAAc,CAAkD;IAExE,gBAAgB;IAahB;;OAEG;IAWH,IACI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,EAIrE;IAED,IAAI,MAAM,IAAI,MAAM,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,CAEhE;IAGD;;;OAGG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAgB;IAO7D,MAAM,IAAI,cAAc;CAO3B;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,iBAAiB,EAAE,cAAc,CAAC;KACrC;CACJ"}

View File

@@ -1,118 +0,0 @@
var __decorate =
(this && this.__decorate) ||
function (decorators, target, key, desc) {
var c = arguments.length,
r =
c < 3
? target
: desc === null
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i]))
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { html, LitElement } from "lit";
import { customElement } from "lit/decorators/custom-element.js";
import { property } from "lit/decorators/property.js";
import { scroll } from "./scroll.js";
import { scrollerRef } from "./uni-virtualizer/lib/VirtualScroller.js";
/**
* A LitElement wrapper of the scroll directive.
*
* Import this module to declare the lit-virtualizer custom element.
* Pass an items array, renderItem method, and scroll target as properties
* to the <lit-virtualizer> element.
*/
let LitVirtualizer = class LitVirtualizer extends LitElement {
constructor() {
super(...arguments);
this.items = [];
this.scrollTarget = this;
this.keyFunction = undefined;
this._layout = null;
this._scrollToIndex = null;
}
createRenderRoot() {
return this;
}
// get items() {
// return this._items;
// }
// set items(items) {
// this._items = items;
// this._scroller.totalItems = items.length;
// }
/**
* The method used for rendering each item.
*/
// get renderItem() {
// return this._renderItem;
// }
// set renderItem(renderItem) {
// if (renderItem !== this.renderItem) {
// this._renderItem = renderItem;
// this.requestUpdate();
// }
// }
set layout(layout) {
// TODO (graynorton): Shouldn't have to set this here
this._layout = layout;
this.requestUpdate();
}
get layout() {
return this[scrollerRef].layout;
}
/**
* Scroll to the specified index, placing that item at the given position
* in the scroll view.
*/
async scrollToIndex(index, position = "start") {
this._scrollToIndex = { index, position };
this.requestUpdate();
await this.updateComplete;
this._scrollToIndex = null;
}
render() {
const { items, renderItem, keyFunction, scrollTarget } = this;
const layout = this._layout;
return html`
${scroll({
items,
renderItem,
layout,
keyFunction,
scrollTarget,
scrollToIndex: this._scrollToIndex,
})}
`;
}
};
__decorate([property()], LitVirtualizer.prototype, "renderItem", void 0);
__decorate(
[property({ attribute: false })],
LitVirtualizer.prototype,
"items",
void 0
);
__decorate(
[property({ attribute: false })],
LitVirtualizer.prototype,
"scrollTarget",
void 0
);
__decorate([property()], LitVirtualizer.prototype, "keyFunction", void 0);
__decorate(
[property({ attribute: false })],
LitVirtualizer.prototype,
"layout",
null
);
LitVirtualizer = __decorate([customElement("lit-virtualizer")], LitVirtualizer);
export { LitVirtualizer };
//# sourceMappingURL=lit-virtualizer.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"lit-virtualizer.js","sourceRoot":"","sources":["../src/lib/lit-virtualizer.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAoB,MAAM,0CAA0C,CAAC;AAGzF;;;;;;GAMG;AAEH,IAAa,cAAc,GAA3B,MAAa,cAAe,SAAQ,UAAU;IAA9C;;QAKI,UAAK,GAAmB,EAAE,CAAC;QAG3B,iBAAY,GAAqB,IAAI,CAAC;QAGtC,gBAAW,GAA4C,SAAS,CAAC;QAEzD,YAAO,GAAwD,IAAI,CAAC;QAEpE,mBAAc,GAA6C,IAAI,CAAC;IA0D5E,CAAC;IAxDG,gBAAgB;QACZ,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,gBAAgB;IAChB,0BAA0B;IAC1B,IAAI;IAEJ,qBAAqB;IACrB,2BAA2B;IAC3B,gDAAgD;IAChD,IAAI;IAEJ;;OAEG;IACH,qBAAqB;IACrB,+BAA+B;IAC/B,IAAI;IACJ,+BAA+B;IAC/B,4CAA4C;IAC5C,yCAAyC;IACzC,gCAAgC;IAChC,QAAQ;IACR,IAAI;IAGJ,IAAI,MAAM,CAAC,MAA2D;QAClE,qDAAqD;QACrD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,MAAM;QACN,OAAQ,IAAyB,CAAC,WAAW,CAAE,CAAC,MAAM,CAAC;IAC3D,CAAC;IAGD;;;OAGG;IACH,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,WAAmB,OAAO;QACzD,IAAI,CAAC,cAAc,GAAG,EAAC,KAAK,EAAE,QAAQ,EAAC,CAAC;QACxC,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,MAAM,IAAI,CAAC,cAAc,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC/B,CAAC;IAED,MAAM;QACF,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,OAAO,IAAI,CAAA;cACL,MAAM,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;SACzG,CAAC;IACN,CAAC;CACJ,CAAA;AAvEG;IADC,QAAQ,EAAE;kDACkD;AAG7D;IADC,QAAQ,CAAC,EAAC,SAAS,EAAE,KAAK,EAAC,CAAC;6CACF;AAG3B;IADC,QAAQ,CAAC,EAAC,SAAS,EAAE,KAAK,EAAC,CAAC;oDACS;AAGtC;IADC,QAAQ,EAAE;mDACsD;AAiCjE;IADC,QAAQ,CAAC,EAAC,SAAS,EAAC,KAAK,EAAC,CAAC;4CAK3B;AAhDQ,cAAc;IAD1B,aAAa,CAAC,iBAAiB,CAAC;GACpB,cAAc,CAyE1B;SAzEY,cAAc","sourcesContent":["import { html, LitElement, TemplateResult } from 'lit';\nimport { customElement } from 'lit/decorators/custom-element.js';\nimport { property } from 'lit/decorators/property.js';\nimport { scroll } from './scroll.js';\nimport { scrollerRef, ContainerElement } from './uni-virtualizer/lib/VirtualScroller.js';\nimport { LayoutSpecifier, Layout, LayoutConstructor } from './uni-virtualizer/lib/layouts/Layout.js';\n\n/**\n * A LitElement wrapper of the scroll directive.\n *\n * Import this module to declare the lit-virtualizer custom element.\n * Pass an items array, renderItem method, and scroll target as properties\n * to the <lit-virtualizer> element.\n */\n@customElement('lit-virtualizer')\nexport class LitVirtualizer extends LitElement {\n @property()\n renderItem?: ((item: any, index?: number) => TemplateResult);\n\n @property({attribute: false})\n items: Array<unknown> = [];\n\n @property({attribute: false})\n scrollTarget: Element | Window = this;\n\n @property()\n keyFunction: ((item:unknown) => unknown) | undefined = undefined;\n\n private _layout: Layout | LayoutConstructor | LayoutSpecifier | null = null;\n\n private _scrollToIndex: {index: number, position: string} | null = null;\n \n createRenderRoot() {\n return this;\n }\n\n // get items() {\n // return this._items;\n // }\n\n // set items(items) {\n // this._items = items;\n // this._scroller.totalItems = items.length;\n // }\n\n /**\n * The method used for rendering each item.\n */\n // get renderItem() {\n // return this._renderItem;\n // }\n // set renderItem(renderItem) {\n // if (renderItem !== this.renderItem) {\n // this._renderItem = renderItem;\n // this.requestUpdate();\n // }\n // }\n\n @property({attribute:false})\n set layout(layout: Layout | LayoutConstructor | LayoutSpecifier | null) {\n // TODO (graynorton): Shouldn't have to set this here\n this._layout = layout;\n this.requestUpdate();\n }\n\n get layout(): Layout | LayoutConstructor | LayoutSpecifier | null {\n return (this as ContainerElement)[scrollerRef]!.layout;\n }\n \n \n /**\n * Scroll to the specified index, placing that item at the given position\n * in the scroll view.\n */\n async scrollToIndex(index: number, position: string = 'start') {\n this._scrollToIndex = {index, position};\n this.requestUpdate();\n await this.updateComplete;\n this._scrollToIndex = null;\n }\n\n render(): TemplateResult {\n const { items, renderItem, keyFunction, scrollTarget } = this;\n const layout = this._layout;\n return html`\n ${scroll({ items, renderItem, layout, keyFunction, scrollTarget, scrollToIndex: this._scrollToIndex })}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'lit-virtualizer': LitVirtualizer;\n }\n}"]}

View File

@@ -1,61 +0,0 @@
import { TemplateResult, ChildPart } from "lit";
import { PartInfo } from "lit/directive.js";
import { AsyncDirective } from "lit/async-directive.js";
import {
Layout,
LayoutConstructor,
LayoutSpecifier,
} from "./uni-virtualizer/lib/layouts/Layout.js";
import {
VirtualScroller,
ScrollToIndexValue,
} from "./uni-virtualizer/lib/VirtualScroller.js";
/**
* Configuration options for the scroll directive.
*/
interface ScrollConfig {
/**
* A function that returns a lit-html TemplateResult. It will be used
* to generate the DOM for each item in the virtual list.
*/
renderItem?: (item: any, index?: number) => TemplateResult;
keyFunction?: (item: any) => unknown;
layout?: Layout | LayoutConstructor | LayoutSpecifier | null;
/**
* An element that receives scroll events for the virtual scroller.
*/
scrollTarget?: Element | Window;
/**
* The list of items to display via the renderItem function.
*/
items?: Array<any>;
/**
* Limit for the number of items to display. Defaults to the length of the
* items array.
*/
totalItems?: number;
/**
* Index and position of the item to scroll to.
*/
scrollToIndex?: ScrollToIndexValue;
}
export declare const defaultKeyFunction: (item: any) => any;
export declare const defaultRenderItem: (item: any) => TemplateResult<1>;
declare class ScrollDirective extends AsyncDirective {
container: HTMLElement | null;
scroller: VirtualScroller | null;
first: number;
last: number;
renderItem: (item: any, index?: number) => TemplateResult;
keyFunction: (item: any) => unknown;
items: Array<unknown>;
constructor(part: PartInfo);
render(config?: ScrollConfig): unknown;
update(part: ChildPart, [config]: [ScrollConfig]): unknown;
private _initialize;
}
export declare const scroll: (
config?: ScrollConfig | undefined
) => import("lit-html/directive").DirectiveResult<typeof ScrollDirective>;
export {};
//# sourceMappingURL=scroll.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"scroll.d.ts","sourceRoot":"","sources":["../src/lib/scroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAW,SAAS,EAAQ,MAAM,KAAK,CAAC;AAC/D,OAAO,EAAa,QAAQ,EAAY,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAE/F;;GAEG;AACH,UAAU,YAAY;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,cAAc,CAAC;IAE3D,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;IAGrC,MAAM,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,CAAC;IAE7D;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAEhC;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAEnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAEH,eAAO,MAAM,kBAAkB,SAAU,GAAG,QAAS,CAAC;AACtD,eAAO,MAAM,iBAAiB,SAAU,GAAG,sBAA2C,CAAC;AAEvF,cAAM,eAAgB,SAAQ,cAAc;IACxC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAO;IACpC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAO;IACvC,KAAK,SAAI;IACT,IAAI,SAAK;IACT,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,cAAc,CAAqB;IAC9E,WAAW,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAsB;IACzD,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAK;gBAEd,IAAI,EAAE,QAAQ;IAO1B,MAAM,CAAC,MAAM,CAAC,EAAE,YAAY;IAc5B,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC;IAehD,OAAO,CAAC,WAAW;CAiBtB;AAED,eAAO,MAAM,MAAM,6GAA6B,CAAC"}

View File

@@ -1,79 +0,0 @@
import { nothing, html } from "lit";
import { directive, PartType } from "lit/directive.js";
import { AsyncDirective } from "lit/async-directive.js";
import { repeat } from "lit/directives/repeat.js";
import { VirtualScroller } from "./uni-virtualizer/lib/VirtualScroller.js";
export const defaultKeyFunction = (item) => item;
export const defaultRenderItem = (item) =>
html`${JSON.stringify(item, null, 2)}`;
class ScrollDirective extends AsyncDirective {
constructor(part) {
super(part);
this.container = null;
this.scroller = null;
this.first = 0;
this.last = -1;
this.renderItem = defaultRenderItem;
this.keyFunction = defaultKeyFunction;
this.items = [];
if (part.type !== PartType.CHILD) {
throw new Error(
"The scroll directive can only be used in child expressions"
);
}
}
render(config) {
if (config) {
this.renderItem = config.renderItem || this.renderItem;
this.keyFunction = config.keyFunction || this.keyFunction;
}
const itemsToRender = [];
if (this.first >= 0 && this.last >= this.first) {
for (let i = this.first; i < this.last + 1; i++) {
itemsToRender.push(this.items[i]);
}
}
return repeat(
itemsToRender,
this.keyFunction || defaultKeyFunction,
this.renderItem
);
}
update(part, [config]) {
var _a;
if (this.scroller || this._initialize(part, config)) {
const { scroller } = this;
this.items = scroller.items = config.items || [];
scroller.totalItems =
config.totalItems ||
((_a = config.items) === null || _a === void 0 ? void 0 : _a.length) ||
0;
scroller.layout = config.layout || null;
scroller.scrollTarget = config.scrollTarget || this.container;
if (config.scrollToIndex) {
scroller.scrollToIndex = config.scrollToIndex;
}
return this.render(config);
}
return nothing;
}
_initialize(part, config) {
const container = (this.container = part.parentNode);
if (container && container.nodeType === 1) {
this.scroller = new VirtualScroller({ container });
container.addEventListener("rangeChanged", (e) => {
this.first = e.detail.first;
this.last = e.detail.last;
this.setValue(this.render());
});
return true;
}
// TODO (GN): This seems to be needed in the case where the `scroll`
// directive is used within the `LitVirtualizer` element. Figure out why
// and see if there's a cleaner solution.
Promise.resolve().then(() => this.update(part, [config]));
return false;
}
}
export const scroll = directive(ScrollDirective);
//# sourceMappingURL=scroll.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,230 +0,0 @@
import {
ItemBox,
Layout,
LayoutConstructor,
LayoutSpecifier,
} from "./layouts/Layout.js";
export declare const scrollerRef: unique symbol;
export declare type RangeChangeEvent = {
first: number;
last: number;
firstVisible: number;
lastVisible: number;
};
interface ElementWithOptionalScrollerRef extends Element {
[scrollerRef]?: VirtualScroller;
}
interface ShadowRootWithOptionalScrollerRef extends ShadowRoot {
[scrollerRef]?: VirtualScroller;
}
declare type Container =
| ElementWithOptionalScrollerRef
| ShadowRootWithOptionalScrollerRef;
export declare type ContainerElement = ElementWithOptionalScrollerRef;
declare type ChildMeasurements = {
[key: number]: ItemBox;
};
export declare type ScrollToIndexValue = {
index: number;
position?: string;
} | null;
export interface VirtualScrollerConfig {
layout?: Layout | LayoutConstructor | LayoutSpecifier;
/**
* An element that receives scroll events for the virtual scroller.
*/
scrollTarget?: Element | Window;
/**
* The parent of all child nodes to be rendered.
*/
container: Element | ShadowRoot;
}
/**
* Provides virtual scrolling boilerplate.
*
* Extensions of this class must set container, layout, and scrollTarget.
*
* Extensions of this class must also override VirtualRepeater's DOM
* manipulation methods.
*/
export declare class VirtualScroller {
private _benchmarkStart;
/**
* Whether the layout should receive an updated viewport size on the next
* render.
*/
private _layout;
/**
* The element that generates scroll events and defines the container
* viewport. Set by scrollTarget.
*/
private _scrollTarget;
/**
* A sentinel element that sizes the container when it is a scrolling
* element. This ensures the scroll bar accurately reflects the total
* size of the list.
*/
private _sizer;
/**
* Layout provides these values, we set them on _render().
* TODO @straversi: Can we find an XOR type, usable for the key here?
*/
private _scrollSize;
/**
* Difference between scroll target's current and required scroll offsets.
* Provided by layout.
*/
private _scrollErr;
/**
* A list of the positions (top, left) of the children in the current range.
*/
private _childrenPos;
private _childMeasurements;
private _toBeMeasured;
private _rangeChanged;
private _itemsChanged;
private _visibilityChanged;
/**
* Containing element. Set by container.
*/
protected _container: Container | null;
/**
* The parent of all child nodes to be rendered. Set by container.
*/
private _containerElement;
/**
* Keep track of original inline style of the container, so it can be
* restored when container is changed.
*/
private _containerInlineStyle;
/**
* Size of the container.
*/
private _containerSize;
/**
* Resize observer attached to container.
*/
private _containerRO;
/**
* Resize observer attached to children.
*/
private _childrenRO;
private _mutationObserver;
private _mutationPromise;
private _mutationPromiseResolver;
private _mutationsObserved;
private _loadListener;
/**
* Index and position of item to scroll to.
*/
private _scrollToIndex;
/**
* Items to render. Set by items.
*/
private _items;
/**
* Total number of items to render. Set by totalItems.
*/
private _totalItems;
/**
* Index of the first child in the range, not necessarily the first visible child.
* TODO @straversi: Consider renaming these.
*/
protected _first: number;
/**
* Index of the last child in the range.
*/
protected _last: number;
/**
* Index of the first item intersecting the container element.
*/
private _firstVisible;
/**
* Index of the last item intersecting the container element.
*/
private _lastVisible;
protected _scheduled: WeakSet<object>;
/**
* Invoked at the end of each render cycle: children in the range are
* measured, and their dimensions passed to this callback. Use it to layout
* children as needed.
*/
protected _measureCallback: ((sizes: ChildMeasurements) => void) | null;
protected _measureChildOverride:
| ((element: Element, item: unknown) => ItemBox)
| null;
constructor(config?: VirtualScrollerConfig);
set items(items: Array<unknown> | undefined);
/**
* The total number of items, regardless of the range, that can be rendered
* as child nodes.
*/
get totalItems(): number;
set totalItems(num: number);
/**
* The parent of all child nodes to be rendered.
*/
get container(): Container | null;
set container(container: Container | null);
get layout(): Layout | LayoutConstructor | LayoutSpecifier | null;
set layout(layout: Layout | LayoutConstructor | LayoutSpecifier | null);
startBenchmarking(): void;
stopBenchmarking(): {
timeElapsed: number;
virtualizationTime: number;
} | null;
private _measureChildren;
/**
* Returns the width, height, and margins of the given child.
*/
_measureChild(element: Element): ItemBox;
/**
* The element that generates scroll events and defines the container
* viewport. The value `null` (default) corresponds to `window` as scroll
* target.
*/
get scrollTarget(): Element | Window | null;
set scrollTarget(target: Element | Window | null);
/**
* Index and position of item to scroll to. The scroller will fix to that point
* until the user scrolls.
*/
set scrollToIndex(newValue: ScrollToIndexValue);
protected _schedule(method: Function): Promise<void>;
_updateDOM(): Promise<void>;
_updateLayout(): void;
private _handleScrollEvent;
handleEvent(event: CustomEvent): void;
private _initResizeObservers;
private _createContainerSizer;
get _children(): Array<HTMLElement>;
private _updateView;
/**
* Styles the _sizer element or the container so that its size reflects the
* total size of all items.
*/
private _sizeContainer;
/**
* Sets the top and left transform style of the children from the values in
* pos.
*/
private _positionChildren;
private _adjustRange;
private _correctScrollError;
/**
* Emits a rangechange event with the current first, last, firstVisible, and
* lastVisible.
*/
private _notifyRange;
private _notifyVisibility;
/**
* Render and update the view at the next opportunity with the given
* container size.
*/
private _containerSizeChanged;
private _observeMutations;
private _childLoaded;
private _childrenSizeChanged;
}
export {};
//# sourceMappingURL=VirtualScroller.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"VirtualScroller.d.ts","sourceRoot":"","sources":["../../../src/lib/uni-virtualizer/lib/VirtualScroller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAW,MAAM,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEnG,eAAO,MAAM,WAAW,eAAwB,CAAC;AAYjD,oBAAY,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,UAAU,8BAA+B,SAAQ,OAAO;IACtD,CAAC,WAAW,CAAC,CAAC,EAAE,eAAe,CAAA;CAChC;AAED,UAAU,iCAAkC,SAAQ,UAAU;IAC5D,CAAC,WAAW,CAAC,CAAC,EAAE,eAAe,CAAA;CAChC;AAED,aAAK,SAAS,GAAG,8BAA8B,GAAG,iCAAiC,CAAC;AACpF,oBAAY,gBAAgB,GAAG,8BAA8B,CAAC;AAM9D,aAAK,iBAAiB,GAAG;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,CAAC;AAElD,oBAAY,kBAAkB,GAAG;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAC,GAAG,IAAI,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,eAAe,CAAC;IAEtD;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAEhC;;OAEG;IACH,SAAS,EAAE,OAAO,GAAG,UAAU,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,eAAe,CAAuB;IAC9C;;;OAGG;IAGH,OAAO,CAAC,OAAO,CAAuB;IAEtC;;;OAGG;IACH,OAAO,CAAC,aAAa,CAAwB;IAE7C;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAA4B;IAE1C;;;OAGG;IACH,OAAO,CAAC,WAAW,CAA2B;IAE9C;;;OAGG;IACH,OAAO,CAAC,UAAU,CAA4C;IAE9D;;OAEG;IACH,OAAO,CAAC,YAAY,CAAmD;IAGvE,OAAO,CAAC,kBAAkB,CAAkC;IAE5D,OAAO,CAAC,aAAa,CAAwC;IAE7D,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,kBAAkB,CAAQ;IAElC;;OAEG;IACH,SAAS,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI,CAAQ;IAE9C;;OAEG;IACH,OAAO,CAAC,iBAAiB,CAAiC;IAE1D;;;OAGG;IACH,OAAO,CAAC,qBAAqB,CAAuB;IAEpD;;OAEG;IACH,OAAO,CAAC,cAAc,CAAgD;IAEtE;;OAEG;IACH,OAAO,CAAC,YAAY,CAA+B;IAEnD;;OAEG;IACH,OAAO,CAAC,WAAW,CAA+B;IAElD,OAAO,CAAC,iBAAiB,CAAiC;IAC1D,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,wBAAwB,CAAyB;IACzD,OAAO,CAAC,kBAAkB,CAAS;IAInC,OAAO,CAAC,aAAa,CAAgC;IAErD;;OAEG;IACH,OAAO,CAAC,cAAc,CAA4B;IAElD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAsB;IAEpC;;OAEG;IACH,OAAO,CAAC,WAAW,CAAuB;IAE1C;;;OAGG;IACH,SAAS,CAAC,MAAM,SAAK;IAErB;;OAEG;IACH,SAAS,CAAC,KAAK,SAAK;IAEpB;;OAEG;IACH,OAAO,CAAC,aAAa,CAAK;IAE1B;;OAEG;IACH,OAAO,CAAC,YAAY,CAAK;IAEzB,SAAS,CAAC,UAAU,kBAAiB;IAErC;;;;OAIG;IACF,SAAS,CAAC,gBAAgB,EAAE,CAAC,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAE/E,SAAS,CAAC,qBAAqB,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI,CAAQ;gBAEnF,MAAM,CAAC,EAAE,qBAAqB;IAS1C,IAAI,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,SAAS,EAM1C;IAED;;;OAGG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,UAAU,CAAC,GAAG,EAAE,MAAM,EAWzB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,SAAS,GAAG,IAAI,CAEhC;IAED,IAAI,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,EA6ExC;IAID,IAAI,MAAM,IAAI,MAAM,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,CAEhE;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,EAiErE;IAID,iBAAiB;IAMjB,gBAAgB;;;;IAchB,OAAO,CAAC,gBAAgB;IAgBxB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAQxC;;;;OAIG;IACH,IAAI,YAAY,IAAI,OAAO,GAAG,MAAM,GAAG,IAAI,CAE1C;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,EAyB/C;IAED;;;OAGG;IACH,IAAI,aAAa,CAAC,QAAQ,EAAE,kBAAkB,EAG7C;cAEe,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IASpD,UAAU;IA0BhB,aAAa;IAoBb,OAAO,CAAC,kBAAkB;IAgB1B,WAAW,CAAC,KAAK,EAAE,WAAW;YA4BhB,oBAAoB;IAWlC,OAAO,CAAC,qBAAqB;IAgB7B,IAAI,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,CAWlC;IAED,OAAO,CAAC,WAAW;IAiDnB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;YAsBX,YAAY;IAkB1B,OAAO,CAAC,mBAAmB;IAS3B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;YAMf,iBAAiB;IAc/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,oBAAoB;CAO7B"}

View File

@@ -1,725 +0,0 @@
import getResizeObserver from "./polyfillLoaders/ResizeObserver.js";
export const scrollerRef = Symbol("scrollerRef");
/**
* Provides virtual scrolling boilerplate.
*
* Extensions of this class must set container, layout, and scrollTarget.
*
* Extensions of this class must also override VirtualRepeater's DOM
* manipulation methods.
*/
export class VirtualScroller {
constructor(config) {
this._benchmarkStart = null;
/**
* Whether the layout should receive an updated viewport size on the next
* render.
*/
// private _needsUpdateView: boolean = false;
this._layout = null;
/**
* The element that generates scroll events and defines the container
* viewport. Set by scrollTarget.
*/
this._scrollTarget = null;
/**
* A sentinel element that sizes the container when it is a scrolling
* element. This ensures the scroll bar accurately reflects the total
* size of the list.
*/
this._sizer = null;
/**
* Layout provides these values, we set them on _render().
* TODO @straversi: Can we find an XOR type, usable for the key here?
*/
this._scrollSize = null;
/**
* Difference between scroll target's current and required scroll offsets.
* Provided by layout.
*/
this._scrollErr = null;
/**
* A list of the positions (top, left) of the children in the current range.
*/
this._childrenPos = null;
// TODO: (graynorton): type
this._childMeasurements = null;
this._toBeMeasured = new Map();
this._rangeChanged = true;
this._itemsChanged = true;
this._visibilityChanged = true;
/**
* Containing element. Set by container.
*/
this._container = null;
/**
* The parent of all child nodes to be rendered. Set by container.
*/
this._containerElement = null;
/**
* Keep track of original inline style of the container, so it can be
* restored when container is changed.
*/
this._containerInlineStyle = null;
/**
* Size of the container.
*/
this._containerSize = null;
/**
* Resize observer attached to container.
*/
this._containerRO = null;
/**
* Resize observer attached to children.
*/
this._childrenRO = null;
this._mutationObserver = null;
this._mutationPromise = null;
this._mutationPromiseResolver = null;
this._mutationsObserved = false;
// TODO (graynorton): Rethink, per longer comment below
this._loadListener = this._childLoaded.bind(this);
/**
* Index and position of item to scroll to.
*/
this._scrollToIndex = null;
/**
* Items to render. Set by items.
*/
this._items = [];
/**
* Total number of items to render. Set by totalItems.
*/
this._totalItems = null;
/**
* Index of the first child in the range, not necessarily the first visible child.
* TODO @straversi: Consider renaming these.
*/
this._first = 0;
/**
* Index of the last child in the range.
*/
this._last = 0;
/**
* Index of the first item intersecting the container element.
*/
this._firstVisible = 0;
/**
* Index of the last item intersecting the container element.
*/
this._lastVisible = 0;
this._scheduled = new WeakSet();
/**
* Invoked at the end of each render cycle: children in the range are
* measured, and their dimensions passed to this callback. Use it to layout
* children as needed.
*/
this._measureCallback = null;
this._measureChildOverride = null;
this._first = -1;
this._last = -1;
if (config) {
Object.assign(this, config);
}
}
set items(items) {
if (Array.isArray(items) && items !== this._items) {
this._itemsChanged = true;
this._items = items;
this._schedule(this._updateLayout);
}
}
/**
* The total number of items, regardless of the range, that can be rendered
* as child nodes.
*/
get totalItems() {
return this._totalItems === null ? this._items.length : this._totalItems;
}
set totalItems(num) {
if (typeof num !== "number" && num !== null) {
throw new Error("New value must be a number.");
}
// TODO(valdrin) should we check if it is a finite number?
// Technically, Infinity would break Layout, not VirtualRepeater.
if (num !== this._totalItems) {
this._totalItems = num;
this._schedule(this._updateLayout);
}
}
/**
* The parent of all child nodes to be rendered.
*/
get container() {
return this._container;
}
set container(container) {
if (container === this._container) {
return;
}
if (this._container) {
// Remove children from old container.
// TODO (graynorton): Decide whether we'd rather fire an event to clear
// the range and let the renderer take care of removing the DOM children
this._children.forEach((child) => child.parentNode.removeChild(child));
}
this._container = container;
this._schedule(this._updateLayout);
this._initResizeObservers().then(() => {
const oldEl = this._containerElement;
// Consider document fragments as shadowRoots.
const newEl =
container && container.nodeType === Node.DOCUMENT_FRAGMENT_NODE
? container.host
: container;
if (oldEl === newEl) {
return;
}
this._containerRO.disconnect();
this._containerSize = null;
if (oldEl) {
if (this._containerInlineStyle) {
oldEl.setAttribute("style", this._containerInlineStyle);
} else {
oldEl.removeAttribute("style");
}
this._containerInlineStyle = null;
if (oldEl === this._scrollTarget) {
oldEl.removeEventListener("scroll", this, { passive: true });
this._sizer && this._sizer.remove();
}
oldEl.removeEventListener("load", this._loadListener, true);
this._mutationObserver.disconnect();
} else {
// First time container was setup, add listeners only now.
addEventListener("scroll", this, { passive: true });
}
this._containerElement = newEl;
if (newEl) {
this._containerInlineStyle = newEl.getAttribute("style") || null;
// https://github.com/PolymerLabs/uni-virtualizer/issues/104
// Would rather set these CSS properties on the host using Shadow Root
// style scoping (and fall back to a global stylesheet where native
// Shadow DOM is not available), but this Mobile Safari bug is preventing
// that from working: https://bugs.webkit.org/show_bug.cgi?id=226195
const style = newEl.style;
style.display = style.display || "block";
style.position = style.position || "relative";
style.overflow = style.overflow || "auto";
style.contain = style.contain || "strict";
if (newEl === this._scrollTarget) {
this._sizer = this._sizer || this._createContainerSizer();
this._container.insertBefore(this._sizer, this._container.firstChild);
}
this._schedule(this._updateLayout);
this._containerRO.observe(newEl);
this._mutationObserver.observe(newEl, { childList: true });
this._mutationPromise = new Promise(
(resolve) => (this._mutationPromiseResolver = resolve)
);
if (this._layout && this._layout.listenForChildLoadEvents) {
newEl.addEventListener("load", this._loadListener, true);
}
}
});
}
// This will always actually return a layout instance,
// but TypeScript wants the getter and setter types to be the same
get layout() {
return this._layout;
}
set layout(layout) {
if (this._layout === layout) {
return;
}
let _layout = null;
let _config = {};
if (typeof layout === "object") {
if (layout.type !== undefined) {
_layout = layout.type;
// delete (layout as LayoutSpecifier).type;
}
_config = layout;
} else {
_layout = layout;
}
if (typeof _layout === "function") {
if (this._layout instanceof _layout) {
if (_config) {
this._layout.config = _config;
}
return;
} else {
_layout = new _layout(_config);
}
}
if (this._layout) {
this._measureCallback = null;
this._measureChildOverride = null;
this._layout.removeEventListener("scrollsizechange", this);
this._layout.removeEventListener("scrollerrorchange", this);
this._layout.removeEventListener("itempositionchange", this);
this._layout.removeEventListener("rangechange", this);
delete this.container[scrollerRef];
this.container.removeEventListener("load", this._loadListener, true);
// Reset container size so layout can get correct viewport size.
if (this._containerElement) {
this._sizeContainer(undefined);
}
}
this._layout = _layout;
if (this._layout) {
if (
this._layout.measureChildren &&
typeof this._layout.updateItemSizes === "function"
) {
if (typeof this._layout.measureChildren === "function") {
this._measureChildOverride = this._layout.measureChildren;
}
this._measureCallback = this._layout.updateItemSizes.bind(this._layout);
}
this._layout.addEventListener("scrollsizechange", this);
this._layout.addEventListener("scrollerrorchange", this);
this._layout.addEventListener("itempositionchange", this);
this._layout.addEventListener("rangechange", this);
this._container[scrollerRef] = this;
if (this._layout.listenForChildLoadEvents) {
this._container.addEventListener("load", this._loadListener, true);
}
this._schedule(this._updateLayout);
}
}
// TODO (graynorton): Rework benchmarking so that it has no API and
// instead is always on except in production builds
startBenchmarking() {
if (this._benchmarkStart === null) {
this._benchmarkStart = window.performance.now();
}
}
stopBenchmarking() {
if (this._benchmarkStart !== null) {
const now = window.performance.now();
const timeElapsed = now - this._benchmarkStart;
const entries = performance.getEntriesByName(
"uv-virtualizing",
"measure"
);
const virtualizationTime = entries
.filter((e) => e.startTime >= this._benchmarkStart && e.startTime < now)
.reduce((t, m) => t + m.duration, 0);
this._benchmarkStart = null;
return { timeElapsed, virtualizationTime };
}
return null;
}
_measureChildren() {
const mm = {};
const children = this._children;
const fn = this._measureChildOverride || this._measureChild;
for (let i = 0; i < children.length; i++) {
const child = children[i];
const idx = this._first + i;
if (this._itemsChanged || this._toBeMeasured.has(child)) {
mm[idx] = fn.call(
this,
child,
this._items[idx] /*as unknown as object*/
);
}
}
this._childMeasurements = mm;
this._schedule(this._updateLayout);
this._toBeMeasured.clear();
}
/**
* Returns the width, height, and margins of the given child.
*/
_measureChild(element) {
// offsetWidth doesn't take transforms in consideration, so we use
// getBoundingClientRect which does.
const { width, height } = element.getBoundingClientRect();
return Object.assign({ width, height }, getMargins(element));
}
/**
* The element that generates scroll events and defines the container
* viewport. The value `null` (default) corresponds to `window` as scroll
* target.
*/
get scrollTarget() {
return this._scrollTarget;
}
set scrollTarget(target) {
// Consider window as null.
if (target === window) {
target = null;
}
if (this._scrollTarget === target) {
return;
}
this._sizeContainer(undefined);
if (this._scrollTarget) {
this._scrollTarget.removeEventListener("scroll", this, { passive: true });
if (this._sizer && this._scrollTarget === this._containerElement) {
this._sizer.remove();
}
}
this._scrollTarget = target;
if (target) {
target.addEventListener("scroll", this, { passive: true });
if (target === this._containerElement) {
this._sizer = this._sizer || this._createContainerSizer();
this._container.insertBefore(this._sizer, this._container.firstChild);
}
}
}
/**
* Index and position of item to scroll to. The scroller will fix to that point
* until the user scrolls.
*/
set scrollToIndex(newValue) {
this._scrollToIndex = newValue;
this._schedule(this._updateLayout);
}
async _schedule(method) {
if (!this._scheduled.has(method)) {
this._scheduled.add(method);
await Promise.resolve();
this._scheduled.delete(method);
method.call(this);
}
}
async _updateDOM() {
const { _rangeChanged, _itemsChanged } = this;
if (this._visibilityChanged) {
this._notifyVisibility();
this._visibilityChanged = false;
}
if (_rangeChanged || _itemsChanged) {
this._notifyRange();
this._rangeChanged = false;
this._itemsChanged = false;
await this._mutationPromise;
}
if (this._layout.measureChildren) {
this._children.forEach((child) => this._childrenRO.observe(child));
}
this._positionChildren(this._childrenPos);
this._sizeContainer(this._scrollSize);
if (this._scrollErr) {
this._correctScrollError(this._scrollErr);
this._scrollErr = null;
}
if (this._benchmarkStart && "mark" in window.performance) {
window.performance.mark("uv-end");
}
}
_updateLayout() {
this._layout.totalItems = this._totalItems;
if (this._scrollToIndex !== null) {
this._layout.scrollToIndex(
this._scrollToIndex.index,
this._scrollToIndex.position
);
this._scrollToIndex = null;
}
this._updateView();
if (this._childMeasurements !== null) {
// If the layout has been changed, we may have measurements but no callback
if (this._measureCallback) {
this._measureCallback(this._childMeasurements);
}
this._childMeasurements = null;
}
this._layout.reflowIfNeeded(this._itemsChanged);
if (this._benchmarkStart && "mark" in window.performance) {
window.performance.mark("uv-end");
}
}
_handleScrollEvent() {
if (this._benchmarkStart && "mark" in window.performance) {
try {
window.performance.measure("uv-virtualizing", "uv-start", "uv-end");
} catch (e) {
console.warn("Error measuring performance data: ", e);
}
window.performance.mark("uv-start");
}
this._schedule(this._updateLayout);
}
handleEvent(event) {
switch (event.type) {
case "scroll":
if (!this._scrollTarget || event.target === this._scrollTarget) {
this._handleScrollEvent();
}
break;
case "scrollsizechange":
this._scrollSize = event.detail;
this._schedule(this._updateDOM);
break;
case "scrollerrorchange":
this._scrollErr = event.detail;
this._schedule(this._updateDOM);
break;
case "itempositionchange":
this._childrenPos = event.detail;
this._schedule(this._updateDOM);
break;
case "rangechange":
this._adjustRange(event.detail);
this._schedule(this._updateDOM);
break;
default:
console.warn("event not handled", event);
}
}
async _initResizeObservers() {
if (this._containerRO === null) {
const ResizeObserver = await getResizeObserver();
this._containerRO = new ResizeObserver((entries) =>
this._containerSizeChanged(entries[0].contentRect)
);
this._childrenRO = new ResizeObserver(
this._childrenSizeChanged.bind(this)
);
this._mutationObserver = new MutationObserver(
this._observeMutations.bind(this)
);
}
}
_createContainerSizer() {
const sizer = document.createElement("div");
// When the scrollHeight is large, the height of this element might be
// ignored. Setting content and font-size ensures the element has a size.
Object.assign(sizer.style, {
position: "absolute",
margin: "-2px 0 0 0",
padding: 0,
visibility: "hidden",
fontSize: "2px",
});
sizer.innerHTML = "&nbsp;";
sizer.id = "uni-virtualizer-spacer";
return sizer;
}
get _children() {
const arr = [];
let next = this.container.firstElementChild;
while (next) {
// Skip our spacer. TODO (graynorton): Feels a bit hacky. Anything better?
if (next.id !== "uni-virtualizer-spacer") {
arr.push(next);
}
next = next.nextElementSibling;
}
return arr;
}
_updateView() {
if (!this.container || !this._containerElement || !this._layout) {
return;
}
let width, height, top, left;
if (
this._scrollTarget === this._containerElement &&
this._containerSize !== null
) {
width = this._containerSize.width;
height = this._containerSize.height;
left = this._containerElement.scrollLeft;
top = this._containerElement.scrollTop;
} else {
const containerBounds = this._containerElement.getBoundingClientRect();
const scrollBounds = this._scrollTarget
? this._scrollTarget.getBoundingClientRect()
: {
top: containerBounds.top + window.pageYOffset,
left: containerBounds.left + window.pageXOffset,
width: innerWidth,
height: innerHeight,
};
const scrollerWidth = scrollBounds.width;
const scrollerHeight = scrollBounds.height;
const xMin = Math.max(
0,
Math.min(scrollerWidth, containerBounds.left - scrollBounds.left)
);
const yMin = Math.max(
0,
Math.min(scrollerHeight, containerBounds.top - scrollBounds.top)
);
// TODO (graynorton): Direction is intended to be a layout-level concept, not a scroller-level concept,
// so this feels like a factoring problem
const xMax =
this._layout.direction === "vertical"
? Math.max(
0,
Math.min(scrollerWidth, containerBounds.right - scrollBounds.left)
)
: scrollerWidth;
const yMax =
this._layout.direction === "vertical"
? scrollerHeight
: Math.max(
0,
Math.min(
scrollerHeight,
containerBounds.bottom - scrollBounds.top
)
);
width = xMax - xMin;
height = yMax - yMin;
left = Math.max(0, -(containerBounds.left - scrollBounds.left));
top = Math.max(0, -(containerBounds.top - scrollBounds.top));
}
this._layout.viewportSize = { width, height };
this._layout.viewportScroll = { top, left };
}
/**
* Styles the _sizer element or the container so that its size reflects the
* total size of all items.
*/
_sizeContainer(size) {
if (this._scrollTarget === this._containerElement) {
const left = size && size.width ? size.width - 1 : 0;
const top = size && size.height ? size.height - 1 : 0;
if (this._sizer) {
this._sizer.style.transform = `translate(${left}px, ${top}px)`;
}
} else {
if (this._containerElement) {
const style = this._containerElement.style;
style.minWidth = size && size.width ? size.width + "px" : null;
style.minHeight = size && size.height ? size.height + "px" : null;
}
}
}
/**
* Sets the top and left transform style of the children from the values in
* pos.
*/
_positionChildren(pos) {
if (pos) {
const children = this._children;
Object.keys(pos).forEach((key) => {
const idx = key - this._first;
const child = children[idx];
if (child) {
const { top, left, width, height } = pos[key];
child.style.position = "absolute";
child.style.boxSizing = "border-box";
child.style.transform = `translate(${left}px, ${top}px)`;
if (width !== undefined) {
child.style.width = width + "px";
}
if (height !== undefined) {
child.style.height = height + "px";
}
}
});
}
}
async _adjustRange(range) {
const { _first, _last, _firstVisible, _lastVisible } = this;
this._first = range.first;
this._last = range.last;
this._firstVisible = range.firstVisible;
this._lastVisible = range.lastVisible;
this._rangeChanged =
this._rangeChanged || this._first !== _first || this._last !== _last;
this._visibilityChanged =
this._visibilityChanged ||
this._firstVisible !== _firstVisible ||
this._lastVisible !== _lastVisible;
}
_correctScrollError(err) {
if (this._scrollTarget) {
this._scrollTarget.scrollTop -= err.top;
this._scrollTarget.scrollLeft -= err.left;
} else {
window.scroll(
window.pageXOffset - err.left,
window.pageYOffset - err.top
);
}
}
/**
* Emits a rangechange event with the current first, last, firstVisible, and
* lastVisible.
*/
_notifyRange() {
// TODO (graynorton): Including visibility here for backward compat, but
// may decide to remove at some point. The rationale for separating is that
// range change events are mainly intended for "internal" consumption by the
// renderer, whereas visibility change events are mainly intended for "external"
// consumption by application code.
this._container.dispatchEvent(
new CustomEvent("rangeChanged", {
detail: {
first: this._first,
last: this._last,
firstVisible: this._firstVisible,
lastVisible: this._lastVisible,
},
})
);
}
_notifyVisibility() {
this._container.dispatchEvent(
new CustomEvent("visibilityChanged", {
detail: {
first: this._first,
last: this._last,
firstVisible: this._firstVisible,
lastVisible: this._lastVisible,
},
})
);
}
/**
* Render and update the view at the next opportunity with the given
* container size.
*/
_containerSizeChanged(size) {
const { width, height } = size;
this._containerSize = { width, height };
this._schedule(this._updateLayout);
}
async _observeMutations() {
if (!this._mutationsObserved) {
this._mutationsObserved = true;
this._mutationPromiseResolver();
this._mutationPromise = new Promise(
(resolve) => (this._mutationPromiseResolver = resolve)
);
this._mutationsObserved = false;
}
}
// TODO (graynorton): Rethink how this works. Probably child loading is too specific
// to have dedicated support for; might want some more generic lifecycle hooks for
// layouts to use. Possibly handle measurement this way, too, or maybe that remains
// a first-class feature?
_childLoaded() {
// this.requestRemeasure();
}
_childrenSizeChanged(changes) {
for (const change of changes) {
this._toBeMeasured.set(change.target, change.contentRect);
}
this._measureChildren();
this._schedule(this._updateLayout);
}
}
function getMargins(el) {
const style = window.getComputedStyle(el);
return {
marginTop: getMarginValue(style.marginTop),
marginRight: getMarginValue(style.marginRight),
marginBottom: getMarginValue(style.marginBottom),
marginLeft: getMarginValue(style.marginLeft),
};
}
function getMarginValue(value) {
const float = value ? parseFloat(value) : NaN;
return Number.isNaN(float) ? 0 : float;
}
//# sourceMappingURL=VirtualScroller.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,90 +0,0 @@
export declare type dimension = "height" | "width";
export declare type Size = {
[key in dimension]: number;
};
export declare type Margins = {
marginTop: number;
marginRight: number;
marginBottom: number;
marginLeft: number;
};
export declare type ItemBox = Size | (Size & Margins);
export declare type position = "left" | "top";
export declare type Positions = {
left: number;
top: number;
width?: number;
height?: number;
};
export declare type LayoutConstructor = new (config?: object) => Layout;
export interface LayoutSpecifier {
type: LayoutConstructor;
}
export declare type LayoutSpecifierFactory = (
config?: object
) => LayoutSpecifier;
export declare type ScrollDirection = "vertical" | "horizontal";
/**
* Interface for layouts consumed by VirtualScroller or VirtualRepeater.
*/
export interface Layout {
config?: object;
totalItems: number;
direction: ScrollDirection;
viewportSize: Size;
viewportScroll: Positions;
readonly measureChildren?: boolean | ((e: Element, i: unknown) => ItemBox);
readonly listenForChildLoadEvents?: boolean;
updateItemSizes?: (sizes: { [key: number]: ItemBox }) => void;
addEventListener: Function;
removeEventListener: Function;
scrollToIndex: (index: number, position: string) => void;
/**
* Called by a VirtualRepeater or VirtualScroller when an update that
* potentially affects layout has occurred. For example, a viewport size
* change.
*
* The layout is in turn responsible for dispatching events, as necessary,
* to the VirtualRepeater or VirtualScroller. Each of the following events
* represents an update that should be determined during a reflow. Dispatch
* each event at maximum once during a single reflow.
*
* Events that should be dispatched:
* - scrollsizechange
* Dispatch when the total length of all items in the scrolling direction,
* including spacing, changes.
* detail: {
* 'height' | 'width': number
* }
* - rangechange
* Dispatch when the range of children that should be displayed changes
* (based on layout calculations and the size of the container) or when
* the first or last item to intersect the container changes.
* detail: {
* first: number,
* last: number,
* num: number,
* stable: boolean,
* remeasure: boolean,
* firstVisible: number,
* lastVisible: number,
* }
* - itempositionchange
* Dispatch when the child positions change, for example due to a range
* change.
* detail {
* [number]: {
* left: number,
* top: number
* }
* }
* - scrollerrorchange
* Dispatch when the set viewportScroll offset is not what it should be.
* detail {
* height: number,
* width: number,
* }
*/
reflowIfNeeded: (force: boolean) => void;
}
//# sourceMappingURL=Layout.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC3C,oBAAY,IAAI,GAAG;KAChB,GAAG,IAAI,SAAS,GAAG,MAAM;CAC3B,CAAC;AAEF,oBAAY,OAAO,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC;AAEF,oBAAY,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;AAE9C,oBAAY,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AACtC,oBAAY,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAC;AAGF,oBAAY,iBAAiB,GAAG,KAAI,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,iBAAiB,CAAA;CACxB;AAED,oBAAY,sBAAsB,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,eAAe,CAAC;AAG1E,oBAAY,eAAe,GAAG,UAAU,GAAG,YAAY,CAAC;AAExD;;GAEG;AACF,MAAM,WAAW,MAAM;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,eAAe,CAAC;IAE3B,YAAY,EAAE,IAAI,CAAC;IAEnB,cAAc,EAAE,SAAS,CAAC;IAE1B,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;IAE3E,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAE5C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,KAAK,IAAI,CAAC;IAEX,gBAAgB,EAAE,QAAQ,CAAC;IAE3B,mBAAmB,EAAE,QAAQ,CAAC;IAE9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C"}

View File

@@ -1,2 +0,0 @@
export {};
//# sourceMappingURL=Layout.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout.js","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout.ts"],"names":[],"mappings":"","sourcesContent":["export type dimension = 'height' | 'width';\nexport type Size = {\n [key in dimension]: number\n};\n\nexport type Margins = {\n marginTop: number,\n marginRight: number,\n marginBottom: number,\n marginLeft: number\n};\n\nexport type ItemBox = Size | (Size & Margins);\n\nexport type position = 'left' | 'top';\nexport type Positions = {\n left: number,\n top: number,\n width?: number,\n height?: number\n};\n\n\nexport type LayoutConstructor = new(config?: object) => Layout;\n\nexport interface LayoutSpecifier {\n type: LayoutConstructor\n}\n\nexport type LayoutSpecifierFactory = (config?: object) => LayoutSpecifier;\n\n\nexport type ScrollDirection = 'vertical' | 'horizontal';\n\n/**\n * Interface for layouts consumed by VirtualScroller or VirtualRepeater.\n */\n export interface Layout {\n config?: object;\n \n totalItems: number;\n\n direction: ScrollDirection;\n\n viewportSize: Size;\n\n viewportScroll: Positions;\n\n readonly measureChildren?: boolean | ((e: Element, i: unknown) => ItemBox);\n\n readonly listenForChildLoadEvents?: boolean;\n\n updateItemSizes?: (sizes: {\n [key: number]: ItemBox\n }) => void;\n\n addEventListener: Function;\n\n removeEventListener: Function;\n\n scrollToIndex: (index: number, position: string) => void;\n\n /**\n * Called by a VirtualRepeater or VirtualScroller when an update that\n * potentially affects layout has occurred. For example, a viewport size\n * change.\n *\n * The layout is in turn responsible for dispatching events, as necessary,\n * to the VirtualRepeater or VirtualScroller. Each of the following events\n * represents an update that should be determined during a reflow. Dispatch\n * each event at maximum once during a single reflow.\n *\n * Events that should be dispatched:\n * - scrollsizechange\n * Dispatch when the total length of all items in the scrolling direction,\n * including spacing, changes.\n * detail: {\n * 'height' | 'width': number\n * }\n * - rangechange\n * Dispatch when the range of children that should be displayed changes\n * (based on layout calculations and the size of the container) or when\n * the first or last item to intersect the container changes.\n * detail: {\n * first: number,\n * last: number,\n * num: number,\n * stable: boolean,\n * remeasure: boolean,\n * firstVisible: number,\n * lastVisible: number,\n * }\n * - itempositionchange\n * Dispatch when the child positions change, for example due to a range\n * change.\n * detail {\n * [number]: {\n * left: number,\n * top: number\n * }\n * }\n * - scrollerrorchange\n * Dispatch when the set viewportScroll offset is not what it should be.\n * detail {\n * height: number,\n * width: number,\n * }\n */\n reflowIfNeeded: (force: boolean) => void;\n}"]}

View File

@@ -1,108 +0,0 @@
import { Layout1dBase, Layout1dBaseConfig } from "./Layout1dBase.js";
import { ItemBox, Positions, Size } from "./Layout.js";
declare type ItemBounds = {
pos: number;
size: number;
};
declare type Layout1dConstructor = {
prototype: Layout1d;
new (config?: Layout1dBaseConfig): Layout1d;
};
declare type Layout1dSpecifier = Layout1dBaseConfig & {
type: Layout1dConstructor;
};
declare type Layout1dSpecifierFactory = (
config?: Layout1dBaseConfig
) => Layout1dSpecifier;
export declare const layout1d: Layout1dSpecifierFactory;
export declare class Layout1d extends Layout1dBase<Layout1dBaseConfig> {
/**
* Indices of children mapped to their (position and length) in the scrolling
* direction. Used to keep track of children that are in range.
*/
_physicalItems: Map<number, ItemBounds>;
/**
* Used in tandem with _physicalItems to track children in range across
* reflows.
*/
_newPhysicalItems: Map<number, ItemBounds>;
/**
* Width and height of children by their index.
*/
_metrics: Map<number, Size>;
/**
* anchorIdx is the anchor around which we reflow. It is designed to allow
* jumping to any point of the scroll size. We choose it once and stick with
* it until stable. _first and _last are deduced around it.
*/
_anchorIdx: number | null;
/**
* Position in the scrolling direction of the anchor child.
*/
_anchorPos: number | null;
/**
* Whether all children in range were in range during the previous reflow.
*/
_stable: boolean;
/**
* Whether to remeasure children during the next reflow.
*/
_needsRemeasure: boolean;
/**
* Number of children to lay out.
*/
private _nMeasured;
/**
* Total length in the scrolling direction of the laid out children.
*/
private _tMeasured;
private _measureChildren;
_estimate: boolean;
get measureChildren(): boolean;
/**
* Determine the average size of all children represented in the sizes
* argument.
*/
updateItemSizes(sizes: { [key: number]: ItemBox }): void;
/**
* Set the average item size based on the total length and number of children
* in range.
*/
_updateItemSize(): void;
_getMetrics(idx: number): ItemBox;
_getPhysicalItem(idx: number): ItemBounds | undefined;
_getSize(idx: number): number | undefined;
/**
* Returns the position in the scrolling direction of the item at idx.
* Estimates it if the item at idx is not in the DOM.
*/
_getPosition(idx: number): number;
_calculateAnchor(lower: number, upper: number): number;
_getAnchor(lower: number, upper: number): number;
/**
* Updates _first and _last based on items that should be in the current
* viewed range.
*/
_getActiveItems(): void;
/**
* Sets the range to empty.
*/
_clearItems(): void;
_getItems(): void;
_calculateError(): number;
_updateScrollSize(): void;
_reflow(): void;
_resetReflowState(): void;
/**
* Returns the top and left positioning of the item at idx.
*/
_getItemPosition(idx: number): Positions;
/**
* Returns the height and width of the item at idx.
*/
_getItemSize(idx: number): Size;
_viewDim2Changed(): void;
_emitRange(): void;
}
export {};
//# sourceMappingURL=Layout1d.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1d.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1d.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAU,MAAM,aAAa,CAAC;AAE9D,aAAK,UAAU,GAAG;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAC;AAEF,aAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,QAAQ,CAAC;IACpB,KAAI,MAAM,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CAAA;CAC3C,CAAA;AAED,aAAK,iBAAiB,GAAG,kBAAkB,GAAG;IAC5C,IAAI,EAAE,mBAAmB,CAAA;CAC1B,CAAA;AAED,aAAK,wBAAwB,GAAG,CAAC,MAAM,CAAC,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;AAEnF,eAAO,MAAM,QAAQ,EAAE,wBAEb,CAAC;AAGX,qBAAa,QAAS,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAC5D;;;OAGG;IACH,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAa;IAEpD;;;OAGG;IACH,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAa;IAEvD;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAa;IAExC;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEjC;;OAEG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEjC;;OAEG;IACH,OAAO,UAAQ;IAEf;;OAEG;IACH,eAAe,UAAS;IAExB;;OAEG;IACH,OAAO,CAAC,UAAU,CAAK;IAEvB;;OAEG;IACH,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,gBAAgB,CAAQ;IAEhC,SAAS,UAAQ;IAUjB,IAAI,eAAe,YAElB;IAED;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAC;IAmC/C;;;OAGG;IACH,eAAe;IAMf,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IASjC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIrD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKzC;;;OAGG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAKjC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IActD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAqDhD;;;OAGG;IACH,eAAe;IAQf;;OAEG;IACH,WAAW;IAeX,SAAS;IA+GT,eAAe,IAAI,MAAM;IAezB,iBAAiB;IAQjB,OAAO;IA0BP,iBAAiB;IAMjB;;OAEG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IAOxC;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAO/B,gBAAgB;IAKhB,UAAU;CAMX"}

View File

@@ -1,406 +0,0 @@
import { Layout1dBase } from "./Layout1dBase.js";
export const layout1d = (config) =>
Object.assign(
{
type: Layout1d,
},
config
);
export class Layout1d extends Layout1dBase {
constructor() {
super(...arguments);
/**
* Indices of children mapped to their (position and length) in the scrolling
* direction. Used to keep track of children that are in range.
*/
this._physicalItems = new Map();
/**
* Used in tandem with _physicalItems to track children in range across
* reflows.
*/
this._newPhysicalItems = new Map();
/**
* Width and height of children by their index.
*/
this._metrics = new Map();
/**
* anchorIdx is the anchor around which we reflow. It is designed to allow
* jumping to any point of the scroll size. We choose it once and stick with
* it until stable. _first and _last are deduced around it.
*/
this._anchorIdx = null;
/**
* Position in the scrolling direction of the anchor child.
*/
this._anchorPos = null;
/**
* Whether all children in range were in range during the previous reflow.
*/
this._stable = true;
/**
* Whether to remeasure children during the next reflow.
*/
this._needsRemeasure = false;
/**
* Number of children to lay out.
*/
this._nMeasured = 0;
/**
* Total length in the scrolling direction of the laid out children.
*/
this._tMeasured = 0;
this._measureChildren = true;
this._estimate = true;
}
// protected _defaultConfig: Layout1dBaseConfig = Object.assign({}, super._defaultConfig, {
// })
// constructor(config: Layout1dConfig) {
// super(config);
// }
get measureChildren() {
return this._measureChildren;
}
/**
* Determine the average size of all children represented in the sizes
* argument.
*/
updateItemSizes(sizes) {
Object.keys(sizes).forEach((key) => {
const metrics = sizes[Number(key)],
mi = this._getMetrics(Number(key)),
prevSize = mi[this._sizeDim];
// TODO(valdrin) Handle margin collapsing.
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing
mi.width =
metrics.width + (metrics.marginLeft || 0) + (metrics.marginRight || 0);
mi.height =
metrics.height + (metrics.marginTop || 0) + (metrics.marginBottom || 0);
const size = mi[this._sizeDim];
const item = this._getPhysicalItem(Number(key));
if (item) {
let delta = 0;
if (size !== undefined) {
item.size = size;
if (prevSize === -1) {
delta = size;
this._nMeasured++;
} else {
delta = size - prevSize;
}
}
this._tMeasured = this._tMeasured + delta;
}
});
if (this._nMeasured) {
this._updateItemSize();
this._scheduleReflow();
}
}
/**
* Set the average item size based on the total length and number of children
* in range.
*/
_updateItemSize() {
// Keep integer values.
this._itemSize[this._sizeDim] = Math.round(
this._tMeasured / this._nMeasured
);
}
_getMetrics(idx) {
let metrics = this._metrics.get(idx);
if (metrics === undefined) {
metrics = { height: -1, width: -1 };
this._metrics.set(idx, metrics);
}
return metrics;
}
_getPhysicalItem(idx) {
return this._newPhysicalItems.get(idx) || this._physicalItems.get(idx);
}
_getSize(idx) {
const item = this._getPhysicalItem(idx);
return item && item.size;
}
/**
* Returns the position in the scrolling direction of the item at idx.
* Estimates it if the item at idx is not in the DOM.
*/
_getPosition(idx) {
const item = this._getPhysicalItem(idx);
return item ? item.pos : idx * this._delta + this._spacing;
}
_calculateAnchor(lower, upper) {
if (lower === 0) {
return 0;
}
if (upper > this._scrollSize - this._viewDim1) {
return this._totalItems - 1;
}
return Math.max(
0,
Math.min(
this._totalItems - 1,
Math.floor((lower + upper) / 2 / this._delta)
)
);
}
_getAnchor(lower, upper) {
if (this._physicalItems.size === 0) {
return this._calculateAnchor(lower, upper);
}
if (this._first < 0) {
console.error("_getAnchor: negative _first");
return this._calculateAnchor(lower, upper);
}
if (this._last < 0) {
console.error("_getAnchor: negative _last");
return this._calculateAnchor(lower, upper);
}
const firstItem = this._getPhysicalItem(this._first),
lastItem = this._getPhysicalItem(this._last),
firstMin = firstItem.pos,
firstMax = firstMin + firstItem.size,
lastMin = lastItem.pos,
lastMax = lastMin + lastItem.size;
if (lastMax < lower) {
// Window is entirely past physical items, calculate new anchor
return this._calculateAnchor(lower, upper);
}
if (firstMin > upper) {
// Window is entirely before physical items, calculate new anchor
return this._calculateAnchor(lower, upper);
}
if (firstMin >= lower || firstMax >= lower) {
// First physical item overlaps window, choose it
return this._first;
}
if (lastMax <= upper || lastMin <= upper) {
// Last physical overlaps window, choose it
return this._last;
}
// Window contains a physical item, but not the first or last
let maxIdx = this._last,
minIdx = this._first;
while (true) {
const candidateIdx = Math.round((maxIdx + minIdx) / 2),
candidate = this._physicalItems.get(candidateIdx),
cMin = candidate.pos,
cMax = cMin + candidate.size;
if (
(cMin >= lower && cMin <= upper) ||
(cMax >= lower && cMax <= upper)
) {
return candidateIdx;
} else if (cMax < lower) {
minIdx = candidateIdx + 1;
} else if (cMin > upper) {
maxIdx = candidateIdx - 1;
}
}
}
/**
* Updates _first and _last based on items that should be in the current
* viewed range.
*/
_getActiveItems() {
if (this._viewDim1 === 0 || this._totalItems === 0) {
this._clearItems();
} else {
this._getItems();
}
}
/**
* Sets the range to empty.
*/
_clearItems() {
this._first = -1;
this._last = -1;
this._physicalMin = 0;
this._physicalMax = 0;
const items = this._newPhysicalItems;
this._newPhysicalItems = this._physicalItems;
this._newPhysicalItems.clear();
this._physicalItems = items;
this._stable = true;
}
/*
* Updates _first and _last based on items that should be in the given range.
*/
_getItems() {
const items = this._newPhysicalItems;
let lower, upper;
// The anchorIdx is the anchor around which we reflow. It is designed to
// allow jumping to any point of the scroll size. We choose it once and
// stick with it until stable. first and last are deduced around it.
if (this._scrollToIndex >= 0) {
// If we have a scrollToIndex, we anchor on the given
// index and set the scroll position accordingly
this._anchorIdx = this._scrollToIndex;
this._anchorPos = this._getPosition(this._anchorIdx);
this._scrollIfNeeded();
lower = Math.max(0, this._scrollPosition - this._overhang);
upper = Math.min(
this._scrollSize,
this._scrollPosition + this._viewDim1 + this._overhang
);
} else {
// Otherwise, we find an appropriate index to anchor on
// given the current scroll position
upper = Math.min(
this._scrollSize,
this._scrollPosition + this._viewDim1 + this._overhang
);
lower = Math.max(0, upper - this._viewDim1 - 2 * this._overhang);
if (this._anchorIdx === null || this._anchorPos === null) {
this._anchorIdx = this._getAnchor(lower, upper);
this._anchorPos = this._getPosition(this._anchorIdx);
}
}
let anchorSize = this._getSize(this._anchorIdx);
if (anchorSize === undefined) {
anchorSize = this._itemDim1;
}
// Anchor might be outside bounds, so prefer correcting the error and keep
// that anchorIdx.
let anchorErr = 0;
if (this._anchorPos + anchorSize + this._spacing < lower) {
anchorErr = lower - (this._anchorPos + anchorSize + this._spacing);
}
if (this._anchorPos > upper) {
anchorErr = upper - this._anchorPos;
}
if (anchorErr) {
this._scrollPosition -= anchorErr;
lower -= anchorErr;
upper -= anchorErr;
this._scrollError += anchorErr;
}
// TODO @straversi: If size is always itemDim1, then why keep track of it?
items.set(this._anchorIdx, { pos: this._anchorPos, size: anchorSize });
this._first = this._last = this._anchorIdx;
this._physicalMin = this._physicalMax = this._anchorPos;
this._stable = true;
while (this._physicalMin > lower && this._first > 0) {
let size = this._getSize(--this._first);
if (size === undefined) {
this._stable = false;
size = this._itemDim1;
}
const pos = (this._physicalMin -= size + this._spacing);
items.set(this._first, { pos, size });
if (this._stable === false && this._estimate === false) {
break;
}
}
while (this._physicalMax < upper && this._last < this._totalItems) {
let size = this._getSize(this._last);
if (size === undefined) {
this._stable = false;
size = this._itemDim1;
}
items.set(this._last++, { pos: this._physicalMax, size });
if (this._stable === false && this._estimate === false) {
break;
} else {
this._physicalMax += size + this._spacing;
}
}
this._last--;
// This handles the cases where we were relying on estimated sizes.
const extentErr = this._calculateError();
if (extentErr) {
this._physicalMin -= extentErr;
this._physicalMax -= extentErr;
this._anchorPos -= extentErr;
this._scrollPosition -= extentErr;
items.forEach((item) => (item.pos -= extentErr));
this._scrollError += extentErr;
}
if (this._stable) {
this._newPhysicalItems = this._physicalItems;
this._newPhysicalItems.clear();
this._physicalItems = items;
}
}
_calculateError() {
if (this._first === 0) {
return this._physicalMin;
} else if (this._physicalMin <= 0) {
return this._physicalMin - this._first * this._delta;
} else if (this._last === this._totalItems - 1) {
return this._physicalMax - this._scrollSize;
} else if (this._physicalMax >= this._scrollSize) {
return (
this._physicalMax -
this._scrollSize +
(this._totalItems - 1 - this._last) * this._delta
);
}
return 0;
}
_updateScrollSize() {
// Reuse previously calculated physical max, as it might be higher than the
// estimated size.
super._updateScrollSize();
this._scrollSize = Math.max(this._physicalMax, this._scrollSize);
}
// TODO: Can this be made to inherit from base, with proper hooks?
_reflow() {
const { _first, _last, _scrollSize } = this;
this._updateScrollSize();
this._getActiveItems();
if (this._scrollSize !== _scrollSize) {
this._emitScrollSize();
}
this._updateVisibleIndices();
this._emitRange();
if (this._first === -1 && this._last === -1) {
this._resetReflowState();
} else if (
this._first !== _first ||
this._last !== _last ||
this._needsRemeasure
) {
this._emitChildPositions();
this._emitScrollError();
} else {
this._emitChildPositions();
this._emitScrollError();
this._resetReflowState();
}
}
_resetReflowState() {
this._anchorIdx = null;
this._anchorPos = null;
this._stable = true;
}
/**
* Returns the top and left positioning of the item at idx.
*/
_getItemPosition(idx) {
return {
[this._positionDim]: this._getPosition(idx),
[this._secondaryPositionDim]: 0,
};
}
/**
* Returns the height and width of the item at idx.
*/
_getItemSize(idx) {
return {
[this._sizeDim]: this._getSize(idx) || this._itemDim1,
[this._secondarySizeDim]: this._itemDim2,
};
}
_viewDim2Changed() {
this._needsRemeasure = true;
this._scheduleReflow();
}
_emitRange() {
const remeasure = this._needsRemeasure;
const stable = this._stable;
this._needsRemeasure = false;
super._emitRange({ remeasure, stable });
}
}
//# sourceMappingURL=Layout1d.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,236 +0,0 @@
import {
Layout,
Positions,
ScrollDirection,
Size,
dimension,
position,
} from "./Layout.js";
declare type UpdateVisibleIndicesOptions = {
emit?: boolean;
};
export interface Layout1dBaseConfig {
direction?: ScrollDirection;
totalItems?: number;
}
export declare abstract class Layout1dBase<C extends Layout1dBaseConfig>
implements Layout {
/**
* The last set viewport scroll position.
*/
private _latestCoords;
/**
* Scrolling direction.
*/
private _direction;
/**
* Dimensions of the viewport.
*/
private _viewportSize;
/**
* Flag for debouncing asynchnronous reflow requests.
*/
private _pendingReflow;
private _pendingLayoutUpdate;
/**
* Index of the item that has been scrolled to via the public API. When the
* container is otherwise scrolled, this value is set back to -1.
*/
protected _scrollToIndex: number;
/**
* When a child is scrolled to, the offset from the top of the child and the
* top of the viewport. Value is a proportion of the item size.
*/
private _scrollToAnchor;
/**
* The index of the first item intersecting the viewport.
*/
private _firstVisible;
/**
* The index of the last item intersecting the viewport.
*/
private _lastVisible;
private _eventTargetPromise;
/**
* Pixel offset in the scroll direction of the first child.
*/
protected _physicalMin: number;
/**
* Pixel offset in the scroll direction of the last child.
*/
protected _physicalMax: number;
/**
* Index of the first child.
*/
protected _first: number;
/**
* Index of the last child.
*/
protected _last: number;
/**
* The _estimated_ size of a child.
*/
protected _itemSize: Size;
/**
* Space in pixels between children.
*/
protected _spacing: number;
/**
* Length in the scrolling direction.
*/
protected _sizeDim: dimension;
/**
* Length in the non-scrolling direction.
*/
protected _secondarySizeDim: dimension;
/**
* Position in the scrolling direction.
*/
protected _positionDim: position;
/**
* Position in the non-scrolling direction.
*/
protected _secondaryPositionDim: position;
/**
* Current scroll offset in pixels.
*/
protected _scrollPosition: number;
/**
* Difference between current scroll offset and scroll offset calculated due
* to a reflow.
*/
protected _scrollError: number;
/**
* Total number of items that could possibly be displayed. Used to help
* calculate the scroll size.
*/
protected _totalItems: number;
/**
* The total (estimated) length of all items in the scrolling direction.
*/
protected _scrollSize: number;
/**
* Number of pixels beyond the visible size of the container to still include
* in the active range of items.
*/
protected _overhang: number;
private _eventTarget;
protected _spacingChanged: boolean;
protected _defaultConfig: C;
constructor(config?: C);
set config(config: C);
get config(): C;
/**
* Maximum index of children + 1, to help estimate total height of the scroll
* space.
*/
get totalItems(): number;
set totalItems(num: number);
/**
* Primary scrolling direction.
*/
get direction(): ScrollDirection;
set direction(dir: ScrollDirection);
/**
* Estimate of the dimensions of a single child.
*/
get itemSize(): Size;
set itemSize(dims: Size);
/**
* Amount of space in between items.
*/
get spacing(): number;
set spacing(px: number);
/**
* Height and width of the viewport.
*/
get viewportSize(): Size;
set viewportSize(dims: Size);
/**
* Scroll offset of the viewport.
*/
get viewportScroll(): Positions;
set viewportScroll(coords: Positions);
/**
* Perform a reflow if one has been scheduled.
*/
reflowIfNeeded(force: boolean): void;
/**
* Scroll to the child at the given index, and the given position within that
* child.
*/
scrollToIndex(index: number, position?: string): void;
dispatchEvent(evt: Event): Promise<void>;
addEventListener(
type: string,
listener: EventListener | EventListenerObject | null,
options?: boolean | AddEventListenerOptions | undefined
): Promise<void>;
removeEventListener(
type: string,
callback: EventListener | EventListenerObject | null,
options?: boolean | EventListenerOptions | undefined
): Promise<void>;
/**
* Get the top and left positioning of the item at idx.
*/
abstract _getItemPosition(idx: number): Positions;
/**
* Update _first and _last based on items that should be in the current
* range.
*/
abstract _getActiveItems(): void;
protected _itemDim2Changed(): void;
protected _viewDim2Changed(): void;
protected _updateLayout(): void;
protected _getItemSize(_idx: number): Size;
/**
* The size of an item in the scrolling direction + space between items.
*/
protected get _delta(): number;
/**
* The height or width of an item, whichever corresponds to the scrolling direction.
*/
protected get _itemDim1(): number;
/**
* The height or width of an item, whichever does NOT correspond to the scrolling direction.
*/
protected get _itemDim2(): number;
/**
* The height or width of the viewport, whichever corresponds to the scrolling direction.
*/
protected get _viewDim1(): number;
/**
* The height or width of the viewport, whichever does NOT correspond to the scrolling direction.
*/
protected get _viewDim2(): number;
protected _scheduleReflow(): void;
protected _scheduleLayoutUpdate(): void;
protected _reflow(): void;
/**
* Estimates the total length of all items in the scrolling direction, including spacing.
*/
protected _updateScrollSize(): void;
protected _scrollIfNeeded(): void;
protected _emitRange(inProps?: unknown): void;
protected _emitScrollSize(): void;
protected _emitScrollError(): void;
/**
* Get or estimate the top and left positions of items in the current range.
* Emit an itempositionchange event with these positions.
*/
protected _emitChildPositions(): void;
/**
* Number of items to display.
*/
private get _num();
private _checkThresholds;
/**
* Find the indices of the first and last items to intersect the viewport.
* Emit a visibleindiceschange event when either index changes.
*/
protected _updateVisibleIndices(options?: UpdateVisibleIndicesOptions): void;
private _scrollPositionChanged;
}
export {};
//# sourceMappingURL=Layout1dBase.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dBase.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dBase.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAE1F,aAAK,2BAA2B,GAAG;IACjC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,8BAAsB,YAAY,CAAC,CAAC,SAAS,kBAAkB,CAAE,YAAW,MAAM;IAChF;;OAEG;IACH,OAAO,CAAC,aAAa,CAAgC;IAErD;;OAEG;IACH,OAAO,CAAC,UAAU,CAA+B;IAEjD;;OAEG;IACH,OAAO,CAAC,aAAa,CAA+B;IAEpD;;OAEG;IACH,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,oBAAoB,CAAS;IAErC;;;OAGG;IACH,SAAS,CAAC,cAAc,SAAM;IAE9B;;;OAGG;IACH,OAAO,CAAC,eAAe,CAAK;IAE5B;;OAEG;IACH,OAAO,CAAC,aAAa,CAAK;IAE1B;;OAEG;IACH,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,mBAAmB,CAEvB;IAEJ;;OAEG;IACH,SAAS,CAAC,YAAY,SAAK;IAE3B;;OAEG;IACH,SAAS,CAAC,YAAY,SAAK;IAE3B;;OAEG;IACH,SAAS,CAAC,MAAM,SAAM;IAEtB;;OAEG;IACH,SAAS,CAAC,KAAK,SAAM;IAErB;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,IAAI,CAA6B;IAEtD;;OAEG;IACH,SAAS,CAAC,QAAQ,SAAK;IAEvB;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAY;IAEzC;;OAEG;IACH,SAAS,CAAC,iBAAiB,EAAE,SAAS,CAAW;IAEjD;;OAEG;IACH,SAAS,CAAC,YAAY,EAAE,QAAQ,CAAS;IAEzC;;OAEG;IACH,SAAS,CAAC,qBAAqB,EAAE,QAAQ,CAAU;IAEnD;;OAEG;IACH,SAAS,CAAC,eAAe,SAAK;IAE9B;;;OAGG;IACH,SAAS,CAAC,YAAY,SAAK;IAE3B;;;OAGG;IACH,SAAS,CAAC,WAAW,SAAK;IAE1B;;OAEG;IACH,SAAS,CAAC,WAAW,SAAK;IAE1B;;;OAGG;IAGH,SAAS,CAAC,SAAS,SAAQ;IAE3B,OAAO,CAAC,YAAY,CAA4B;IAChD,SAAS,CAAC,eAAe,UAAS;IAElC,SAAS,CAAC,cAAc,EAAE,CAAC,CAErB;gBAEM,MAAM,CAAC,EAAE,CAAC;IAItB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,EAEnB;IAED,IAAI,MAAM,IAAI,CAAC,CAId;IAED;;;OAGG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IACD,IAAI,UAAU,CAAC,GAAG,EAHA,MAGA,EAMjB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,eAAe,CAE/B;IACD,IAAI,SAAS,CAAC,GAAG,EAHA,eAGA,EAWhB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,IAAI,CAEnB;IACD,IAAI,QAAQ,CAAC,IAAI,EAHD,IAGC,EAUhB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,OAAO,CAAC,EAAE,EAHC,MAGD,EAMb;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,IAAI,CAEvB;IACD,IAAI,YAAY,CAAC,IAAI,EAHD,IAGC,EAQpB;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,SAAS,CAE9B;IACD,IAAI,cAAc,CAAC,MAAM,EAHH,SAGG,EASxB;IAED;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,OAAO;IAO7B;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAU;IAyBzC,aAAa,CAAC,GAAG,EAAE,KAAK;IAKxB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,mBAAmB,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS;IAK5I,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,mBAAmB,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS;IAKlJ;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IAEjD;;;OAGG;IACH,QAAQ,CAAC,eAAe,IAAI,IAAI;IAEhC,SAAS,CAAC,gBAAgB;IAI1B,SAAS,CAAC,gBAAgB;IAI1B,SAAS,CAAC,aAAa;IAIvB,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO1C;;OAEG;IACH,SAAS,KAAK,MAAM,IAAI,MAAM,CAE7B;IAED;;OAEG;IACH,SAAS,KAAK,SAAS,IAAI,MAAM,CAEhC;IAED;;OAEG;IACH,SAAS,KAAK,SAAS,IAAI,MAAM,CAEhC;IAED;;OAEG;IACH,SAAS,KAAK,SAAS,IAAI,MAAM,CAEhC;IAED;;OAEG;IACH,SAAS,KAAK,SAAS,IAAI,MAAM,CAEhC;IAED,SAAS,CAAC,eAAe;IAIzB,SAAS,CAAC,qBAAqB;IAK/B,SAAS,CAAC,OAAO;IA6BjB;;OAEG;IACH,SAAS,CAAC,iBAAiB;IAM3B,SAAS,CAAC,eAAe;IAmBzB,SAAS,CAAC,UAAU,CAAC,OAAO,GAAE,OAAmB;IAcjD,SAAS,CAAC,eAAe;IAOzB,SAAS,CAAC,gBAAgB;IAW1B;;;OAGG;IACH,SAAS,CAAC,mBAAmB;IAQ7B;;OAEG;IACH,OAAO,KAAK,IAAI,GAKf;IAED,OAAO,CAAC,gBAAgB;IAcxB;;;OAGG;IACF,SAAS,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,2BAA2B;IAiCtE,OAAO,CAAC,sBAAsB;CAQ/B"}

View File

@@ -1,477 +0,0 @@
import EventTarget from "../polyfillLoaders/EventTarget.js";
export class Layout1dBase {
constructor(config) {
/**
* The last set viewport scroll position.
*/
this._latestCoords = { left: 0, top: 0 };
/**
* Scrolling direction.
*/
this._direction = "vertical";
/**
* Dimensions of the viewport.
*/
this._viewportSize = { width: 0, height: 0 };
/**
* Flag for debouncing asynchnronous reflow requests.
*/
this._pendingReflow = false;
this._pendingLayoutUpdate = false;
/**
* Index of the item that has been scrolled to via the public API. When the
* container is otherwise scrolled, this value is set back to -1.
*/
this._scrollToIndex = -1;
/**
* When a child is scrolled to, the offset from the top of the child and the
* top of the viewport. Value is a proportion of the item size.
*/
this._scrollToAnchor = 0;
/**
* The index of the first item intersecting the viewport.
*/
this._firstVisible = 0;
/**
* The index of the last item intersecting the viewport.
*/
this._lastVisible = 0;
this._eventTargetPromise = EventTarget().then((Ctor) => {
this._eventTarget = new Ctor();
});
/**
* Pixel offset in the scroll direction of the first child.
*/
this._physicalMin = 0;
/**
* Pixel offset in the scroll direction of the last child.
*/
this._physicalMax = 0;
/**
* Index of the first child.
*/
this._first = -1;
/**
* Index of the last child.
*/
this._last = -1;
/**
* The _estimated_ size of a child.
*/
this._itemSize = { width: 100, height: 100 };
/**
* Space in pixels between children.
*/
this._spacing = 0;
/**
* Length in the scrolling direction.
*/
this._sizeDim = "height";
/**
* Length in the non-scrolling direction.
*/
this._secondarySizeDim = "width";
/**
* Position in the scrolling direction.
*/
this._positionDim = "top";
/**
* Position in the non-scrolling direction.
*/
this._secondaryPositionDim = "left";
/**
* Current scroll offset in pixels.
*/
this._scrollPosition = 0;
/**
* Difference between current scroll offset and scroll offset calculated due
* to a reflow.
*/
this._scrollError = 0;
/**
* Total number of items that could possibly be displayed. Used to help
* calculate the scroll size.
*/
this._totalItems = 0;
/**
* The total (estimated) length of all items in the scrolling direction.
*/
this._scrollSize = 1;
/**
* Number of pixels beyond the visible size of the container to still include
* in the active range of items.
*/
// TODO (graynorton): Probably want to make this something we calculate based
// on viewport size, item size, other factors, possibly still with a dial of some kind
this._overhang = 1000;
this._eventTarget = null;
this._spacingChanged = false;
this._defaultConfig = {
direction: "vertical",
};
this.config = config || this._defaultConfig;
}
set config(config) {
Object.assign(this, Object.assign({}, this._defaultConfig, config));
}
get config() {
return {
direction: this.direction,
};
}
/**
* Maximum index of children + 1, to help estimate total height of the scroll
* space.
*/
get totalItems() {
return this._totalItems;
}
set totalItems(num) {
const _num = Number(num);
if (_num !== this._totalItems) {
this._totalItems = _num;
this._scheduleReflow();
}
}
/**
* Primary scrolling direction.
*/
get direction() {
return this._direction;
}
set direction(dir) {
// Force it to be either horizontal or vertical.
dir = dir === "horizontal" ? dir : "vertical";
if (dir !== this._direction) {
this._direction = dir;
this._sizeDim = dir === "horizontal" ? "width" : "height";
this._secondarySizeDim = dir === "horizontal" ? "height" : "width";
this._positionDim = dir === "horizontal" ? "left" : "top";
this._secondaryPositionDim = dir === "horizontal" ? "top" : "left";
this._scheduleLayoutUpdate();
}
}
/**
* Estimate of the dimensions of a single child.
*/
get itemSize() {
return this._itemSize;
}
set itemSize(dims) {
const { _itemDim1, _itemDim2 } = this;
Object.assign(this._itemSize, dims);
if (_itemDim1 !== this._itemDim1 || _itemDim2 !== this._itemDim2) {
if (_itemDim2 !== this._itemDim2) {
this._itemDim2Changed();
} else {
this._scheduleLayoutUpdate();
}
}
}
/**
* Amount of space in between items.
*/
get spacing() {
return this._spacing;
}
set spacing(px) {
const _px = Number(px);
if (_px !== this._spacing) {
this._spacing = _px;
this._scheduleLayoutUpdate();
}
}
/**
* Height and width of the viewport.
*/
get viewportSize() {
return this._viewportSize;
}
set viewportSize(dims) {
const { _viewDim1, _viewDim2 } = this;
Object.assign(this._viewportSize, dims);
if (_viewDim2 !== this._viewDim2) {
this._viewDim2Changed();
} else if (_viewDim1 !== this._viewDim1) {
this._checkThresholds();
}
}
/**
* Scroll offset of the viewport.
*/
get viewportScroll() {
return this._latestCoords;
}
set viewportScroll(coords) {
Object.assign(this._latestCoords, coords);
const oldPos = this._scrollPosition;
this._scrollPosition = this._latestCoords[this._positionDim];
if (oldPos !== this._scrollPosition) {
this._scrollPositionChanged(oldPos, this._scrollPosition);
this._updateVisibleIndices({ emit: true });
}
this._checkThresholds();
}
/**
* Perform a reflow if one has been scheduled.
*/
reflowIfNeeded(force) {
if (force || this._pendingReflow) {
this._pendingReflow = false;
this._reflow();
}
}
/**
* Scroll to the child at the given index, and the given position within that
* child.
*/
scrollToIndex(index, position = "start") {
if (!Number.isFinite(index)) return;
index = Math.min(this.totalItems, Math.max(0, index));
this._scrollToIndex = index;
if (position === "nearest") {
position = index > this._first + this._num / 2 ? "end" : "start";
}
switch (position) {
case "start":
this._scrollToAnchor = 0;
break;
case "center":
this._scrollToAnchor = 0.5;
break;
case "end":
this._scrollToAnchor = 1;
break;
default:
throw new TypeError(
"position must be one of: start, center, end, nearest"
);
}
this._scheduleReflow();
}
async dispatchEvent(evt) {
await this._eventTargetPromise;
this._eventTarget.dispatchEvent(evt);
}
async addEventListener(type, listener, options) {
await this._eventTargetPromise;
this._eventTarget.addEventListener(type, listener, options);
}
async removeEventListener(type, callback, options) {
await this._eventTargetPromise;
this._eventTarget.removeEventListener(type, callback, options);
}
_itemDim2Changed() {
// Override
}
_viewDim2Changed() {
// Override
}
_updateLayout() {
// Override
}
_getItemSize(_idx) {
return {
[this._sizeDim]: this._itemDim1,
[this._secondarySizeDim]: this._itemDim2,
};
}
/**
* The size of an item in the scrolling direction + space between items.
*/
get _delta() {
return this._itemDim1 + this._spacing;
}
/**
* The height or width of an item, whichever corresponds to the scrolling direction.
*/
get _itemDim1() {
return this._itemSize[this._sizeDim];
}
/**
* The height or width of an item, whichever does NOT correspond to the scrolling direction.
*/
get _itemDim2() {
return this._itemSize[this._secondarySizeDim];
}
/**
* The height or width of the viewport, whichever corresponds to the scrolling direction.
*/
get _viewDim1() {
return this._viewportSize[this._sizeDim];
}
/**
* The height or width of the viewport, whichever does NOT correspond to the scrolling direction.
*/
get _viewDim2() {
return this._viewportSize[this._secondarySizeDim];
}
_scheduleReflow() {
this._pendingReflow = true;
}
_scheduleLayoutUpdate() {
this._pendingLayoutUpdate = true;
this._scheduleReflow();
}
_reflow() {
const { _first, _last, _scrollSize } = this;
if (this._pendingLayoutUpdate) {
this._updateLayout();
this._pendingLayoutUpdate = false;
}
this._updateScrollSize();
this._getActiveItems();
this._scrollIfNeeded();
this._updateVisibleIndices();
if (this._scrollSize !== _scrollSize) {
this._emitScrollSize();
}
if (this._first === -1 && this._last === -1) {
// TODO: have default empty object for emitRange instead
this._emitRange();
} else if (
this._first !== _first ||
this._last !== _last ||
this._spacingChanged
) {
// TODO: have default empty object for emitRange instead
this._emitRange();
this._emitChildPositions();
}
this._emitScrollError();
}
/**
* Estimates the total length of all items in the scrolling direction, including spacing.
*/
_updateScrollSize() {
// Ensure we have at least 1px - this allows getting at least 1 item to be
// rendered.
this._scrollSize = Math.max(1, this._totalItems * this._delta);
}
_scrollIfNeeded() {
if (this._scrollToIndex === -1) {
return;
}
const index = this._scrollToIndex;
const anchor = this._scrollToAnchor;
const pos = this._getItemPosition(index)[this._positionDim];
const size = this._getItemSize(index)[this._sizeDim];
const curAnchorPos = this._scrollPosition + this._viewDim1 * anchor;
const newAnchorPos = pos + size * anchor;
// Ensure scroll position is an integer within scroll bounds.
const scrollPosition = Math.floor(
Math.min(
this._scrollSize - this._viewDim1,
Math.max(0, this._scrollPosition - curAnchorPos + newAnchorPos)
)
);
this._scrollError += this._scrollPosition - scrollPosition;
this._scrollPosition = scrollPosition;
}
_emitRange(inProps = undefined) {
const detail = Object.assign(
{
first: this._first,
last: this._last,
num: this._num,
stable: true,
firstVisible: this._firstVisible,
lastVisible: this._lastVisible,
},
inProps
);
this.dispatchEvent(new CustomEvent("rangechange", { detail }));
}
_emitScrollSize() {
const detail = {
[this._sizeDim]: this._scrollSize,
};
this.dispatchEvent(new CustomEvent("scrollsizechange", { detail }));
}
_emitScrollError() {
if (this._scrollError) {
const detail = {
[this._positionDim]: this._scrollError,
[this._secondaryPositionDim]: 0,
};
this.dispatchEvent(new CustomEvent("scrollerrorchange", { detail }));
this._scrollError = 0;
}
}
/**
* Get or estimate the top and left positions of items in the current range.
* Emit an itempositionchange event with these positions.
*/
_emitChildPositions() {
const detail = {};
for (let idx = this._first; idx <= this._last; idx++) {
detail[idx] = this._getItemPosition(idx);
}
this.dispatchEvent(new CustomEvent("itempositionchange", { detail }));
}
/**
* Number of items to display.
*/
get _num() {
if (this._first === -1 || this._last === -1) {
return 0;
}
return this._last - this._first + 1;
}
_checkThresholds() {
if (this._viewDim1 === 0 && this._num > 0) {
this._scheduleReflow();
} else {
const min = Math.max(0, this._scrollPosition - this._overhang);
const max = Math.min(
this._scrollSize,
this._scrollPosition + this._viewDim1 + this._overhang
);
if (this._physicalMin > min || this._physicalMax < max) {
this._scheduleReflow();
}
}
}
/**
* Find the indices of the first and last items to intersect the viewport.
* Emit a visibleindiceschange event when either index changes.
*/
_updateVisibleIndices(options) {
if (this._first === -1 || this._last === -1) return;
let firstVisible = this._first;
while (
Math.round(
this._getItemPosition(firstVisible)[this._positionDim] +
this._getItemSize(firstVisible)[this._sizeDim]
) <= Math.round(this._scrollPosition)
) {
firstVisible++;
}
let lastVisible = this._last;
while (
Math.round(this._getItemPosition(lastVisible)[this._positionDim]) >=
Math.round(this._scrollPosition + this._viewDim1)
) {
lastVisible--;
}
if (
firstVisible !== this._firstVisible ||
lastVisible !== this._lastVisible
) {
this._firstVisible = firstVisible;
this._lastVisible = lastVisible;
if (options && options.emit) {
this._emitRange();
}
}
}
_scrollPositionChanged(oldPos, newPos) {
// When both values are bigger than the max scroll position, keep the
// current _scrollToIndex, otherwise invalidate it.
const maxPos = this._scrollSize - this._viewDim1;
if (oldPos < maxPos || newPos < maxPos) {
this._scrollToIndex = -1;
}
}
}
//# sourceMappingURL=Layout1dBase.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,65 +0,0 @@
import { Layout1dBase, Layout1dBaseConfig } from "./Layout1dBase";
import { ItemBox, Positions, Size } from "./Layout";
interface Layout1dFlexConfig extends Layout1dBaseConfig {
spacing?: number;
idealSize?: number;
}
declare type Layout1dFlexSpecifier = Layout1dFlexConfig & {
type: new (config?: Layout1dFlexConfig) => Layout1dFlex;
};
declare type Layout1dFlexSpecifierFactory = (
config?: Layout1dFlexConfig
) => Layout1dFlexSpecifier;
export declare const layout1dFlex: Layout1dFlexSpecifierFactory;
interface Rolumn {
_startIdx: number;
_endIdx: number;
_startPos: number;
_size: number;
}
interface Chunk {
_itemPositions: Array<Positions>;
_rolumns: Array<Rolumn>;
_size: number;
_dirty: boolean;
}
/**
* TODO @straversi: document and test this Layout.
*/
export declare class Layout1dFlex extends Layout1dBase<Layout1dFlexConfig> {
private _itemSizes;
private _chunkSize;
private _chunks;
private _aspectRatios;
private _numberOfAspectRatiosMeasured;
protected _idealSize: number | null;
protected _config: Layout1dFlexConfig;
protected _defaultConfig: Layout1dFlexConfig;
listenForChildLoadEvents: boolean;
/**
* TODO graynorton@ Don't hard-code Flickr - probably need a config option
*/
measureChildren: (e: Element, i: unknown) => ItemBox;
set idealSize(px: number | null);
get idealSize(): number | null;
updateItemSizes(sizes: { [key: number]: ItemBox }): void;
_newChunk(): {
_rolumns: never[];
_itemPositions: never[];
_size: number;
_dirty: boolean;
};
_getChunk(idx: number | string): Chunk;
_recordAspectRatio(dims: ItemBox): void;
_getRandomAspectRatio(): Size;
_viewDim2Changed(): void;
_getActiveItems(): void;
_getItemPosition(idx: number): Positions;
_getItemSize(idx: number): Size;
_getNaturalItemDims(idx: number): Size;
_layOutChunk(startIdx: number): Chunk;
_updateLayout(): void;
_updateScrollSize(): void;
}
export {};
//# sourceMappingURL=Layout1dFlex.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dFlex.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dFlex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAC,MAAM,UAAU,CAAC;AAElD,UAAU,kBAAmB,SAAQ,kBAAkB;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,aAAK,qBAAqB,GAAG,kBAAkB,GAAG;IAChD,IAAI,EAAE,KAAI,MAAM,CAAC,EAAE,kBAAkB,KAAK,YAAY,CAAA;CACvD,CAAA;AAED,aAAK,4BAA4B,GAAG,CAAC,MAAM,CAAC,EAAE,kBAAkB,KAAK,qBAAqB,CAAC;AAE3F,eAAO,MAAM,YAAY,EAAE,4BAEjB,CAAC;AAEX,UAAU,MAAM;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,KAAK;IACb,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACjC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAeD;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAChE,OAAO,CAAC,UAAU,CAAmB;IAIrC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,6BAA6B,CAAa;IAClD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,SAAS,CAAC,OAAO,EAAE,kBAAkB,CAAM;IAC3C,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAGzC;IAEH,wBAAwB,UAAQ;IAElC;;OAEG;IACD,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAUvD;IAED,IAAI,SAAS,CAAC,EAAE,eAAA,EAMf;IAED,IAAI,SAAS,kBAEZ;IAED,eAAe,CAAC,KAAK,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAC;IAqB/C,SAAS;;;;;;IAST,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAI9B,kBAAkB,CAAC,IAAI,EAAE,OAAO;IAahC,qBAAqB,IAAI,IAAI;IAa7B,gBAAgB;IAIhB,eAAe;IA2Bf,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IAKxC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM/B,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAStC,YAAY,CAAC,QAAQ,EAAE,MAAM;IA+D7B,aAAa,IAAI,IAAI;IAYrB,iBAAiB;CAOlB"}

View File

@@ -1,264 +0,0 @@
import { Layout1dBase } from "./Layout1dBase";
export const layout1dFlex = (config) =>
Object.assign(
{
type: Layout1dFlex,
},
config
);
/**
* TODO @straversi: document and test this Layout.
*/
export class Layout1dFlex extends Layout1dBase {
constructor() {
super(...arguments);
this._itemSizes = [];
// private _itemPositions: Array<Positions> = [];
// private _rolumnStartIdx: Array<number> = [];
// private _rolumnStartPos: Array<number> = [];
this._chunkSize = null;
this._chunks = [];
this._aspectRatios = {};
this._numberOfAspectRatiosMeasured = 0;
this._idealSize = null;
this._config = {};
this._defaultConfig = Object.assign({}, super._defaultConfig, {
spacing: 0,
idealSize: 200,
});
this.listenForChildLoadEvents = true;
/**
* TODO graynorton@ Don't hard-code Flickr - probably need a config option
*/
this.measureChildren = function (e, i) {
const { naturalWidth, naturalHeight } = e;
if (naturalWidth !== undefined && naturalHeight != undefined) {
return { width: naturalWidth, height: naturalHeight };
}
const { o_width, o_height } = i;
if (o_width !== undefined && o_height !== undefined) {
return { width: o_width, height: o_height };
}
return { width: -1, height: -1 };
};
}
set idealSize(px) {
const _px = Number(px);
if (_px !== this._idealSize) {
this._idealSize = _px;
this._scheduleLayoutUpdate();
}
}
get idealSize() {
return this._idealSize;
}
updateItemSizes(sizes) {
let dirty;
Object.keys(sizes).forEach((key) => {
const n = Number(key);
const chunk = this._getChunk(n);
const dims = sizes[n];
const prevDims = this._itemSizes[n];
if (dims.width && dims.height) {
if (
!prevDims ||
prevDims.width !== dims.width ||
prevDims.height !== dims.height
) {
chunk._dirty = true;
dirty = true;
this._itemSizes[n] = sizes[n];
this._recordAspectRatio(sizes[n]);
}
}
});
if (dirty) {
this._scheduleLayoutUpdate();
}
}
_newChunk() {
return {
["_rolumns"]: [],
_itemPositions: [],
_size: 0,
_dirty: false,
};
}
_getChunk(idx) {
return (
this._chunks[Math.floor(Number(idx) / this._chunkSize)] ||
this._newChunk()
);
}
_recordAspectRatio(dims) {
if (dims.width && dims.height) {
const bucket = Math.round((dims.width / dims.height) * 10) / 10;
if (this._aspectRatios[bucket]) {
this._aspectRatios[bucket]++;
} else {
this._aspectRatios[bucket] = 1;
}
this._numberOfAspectRatiosMeasured++;
}
}
_getRandomAspectRatio() {
if (this._numberOfAspectRatiosMeasured === 0) {
return { width: 1, height: 1 };
}
const n = Math.random() * this._numberOfAspectRatiosMeasured;
const buckets = Object.keys(this._aspectRatios);
let i = -1,
m = 0;
while (m < n && i < buckets.length) {
m += this._aspectRatios[buckets[++i]];
}
return { width: Number(buckets[i]), height: 1 };
}
_viewDim2Changed() {
this._scheduleLayoutUpdate();
}
_getActiveItems() {
const chunk = this._getChunk(0);
if (chunk._rolumns.length === 0) return;
const scrollPos = Math.max(
0,
Math.min(this._scrollPosition, this._scrollSize - this._viewDim1)
);
const min = Math.max(0, scrollPos - this._overhang);
const max = Math.min(
this._scrollSize,
scrollPos + this._viewDim1 + this._overhang
);
const mid = (min + max) / 2;
const estMidRolumn = Math.round(
(mid / this._scrollSize) * chunk._rolumns.length
);
let idx = estMidRolumn;
while (chunk._rolumns[idx]._startPos < min) {
idx++;
}
while (chunk._rolumns[idx]._startPos > min) {
idx--;
}
this._first = chunk._rolumns[idx]._startIdx;
this._physicalMin = chunk._rolumns[idx]._startPos;
let rolumnMax;
while (
(rolumnMax =
chunk._rolumns[idx]._startPos +
chunk._rolumns[idx]._size +
this._spacing * 2) < max
) {
idx++;
}
this._last = chunk._rolumns[idx]._endIdx;
this._physicalMax = rolumnMax;
}
_getItemPosition(idx) {
const chunk = this._getChunk(0);
return chunk._itemPositions[idx];
}
_getItemSize(idx) {
const chunk = this._getChunk(0);
const { width, height } = chunk._itemPositions[idx];
return { width, height };
}
_getNaturalItemDims(idx) {
let itemDims = this._itemSizes[idx];
if (
itemDims === undefined ||
itemDims.width === -1 ||
itemDims.height === -1
) {
itemDims = this._getRandomAspectRatio();
}
return itemDims;
}
_layOutChunk(startIdx) {
const chunk = this._newChunk();
let startPos = this._spacing;
let idx = 0;
let rolumnSize2 = 0;
let lastRatio = Infinity;
const finishRolumn = (lastIdx) => {
const rolumn = {
_startIdx: startIdx,
_endIdx: lastIdx,
_startPos: startPos - this._spacing,
_size: 0,
};
chunk._rolumns.push(rolumn);
let itemStartPos = this._spacing;
for (let i = startIdx; i <= lastIdx; i++) {
const pos = chunk._itemPositions[i];
pos.width = pos.width * lastRatio;
pos.height = pos.height * lastRatio;
pos.left = this._positionDim === "left" ? startPos : itemStartPos;
pos.top = this._positionDim === "top" ? startPos : itemStartPos;
itemStartPos += pos[this._secondarySizeDim] + this._spacing;
}
rolumn._size = chunk._itemPositions[lastIdx][this._sizeDim];
};
while (idx < this._chunkSize) {
const itemDims = this._getNaturalItemDims(idx);
const availableSpace =
this._viewDim2 - this._spacing * (idx - startIdx + 2);
const itemSize = itemDims[this._sizeDim];
const itemSize2 = itemDims[this._secondarySizeDim];
const idealScaleFactor = this._idealSize / itemSize;
const adjItemSize = idealScaleFactor * itemSize;
const adjItemSize2 = idealScaleFactor * itemSize2;
chunk._itemPositions[idx] = {
left: 0,
top: 0,
width: this._sizeDim === "width" ? adjItemSize : adjItemSize2,
height: this._sizeDim === "height" ? adjItemSize : adjItemSize2,
};
const ratio = availableSpace / (rolumnSize2 + adjItemSize2);
if (Math.abs(1 - ratio) > Math.abs(1 - lastRatio)) {
// rolumn is better without adding this item
finishRolumn(idx - 1);
startIdx = idx;
startPos += this._idealSize * lastRatio + this._spacing;
lastRatio = (this._viewDim2 - 2 * this._spacing) / adjItemSize2;
rolumnSize2 = adjItemSize2;
} else {
// add this item and continue
rolumnSize2 += adjItemSize2;
lastRatio = ratio;
}
if (idx === this._chunkSize - 1) {
finishRolumn(idx);
}
idx++;
}
const lastRolumn = chunk._rolumns[chunk._rolumns.length - 1];
chunk._size = lastRolumn._startPos + lastRolumn._size;
return chunk;
}
_updateLayout() {
if (/*this._rolumnStartIdx === undefined ||*/ this._viewDim2 === 0) return;
this._chunkSize = Math.ceil(
(2 * (this._viewDim1 * this._viewDim2)) /
(this._idealSize * this._idealSize)
);
console.log("chunkSize", this._chunkSize);
// TODO: An odd place to do this, need to think through the logistics of getting size info to the layout
// in all cases
// this._itemSizes.length = 100;//this._totalItems;
this._chunks[0] = this._layOutChunk(0);
// TODO (graynorton): This is a hack to force reflow
this._spacingChanged = true;
}
_updateScrollSize() {
const chunk = this._chunks[0];
this._scrollSize =
!chunk || chunk._rolumns.length === 0
? 1
: chunk._size + 2 * this._spacing;
// chunk._rolumns[chunk._rolumns.length - 1]._startPos +
// chunk._itemPositions[chunk._rolumns.length - 1][this._sizeDim] +
// (this._spacing * 2);
}
}
//# sourceMappingURL=Layout1dFlex.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +0,0 @@
import { Layout1dBase } from "./Layout1dBase.js";
/**
* TODO @straversi: document and test this Layout.
*/
export declare abstract class Layout1dGrid<
Config
> extends Layout1dBase<Config> {
protected _rolumns: number;
_viewDim2Changed(): void;
_itemDim2Changed(): void;
_getActiveItems(): void;
_getItemPosition(
idx: number
): {
top: number;
left: number;
};
_updateScrollSize(): void;
}
//# sourceMappingURL=Layout1dGrid.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dGrid.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAE/C;;GAEG;AACH,8BAAsB,YAAY,CAAC,MAAM,CAAE,SAAQ,YAAY,CAAC,MAAM,CAAC;IACrE,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAK;IAO/B,gBAAgB;IAIhB,gBAAgB;IAIhB,eAAe;IAef,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC;IAQ1D,iBAAiB;CAIlB"}

View File

@@ -1,52 +0,0 @@
import { Layout1dBase } from "./Layout1dBase.js";
/**
* TODO @straversi: document and test this Layout.
*/
export class Layout1dGrid extends Layout1dBase {
constructor() {
super(...arguments);
this._rolumns = 1;
}
// constructor(config) {
// super(config);
// this._rolumns = 1;
// }
_viewDim2Changed() {
this._scheduleLayoutUpdate();
}
_itemDim2Changed() {
this._scheduleLayoutUpdate();
}
_getActiveItems() {
const min = Math.max(0, this._scrollPosition - this._overhang);
const max = Math.min(
this._scrollSize,
this._scrollPosition + this._viewDim1 + this._overhang
);
const firstCow = Math.floor(min / this._delta);
const lastCow = Math.ceil(max / this._delta) - 1;
this._first = firstCow * this._rolumns;
this._last = Math.min(
(lastCow + 1) * this._rolumns - 1,
this._totalItems - 1
);
this._physicalMin = this._delta * firstCow;
this._physicalMax = this._delta * (lastCow + 1);
}
_getItemPosition(idx) {
return {
[this._positionDim]:
this._spacing + Math.floor(idx / this._rolumns) * this._delta,
[this._secondaryPositionDim]:
this._spacing +
(idx % this._rolumns) * (this._spacing + this._itemDim2),
};
}
_updateScrollSize() {
this._scrollSize = Math.max(
1,
Math.ceil(this._totalItems / this._rolumns) * this._delta + this._spacing
);
}
}
//# sourceMappingURL=Layout1dGrid.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dGrid.js","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAE/C;;GAEG;AACH,MAAM,OAAgB,YAAqB,SAAQ,YAAoB;IAAvE;;QACY,aAAQ,GAAW,CAAC,CAAC;IA0CjC,CAAC;IAxCC,wBAAwB;IACxB,mBAAmB;IACnB,uBAAuB;IACvB,IAAI;IAEJ,gBAAgB;QACd,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAED,eAAe;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAChB,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QACvC,IAAI,CAAC,KAAK;YACN,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;QAC3C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,gBAAgB,CAAC,GAAW;QAC1B,OAAO;YACL,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM;YAC9E,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC,QAAQ;gBAC3C,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;SACrB,CAAC;IAC9C,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,WAAW;YACZ,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7F,CAAC;CACF","sourcesContent":["import {Layout1dBase} from './Layout1dBase.js';\n\n/**\n * TODO @straversi: document and test this Layout.\n */\nexport abstract class Layout1dGrid<Config> extends Layout1dBase<Config> {\n protected _rolumns: number = 1;\n\n // constructor(config) {\n // super(config);\n // this._rolumns = 1;\n // }\n\n _viewDim2Changed() {\n this._scheduleLayoutUpdate();\n }\n\n _itemDim2Changed() {\n this._scheduleLayoutUpdate();\n }\n\n _getActiveItems() {\n const min = Math.max(0, this._scrollPosition - this._overhang);\n const max = Math.min(\n this._scrollSize,\n this._scrollPosition + this._viewDim1 + this._overhang);\n const firstCow = Math.floor(min / this._delta);\n const lastCow = Math.ceil(max / this._delta) - 1;\n\n this._first = firstCow * this._rolumns;\n this._last =\n Math.min(((lastCow + 1) * this._rolumns) - 1, this._totalItems - 1);\n this._physicalMin = this._delta * firstCow;\n this._physicalMax = this._delta * (lastCow + 1);\n }\n\n _getItemPosition(idx: number): {top: number, left: number} {\n return {\n [this._positionDim]: this._spacing + Math.floor(idx / this._rolumns) * this._delta,\n [this._secondaryPositionDim]: this._spacing +\n ((idx % this._rolumns) * (this._spacing + this._itemDim2))\n } as unknown as {top: number, left: number};\n }\n\n _updateScrollSize() {\n this._scrollSize =\n Math.max(1, Math.ceil(this._totalItems / this._rolumns) * this._delta + this._spacing);\n }\n}\n"]}

View File

@@ -1,8 +0,0 @@
import { Layout1dGrid } from "./Layout1dGrid.js";
import { Layout1dBaseConfig } from "./Layout1dBase.js";
import { ItemBox } from "./Layout";
export declare class Layout1dNaturalSizeGrid extends Layout1dGrid<Layout1dBaseConfig> {
updateItemSizes(sizes: { [key: number]: ItemBox }): void;
_updateLayout(): void;
}
//# sourceMappingURL=Layout1dNaturalSizeGrid.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dNaturalSizeGrid.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dNaturalSizeGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAC,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAC,OAAO,EAAC,MAAM,UAAU,CAAC;AAEjC,qBAAa,uBAAwB,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,eAAe,CAAC,KAAK,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAC;IAQ7C,aAAa;CAYlB"}

View File

@@ -1,23 +0,0 @@
import { Layout1dGrid } from "./Layout1dGrid.js";
export class Layout1dNaturalSizeGrid extends Layout1dGrid {
updateItemSizes(sizes) {
// Assume all items have the same size.
const size = Object.values(sizes)[0];
if (size) {
this.itemSize = size;
}
}
_updateLayout() {
const { _spacing } = this;
this._rolumns = Math.max(1, Math.floor(this._viewDim2 / this._itemDim2));
if (this._rolumns > 1) {
this._spacing =
(this._viewDim2 % (this._rolumns * this._itemDim2)) /
(this._rolumns + 1);
} else {
this._spacing = 0;
}
this._spacingChanged = !(_spacing === this._spacing);
}
}
//# sourceMappingURL=Layout1dNaturalSizeGrid.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dNaturalSizeGrid.js","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dNaturalSizeGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAI/C,MAAM,OAAO,uBAAwB,SAAQ,YAAgC;IACzE,eAAe,CAAC,KAA+B;QAC3C,uCAAuC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;SACtB;IACH,CAAC;IAED,aAAa;QACX,MAAM,EAAC,QAAQ,EAAC,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QACzE,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE;YACrB,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC/D,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;SACzB;aACI;YACH,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;SACnB;QACD,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;CACN","sourcesContent":["import {Layout1dGrid} from './Layout1dGrid.js';\nimport {Layout1dBaseConfig} from './Layout1dBase.js';\nimport {ItemBox} from './Layout';\n\nexport class Layout1dNaturalSizeGrid extends Layout1dGrid<Layout1dBaseConfig> {\n updateItemSizes(sizes: {[key: number]: ItemBox}) {\n // Assume all items have the same size.\n const size = Object.values(sizes)[0];\n if (size) {\n this.itemSize = size;\n }\n }\n \n _updateLayout() {\n const {_spacing} = this;\n this._rolumns = Math.max(1, Math.floor(this._viewDim2 / this._itemDim2));\n if (this._rolumns > 1) {\n this._spacing = (this._viewDim2 % (this._rolumns * this._itemDim2)) /\n (this._rolumns + 1);\n }\n else {\n this._spacing = 0;\n }\n this._spacingChanged = !(_spacing === this._spacing);\n } \n}"]}

View File

@@ -1,22 +0,0 @@
import { Layout1dBaseConfig } from "./Layout1dBase.js";
import { Layout1dGrid } from "./Layout1dGrid.js";
import { Positions } from "./Layout.js";
interface Layout1dSquareGridConfig extends Layout1dBaseConfig {
spacing?: number;
idealSize?: number;
}
declare type Layout1dSquareGridSpecifier = Layout1dSquareGridConfig & {
type: new (config?: Layout1dSquareGridConfig) => Layout1dSquareGrid;
};
declare type Layout1dSquareGridSpecifierFactory = (
config?: Layout1dSquareGridConfig
) => Layout1dSquareGridSpecifier;
export declare const layout1dSquareGrid: Layout1dSquareGridSpecifierFactory;
export declare class Layout1dSquareGrid extends Layout1dGrid<Layout1dSquareGridConfig> {
protected _idealSize: number;
set idealSize(px: number);
_getItemPosition(idx: number): Positions;
_updateLayout(): void;
}
export {};
//# sourceMappingURL=Layout1dSquareGrid.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dSquareGrid.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dSquareGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAEtC,UAAU,wBAAyB,SAAQ,kBAAkB;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,aAAK,2BAA2B,GAAG,wBAAwB,GAAG;IAC5D,IAAI,EAAE,KAAI,MAAM,CAAC,EAAE,wBAAwB,KAAK,kBAAkB,CAAA;CACnE,CAAA;AAED,aAAK,kCAAkC,GAAG,CAAC,MAAM,CAAC,EAAE,wBAAwB,KAAK,2BAA2B,CAAC;AAE7G,eAAO,MAAM,kBAAkB,EAAE,kCAEvB,CAAC;AAEX,qBAAa,kBAAmB,SAAQ,YAAY,CAAC,wBAAwB,CAAC;IAC5E,SAAS,CAAC,UAAU,EAAE,MAAM,CAAO;IASnC,IAAI,SAAS,CAAC,EAAE,EAAE,MAAM,EAKvB;IAED,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IAIxC,aAAa;CASd"}

View File

@@ -1,41 +0,0 @@
import { Layout1dGrid } from "./Layout1dGrid.js";
export const layout1dSquareGrid = (config) =>
Object.assign(
{
type: Layout1dSquareGrid,
},
config
);
export class Layout1dSquareGrid extends Layout1dGrid {
constructor() {
super(...arguments);
this._idealSize = 200;
}
// constructor(config) {
// super(config);
// if (config.idealSize === undefined) {
// this._idealSize = 200;
// }
// }
set idealSize(px) {
if (px !== this._idealSize) {
this._idealSize = px;
this._scheduleLayoutUpdate();
}
}
_getItemPosition(idx) {
return Object.assign(super._getItemPosition(idx), this._itemSize);
}
_updateLayout() {
const frolumns = this._viewDim2 / this._idealSize;
this._rolumns =
frolumns % 1 < 0.5 ? Math.floor(frolumns) : Math.ceil(frolumns);
const adjSize =
(this._viewDim2 - (this._rolumns + 1) * this._spacing) / this._rolumns;
if (adjSize !== this._itemSize.width) {
this._itemSize = { width: adjSize, height: adjSize };
this._spacingChanged = true;
}
}
}
//# sourceMappingURL=Layout1dSquareGrid.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Layout1dSquareGrid.js","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/layouts/Layout1dSquareGrid.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAc/C,MAAM,CAAC,MAAM,kBAAkB,GAAuC,CAAC,MAAiC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;IACzH,IAAI,EAAE,kBAAkB;CACzB,EAAE,MAAM,CAAC,CAAC;AAEX,MAAM,OAAO,kBAAmB,SAAQ,YAAsC;IAA9E;;QACY,eAAU,GAAW,GAAG,CAAC;IA6BrC,CAAC;IA3BC,wBAAwB;IACxB,mBAAmB;IACnB,0CAA0C;IAC1C,+BAA+B;IAC/B,MAAM;IACN,IAAI;IAEJ,IAAI,SAAS,CAAC,EAAU;QACtB,IAAI,EAAE,KAAK,IAAI,CAAC,UAAU,EAAE;YAC1B,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,qBAAqB,EAAE,CAAC;SAC9B;IACH,CAAC;IAED,gBAAgB,CAAC,GAAW;QAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACpE,CAAC;IAED,aAAa;QACX,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC;QAClD,IAAI,CAAC,QAAQ,GAAG,QAAQ,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChF,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QACzF,IAAI,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;YACpC,IAAI,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;YACrD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;SAC7B;IACH,CAAC;CACF","sourcesContent":["import {Layout1dBaseConfig} from './Layout1dBase.js';\nimport {Layout1dGrid} from './Layout1dGrid.js';\nimport {Positions} from './Layout.js';\n\ninterface Layout1dSquareGridConfig extends Layout1dBaseConfig {\n spacing?: number,\n idealSize?: number\n}\n\ntype Layout1dSquareGridSpecifier = Layout1dSquareGridConfig & {\n type: new(config?: Layout1dSquareGridConfig) => Layout1dSquareGrid\n}\n\ntype Layout1dSquareGridSpecifierFactory = (config?: Layout1dSquareGridConfig) => Layout1dSquareGridSpecifier;\n\nexport const layout1dSquareGrid: Layout1dSquareGridSpecifierFactory = (config?: Layout1dSquareGridConfig) => Object.assign({\n type: Layout1dSquareGrid\n}, config);\n\nexport class Layout1dSquareGrid extends Layout1dGrid<Layout1dSquareGridConfig> {\n protected _idealSize: number = 200;\n\n // constructor(config) {\n // super(config);\n // if (config.idealSize === undefined) {\n // this._idealSize = 200;\n // }\n // }\n\n set idealSize(px: number) {\n if (px !== this._idealSize) {\n this._idealSize = px;\n this._scheduleLayoutUpdate();\n }\n }\n\n _getItemPosition(idx: number): Positions {\n return Object.assign(super._getItemPosition(idx), this._itemSize);\n }\n\n _updateLayout() {\n const frolumns = this._viewDim2 / this._idealSize;\n this._rolumns = frolumns % 1 < 0.5 ? Math.floor(frolumns) : Math.ceil(frolumns);\n const adjSize = (this._viewDim2 - ((this._rolumns + 1) * this._spacing)) / this._rolumns;\n if (adjSize !== this._itemSize.width) {\n this._itemSize = { width: adjSize, height: adjSize };\n this._spacingChanged = true;\n }\n } \n}"]}

View File

@@ -1,6 +0,0 @@
interface EventTargetConstructor {
new (): EventTarget;
}
export default function EventTarget(): Promise<EventTargetConstructor>;
export {};
//# sourceMappingURL=EventTarget.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"EventTarget.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.ts"],"names":[],"mappings":"AAEA,UAAU,sBAAsB;IAC5B,QAAO,WAAW,CAAA;CACrB;AAKD,wBAA8B,WAAW,oCAExC"}

View File

@@ -1,15 +0,0 @@
let _ET;
let ET;
export default async function EventTarget() {
return ET || init();
}
async function init() {
_ET = window.EventTarget;
try {
new _ET();
} catch (_a) {
_ET = (await import("event-target-shim")).EventTarget;
}
return (ET = _ET);
}
//# sourceMappingURL=EventTarget.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"EventTarget.js","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.ts"],"names":[],"mappings":"AAMA,IAAI,GAA+C,CAAC;AACpD,IAAI,EAA0B,CAAC;AAE/B,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,WAAW;IACrC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,IAAI;IACf,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;IACzB,IAAI;QACA,IAAI,GAAG,EAAE,CAAC;KACb;IACD,WAAM;QACF,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,WAAW,CAAC;KACzD;IACD,OAAO,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;AACtB,CAAC","sourcesContent":["type EventTargetModule = typeof import('event-target-shim');\n\ninterface EventTargetConstructor {\n new(): EventTarget\n}\n\nlet _ET: EventTargetModule | EventTargetConstructor;\nlet ET: EventTargetConstructor;\n\nexport default async function EventTarget() {\n return ET || init();\n}\n\nasync function init() {\n _ET = window.EventTarget;\n try {\n new _ET();\n }\n catch {\n _ET = (await import('event-target-shim')).EventTarget;\n }\n return (ET = _ET);\n}"]}

View File

@@ -1,3 +0,0 @@
import { ResizeObserverConstructor } from "../polyfills/resize-observer-polyfill/ResizeObserver.js";
export default function ResizeObserver(): Promise<ResizeObserverConstructor>;
//# sourceMappingURL=ResizeObserver.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"ResizeObserver.d.ts","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/polyfillLoaders/ResizeObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,yDAAyD,CAAC;AAMpG,wBAA8B,cAAc,uCAE3C"}

View File

@@ -1,20 +0,0 @@
let _RO;
let RO;
export default async function ResizeObserver() {
return RO || init();
}
async function init() {
if (_RO) {
return (await _RO).default;
} else {
_RO = window.ResizeObserver;
try {
new _RO(function () {});
} catch (e) {
_RO = import("../polyfills/resize-observer-polyfill/ResizeObserver.js");
_RO = (await _RO).default;
}
return (RO = _RO);
}
}
//# sourceMappingURL=ResizeObserver.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"ResizeObserver.js","sourceRoot":"","sources":["../../../../src/lib/uni-virtualizer/lib/polyfillLoaders/ResizeObserver.ts"],"names":[],"mappings":"AAGA,IAAI,GAAqD,CAAC;AAC1D,IAAI,EAA6B,CAAC;AAElC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,cAAc;IACxC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,IAAI;IACf,IAAI,GAAG,EAAE;QACL,OAAO,CAAC,MAAM,GAA4B,CAAA,CAAC,OAAO,CAAC;KACtD;SACI;QACD,GAAG,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5B,IAAI;YACA,IAAI,GAAG,CAAC,cAAY,CAAC,CAAC,CAAC;SAC1B;QACD,OAAO,CAAC,EAAE;YACN,GAAG,GAAG,MAAM,CAAC,yDAAyD,CAAoC,CAAC;YAC3G,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;SAC7B;QACD,OAAO,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;KACrB;AACL,CAAC","sourcesContent":["import { ResizeObserverConstructor } from '../polyfills/resize-observer-polyfill/ResizeObserver.js';\ntype ResizeObserverModule = typeof import('../polyfills/resize-observer-polyfill/ResizeObserver.js');\n\nlet _RO: ResizeObserverModule | ResizeObserverConstructor;\nlet RO: ResizeObserverConstructor;\n\nexport default async function ResizeObserver() {\n return RO || init();\n}\n\nasync function init() {\n if (_RO) {\n return (await _RO as ResizeObserverModule).default;\n }\n else {\n _RO = window.ResizeObserver;\n try {\n new _RO(function() {});\n }\n catch (e) {\n _RO = import('../polyfills/resize-observer-polyfill/ResizeObserver.js') as unknown as ResizeObserverModule;\n _RO = (await _RO).default;\n }\n return (RO = _RO); \n }\n}"]}

View File

@@ -1,960 +0,0 @@
/**
* Detects whether window and document objects are available in current environment.
*/
var isBrowser =
typeof window !== "undefined" &&
typeof document !== "undefined" &&
window.document === document;
// Returns global object of a current environment.
var global$1 = (function () {
if (typeof global !== "undefined" && global.Math === Math) {
return global;
}
if (typeof self !== "undefined" && self.Math === Math) {
return self;
}
if (typeof window !== "undefined" && window.Math === Math) {
return window;
}
// eslint-disable-next-line no-new-func
return Function("return this")();
})();
/**
* A shim for the requestAnimationFrame which falls back to the setTimeout if
* first one is not supported.
*
* @returns {number} Requests' identifier.
*/
var requestAnimationFrame$1 = (function () {
if (typeof requestAnimationFrame === "function") {
// It's required to use a bounded function because IE sometimes throws
// an "Invalid calling object" error if rAF is invoked without the global
// object on the left hand side.
return requestAnimationFrame.bind(global$1);
}
var result = function (callback) {
return setTimeout(function () {
callback(+Date.now());
}, 1000 / 60);
};
return result;
})();
// Defines minimum timeout before adding a trailing call.
var trailingTimeout = 2;
/**
* Creates a wrapper function which ensures that provided callback will be
* invoked only once during the specified delay period.
*
* @param callback - Function to be invoked after the delay period.
* @param delay - Delay after which to invoke callback.
*/
function throttle(callback, delay) {
var leadingCall = false,
trailingCall = false,
lastCallTime = 0;
/**
* Invokes the original callback function and schedules new invocation if
* the "proxy" was called during current request.
*/
function resolvePending() {
if (leadingCall) {
leadingCall = false;
callback();
}
if (trailingCall) {
proxy();
}
}
/**
* Callback invoked after the specified delay. It will further postpone
* invocation of the original function delegating it to the
* requestAnimationFrame.
*
* @returns {void}
*/
function timeoutCallback() {
requestAnimationFrame$1(resolvePending);
}
/**
* Schedules invocation of the original function.
*/
function proxy() {
var timeStamp = Date.now();
if (leadingCall) {
// Reject immediately following calls.
if (timeStamp - lastCallTime < trailingTimeout) {
return;
}
// Schedule new call to be in invoked when the pending one is resolved.
// This is important for "transitions" which never actually start
// immediately so there is a chance that we might miss one if change
// happens amids the pending invocation.
trailingCall = true;
} else {
leadingCall = true;
trailingCall = false;
setTimeout(timeoutCallback, delay);
}
lastCallTime = timeStamp;
}
return proxy;
}
// Minimum delay before invoking the update of observers.
var REFRESH_DELAY = 20;
// A list of substrings of CSS properties used to find transition events that
// might affect dimensions of observed elements.
var transitionKeys = [
"top",
"right",
"bottom",
"left",
"width",
"height",
"size",
"weight",
];
// Check if MutationObserver is available.
var mutationObserverSupported = typeof MutationObserver !== "undefined";
// Get the native implementation of HTMLElement.attachShadow
var origAttachShadow =
isBrowser &&
HTMLElement.prototype.attachShadow &&
HTMLElement.prototype.attachShadow.toString().indexOf("[native code]") !== -1
? HTMLElement.prototype.attachShadow
: null;
/**
* Singleton controller class which handles updates of ResizeObserver instances.
*/
var ResizeObserverController = /** @class */ (function () {
/**
* Creates a new instance of ResizeObserverController.
*/
function ResizeObserverController() {
/**
* Indicates whether DOM listeners have been added.
*/
this.connected_ = false;
/**
* Tells that controller has subscribed for Mutation Events.
*/
this.mutationEventsAdded_ = false;
/**
* Keeps reference to the instance of MutationObserver.
*/
this.mutationsObserver_ = null;
/**
* A list of connected observers.
*/
this.observers_ = [];
this.onTransitionEnd_ = this.onTransitionEnd_.bind(this);
this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY);
}
/**
* Adds observer to observers list.
*
* @param observer Observer to be added.
*/
ResizeObserverController.prototype.addObserver = function (observer) {
if (!~this.observers_.indexOf(observer)) {
this.observers_.push(observer);
}
// Add listeners if they haven't been added yet.
if (!this.connected_) {
this.connect_();
}
};
/**
* Removes observer from observers list.
*
* @param observer Observer to be removed.
*/
ResizeObserverController.prototype.removeObserver = function (observer) {
var observers = this.observers_;
var index = observers.indexOf(observer);
// Remove observer if it's present in registry.
if (~index) {
observers.splice(index, 1);
}
// Remove listeners if controller has no connected observers.
if (!observers.length && this.connected_) {
this.disconnect_();
}
};
/**
* Invokes the update of observers. It will continue running updates insofar
* it detects changes.
*/
ResizeObserverController.prototype.refresh = function () {
var changesDetected = this.updateObservers_();
// Continue running updates if changes have been detected as there might
// be future ones caused by CSS transitions.
if (changesDetected) {
this.refresh();
}
};
/**
* Updates every observer from observers list and notifies them of queued
* entries.
*
* @returns Returns "true" if any observer has detected changes in
* dimensions of it's elements.
*/
ResizeObserverController.prototype.updateObservers_ = function () {
// Collect observers that have active observations.
var activeObservers = this.observers_.filter(function (observer) {
return observer.gatherActive(), observer.hasActive();
});
// Deliver notifications in a separate cycle in order to avoid any
// collisions between observers, e.g. when multiple instances of
// ResizeObserver are tracking the same element and the callback of one
// of them changes content dimensions of the observed target. Sometimes
// this may result in notifications being blocked for the rest of observers.
activeObservers.forEach(function (observer) {
return observer.broadcastActive();
});
return activeObservers.length > 0;
};
/**
* Initializes DOM listeners.
*/
ResizeObserverController.prototype.connect_ = function () {
// Do nothing if running in a non-browser environment or if listeners
// have been already added.
if (!isBrowser || this.connected_) {
return;
}
// Subscription to the "Transitionend" event is used as a workaround for
// delayed transitions. This way it's possible to capture at least the
// final state of an element.
document.addEventListener("transitionend", this.onTransitionEnd_);
window.addEventListener("resize", this.refresh);
if (mutationObserverSupported) {
this.mutationsObserver_ = new MutationObserver(this.refresh);
var options_1 = {
attributes: true,
childList: true,
characterData: true,
subtree: true,
};
this.mutationsObserver_.observe(document, options_1);
if (origAttachShadow) {
var controller_1 = this;
(function observeExistingShadowRoots(node) {
var shadowRoot = node.shadowRoot;
if (shadowRoot) {
controller_1.mutationsObserver_.observe(shadowRoot, options_1);
observeExistingShadowRoots(shadowRoot);
}
var child = node.firstElementChild;
while (child) {
observeExistingShadowRoots(child);
child = child.nextElementSibling;
}
})(document);
HTMLElement.prototype.attachShadow = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var shadowRoot = origAttachShadow.apply(this, args);
controller_1.mutationsObserver_.observe(shadowRoot, options_1);
return shadowRoot;
};
}
} else {
document.addEventListener("DOMSubtreeModified", this.refresh);
this.mutationEventsAdded_ = true;
}
this.connected_ = true;
};
/**
* Removes DOM listeners.
*/
ResizeObserverController.prototype.disconnect_ = function () {
// Do nothing if running in a non-browser environment or if listeners
// have been already removed.
if (!isBrowser || !this.connected_) {
return;
}
document.removeEventListener("transitionend", this.onTransitionEnd_);
window.removeEventListener("resize", this.refresh);
if (this.mutationsObserver_) {
this.mutationsObserver_.disconnect();
if (origAttachShadow) {
HTMLElement.prototype.attachShadow = origAttachShadow;
}
}
if (this.mutationEventsAdded_) {
document.removeEventListener("DOMSubtreeModified", this.refresh);
}
this.mutationsObserver_ = null;
this.mutationEventsAdded_ = false;
this.connected_ = false;
};
/**
* "Transitionend" event handler.
*/
ResizeObserverController.prototype.onTransitionEnd_ = function (_a) {
var _b = _a.propertyName,
propertyName = _b === void 0 ? "" : _b;
// Detect whether transition may affect dimensions of an element.
var isReflowProperty = transitionKeys.some(function (key) {
return !!~propertyName.indexOf(key);
});
if (isReflowProperty) {
this.refresh();
}
};
/**
* Returns instance of the ResizeObserverController.
*/
ResizeObserverController.getInstance = function () {
if (!ResizeObserverController.instance_) {
ResizeObserverController.instance_ = new ResizeObserverController();
}
return ResizeObserverController.instance_;
};
/**
* Holds reference to the controller's instance.
*/
ResizeObserverController.instance_ = null;
return ResizeObserverController;
})();
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
function __values(o) {
var m = typeof Symbol === "function" && o[Symbol.iterator],
i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
},
};
}
/**
* Defines non-writable/enumerable properties of the provided target object.
*
* @param target Object for which to define properties.
* @param props Properties to be defined.
* @returns Target object.
*/
var defineConfigurable = function (target, props) {
var e_1, _a;
try {
for (
var _b = __values(Object.keys(props)), _c = _b.next();
!_c.done;
_c = _b.next()
) {
var key = _c.value;
Object.defineProperty(target, key, {
value: props[key],
enumerable: false,
writable: false,
configurable: true,
});
}
} catch (e_1_1) {
e_1 = { error: e_1_1 };
} finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
} finally {
if (e_1) throw e_1.error;
}
}
return target;
};
/**
* Returns the global object associated with provided element.
*
* @param {EventT} target
* @returns {Object}
*/
var getWindowOf = function (target) {
var _a;
// Assume that the element is an instance of Node, which means that it
// has the "ownerDocument" property from which we can retrieve a
// corresponding global object.
// Return the local global object if it's not possible extract one from
// provided element.
return (
((_a =
target === null || target === void 0 ? void 0 : target.ownerDocument) ===
null || _a === void 0
? void 0
: _a.defaultView) || global$1
);
};
// Placeholder of an empty content rectangle.
var emptyRect = createRectInit(0, 0, 0, 0);
/**
* Converts provided string to a number.
*/
function toFloat(value) {
if (typeof value === "number") {
return value;
}
return parseFloat(value) || 0;
}
/**
* Extracts borders size from provided styles.
*/
function getBordersSize(styles) {
var positions = [];
for (var _i = 1; _i < arguments.length; _i++) {
positions[_i - 1] = arguments[_i];
}
return positions.reduce(function (size, position) {
var value = styles["border-" + position + "-width"];
return size + toFloat(value);
}, 0);
}
/**
* Extracts paddings sizes from provided styles.
*/
function getPaddings(styles) {
var st = styles;
return {
top: toFloat(st["padding-top"]),
right: toFloat(st["padding-right"]),
bottom: toFloat(st["padding-bottom"]),
left: toFloat(st["padding-left"]),
};
}
/**
* Calculates content rectangle of provided SVG element.
*
* @param target Element content rectangle of which needs to be calculated.
*/
function getSVGContentRect(target) {
var bbox = target.getBBox();
return createRectInit(0, 0, bbox.width, bbox.height);
}
/**
* Calculates content rectangle of provided HTMLElement.
*
* @param target Element for which to calculate the content rectangle.
*/
function getHTMLElementContentRect(target) {
// Client width & height properties can't be
// used exclusively as they provide rounded values.
var clientWidth = target.clientWidth,
clientHeight = target.clientHeight;
// By this condition we can catch all non-replaced inline, hidden and
// detached elements. Though elements with width & height properties less
// than 0.5 will be discarded as well.
//
// Without it we would need to implement separate methods for each of
// those cases and it's not possible to perform a precise and performance
// effective test for hidden elements. E.g. even jQuery's ':visible' filter
// gives wrong results for elements with width & height less than 0.5.
if (!clientWidth && !clientHeight) {
return emptyRect;
}
var styles = getWindowOf(target).getComputedStyle(target);
var paddings = getPaddings(styles);
var horizPad = paddings.left + paddings.right;
var vertPad = paddings.top + paddings.bottom;
// Computed styles of width & height are being used because they are the
// only dimensions available to JS that contain non-rounded values. It could
// be possible to utilize the getBoundingClientRect if only it's data wasn't
// affected by CSS transformations let alone paddings, borders and scroll
// bars.
var width = toFloat(styles.width),
height = toFloat(styles.height);
// Width & height include paddings and borders when the 'border-box' box
// model is applied (except for IE).
if (styles.boxSizing === "border-box") {
// Following conditions are required to handle Internet Explorer which
// doesn't include paddings and borders to computed CSS dimensions.
//
// We can say that if CSS dimensions + paddings are equal to the "client"
// properties then it's either IE, and thus we don't need to subtract
// anything, or an element merely doesn't have paddings/borders styles.
if (Math.round(width + horizPad) !== clientWidth) {
width -= getBordersSize(styles, "left", "right") + horizPad;
}
if (Math.round(height + vertPad) !== clientHeight) {
height -= getBordersSize(styles, "top", "bottom") + vertPad;
}
}
// Following steps can't be applied to the document's root element as its
// client[Width/Height] properties represent viewport area of the window.
// Besides, it's as well not necessary as the <html> itself neither has
// rendered scroll bars nor it can be clipped.
if (!isDocumentElement(target)) {
// In some browsers (only in Firefox, actually) CSS width & height
// include scroll bars size which can be removed at this step as scroll
// bars are the only difference between rounded dimensions + paddings
// and "client" properties, though that is not always true in Chrome.
var vertScrollbar = Math.round(width + horizPad) - clientWidth;
var horizScrollbar = Math.round(height + vertPad) - clientHeight;
// Chrome has a rather weird rounding of "client" properties.
// E.g. for an element with content width of 314.2px it sometimes gives
// the client width of 315px and for the width of 314.7px it may give
// 314px. And it doesn't happen all the time. So just ignore this delta
// as a non-relevant.
if (Math.abs(vertScrollbar) !== 1) {
width -= vertScrollbar;
}
if (Math.abs(horizScrollbar) !== 1) {
height -= horizScrollbar;
}
}
return createRectInit(paddings.left, paddings.top, width, height);
}
/**
* Checks whether provided element is an instance of the SVGGraphicsElement.
*
* @param target Element to be checked.
*/
var isSVGGraphicsElement = (function () {
// Some browsers, namely IE and Edge, don't have the SVGGraphicsElement
// interface.
if (typeof SVGGraphicsElement !== "undefined") {
return function (target) {
return target instanceof getWindowOf(target).SVGGraphicsElement;
};
}
// If it's so, then check that element is at least an instance of the
// SVGElement and that it has the "getBBox" method.
// eslint-disable-next-line no-extra-parens
return function (target) {
return (
target instanceof getWindowOf(target).SVGElement &&
typeof target.getBBox === "function"
);
};
})();
/**
* Checks whether provided element is a document element (<html>).
*
* @param target Element to be checked.
*/
function isDocumentElement(target) {
return target === getWindowOf(target).document.documentElement;
}
/**
* Calculates an appropriate content rectangle for provided html or svg element.
*
* @param target Element content rectangle of which needs to be calculated.
*/
function getContentRect(target) {
if (!isBrowser) {
return emptyRect;
}
if (isSVGGraphicsElement(target)) {
return getSVGContentRect(target);
}
return getHTMLElementContentRect(target);
}
/**
* Creates rectangle with an interface of the DOMRectReadOnly.
* Spec: https://drafts.fxtf.org/geometry/#domrectreadonly
*
* @param rectInit Object with rectangle's x/y coordinates and
* dimensions.
*/
function createReadOnlyRect(_a) {
var x = _a.x,
y = _a.y,
width = _a.width,
height = _a.height;
// If DOMRectReadOnly is available use it as a prototype for the rectangle.
var Constr =
typeof DOMRectReadOnly !== "undefined" ? DOMRectReadOnly : Object;
var rect = Object.create(Constr.prototype);
// Rectangle's properties are not writable and non-enumerable.
defineConfigurable(rect, {
x: x,
y: y,
width: width,
height: height,
top: y,
right: x + width,
bottom: height + y,
left: x,
});
return rect;
}
/**
* Creates DOMRectInit object based on the provided dimensions and the x/y
* coordinates. Spec: https://drafts.fxtf.org/geometry/#dictdef-domrectinit
*
* @param x X coordinate.
* @param y Y coordinate.
* @param width Rectangle's width.
* @param height Rectangle's height.
*/
function createRectInit(x, y, width, height) {
return { x: x, y: y, width: width, height: height };
}
/**
* Class that is responsible for computations of the content rectangle of
* provided DOM element and for keeping track of it's changes.
*/
var ResizeObservation = /** @class */ (function () {
/**
* Creates an instance of ResizeObservation.
*
* @param target Element to be observed.
*/
function ResizeObservation(target) {
/**
* Broadcasted width of content rectangle.
*/
this.broadcastWidth = 0;
/**
* Broadcasted height of content rectangle.
*/
this.broadcastHeight = 0;
/**
* Reference to the last observed content rectangle.
*/
this.contentRect_ = createRectInit(0, 0, 0, 0);
this.target = target;
}
/**
* Updates content rectangle and tells whether it's width or height properties
* have changed since the last broadcast.
*/
ResizeObservation.prototype.isActive = function () {
var rect = getContentRect(this.target);
this.contentRect_ = rect;
return (
rect.width !== this.broadcastWidth || rect.height !== this.broadcastHeight
);
};
/**
* Updates 'broadcastWidth' and 'broadcastHeight' properties with a data
* from the corresponding properties of the last observed content rectangle.
*
* @returns Last observed content rectangle.
*/
ResizeObservation.prototype.broadcastRect = function () {
var rect = this.contentRect_;
this.broadcastWidth = rect.width;
this.broadcastHeight = rect.height;
return rect;
};
return ResizeObservation;
})();
var ResizeObserverEntry = /** @class */ (function () {
/**
* Creates an instance of ResizeObserverEntry.
*
* @param target Element that is being observed.
* @param rectInit Data of the element's content rectangle.
*/
function ResizeObserverEntry(target, rectInit) {
var contentRect = createReadOnlyRect(rectInit);
// According to the specification following properties are not writable
// and are also not enumerable in the native implementation.
//
// Property accessors are not being used as they'd require to define a
// private WeakMap storage which may cause memory leaks in browsers that
// don't support this type of collections.
defineConfigurable(this, { target: target, contentRect: contentRect });
}
return ResizeObserverEntry;
})();
/**
* A collection of shims that provide minimal functionality of the ES6
* collections.
*
* These implementations are not meant to be used outside of the ResizeObserver
* modules as they cover only a limited range of use cases.
*/
/* eslint-disable require-jsdoc, valid-jsdoc */
var MapShim = (function () {
if (typeof Map !== "undefined") {
return Map;
}
/**
* Returns index in provided array that matches the specified key.
*/
function getIndex(arr, key) {
var result = -1;
arr.some(function (entry, index) {
if (entry[0] === key) {
result = index;
return true;
}
return false;
});
return result;
}
return /** @class */ (function () {
function class_1() {
this.__entries__ = [];
}
Object.defineProperty(class_1.prototype, "size", {
get: function () {
return this.__entries__.length;
},
enumerable: true,
configurable: true,
});
class_1.prototype.get = function (key) {
var _a;
var index = getIndex(this.__entries__, key);
return (_a = this.__entries__[index]) === null || _a === void 0
? void 0
: _a[1];
};
class_1.prototype.set = function (key, value) {
var index = getIndex(this.__entries__, key);
if (~index) {
this.__entries__[index][1] = value;
} else {
this.__entries__.push([key, value]);
}
};
class_1.prototype.delete = function (key) {
var entries = this.__entries__;
var index = getIndex(entries, key);
if (~index) {
entries.splice(index, 1);
}
};
class_1.prototype.has = function (key) {
return !!~getIndex(this.__entries__, key);
};
class_1.prototype.clear = function () {
this.__entries__.splice(0);
};
class_1.prototype.forEach = function (callback, ctx) {
var e_1, _a;
if (ctx === void 0) {
ctx = null;
}
try {
for (
var _b = __values(this.__entries__), _c = _b.next();
!_c.done;
_c = _b.next()
) {
var entry = _c.value;
callback.call(ctx, entry[1], entry[0]);
}
} catch (e_1_1) {
e_1 = { error: e_1_1 };
} finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
} finally {
if (e_1) throw e_1.error;
}
}
};
return class_1;
})();
})();
var ResizeObserverSPI = /** @class */ (function () {
/**
* Creates a new instance of ResizeObserver.
*
* @param callback Callback function that is invoked when one of the observed
* elements changes it's content dimensions.
* @param controller Controller instance which is responsible for the updates
* of observer.
* @param callbackCtx Reference to the public ResizeObserver instance which
* will be passed to callback function.
*/
function ResizeObserverSPI(callback, controller, callbackCtx) {
/**
* Collection of resize observations that have detected changes in dimensions
* of elements.
*/
this.activeObservations_ = [];
/**
* Registry of the ResizeObservation instances.
*/
this.observations_ = new MapShim();
if (typeof callback !== "function") {
throw new TypeError(
"The callback provided as parameter 1 is not a function."
);
}
this.callback_ = callback;
this.controller_ = controller;
this.callbackCtx_ = callbackCtx;
}
/**
* Starts observing provided element.
*
* @param target Element to be observed.
*/
ResizeObserverSPI.prototype.observe = function (target) {
if (target === undefined) {
throw new TypeError("1 argument required, but only 0 present.");
}
// Do nothing if current environment doesn't have the Element interface.
if (typeof Element === "undefined" || !(Element instanceof Object)) {
return;
}
if (!(target instanceof getWindowOf(target).Element)) {
throw new TypeError('parameter 1 is not of type "Element".');
}
var observations = this.observations_;
// Do nothing if element is already being observed.
if (observations.has(target)) {
return;
}
observations.set(target, new ResizeObservation(target));
this.controller_.addObserver(this);
// Force the update of observations.
this.controller_.refresh();
};
/**
* Stops observing provided element.
*
* @param target Element to stop observing.
*/
ResizeObserverSPI.prototype.unobserve = function (target) {
if (target === undefined) {
throw new TypeError("1 argument required, but only 0 present.");
}
// Do nothing if current environment doesn't have the Element interface.
if (typeof Element === "undefined" || !(Element instanceof Object)) {
return;
}
if (!(target instanceof getWindowOf(target).Element)) {
throw new TypeError('parameter 1 is not of type "Element".');
}
var observations = this.observations_;
// Do nothing if element is not being observed.
if (!observations.has(target)) {
return;
}
observations.delete(target);
if (!observations.size) {
this.controller_.removeObserver(this);
}
};
/**
* Stops observing all elements.
*/
ResizeObserverSPI.prototype.disconnect = function () {
this.clearActive();
this.observations_.clear();
this.controller_.removeObserver(this);
};
/**
* Collects observation instances the associated element of which has changed
* it's content rectangle.
*/
ResizeObserverSPI.prototype.gatherActive = function () {
var _this = this;
this.clearActive();
this.observations_.forEach(function (observation) {
if (observation.isActive()) {
_this.activeObservations_.push(observation);
}
});
};
/**
* Invokes initial callback function with a list of ResizeObserverEntry
* instances collected from active resize observations.
*/
ResizeObserverSPI.prototype.broadcastActive = function () {
// Do nothing if observer doesn't have active observations.
if (!this.hasActive()) {
return;
}
var ctx = this.callbackCtx_;
// Create ResizeObserverEntry instance for every active observation.
var entries = this.activeObservations_.map(function (observation) {
return new ResizeObserverEntry(
observation.target,
observation.broadcastRect()
);
});
this.callback_.call(ctx, entries, ctx);
this.clearActive();
};
/**
* Clears the collection of active observations.
*/
ResizeObserverSPI.prototype.clearActive = function () {
this.activeObservations_.splice(0);
};
/**
* Tells whether observer has active observations.
*/
ResizeObserverSPI.prototype.hasActive = function () {
return this.activeObservations_.length > 0;
};
return ResizeObserverSPI;
})();
/**
* ResizeObserver API. Encapsulates the ResizeObserver SPI implementation
* exposing only those methods and properties that are defined in the spec.
*/
var ResizeObserver = /** @class */ (function () {
/**
* Creates a new instance of ResizeObserver.
*
* @param callback Callback that is invoked when dimensions of the observed
* elements change.
*/
function ResizeObserver(callback) {
if (!(this instanceof ResizeObserver)) {
throw new TypeError("Cannot call a class as a function.");
}
if (!arguments.length) {
throw new TypeError("1 argument required, but only 0 present.");
}
var controller = ResizeObserverController.getInstance();
this.observer_ = new ResizeObserverSPI(callback, controller, this);
}
ResizeObserver.prototype.observe = function (target) {
this.observer_.observe(target);
};
ResizeObserver.prototype.unobserve = function (target) {
this.observer_.unobserve(target);
};
ResizeObserver.prototype.disconnect = function () {
this.observer_.disconnect();
};
return ResizeObserver;
})();
var index = (function () {
// Export existing implementation if available.
if (typeof global$1.ResizeObserver !== "undefined") {
return global$1.ResizeObserver;
}
return ResizeObserver;
})();
export default index;

View File

@@ -1,8 +0,0 @@
export {
VirtualScroller,
RangeChangeEvent,
scrollerRef,
} from "./lib/VirtualScroller.js";
export { Layout1d, layout1d } from "./lib/layouts/Layout1d.js";
export { Layout1dGrid } from "./lib/layouts/Layout1dGrid.js";
//# sourceMappingURL=uni-virtualizer.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"uni-virtualizer.d.ts","sourceRoot":"","sources":["../../src/lib/uni-virtualizer/uni-virtualizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC"}

View File

@@ -1,4 +0,0 @@
export { VirtualScroller, scrollerRef } from "./lib/VirtualScroller.js";
export { Layout1d, layout1d } from "./lib/layouts/Layout1d.js";
export { Layout1dGrid } from "./lib/layouts/Layout1dGrid.js";
//# sourceMappingURL=uni-virtualizer.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"uni-virtualizer.js","sourceRoot":"","sources":["../../src/lib/uni-virtualizer/uni-virtualizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAoB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC","sourcesContent":["export { VirtualScroller, RangeChangeEvent, scrollerRef } from './lib/VirtualScroller.js';\n\nexport { Layout1d, layout1d } from './lib/layouts/Layout1d.js';\nexport { Layout1dGrid } from './lib/layouts/Layout1dGrid.js';\n"]}

View File

@@ -1,10 +0,0 @@
export { scroll } from "./lib/scroll.js";
export {
Layout1d,
layout1d,
Layout1dGrid,
RangeChangeEvent,
scrollerRef,
} from "./lib/uni-virtualizer/uni-virtualizer.js";
export { LitVirtualizer } from "./lib/lit-virtualizer.js";
//# sourceMappingURL=lit-virtualizer.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"lit-virtualizer.d.ts","sourceRoot":"","sources":["src/lit-virtualizer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAC3H,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC"}

View File

@@ -1,10 +0,0 @@
// export { repeat } from './lib/repeat.js';
export { scroll } from "./lib/scroll.js";
export {
Layout1d,
layout1d,
Layout1dGrid,
scrollerRef,
} from "./lib/uni-virtualizer/uni-virtualizer.js";
export { LitVirtualizer } from "./lib/lit-virtualizer.js";
//# sourceMappingURL=lit-virtualizer.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"lit-virtualizer.js","sourceRoot":"","sources":["src/lit-virtualizer.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAoB,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAC3H,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["// export { repeat } from './lib/repeat.js';\nexport { scroll } from './lib/scroll.js';\nexport { Layout1d, layout1d, Layout1dGrid, RangeChangeEvent, scrollerRef } from './lib/uni-virtualizer/uni-virtualizer.js';\nexport { LitVirtualizer } from './lib/lit-virtualizer.js';\n"]}

View File

@@ -1,55 +0,0 @@
{
"name": "@lit-labs/virtualizer",
"version": "0.7.0",
"description": "Virtual scrolling for Lit",
"license": "BSD-3-Clause",
"main": "lit-virtualizer.js",
"files": [
"/lit-virtualizer.js",
"/lit-virtualizer.d.ts",
"/lit-virtualizer.d.ts.map",
"/lib/"
],
"module": "lit-virtualizer.js",
"scripts": {
"bench": "tach --root=../.. --browser=chrome-headless test/benchmarks/${BENCH:-basic}.html --measure=fcp",
"bench:debug": "tach --root=../.. test/benchmarks/${BENCH:-basic}.html --measure=fcp",
"bench:scroll": "tach --force-clean-npm-install --config=test/benchmarks/scrollingBenchmarks.json",
"build": "tsc & copyfiles -u 2 src/lib/uni-virtualizer/lib/polyfills/resize-observer-polyfill/ResizeObserver.js lib",
"checksize": "rollup -c; rm lit-virtualizer.bundled.js lit-virtualizer-with-polyfills.bundled.js",
"clean": "rm -r node_modules/",
"lint": "tslint --project ./",
"prepare": "npm run build",
"test": "karma start karma.conf.js",
"test:debug": "karma start karma.conf.js --single-run=false --debug",
"test:screenshot": "cd test/screenshot && rollup -c && mocha screenshot.js",
"generate-screenshots": "cd test/screenshot && rollup -c && mocha screenshot.js --generate-screenshots"
},
"author": "Google LLC",
"devDependencies": {
"chai": "^4.2.0",
"copyfiles": "^2.4.1",
"http-server": "^0.11.1",
"karma": "^4.1.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-rollup-preprocessor": "^7.0.0",
"mocha": "^6.1.4",
"pixelmatch": "^4.0.2",
"pngjs": "^3.4.0",
"puppeteer": "^1.17.0",
"rollup": "^1.11.2",
"rollup-plugin-filesize": "^6.1.1",
"rollup-plugin-node-resolve": "^4.2.3",
"rollup-plugin-terser": "^5.0.0",
"tachometer": "^0.4.7",
"typescript": "^4.1.3"
},
"dependencies": {
"event-target-shim": "^5.0.1",
"lit": "^2.0.0-rc.1",
"tslib": "^1.10.0"
}
}

View File

@@ -33,7 +33,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
.then(() => {
const el = document.createElement("ha-store-auth-card");
this.provideHass(el);
document.body.appendChild(el);
this.shadowRoot!.appendChild(el);
});
}
}

View File

@@ -759,10 +759,7 @@
"config_entry_system_options": {
"title": "System Options for {integration}",
"enable_new_entities_label": "Enable newly added entities.",
"enable_new_entities_description": "If newly discovered devices for {integration} should be automatically added.",
"enable_polling_label": "Enable polling for updates.",
"enable_polling_description": "If Home Assistant should automatically poll {integration} entities for updates.",
"restart_home_assistant": "You need to restart Home Assistant for your changes to take effect.",
"enable_new_entities_description": "If disabled, newly discovered entities for {integration} will not be automatically added to Home Assistant.",
"update": "Update"
},
"zha_reconfigure_device": {
@@ -1975,7 +1972,6 @@
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
"confirm_disable_config_entry": "There are no more devices for the config entry {entry_name}, do you want to instead disable the config entry?",
"update_device_error": "Updating the device failed",
"disabled": "Disabled",
"data_table": {
"device": "Device",
@@ -2164,7 +2160,6 @@
"reload_restart_confirm": "Restart Home Assistant to finish reloading this integration",
"disable_restart_confirm": "Restart Home Assistant to finish disabling this integration",
"enable_restart_confirm": "Restart Home Assistant to finish enabling this integration",
"disable_error": "Enabling or disabling of the integration failed",
"manuf": "by {manufacturer}",
"hub": "Connected via",
"firmware": "Firmware: {version}",
@@ -2187,7 +2182,6 @@
},
"provided_by_custom_integration": "Provided by a custom integration",
"depends_on_cloud": "Depends on the cloud",
"disabled_polling": "Automatic polling for updated data disabled",
"state": {
"loaded": "Loaded",
"setup_error": "Failed to set up",
@@ -3945,7 +3939,6 @@
"static": "Static",
"dhcp": "DHCP",
"disabled": "Disabled",
"link-local": "link-local",
"ip_netmask": "IP address/Netmask",
"gateway": "Gateway address",
"dns_servers": "DNS Servers",

View File

@@ -39,12 +39,13 @@ export const registerServiceWorker = async (
}
// Notify users a new frontend is available.
// When
showToast(rootEl, {
message: "A new version of the frontend is available.",
action: {
// We tell the service worker to call skipWaiting, which activates
// the new service worker. Above we listen for `controllerchange`
// so we reload the page once a new service worker activates.
// so we reload the page once a new servic worker activates.
action: () => installingWorker.postMessage({ type: "skipWaiting" }),
text: "reload",
},

View File

@@ -929,11 +929,8 @@
},
"dialogs": {
"config_entry_system_options": {
"enable_new_entities_description": "Si esactivat, les noves entitats descobertes per {integration} s'afegiran automàticament a Home Assistant.",
"enable_new_entities_description": "Si es desactiva, les entitats descobertes recentment per a {integration} no s'afegiran automàticament a Home Assistant.",
"enable_new_entities_label": "Activa entitats afegides recentment.",
"enable_polling_description": "Si Home Assistant ha de sondejar automàticament {integration} per obtenir actualitzacions de les entitats.",
"enable_polling_label": "Activa el sondeig per obtenir actualitzacions.",
"restart_home_assistant": "Has de reiniciar Home Assistant per aplicar els canvis.",
"title": "Opcions del sistema per a {integration}",
"update": "Actualitza"
},
@@ -1391,7 +1388,7 @@
"type_select": "Tipus de repetició",
"type": {
"count": {
"label": "Comptador"
"label": "Compta"
},
"until": {
"conditions": "Condicions de \"Fins que\"",
@@ -1543,7 +1540,7 @@
"delete_confirm": "Segur que vols eliminar-ho?",
"duplicate": "Duplica",
"header": "Disparadors",
"introduction": "Els disparadors són les regles que fan que s'executi una automatització. Pots definir més d'un disparador per a cada automatització. Una vegada salti un disparador, Home Assistant validarà les condicions (si n'hi ha) i finalment cridarà l'acció.",
"introduction": "Els activadors són les regles que fan que es dispari una automatització. Pots definir més d'un activador per a cada automatització. Una vegada s'iniciï un activador, Home Assistant validarà les condicions (si n'hi ha) i finalment cridarà l'acció.",
"learn_more": "Més informació sobre els activadors",
"name": "Disparador",
"type_select": "Tipus de disparador",
@@ -2076,8 +2073,7 @@
"scripts": "Programes (scripts)",
"unknown_error": "Error desconegut",
"unnamed_device": "Dispositiu sense nom",
"update": "Actualitza",
"update_device_error": "No s'ha pogut actualitzar el dispositiu"
"update": "Actualitza"
},
"entities": {
"caption": "Entitats",
@@ -2210,7 +2206,6 @@
"depends_on_cloud": "Depèn del núvol",
"device_unavailable": "Dispositiu no disponible",
"devices": "{count} {count, plural,\n one {dispositiu}\n other {dispositius}\n}",
"disable_error": "S'ha produït un error en activar o desactivar la integració",
"disable_restart_confirm": "Reinicia Home Assistant per acabar de desactivar aquesta integració",
"disable": {
"disable_confirm": "Estàs segur que vols desactivar aquesta entrada de configuració? Els seus dispositius i entitats es desactivaran.",
@@ -2222,7 +2217,6 @@
},
"disabled_cause": "Desactivada per {cause}"
},
"disabled_polling": "Sondeig automàtic per l'obtenció de dades actualitzades desactivat",
"documentation": "Documentació",
"enable_restart_confirm": "Reinicia Home Assistant per acabar d'activar aquesta integració",
"entities": "{count} {count, plural,\n one {entitat}\n other {entitats}\n}",

View File

@@ -385,13 +385,8 @@
"create_blocked_not_running": "Vytvoření zálohy není momentálně možné, protože systém je ve \"{state}\".",
"create_snapshot": "Vytvořit zálohu",
"created": "Vytvořeno",
"delete_selected": "Smazat vybrané zálohy",
"delete_snapshot_confirm": "smazat",
"delete_snapshot_text": "Chcete smazat {number} {number, plural,\n one {zálohu}\n few {zálohy}\n other {záloh}\n}?",
"delete_snapshot_title": "Smazat zálohu",
"description": "Zálohy umožňují snadno zálohovat a obnovovat všechna data vaší instance Home Assistant.",
"enter_password": "Prosím zadejte heslo.",
"failed_to_delete": "Smazání se nezdařilo",
"folder": {
"addons/local": "Místní doplňky",
"homeassistant": "Nastavení Home Asistent",
@@ -409,7 +404,6 @@
"password_protection": "Ochrana heslem",
"security": "Zabezpečení",
"select_type": "Vyberte, co chcete obnovit",
"selected": "{number} vybraných",
"type": "Typ zálohy",
"upload_snapshot": "Nahrát zálohu"
},

View File

@@ -929,11 +929,8 @@
},
"dialogs": {
"config_entry_system_options": {
"enable_new_entities_description": "If newly discovered devices for {integration} should be automatically added.",
"enable_new_entities_description": "If disabled, newly discovered entities for {integration} will not be automatically added to Home Assistant.",
"enable_new_entities_label": "Enable newly added entities.",
"enable_polling_description": "If Home Assistant should automatically poll {integration} entities for updates.",
"enable_polling_label": "Enable polling for updates.",
"restart_home_assistant": "You need to restart Home Assistant for your changes to take effect.",
"title": "System Options for {integration}",
"update": "Update"
},
@@ -2076,8 +2073,7 @@
"scripts": "Scripts",
"unknown_error": "Unknown error",
"unnamed_device": "Unnamed device",
"update": "Update",
"update_device_error": "Updating the device failed"
"update": "Update"
},
"entities": {
"caption": "Entities",
@@ -2210,7 +2206,6 @@
"depends_on_cloud": "Depends on the cloud",
"device_unavailable": "Device unavailable",
"devices": "{count} {count, plural,\n one {device}\n other {devices}\n}",
"disable_error": "Enabling or disabling of the integration failed",
"disable_restart_confirm": "Restart Home Assistant to finish disabling this integration",
"disable": {
"disable_confirm": "Are you sure you want to disable this config entry? Its devices and entities will be disabled.",
@@ -2222,7 +2217,6 @@
},
"disabled_cause": "Disabled by {cause}"
},
"disabled_polling": "Automatic polling for updated data disabled",
"documentation": "Documentation",
"enable_restart_confirm": "Restart Home Assistant to finish enabling this integration",
"entities": "{count} {count, plural,\n one {entity}\n other {entities}\n}",

View File

@@ -929,11 +929,8 @@
},
"dialogs": {
"config_entry_system_options": {
"enable_new_entities_description": "Si los dispositivos recién descubiertos para {integration} deberían agregarse automáticamente.",
"enable_new_entities_description": "Si está deshabilitada, las nuevas entidades que se descubran para {integration} no se añadirán automáticamente a Home Assistant.",
"enable_new_entities_label": "Habilitar entidades recién añadidas.",
"enable_polling_description": "Si Home Assistant debería sondear automáticamente las entidades de {integration} para obtener actualizaciones.",
"enable_polling_label": "Habilitar el sondeo de actualizaciones.",
"restart_home_assistant": "Debes reiniciar Home Assistant para que los cambios surtan efecto.",
"title": "Opciones del sistema para {integration}",
"update": "Actualizar"
},
@@ -2076,8 +2073,7 @@
"scripts": "Scripts",
"unknown_error": "Error desconocido",
"unnamed_device": "Dispositivo sin nombre",
"update": "Actualizar",
"update_device_error": "Error al actualizar el dispositivo"
"update": "Actualizar"
},
"entities": {
"caption": "Entidades",
@@ -2210,7 +2206,6 @@
"depends_on_cloud": "Depende de la nube",
"device_unavailable": "Dispositivo no disponible",
"devices": "{count} {count, plural,\n one {dispositivo}\n other {dispositivos}\n}",
"disable_error": "Error al habilitar o deshabilitar la integración",
"disable_restart_confirm": "Reinicia Home Assistant para terminar de deshabilitar esta integración",
"disable": {
"disable_confirm": "¿Estás seguro de que deseas deshabilitar esta entrada de configuración? Sus dispositivos y entidades estarán deshabilitados.",
@@ -2222,7 +2217,6 @@
},
"disabled_cause": "Deshabilitada por {cause}"
},
"disabled_polling": "Sondeo automático para datos actualizados deshabilitado",
"documentation": "Documentación",
"enable_restart_confirm": "Reinicia Home Assistant para terminar de habilitar esta integración",
"entities": "{count} {count, plural,\n one {entidad}\n other {entidades}\n}",

View File

@@ -929,11 +929,8 @@
},
"dialogs": {
"config_entry_system_options": {
"enable_new_entities_description": "Kas lisada äsja avastatud sidumise {integration} olemed automaatselt Home Assistant'i.",
"enable_new_entities_description": "Kui see on keelatud ei lisata äsja avastatud sidumise {integration} olemeid automaatselt Home Assistant'i.",
"enable_new_entities_label": "Luba äsja lisatud olemid.",
"enable_polling_description": "Kas Home Assistant peaks automaatselt küsitlema {integration} üksusi uuenduste saamiseks.",
"enable_polling_label": "Luba värskenduste jaoks küsitlus.",
"restart_home_assistant": "Muudatuste jõustumiseks pead Home Assistanti taaskäivitama.",
"title": "Süsteemi valikud {integration} jaoks",
"update": "Uuenda"
},
@@ -2076,8 +2073,7 @@
"scripts": "Skriptid",
"unknown_error": "Tundmatu viga",
"unnamed_device": "Nimetu seade",
"update": "Uuenda",
"update_device_error": "Seadme värskendamine nurjus"
"update": "Uuenda"
},
"entities": {
"caption": "Olemite register",
@@ -2210,7 +2206,6 @@
"depends_on_cloud": "Sõltub pilveteenusest",
"device_unavailable": "Seade pole saadaval",
"devices": "{count} {count, plural,\n one {seade}\n other {seadet}\n}",
"disable_error": "Sidumise lubamine või keelamine nurjus",
"disable_restart_confirm": "Taaskäivita Home Assistant, et lõpetada selle sidumise keelamine",
"disable": {
"disable_confirm": "Kas soovid selle seadistuskirje kindlasti keelata? Selle seadmed ja üksused keelatakse.",
@@ -2222,7 +2217,6 @@
},
"disabled_cause": "Keelatud {cause} põhjusel"
},
"disabled_polling": "Uuendatud andmete automaatne päring on välja lülitatud",
"documentation": "Vaata dokumentatsiooni",
"enable_restart_confirm": "Selle sidumise lubamise lõpetamiseks taaskäivita Home Assistant",
"entities": "{count} {count, plural,\n one {olem}\n other{olemit}\n}",

Some files were not shown because too many files have changed in this diff Show More