mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
setData method
This commit is contained in:
@@ -446,6 +446,22 @@ render(({
|
||||
});
|
||||
```
|
||||
|
||||
#### setData (EXPERIMENTAL)
|
||||
|
||||
This methods allows you to quckly redraw the DivKit card:
|
||||
|
||||
```ts
|
||||
instance.setData({
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
Some notes:
|
||||
|
||||
* This method is experimental, its logic and api may be changed the future versions.
|
||||
* `setData` doesn't change any existing variables or variable triggers. It will onky create new variables. This is intentional.
|
||||
* This method will try to do as little work as possible and will try to preserve the state of the card (input values and so on).
|
||||
|
||||
### Note about 64-bit integers
|
||||
|
||||
DivKit internally uses the `BigInt` type if the current platform supports it (both client-side and server-side). This means that on unsupported platforms, integers will lose precision if the value exceeds 2^53.
|
||||
|
||||
@@ -1,9 +1,64 @@
|
||||
import type { Variable } from './expressions/variable';
|
||||
import type { Node } from './expressions/ast';
|
||||
import type { WrappedError } from '../typings/common';
|
||||
import type { ComponentCallback, CustomActionCallback, Customization, DivExtensionClass, DivJson, ErrorCallback, FetchInit, Platform, StatCallback, Theme, TypefaceProvider, WrappedError } from '../typings/common';
|
||||
import type { GlobalVariablesController } from './expressions/globalVariablesController';
|
||||
import { parse } from './expressions/expressions';
|
||||
import { evalExpression as evalExpressionInner, EvalResult } from './expressions/eval';
|
||||
import { funcs } from './expressions/funcs/funcs';
|
||||
import { CustomComponentDescription } from '../typings/custom';
|
||||
import { DivkitDebugInstance } from '../typings/client-devtool';
|
||||
import Root from './components/Root.svelte';
|
||||
|
||||
export function render(opts: {
|
||||
target: HTMLElement;
|
||||
json: DivJson;
|
||||
id: string;
|
||||
hydrate?: boolean;
|
||||
globalVariablesController?: GlobalVariablesController;
|
||||
mix?: string;
|
||||
customization?: Customization;
|
||||
builtinProtocols?: string[];
|
||||
extensions?: Map<string, DivExtensionClass>;
|
||||
onStat?: StatCallback;
|
||||
onCustomAction?: CustomActionCallback;
|
||||
onError?: ErrorCallback;
|
||||
onComponent?: ComponentCallback;
|
||||
typefaceProvider?: TypefaceProvider;
|
||||
platform?: Platform;
|
||||
theme?: Theme;
|
||||
fetchInit?: FetchInit;
|
||||
tooltipRoot?: HTMLElement;
|
||||
customComponents?: Map<string, CustomComponentDescription> | undefined;
|
||||
}): DivkitDebugInstance {
|
||||
const { target, hydrate, ...rest } = opts;
|
||||
|
||||
const instance = new Root({
|
||||
target: target,
|
||||
props: rest,
|
||||
hydrate: hydrate
|
||||
});
|
||||
|
||||
return {
|
||||
$destroy() {
|
||||
instance.$destroy();
|
||||
},
|
||||
execAction(action) {
|
||||
instance.execAction(action);
|
||||
},
|
||||
setTheme(theme) {
|
||||
instance.setTheme(theme);
|
||||
},
|
||||
setData(newJson) {
|
||||
instance.setData(newJson);
|
||||
},
|
||||
getDebugVariables() {
|
||||
return instance.getDebugVariables();
|
||||
},
|
||||
getDebugAllVariables() {
|
||||
return instance.getDebugAllVariables();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export * from './client';
|
||||
|
||||
@@ -43,3 +98,13 @@ export { valToString } from './expressions/utils';
|
||||
export function functionNames(): string[] {
|
||||
return Array.from(funcs.keys());
|
||||
}
|
||||
|
||||
export function parseExpression(expr: string, opts?: {
|
||||
type?: 'exact' | 'json';
|
||||
}): Node {
|
||||
return parse(expr, {
|
||||
startRule: opts?.type === 'json' ? 'JsonStringContents' : 'start'
|
||||
});
|
||||
}
|
||||
|
||||
export { walk as walkExpression } from './expressions/walk';
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
Customization,
|
||||
DivExtensionClass,
|
||||
DivJson,
|
||||
DivkitInstance,
|
||||
ErrorCallback,
|
||||
FetchInit,
|
||||
Platform,
|
||||
@@ -35,14 +36,29 @@ export function render(opts: {
|
||||
fetchInit?: FetchInit;
|
||||
tooltipRoot?: HTMLElement;
|
||||
customComponents?: Map<string, CustomComponentDescription> | undefined;
|
||||
}) {
|
||||
}): DivkitInstance {
|
||||
const { target, hydrate, ...rest } = opts;
|
||||
|
||||
return new Root({
|
||||
const instance = new Root({
|
||||
target: target,
|
||||
props: rest,
|
||||
hydrate: hydrate
|
||||
});
|
||||
|
||||
return {
|
||||
$destroy() {
|
||||
instance.$destroy();
|
||||
},
|
||||
execAction(action) {
|
||||
instance.execAction(action);
|
||||
},
|
||||
setTheme(theme) {
|
||||
instance.setTheme(theme);
|
||||
},
|
||||
setData(newJson) {
|
||||
instance.setData(newJson);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
DivExtensionClass,
|
||||
TypefaceProvider,
|
||||
DisappearAction,
|
||||
FetchInit
|
||||
FetchInit,
|
||||
DivVariable
|
||||
} from '../../typings/common';
|
||||
import type { CustomComponentDescription } from '../../typings/custom';
|
||||
import type { AppearanceTransition, DivBaseData, Tooltip, TransitionChange } from '../types/base';
|
||||
@@ -137,34 +138,46 @@
|
||||
|
||||
export function getDebugVariables() {
|
||||
if (!process.env.DEVTOOL) {
|
||||
return;
|
||||
return new Map<string, Variable>();
|
||||
}
|
||||
|
||||
return localVariables;
|
||||
}
|
||||
|
||||
export function getDebugAllVariables() {
|
||||
if (!process.env.DEVTOOL) {
|
||||
return new Map<string, Variable>();
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
|
||||
export function setData(newJson: Partial<DivJson>) {
|
||||
json = newJson;
|
||||
}
|
||||
|
||||
const builtinSet = new Set(builtinProtocols);
|
||||
|
||||
let hasError = false;
|
||||
let hsaIdError = false;
|
||||
|
||||
if (!json) {
|
||||
hasError = true;
|
||||
logError(wrapError(new Error('"json" prop is required')));
|
||||
$: {
|
||||
hasError = false;
|
||||
|
||||
const initialError = simpleCheckInput(json);
|
||||
if (initialError) {
|
||||
hasError = true;
|
||||
logError(initialError);
|
||||
}
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
hasError = true;
|
||||
hsaIdError = true;
|
||||
logError(wrapError(new Error('"id" prop is required')));
|
||||
}
|
||||
|
||||
let initialError = simpleCheckInput(json);
|
||||
let templateContext: TemplateContext = {};
|
||||
const templates = json.templates || {};
|
||||
|
||||
if (initialError) {
|
||||
hasError = true;
|
||||
logError(initialError);
|
||||
}
|
||||
$: templates = json.templates || {};
|
||||
|
||||
const running: Record<Running, boolean> = {
|
||||
stateChange: false
|
||||
@@ -302,12 +315,14 @@
|
||||
};
|
||||
}
|
||||
|
||||
function registerComponentReal({
|
||||
function componentDevtoolReal({
|
||||
type,
|
||||
node,
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
}: {
|
||||
type: 'mount' | 'update' | 'destroy';
|
||||
node: HTMLElement;
|
||||
json: Partial<DivBaseData>;
|
||||
origJson: DivBase | undefined;
|
||||
@@ -315,7 +330,7 @@
|
||||
}): void {
|
||||
if (onComponent) {
|
||||
onComponent({
|
||||
type: 'mount',
|
||||
type,
|
||||
node,
|
||||
json: json as DivBase,
|
||||
origJson,
|
||||
@@ -323,18 +338,6 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
function unregisterComponentReal({
|
||||
node
|
||||
}: {
|
||||
node: HTMLElement;
|
||||
}): void {
|
||||
if (onComponent) {
|
||||
onComponent({
|
||||
type: 'destroy',
|
||||
node
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let idCounter = 0;
|
||||
function genId(key: string): string {
|
||||
@@ -1069,8 +1072,7 @@
|
||||
isDesktop,
|
||||
isPointerFocus,
|
||||
customComponents,
|
||||
registerComponent: process.env.DEVTOOL ? registerComponentReal : undefined,
|
||||
unregisterComponent: process.env.DEVTOOL ? unregisterComponentReal : undefined
|
||||
componentDevtool: process.env.DEVTOOL ? componentDevtoolReal : undefined
|
||||
});
|
||||
|
||||
setContext<ActionCtxValue>(ACTION_CTX, {
|
||||
@@ -1181,10 +1183,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
function declVariable(variable: DivVariable): void {
|
||||
if (!(variable.type in TYPE_TO_CLASS)) {
|
||||
// Skip unknown types (from the future versions maybe)
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
variable.type === 'integer' && typeof variable.value === 'number' &&
|
||||
(variable.value > Number.MAX_SAFE_INTEGER || variable.value < Number.MIN_SAFE_INTEGER)
|
||||
) {
|
||||
logError(wrapError(new Error('The value of the integer variable could lose accuracy'), {
|
||||
level: 'warn',
|
||||
additional: {
|
||||
name: variable.name,
|
||||
value: variable.value
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
try {
|
||||
const varInstance = createVariable(variable.name, variable.type, variable.value);
|
||||
|
||||
localVariables.set(variable.name, varInstance);
|
||||
variables.set(variable.name, varInstance);
|
||||
} catch (err: any) {
|
||||
logError(wrapError(err, {
|
||||
additional: {
|
||||
name: variable.name
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
const startVariables = json?.card?.variables;
|
||||
if (Array.isArray(startVariables)) {
|
||||
startVariables.forEach(variable => {
|
||||
if (variable && variable.type in TYPE_TO_CLASS && variable.name) {
|
||||
if (variable && variable.name) {
|
||||
if (localVariables.has(variable.name)) {
|
||||
logError(wrapError(new Error('Duplicate variable'), {
|
||||
additional: {
|
||||
@@ -1195,31 +1230,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
variable.type === 'integer' && typeof variable.value === 'number' &&
|
||||
(variable.value > Number.MAX_SAFE_INTEGER || variable.value < Number.MIN_SAFE_INTEGER)
|
||||
) {
|
||||
logError(wrapError(new Error('The value of the integer variable could lose accuracy'), {
|
||||
level: 'warn',
|
||||
additional: {
|
||||
name: variable.name,
|
||||
value: variable.value
|
||||
}
|
||||
}));
|
||||
}
|
||||
declVariable(variable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const varInstance = createVariable(variable.name, variable.type, variable.value);
|
||||
|
||||
localVariables.set(variable.name, varInstance);
|
||||
variables.set(variable.name, varInstance);
|
||||
} catch (err: any) {
|
||||
logError(wrapError(err, {
|
||||
additional: {
|
||||
name: variable.name
|
||||
}
|
||||
}));
|
||||
}
|
||||
$: if (json?.card?.variables && Array.isArray(json.card.variables) && json.card.variables !== startVariables) {
|
||||
json.card.variables.forEach(variable => {
|
||||
if (variable && variable.name && !localVariables.has(variable.name)) {
|
||||
declVariable(variable);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1376,9 +1395,9 @@
|
||||
timers.forEach(timer => controller.createTimer(timer));
|
||||
}
|
||||
|
||||
const states = json?.card?.states;
|
||||
$: states = json?.card?.states;
|
||||
let rootStateDiv: DivBaseData | undefined;
|
||||
if (states && !hasError) {
|
||||
$: if (states && !hasError && !hsaIdError) {
|
||||
rootStateDiv = (process.env.ENABLE_COMPONENT_STATE || process.env.ENABLE_COMPONENT_STATE === undefined) ? {
|
||||
type: 'state',
|
||||
id: 'root',
|
||||
@@ -1435,7 +1454,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if !hasError && rootStateDiv}
|
||||
{#if !hasError && !hsaIdError && rootStateDiv}
|
||||
<div
|
||||
class="{css.root}{$isDesktop ? ` ${css.root_platform_desktop}` : ''}{mix ? ` ${mix}` : ''}"
|
||||
on:touchstart={emptyTouchstartHandler}
|
||||
|
||||
@@ -1,40 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import { Readable, derived } from 'svelte/store';
|
||||
|
||||
import css from './Container.module.css';
|
||||
|
||||
import type { ContainerOrientation, DivContainerData } from '../../types/container';
|
||||
import type { LayoutParams } from '../../types/layoutParams';
|
||||
import type { DivBase, TemplateContext } from '../../../typings/common';
|
||||
import type { DivBaseData } from '../../types/base';
|
||||
import type {
|
||||
ContentAlignmentHorizontal,
|
||||
ContentAlignmentVertical
|
||||
} from '../../types/alignment';
|
||||
import type { ContainerChildInfo, SeparatorStyle } from '../../utils/container';
|
||||
import { prepareMargins } from '../../utils/container';
|
||||
import { ROOT_CTX, RootCtxValue } from '../../context/root';
|
||||
import { wrapError } from '../../utils/wrapError';
|
||||
import { genClassName } from '../../utils/genClassName';
|
||||
import { correctContainerOrientation } from '../../utils/correctContainerOrientation';
|
||||
import { assignIfDifferent } from '../../utils/assignIfDifferent';
|
||||
import { correctDrawableStyle, DrawableStyle } from '../../utils/correctDrawableStyles';
|
||||
import { calcAdditionalPaddings, calcItemsGap, hasKnownHeightCheck, hasKnownWidthCheck } from '../../utils/container';
|
||||
import { hasGapSupport } from '../../utils/hasGapSupport';
|
||||
import { isPositiveNumber } from '../../utils/isPositiveNumber';
|
||||
import ContainerSeparators from './ContainerSeparators.svelte';
|
||||
import Unknown from '../utilities/Unknown.svelte';
|
||||
import Outer from '../utilities/Outer.svelte';
|
||||
import { correctContentAlignmentVertical } from '../../utils/correctContentAlignmentVertical';
|
||||
import { correctContentAlignmentHorizontal } from '../../utils/correctContentAlignmentHorizontal';
|
||||
import { Truthy } from '../../utils/truthy';
|
||||
|
||||
export let json: Partial<DivContainerData> = {};
|
||||
export let templateContext: TemplateContext;
|
||||
export let origJson: DivBase | undefined = undefined;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
<script lang="ts" context="module">
|
||||
const HALIGN_MAP = {
|
||||
left: 'start',
|
||||
center: 'center',
|
||||
@@ -56,12 +20,78 @@
|
||||
'space-evenly': 'start'
|
||||
} as const;
|
||||
|
||||
const AVAIL_SEPARATOR_SHAPES = ['rounded_rectangle', 'circle'];
|
||||
const AVAIL_SEPARATOR_SHAPES = [
|
||||
'rounded_rectangle',
|
||||
'circle'
|
||||
];
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import { Readable, derived } from 'svelte/store';
|
||||
|
||||
import css from './Container.module.css';
|
||||
|
||||
import type { ContainerOrientation, DivContainerData } from '../../types/container';
|
||||
import type { LayoutParams } from '../../types/layoutParams';
|
||||
import type { DivBase, TemplateContext } from '../../../typings/common';
|
||||
import type { DivBaseData } from '../../types/base';
|
||||
import type {
|
||||
ContentAlignmentHorizontal,
|
||||
ContentAlignmentVertical
|
||||
} from '../../types/alignment';
|
||||
import type { ContainerChildInfo, SeparatorStyle } from '../../utils/container';
|
||||
import { prepareMargins } from '../../utils/container';
|
||||
import { ROOT_CTX, RootCtxValue } from '../../context/root';
|
||||
import { genClassName } from '../../utils/genClassName';
|
||||
import { correctContainerOrientation } from '../../utils/correctContainerOrientation';
|
||||
import { assignIfDifferent } from '../../utils/assignIfDifferent';
|
||||
import { correctDrawableStyle, DrawableStyle } from '../../utils/correctDrawableStyles';
|
||||
import { calcAdditionalPaddings, calcItemsGap, hasKnownHeightCheck, hasKnownWidthCheck } from '../../utils/container';
|
||||
import { hasGapSupport } from '../../utils/hasGapSupport';
|
||||
import { isPositiveNumber } from '../../utils/isPositiveNumber';
|
||||
import ContainerSeparators from './ContainerSeparators.svelte';
|
||||
import Unknown from '../utilities/Unknown.svelte';
|
||||
import Outer from '../utilities/Outer.svelte';
|
||||
import { correctContentAlignmentVertical } from '../../utils/correctContentAlignmentVertical';
|
||||
import { correctContentAlignmentHorizontal } from '../../utils/correctContentAlignmentHorizontal';
|
||||
import { Truthy } from '../../utils/truthy';
|
||||
|
||||
export let json: Partial<DivContainerData> = {};
|
||||
export let templateContext: TemplateContext;
|
||||
export let origJson: DivBase | undefined = undefined;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
let childStore: Readable<ContainerChildInfo[]>;
|
||||
let orientation: ContainerOrientation = 'vertical';
|
||||
let contentVAlign: ContentAlignmentVertical = 'top';
|
||||
let contentHAlign: ContentAlignmentHorizontal = 'left';
|
||||
let separator: SeparatorStyle | null = null;
|
||||
let lineSeparator: SeparatorStyle | null = null;
|
||||
let aspect: number | undefined = undefined;
|
||||
let childLayoutParams: LayoutParams = {};
|
||||
|
||||
$: if (json) {
|
||||
orientation = 'vertical';
|
||||
contentVAlign = 'top';
|
||||
contentHAlign = 'left';
|
||||
aspect = undefined;
|
||||
}
|
||||
|
||||
$: jsonItems = json.items;
|
||||
|
||||
$: jsonOrientation = rootCtx.getDerivedFromVars(json.orientation);
|
||||
$: jsonLayoutMode = rootCtx.getDerivedFromVars(json.layout_mode);
|
||||
$: jsonContentVAlign = rootCtx.getDerivedFromVars(json.content_alignment_vertical);
|
||||
$: jsonContentHAlign = rootCtx.getDerivedFromVars(json.content_alignment_horizontal);
|
||||
$: jsonSeparator = rootCtx.getDerivedFromVars(json.separator);
|
||||
$: jsonLineSeparator = rootCtx.getDerivedFromVars(json.line_separator);
|
||||
$: jsonAspect = rootCtx.getDerivedFromVars(json.aspect);
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
|
||||
function replaceItems(items: (DivBaseData | undefined)[]): void {
|
||||
json = {
|
||||
...json,
|
||||
@@ -85,7 +115,6 @@
|
||||
};
|
||||
});
|
||||
|
||||
let childStore: Readable<ContainerChildInfo[]>;
|
||||
$: {
|
||||
let children: Readable<ContainerChildInfo>[] = [];
|
||||
|
||||
@@ -102,32 +131,23 @@
|
||||
childStore = derived(children, val => [...val]);
|
||||
}
|
||||
|
||||
let orientation: ContainerOrientation = 'vertical';
|
||||
$: jsonOrientation = rootCtx.getDerivedFromVars(json.orientation);
|
||||
$: {
|
||||
orientation = correctContainerOrientation($jsonOrientation, orientation);
|
||||
}
|
||||
|
||||
$: jsonLayoutMode = rootCtx.getDerivedFromVars(json.layout_mode);
|
||||
$: wrap = $jsonLayoutMode === 'wrap';
|
||||
|
||||
$: hasKnownWidth = orientation !== 'horizontal' && !wrap && $childStore.some(hasKnownWidthCheck);
|
||||
$: hasKnownHeight = orientation !== 'vertical' && !wrap && $childStore.some(hasKnownHeightCheck);
|
||||
|
||||
let contentVAlign: ContentAlignmentVertical = 'top';
|
||||
$: jsonContentVAlign = rootCtx.getDerivedFromVars(json.content_alignment_vertical);
|
||||
$: {
|
||||
contentVAlign = correctContentAlignmentVertical($jsonContentVAlign, contentVAlign);
|
||||
}
|
||||
|
||||
let contentHAlign: ContentAlignmentHorizontal = 'left';
|
||||
$: jsonContentHAlign = rootCtx.getDerivedFromVars(json.content_alignment_horizontal);
|
||||
$: {
|
||||
contentHAlign = correctContentAlignmentHorizontal($jsonContentHAlign, contentHAlign);
|
||||
}
|
||||
|
||||
$: jsonSeparator = rootCtx.getDerivedFromVars(json.separator);
|
||||
let separator: SeparatorStyle | null = null;
|
||||
$: {
|
||||
if ($jsonSeparator?.style && orientation !== 'overlap' && hasGapSupport()) {
|
||||
const style = correctDrawableStyle<DrawableStyle | null>(
|
||||
@@ -152,8 +172,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonLineSeparator = rootCtx.getDerivedFromVars(json.line_separator);
|
||||
let lineSeparator: SeparatorStyle | null = null;
|
||||
$: {
|
||||
if ($jsonLineSeparator?.style && orientation !== 'overlap' && hasGapSupport()) {
|
||||
const style = correctDrawableStyle<DrawableStyle | null>(
|
||||
@@ -182,8 +200,6 @@
|
||||
calcAdditionalPaddings(orientation, separator, lineSeparator) :
|
||||
null;
|
||||
|
||||
$: jsonAspect = rootCtx.getDerivedFromVars(json.aspect);
|
||||
let aspect: number | undefined = undefined;
|
||||
$: {
|
||||
const newRatio = $jsonAspect?.ratio;
|
||||
if (newRatio && isPositiveNumber(newRatio)) {
|
||||
@@ -193,10 +209,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
|
||||
let childLayoutParams: LayoutParams = {};
|
||||
$: {
|
||||
let newChildLayoutParams: LayoutParams = {};
|
||||
|
||||
@@ -269,16 +282,14 @@
|
||||
parentOf={jsonItems}
|
||||
{replaceItems}
|
||||
>
|
||||
{#key jsonItems}
|
||||
{#each items as item}
|
||||
<Unknown
|
||||
layoutParams={childLayoutParams}
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
/>
|
||||
{/each}
|
||||
{/key}
|
||||
{#each items as item}
|
||||
<Unknown
|
||||
layoutParams={childLayoutParams}
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#if separator || lineSeparator}
|
||||
<ContainerSeparators
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<script lang="ts" context="module">
|
||||
const THROTTLE_TIMEOUT = 10;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
|
||||
@@ -17,7 +21,6 @@
|
||||
export let contentHAlign: ContentAlignmentHorizontal;
|
||||
export let contentVAlign: ContentAlignmentVertical;
|
||||
|
||||
const THROTTLE_TIMEOUT = 10;
|
||||
const throttledUpdated = simpleThrottle(updateSeparators, THROTTLE_TIMEOUT);
|
||||
|
||||
interface SeparatorItem {
|
||||
|
||||
@@ -50,8 +50,44 @@
|
||||
const leftClass = rootCtx.getCustomization('galleryLeftClass');
|
||||
const rightClass = rootCtx.getCustomization('galleryRightClass');
|
||||
|
||||
let prevId: string | undefined;
|
||||
let hasError = false;
|
||||
let columns = 1;
|
||||
let orientation: Orientation = 'horizontal';
|
||||
let align: Align = 'start';
|
||||
let gridGap: string | undefined;
|
||||
let itemSpacing = 8;
|
||||
let crossGridGap: string | undefined;
|
||||
let crossSpacing;
|
||||
let padding = '';
|
||||
let templateSizes: string[] = [];
|
||||
let childStore: Readable<(MaybeMissing<Size> | undefined)[]>;
|
||||
let scrollerStyle: Style = {};
|
||||
let scrollSnap = false;
|
||||
let childLayoutParams: LayoutParams = {};
|
||||
let defaultItem = 0;
|
||||
|
||||
$: if (json) {
|
||||
columns = 1;
|
||||
orientation = 'horizontal';
|
||||
align = 'start';
|
||||
itemSpacing = 8;
|
||||
padding = '';
|
||||
}
|
||||
|
||||
$: jsonItems = json.items;
|
||||
|
||||
$: jsonColumnCount = rootCtx.getDerivedFromVars(json.column_count);
|
||||
$: jsonOrientation = rootCtx.getDerivedFromVars(json.orientation);
|
||||
$: jsonCrossContentAlignment = rootCtx.getDerivedFromVars(json.cross_content_alignment);
|
||||
$: jsonItemSpacing = rootCtx.getDerivedFromVars(json.item_spacing);
|
||||
$: jsonCrossSpacing = rootCtx.getDerivedFromVars(json.cross_spacing);
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
$: jsonScrollMode = rootCtx.getDerivedFromVars(json.scroll_mode);
|
||||
$: jsonRestrictParentScroll = rootCtx.getDerivedFromVars(json.restrict_parent_scroll);
|
||||
$: jsonScrollbar = rootCtx.getDerivedFromVars(json.scrollbar);
|
||||
$: jsonDefaultItem = rootCtx.getDerivedFromVars(json.default_item);
|
||||
|
||||
$: {
|
||||
if (!jsonItems?.length || !Array.isArray(jsonItems)) {
|
||||
hasError = true;
|
||||
@@ -106,8 +142,6 @@
|
||||
resizeObserver = null;
|
||||
}
|
||||
|
||||
$: jsonColumnCount = rootCtx.getDerivedFromVars(json.column_count);
|
||||
let columns = 1;
|
||||
$: {
|
||||
columns = correctPositiveNumber($jsonColumnCount, columns);
|
||||
}
|
||||
@@ -130,44 +164,29 @@
|
||||
}
|
||||
$: itemsGrid = rebuildItemsGrid(items, columns);
|
||||
|
||||
$: jsonOrientation = rootCtx.getDerivedFromVars(json.orientation);
|
||||
let orientation: Orientation = 'horizontal';
|
||||
$: {
|
||||
orientation = correctGeneralOrientation($jsonOrientation, orientation);
|
||||
}
|
||||
|
||||
let align: Align = 'start';
|
||||
$: jsonCrossContentAlignment = rootCtx.getDerivedFromVars(json.cross_content_alignment);
|
||||
$: {
|
||||
align = correctAlignment($jsonCrossContentAlignment, align);
|
||||
}
|
||||
|
||||
let gridGap: string | undefined;
|
||||
let itemSpacing = 8;
|
||||
$: jsonItemSpacing = rootCtx.getDerivedFromVars(json.item_spacing);
|
||||
$: {
|
||||
itemSpacing = correctNonNegativeNumber($jsonItemSpacing, itemSpacing);
|
||||
gridGap = pxToEm(itemSpacing);
|
||||
}
|
||||
|
||||
let crossGridGap: string | undefined;
|
||||
let crossSpacing;
|
||||
$: jsonCrossSpacing = rootCtx.getDerivedFromVars(json.cross_spacing);
|
||||
$: {
|
||||
crossSpacing = correctNonNegativeNumber($jsonCrossSpacing, itemSpacing);
|
||||
crossGridGap = pxToEm(crossSpacing);
|
||||
}
|
||||
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
let padding = '';
|
||||
$: {
|
||||
padding = correctEdgeInserts($jsonPaddings, padding);
|
||||
}
|
||||
|
||||
$: gridTemplate = orientation === 'horizontal' ? 'grid-template-columns' : 'grid-template-rows';
|
||||
let templateSizes: string[] = [];
|
||||
|
||||
let childStore: Readable<(MaybeMissing<Size> | undefined)[]>;
|
||||
$: {
|
||||
let children: Readable<MaybeMissing<Size> | undefined>[] = [];
|
||||
|
||||
@@ -194,10 +213,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let scrollerStyle: Style = {};
|
||||
let scrollSnap = false;
|
||||
$: jsonScrollMode = rootCtx.getDerivedFromVars(json.scroll_mode);
|
||||
let childLayoutParams: LayoutParams = {};
|
||||
$: {
|
||||
const newScrollerStyle: Style = {};
|
||||
let newChildLayoutParams: LayoutParams = {};
|
||||
@@ -229,10 +244,6 @@
|
||||
childLayoutParams = assignIfDifferent(newChildLayoutParams, childLayoutParams);
|
||||
}
|
||||
|
||||
$: jsonRestrictParentScroll = rootCtx.getDerivedFromVars(json.restrict_parent_scroll);
|
||||
|
||||
$: jsonScrollbar = rootCtx.getDerivedFromVars(json.scrollbar);
|
||||
|
||||
$: gridStyle = {
|
||||
padding,
|
||||
'grid-gap': crossGridGap
|
||||
@@ -249,14 +260,12 @@
|
||||
scrollbar: $jsonScrollbar === 'auto' ? 'auto' : 'none'
|
||||
};
|
||||
|
||||
$: jsonDefaultItem = rootCtx.getDerivedFromVars(json.default_item);
|
||||
let defaultItem = 0;
|
||||
$: {
|
||||
defaultItem = correctNonNegativeNumber($jsonDefaultItem, defaultItem);
|
||||
}
|
||||
|
||||
function updateArrowsVisibility(): void {
|
||||
if (!scroller) {
|
||||
if (!scroller || hasError) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -270,6 +279,10 @@
|
||||
|
||||
const updateArrowsVisibilityDebounced = debounce(updateArrowsVisibility, 50);
|
||||
|
||||
$: if (json) {
|
||||
updateArrowsVisibilityDebounced();
|
||||
}
|
||||
|
||||
function scroll(type: 'left' | 'right'): void {
|
||||
scroller.scroll({
|
||||
left: scroller.scrollLeft + (scroller.offsetWidth * .75) * (type === 'right' ? 1 : -1),
|
||||
@@ -358,50 +371,58 @@
|
||||
return action === 'prev' ? 1 : galleryElements.length - 2;
|
||||
}
|
||||
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
rootCtx.registerInstance<SwitchElements>(json.id, {
|
||||
setCurrentItem(item: number) {
|
||||
const galleryElements = getItems();
|
||||
if (item < 0 || item > galleryElements.length - 1) {
|
||||
throw new Error('Item is out of range in "set-current-item" action');
|
||||
$: if (json) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerInstance<SwitchElements>(json.id, {
|
||||
setCurrentItem(item: number) {
|
||||
const galleryElements = getItems();
|
||||
if (item < 0 || item > galleryElements.length - 1) {
|
||||
throw new Error('Item is out of range in "set-current-item" action');
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, item);
|
||||
},
|
||||
setPreviousItem(overflow: Overflow) {
|
||||
const currentElementIndex = calculateCurrentElementIndex('prev');
|
||||
const galleryElements = getItems();
|
||||
let previousItem = currentElementIndex - 1;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? galleryElements.length - 1 : currentElementIndex;
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, previousItem);
|
||||
},
|
||||
setNextItem(overflow: Overflow) {
|
||||
// Go to scroller start, if we reached right/bottom edge of scroller
|
||||
const isEdgeScroll = orientation === 'horizontal' ? (
|
||||
scroller.scrollLeft + scroller.offsetWidth === scroller.scrollWidth
|
||||
) : (
|
||||
scroller.scrollTop + scroller.offsetHeight === scroller.scrollHeight
|
||||
);
|
||||
const galleryElements = getItems();
|
||||
if (isEdgeScroll && overflow === 'ring') {
|
||||
scrollToGalleryItem(galleryElements, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const currentElementIndex = calculateCurrentElementIndex('next');
|
||||
let nextItem = currentElementIndex + 1;
|
||||
|
||||
if (nextItem > galleryElements.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : currentElementIndex;
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, nextItem);
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, item);
|
||||
},
|
||||
setPreviousItem(overflow: Overflow) {
|
||||
const currentElementIndex = calculateCurrentElementIndex('prev');
|
||||
const galleryElements = getItems();
|
||||
let previousItem = currentElementIndex - 1;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? galleryElements.length - 1 : currentElementIndex;
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, previousItem);
|
||||
},
|
||||
setNextItem(overflow: Overflow) {
|
||||
// Go to scroller start, if we reached right/bottom edge of scroller
|
||||
const isEdgeScroll = orientation === 'horizontal' ? (
|
||||
scroller.scrollLeft + scroller.offsetWidth === scroller.scrollWidth
|
||||
) : (
|
||||
scroller.scrollTop + scroller.offsetHeight === scroller.scrollHeight
|
||||
);
|
||||
const galleryElements = getItems();
|
||||
if (isEdgeScroll && overflow === 'ring') {
|
||||
scrollToGalleryItem(galleryElements, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const currentElementIndex = calculateCurrentElementIndex('next');
|
||||
let nextItem = currentElementIndex + 1;
|
||||
|
||||
if (nextItem > galleryElements.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : currentElementIndex;
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, nextItem);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
@@ -420,8 +441,9 @@
|
||||
onDestroy(() => {
|
||||
mounted = false;
|
||||
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
rootCtx.unregisterInstance(json.id);
|
||||
if (prevId && !layoutParams?.fakeElement) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -451,24 +473,22 @@
|
||||
class={css['gallery__items-grid']}
|
||||
style={makeStyle(gridStyle)}
|
||||
>
|
||||
{#key itemsGrid}
|
||||
{#each itemsGrid as itemsRow, rowIndex}
|
||||
<div
|
||||
class={css.gallery__items}
|
||||
style={makeStyle(columnStyle)}
|
||||
bind:this={galleryItemsWrappers[rowIndex]}
|
||||
>
|
||||
{#each itemsRow as item}
|
||||
<Unknown
|
||||
layoutParams={childLayoutParams}
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/key}
|
||||
{#each itemsGrid as itemsRow, rowIndex}
|
||||
<div
|
||||
class={css.gallery__items}
|
||||
style={makeStyle(columnStyle)}
|
||||
bind:this={galleryItemsWrappers[rowIndex]}
|
||||
>
|
||||
{#each itemsRow as item}
|
||||
<Unknown
|
||||
layoutParams={childLayoutParams}
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{#if orientation === 'horizontal'}
|
||||
|
||||
@@ -30,7 +30,35 @@
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
let hasItemsError = false;
|
||||
let columnCount = 1;
|
||||
let childStore: Readable<ChildInfo[]>;
|
||||
let resultItems: {
|
||||
json: DivBaseData;
|
||||
templateContext: TemplateContext;
|
||||
origJson: DivBaseData;
|
||||
layoutParams: LayoutParams;
|
||||
}[];
|
||||
let columnsWeight: number[] = [];
|
||||
let rowsWeight: number[] = [];
|
||||
let columnsMinWidth: number[] = [];
|
||||
let rowsMinHeight: number[] = [];
|
||||
let rowCount = 0;
|
||||
let hasLayoutError = false;
|
||||
let contentVAlign: AlignmentVertical = 'top';
|
||||
let contentHAlign: AlignmentHorizontal = 'left';
|
||||
|
||||
$: if (json) {
|
||||
columnCount = 1;
|
||||
contentVAlign = 'top';
|
||||
contentHAlign = 'left';
|
||||
}
|
||||
|
||||
$: jsonItems = json.items;
|
||||
|
||||
$: jsonColumnCount = rootCtx.getDerivedFromVars(json.column_count);
|
||||
$: jsonContentVAlign = rootCtx.getDerivedFromVars(json.content_alignment_vertical);
|
||||
$: jsonContentHAlign = rootCtx.getDerivedFromVars(json.content_alignment_horizontal);
|
||||
|
||||
$: {
|
||||
if (!jsonItems?.length || !Array.isArray(jsonItems)) {
|
||||
hasItemsError = true;
|
||||
@@ -40,9 +68,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let columnCount = 1;
|
||||
$: jsonColumnCount = rootCtx.getDerivedFromVars(json.column_count);
|
||||
$: {
|
||||
columnCount = correctPositiveNumber($jsonColumnCount, columnCount);
|
||||
}
|
||||
@@ -76,7 +101,6 @@
|
||||
width: MaybeMissing<Size> | undefined;
|
||||
height: MaybeMissing<Size> | undefined;
|
||||
}
|
||||
let childStore: Readable<ChildInfo[]>;
|
||||
$: {
|
||||
let children: Readable<ChildInfo>[] = [];
|
||||
|
||||
@@ -95,18 +119,6 @@
|
||||
childStore = derived(children, val => [...val]);
|
||||
}
|
||||
|
||||
let resultItems: {
|
||||
json: DivBaseData;
|
||||
templateContext: TemplateContext;
|
||||
origJson: DivBaseData;
|
||||
layoutParams: LayoutParams;
|
||||
}[];
|
||||
let columnsWeight: number[] = [];
|
||||
let rowsWeight: number[] = [];
|
||||
let columnsMinWidth: number[] = [];
|
||||
let rowsMinHeight: number[] = [];
|
||||
let rowCount = 0;
|
||||
let hasLayoutError = false;
|
||||
$: {
|
||||
const used: Record<string, boolean> = {};
|
||||
let x = 0;
|
||||
@@ -202,14 +214,10 @@
|
||||
rowCount = y;
|
||||
}
|
||||
|
||||
let contentVAlign: AlignmentVertical = 'top';
|
||||
$: jsonContentVAlign = rootCtx.getDerivedFromVars(json.content_alignment_vertical);
|
||||
$: {
|
||||
contentVAlign = correctAlignmentVertical($jsonContentVAlign, contentVAlign);
|
||||
}
|
||||
|
||||
let contentHAlign: AlignmentHorizontal = 'left';
|
||||
$: jsonContentHAlign = rootCtx.getDerivedFromVars(json.content_alignment_horizontal);
|
||||
$: {
|
||||
contentHAlign = correctAlignmentHorizontal($jsonContentHAlign, contentHAlign);
|
||||
}
|
||||
@@ -238,15 +246,13 @@
|
||||
parentOf={json.items}
|
||||
{replaceItems}
|
||||
>
|
||||
{#key resultItems}
|
||||
{#each resultItems as item}
|
||||
<Unknown
|
||||
layoutParams={item.layoutParams}
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
/>
|
||||
{/each}
|
||||
{/key}
|
||||
{#each resultItems as item}
|
||||
<Unknown
|
||||
layoutParams={item.layoutParams}
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
/>
|
||||
{/each}
|
||||
</Outer>
|
||||
{/if}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
<script lang="ts" context="module">
|
||||
const FALLBACK_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
const EMPTY_IMAGE = 'empty://';
|
||||
// const DEFAULT_PLACEHOLDER_COLOR = correctColor('#14000000');
|
||||
const DEFAULT_PLACEHOLDER_COLOR = 'rgba(0,0,0,0.08)';
|
||||
|
||||
const STATE_LOADING = 0;
|
||||
const STATE_LOADED = 1;
|
||||
const STATE_ERROR = 2;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { afterUpdate, getContext, onDestroy } from 'svelte';
|
||||
|
||||
@@ -27,15 +38,6 @@
|
||||
export let origJson: DivBase | undefined = undefined;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const FALLBACK_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
const EMPTY_IMAGE = 'empty://';
|
||||
// const DEFAULT_PLACEHOLDER_COLOR = correctColor('#14000000');
|
||||
const DEFAULT_PLACEHOLDER_COLOR = 'rgba(0,0,0,0.08)';
|
||||
|
||||
const STATE_LOADING = 0;
|
||||
const STATE_LOADED = 1;
|
||||
const STATE_ERROR = 2;
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
let img: HTMLImageElement;
|
||||
@@ -44,10 +46,47 @@
|
||||
let isLottie = false;
|
||||
let placeholderColor = DEFAULT_PLACEHOLDER_COLOR;
|
||||
|
||||
let hasError = false;
|
||||
let imageUrl: string | undefined;
|
||||
let backgroundImage = '';
|
||||
// Exactly "none", "scale-down" would not match android
|
||||
let scale = 'none';
|
||||
let position = '50% 50%';
|
||||
let aspectPaddingBottom = '0';
|
||||
let tintColor: string | undefined = undefined;
|
||||
let tintMode: TintMode = 'source_in';
|
||||
let svgFilterId = '';
|
||||
let animationInterpolator = '';
|
||||
let animationFadeStart = 0;
|
||||
let animationDelay = 0;
|
||||
let animationDuration = 0;
|
||||
let filter = '';
|
||||
let filterClipPath = '';
|
||||
|
||||
$: if (json) {
|
||||
scale = 'none';
|
||||
position = '50% 50%';
|
||||
tintMode = 'source_in';
|
||||
}
|
||||
|
||||
$: jsonImageUrl = rootCtx.getDerivedFromVars(json.image_url);
|
||||
$: jsonGifUrl = rootCtx.getDerivedFromVars(json.gif_url);
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
$: jsonPreview = rootCtx.getDerivedFromVars(json.preview);
|
||||
$: jsonPlaceholderColor = rootCtx.getDerivedFromVars(json.placeholder_color);
|
||||
$: jsonScale = rootCtx.getDerivedFromVars(json.scale);
|
||||
$: jsonPosition = rootCtx.getDerivedFromVars({
|
||||
content_alignment_horizontal: json.content_alignment_horizontal,
|
||||
content_alignment_vertical: json.content_alignment_vertical
|
||||
});
|
||||
$: jsonA11y = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
$: jsonAspect = rootCtx.getDerivedFromVars(json.aspect);
|
||||
$: jsonTintColor = rootCtx.getDerivedFromVars(json.tint_color);
|
||||
$: jsonTintMode = rootCtx.getDerivedFromVars(json.tint_mode);
|
||||
$: jsonAppearanceAnimation = rootCtx.getDerivedFromVars(json.appearance_animation);
|
||||
$: jsonFilters = rootCtx.getDerivedFromVars(json.filters);
|
||||
|
||||
let imageUrl: string | undefined;
|
||||
$: {
|
||||
let img = json.type === 'gif' ? $jsonGifUrl : $jsonImageUrl;
|
||||
isEmpty = img === EMPTY_IMAGE;
|
||||
@@ -62,7 +101,6 @@
|
||||
}
|
||||
$: updateImageUrl(imageUrl);
|
||||
|
||||
let hasError = false;
|
||||
$: {
|
||||
if (!imageUrl) {
|
||||
hasError = true;
|
||||
@@ -72,14 +110,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: isWidthContent = $jsonWidth?.type === 'wrap_content';
|
||||
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
$: isHeightContent = $jsonHeight?.type === 'wrap_content';
|
||||
|
||||
$: jsonPreview = rootCtx.getDerivedFromVars(json.preview);
|
||||
let backgroundImage = '';
|
||||
$: {
|
||||
const preview = $jsonPreview;
|
||||
|
||||
@@ -90,25 +124,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonPlaceholderColor = rootCtx.getDerivedFromVars(json.placeholder_color);
|
||||
$: if (state === STATE_LOADING || state === STATE_ERROR || isEmpty) {
|
||||
placeholderColor = correctColor($jsonPlaceholderColor, 1, placeholderColor);
|
||||
} else {
|
||||
placeholderColor = '';
|
||||
}
|
||||
|
||||
$: jsonScale = rootCtx.getDerivedFromVars(json.scale);
|
||||
// Exactly "none", "scale-down" would not match android
|
||||
let scale = 'none';
|
||||
$: {
|
||||
scale = imageSize($jsonScale) || scale;
|
||||
}
|
||||
|
||||
$: jsonPosition = rootCtx.getDerivedFromVars({
|
||||
content_alignment_horizontal: json.content_alignment_horizontal,
|
||||
content_alignment_vertical: json.content_alignment_vertical
|
||||
});
|
||||
let position = '50% 50%';
|
||||
function updatePosition(pos: {
|
||||
content_alignment_horizontal?: AlignmentHorizontal;
|
||||
content_alignment_vertical?: AlignmentVertical;
|
||||
@@ -117,11 +142,8 @@
|
||||
}
|
||||
$: updatePosition($jsonPosition);
|
||||
|
||||
$: jsonA11y = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
$: alt = $jsonA11y?.description || '';
|
||||
|
||||
$: jsonAspect = rootCtx.getDerivedFromVars(json.aspect);
|
||||
let aspectPaddingBottom = '0';
|
||||
$: {
|
||||
const newRatio = $jsonAspect?.ratio;
|
||||
if (newRatio && isPositiveNumber(newRatio)) {
|
||||
@@ -131,11 +153,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonTintColor = rootCtx.getDerivedFromVars(json.tint_color);
|
||||
let tintColor: string | undefined = undefined;
|
||||
$: jsonTintMode = rootCtx.getDerivedFromVars(json.tint_mode);
|
||||
let tintMode: TintMode = 'source_in';
|
||||
let svgFilterId = '';
|
||||
$: {
|
||||
const val = $jsonTintColor;
|
||||
const newTintColor = val ? correctColor(val) : undefined;
|
||||
@@ -148,12 +165,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonAppearanceAnimation = rootCtx.getDerivedFromVars(json.appearance_animation);
|
||||
let animationInterpolator = '';
|
||||
let animationFadeStart = 0;
|
||||
let animationDelay = 0;
|
||||
let animationDuration = 0;
|
||||
|
||||
$: if ($jsonAppearanceAnimation && $jsonAppearanceAnimation.type === 'fade') {
|
||||
const animation = $jsonAppearanceAnimation;
|
||||
|
||||
@@ -163,9 +174,6 @@
|
||||
animationFadeStart = correctNonNegativeNumber(animation.alpha, 0);
|
||||
}
|
||||
|
||||
$: jsonFilters = rootCtx.getDerivedFromVars(json.filters);
|
||||
let filter = '';
|
||||
let filterClipPath = '';
|
||||
$: {
|
||||
let newFilter = '';
|
||||
let newClipPath = '';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<script lang="ts" context="module">
|
||||
const AVAIL_SHAPES = [
|
||||
'rounded_rectangle',
|
||||
'circle'
|
||||
];
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, tick } from 'svelte';
|
||||
|
||||
@@ -26,16 +33,8 @@
|
||||
export let origJson: DivBase | undefined = undefined;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const AVAIL_SHAPES = ['rounded_rectangle', 'circle'];
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
$: jsonShape = rootCtx.getDerivedFromVars(json.shape);
|
||||
$: jsonActiveItemColor = rootCtx.getDerivedFromVars(json.active_item_color);
|
||||
$: jsonInactiveItemColor = rootCtx.getDerivedFromVars(json.inactive_item_color);
|
||||
$: jsonActiveItemSize = rootCtx.getDerivedFromVars(json.active_item_size);
|
||||
$: jsonActiveShape = rootCtx.getDerivedFromVars(json.active_shape);
|
||||
$: jsonInactiveShape = rootCtx.getDerivedFromVars(json.inactive_shape);
|
||||
let activeStyle: DrawableStyle = {
|
||||
width: 13,
|
||||
height: 13,
|
||||
@@ -48,6 +47,44 @@
|
||||
borderRadius: 5,
|
||||
background: '#33919cb5'
|
||||
};
|
||||
|
||||
let placement: 'default' | 'stretch' = 'default';
|
||||
let spaceBetweenCenters = 15;
|
||||
let maxVisibleItems = 10;
|
||||
let itemSpacing = 5;
|
||||
|
||||
let scroller: HTMLElement;
|
||||
let indicatorItemsWrapper: HTMLElement;
|
||||
let pagerData: PagerData;
|
||||
|
||||
$: if (json) {
|
||||
placement = 'default';
|
||||
spaceBetweenCenters = 15;
|
||||
maxVisibleItems = 10;
|
||||
itemSpacing = 5;
|
||||
activeStyle = {
|
||||
width: 13,
|
||||
height: 13,
|
||||
borderRadius: 6.5,
|
||||
background: '#ffdc60'
|
||||
};
|
||||
inactiveStyle = {
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
background: '#33919cb5'
|
||||
};
|
||||
}
|
||||
|
||||
$: jsonShape = rootCtx.getDerivedFromVars(json.shape);
|
||||
$: jsonActiveItemColor = rootCtx.getDerivedFromVars(json.active_item_color);
|
||||
$: jsonInactiveItemColor = rootCtx.getDerivedFromVars(json.inactive_item_color);
|
||||
$: jsonActiveItemSize = rootCtx.getDerivedFromVars(json.active_item_size);
|
||||
$: jsonActiveShape = rootCtx.getDerivedFromVars(json.active_shape);
|
||||
$: jsonInactiveShape = rootCtx.getDerivedFromVars(json.inactive_shape);
|
||||
$: jsonSpaceBetweenCenters = rootCtx.getDerivedFromVars(json.space_between_centers);
|
||||
$: jsonItemsPlacement = rootCtx.getDerivedFromVars(json.items_placement);
|
||||
|
||||
$: {
|
||||
if ($jsonActiveShape) {
|
||||
activeStyle = correctDrawableStyle<DrawableStyle>({
|
||||
@@ -80,12 +117,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonSpaceBetweenCenters = rootCtx.getDerivedFromVars(json.space_between_centers);
|
||||
$: jsonItemsPlacement = rootCtx.getDerivedFromVars(json.items_placement);
|
||||
let placement: 'default' | 'stretch' = 'default';
|
||||
let spaceBetweenCenters = 15;
|
||||
let maxVisibleItems = 10;
|
||||
let itemSpacing = 5;
|
||||
$: if ($jsonItemsPlacement && ($jsonItemsPlacement.type === 'default' || $jsonItemsPlacement.type === 'stretch')) {
|
||||
placement = $jsonItemsPlacement.type;
|
||||
if (placement === 'default') {
|
||||
@@ -104,11 +135,6 @@
|
||||
spaceBetweenCenters = correctNonNegativeNumber($jsonSpaceBetweenCenters.value, spaceBetweenCenters);
|
||||
}
|
||||
}
|
||||
|
||||
let scroller: HTMLElement;
|
||||
let indicatorItemsWrapper: HTMLElement;
|
||||
let pagerData: PagerData;
|
||||
|
||||
$: pagers = rootCtx.getStore<Map<string, PagerData>>('pagers');
|
||||
$: {
|
||||
onPagerDataUpdate($pagers);
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
<script lang="ts" context="module">
|
||||
const isSupportInputMode = typeof document !== 'undefined' && 'inputMode' in document.createElement('input');
|
||||
|
||||
const KEYBOARD_MAP: Record<KeyboardType, string> = {
|
||||
email: 'email',
|
||||
number: 'number',
|
||||
phone: 'tel',
|
||||
single_line_text: 'text',
|
||||
multi_line_text: 'text',
|
||||
uri: 'url'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy, onMount, tick } from 'svelte';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
@@ -41,25 +54,79 @@
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
let prevId: string | undefined;
|
||||
let input: HTMLInputElement | HTMLSpanElement;
|
||||
let isPressed = false;
|
||||
let inputMask: BaseInputMask | null = null;
|
||||
|
||||
const variable = json.text_variable;
|
||||
const rawVariable = json.mask?.raw_text_variable;
|
||||
|
||||
let value = '';
|
||||
let contentEditableValue = '';
|
||||
let hasError = false;
|
||||
if (!variable) {
|
||||
let hintColor = '';
|
||||
let fontSize = 12;
|
||||
let fontWeight: number | undefined = undefined;
|
||||
let fontFamily = '';
|
||||
let lineHeight: number | undefined = undefined;
|
||||
let letterSpacing = '';
|
||||
let textColor = '#000';
|
||||
let highlightColor = '';
|
||||
let alignmentHorizontal: AlignmentHorizontal = 'left';
|
||||
let alignmentVertical: AlignmentVertical = 'center';
|
||||
let keyboardType = 'multi_line_text';
|
||||
let inputType = 'text';
|
||||
let inputMode: HTMLAttributes<HTMLInputElement>['inputmode'] = undefined;
|
||||
let maxHeight = '';
|
||||
let selfPadding: EdgeInsets | null = null;
|
||||
let padding = '';
|
||||
let verticalPadding = '';
|
||||
let description = '';
|
||||
|
||||
$: if (json) {
|
||||
hintColor = '';
|
||||
fontSize = 12;
|
||||
fontWeight = undefined;
|
||||
fontFamily = '';
|
||||
lineHeight = undefined;
|
||||
textColor = '#000';
|
||||
highlightColor = '';
|
||||
alignmentHorizontal = 'left';
|
||||
alignmentVertical = 'center';
|
||||
keyboardType = 'multi_line_text';
|
||||
inputType = 'text';
|
||||
inputMode = undefined;
|
||||
}
|
||||
|
||||
$: variable = json.text_variable;
|
||||
$: rawVariable = json.mask?.raw_text_variable;
|
||||
|
||||
$: valueVariable = variable && rootCtx.getVariable(variable, 'string') || createVariable('temp', 'string', '');
|
||||
$: rawValueVariable = rawVariable && rootCtx.getVariable(rawVariable, 'string') || createVariable('temp', 'string', '');
|
||||
|
||||
$: jsonHintText = rootCtx.getDerivedFromVars(json.hint_text);
|
||||
$: jsonHintColor = rootCtx.getDerivedFromVars(json.hint_color);
|
||||
$: jsonFontSize = rootCtx.getDerivedFromVars(json.font_size);
|
||||
$: jsonFontWeight = rootCtx.getDerivedFromVars(json.font_weight);
|
||||
$: jsonFontFamily = rootCtx.getDerivedFromVars(json.font_family);
|
||||
$: jsonLineHeight = rootCtx.getDerivedFromVars(json.line_height);
|
||||
$: jsonLetterSpacing = rootCtx.getDerivedFromVars(json.letter_spacing);
|
||||
$: jsonTextColor = rootCtx.getDerivedFromVars(json.text_color);
|
||||
$: jsonHighlightColor = rootCtx.getDerivedFromVars(json.highlight_color);
|
||||
$: jsonAlignmentHorizontal = rootCtx.getDerivedFromVars(json.text_alignment_horizontal);
|
||||
$: jsonAlignmentVertical = rootCtx.getDerivedFromVars(json.text_alignment_vertical);
|
||||
$: jsonKeyboardType = rootCtx.getDerivedFromVars(json.keyboard_type);
|
||||
$: jsonMask = rootCtx.getDerivedFromVars(json.mask);
|
||||
$: jsonVisibleMaxLines = rootCtx.getDerivedFromVars(json.max_visible_lines);
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
$: jsonSelectAll = rootCtx.getDerivedFromVars(json.select_all_on_focus);
|
||||
|
||||
$: if (variable) {
|
||||
hasError = false;
|
||||
} else {
|
||||
hasError = true;
|
||||
rootCtx.logError(wrapError(new Error('Missing "text_variable" in "input"')));
|
||||
}
|
||||
|
||||
let valueVariable = variable && rootCtx.getVariable(variable, 'string') || createVariable('temp', 'string', '');
|
||||
let rawValueVariable = rawVariable && rootCtx.getVariable(rawVariable, 'string') || createVariable('temp', 'string', '');
|
||||
let value = '';
|
||||
let contentEditableValue = '';
|
||||
|
||||
const jsonMask = rootCtx.getDerivedFromVars(json.mask);
|
||||
function updateMaskData(mask: MaybeMissing<InputMask> | undefined): void {
|
||||
if (mask?.type === 'fixed_length') {
|
||||
inputMask = updateFixedMask(mask, rootCtx.logError, inputMask as FixedLengthInputMask);
|
||||
@@ -81,25 +148,16 @@
|
||||
runRawValueMask();
|
||||
}
|
||||
|
||||
const jsonHintText = rootCtx.getDerivedFromVars(json.hint_text);
|
||||
$: placeholder = $jsonHintText;
|
||||
|
||||
const jsonHintColor = rootCtx.getDerivedFromVars(json.hint_color);
|
||||
let hintColor = '';
|
||||
$: {
|
||||
hintColor = correctColor($jsonHintColor, 1, hintColor);
|
||||
}
|
||||
|
||||
const jsonFontSize = rootCtx.getDerivedFromVars(json.font_size);
|
||||
let fontSize = 12;
|
||||
$: {
|
||||
fontSize = correctPositiveNumber($jsonFontSize, fontSize);
|
||||
}
|
||||
|
||||
const jsonFontWeight = rootCtx.getDerivedFromVars(json.font_weight);
|
||||
const jsonFontFamily = rootCtx.getDerivedFromVars(json.font_family);
|
||||
let fontWeight: number | undefined = undefined;
|
||||
let fontFamily = '';
|
||||
$: {
|
||||
fontWeight = correctFontWeight($jsonFontWeight, fontWeight);
|
||||
if ($jsonFontFamily && typeof $jsonFontFamily === 'string') {
|
||||
@@ -111,8 +169,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonLineHeight = rootCtx.getDerivedFromVars(json.line_height);
|
||||
let lineHeight: number | undefined = undefined;
|
||||
$: {
|
||||
const val = $jsonLineHeight;
|
||||
if (isPositiveNumber(val)) {
|
||||
@@ -120,51 +176,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonLetterSpacing = rootCtx.getDerivedFromVars(json.letter_spacing);
|
||||
let letterSpacing = '';
|
||||
$: {
|
||||
if (isNumber($jsonLetterSpacing)) {
|
||||
letterSpacing = pxToEm($jsonLetterSpacing);
|
||||
}
|
||||
}
|
||||
|
||||
const jsonTextColor = rootCtx.getDerivedFromVars(json.text_color);
|
||||
let textColor = '#000';
|
||||
$: {
|
||||
textColor = correctColor($jsonTextColor, 1, textColor);
|
||||
}
|
||||
|
||||
const jsonHighlightColor = rootCtx.getDerivedFromVars(json.highlight_color);
|
||||
let highlightColor = '';
|
||||
$: {
|
||||
highlightColor = correctColor($jsonHighlightColor, 1, highlightColor);
|
||||
}
|
||||
|
||||
const jsonAlignmentHorizontal = rootCtx.getDerivedFromVars(json.text_alignment_horizontal);
|
||||
let alignmentHorizontal: AlignmentHorizontal = 'left';
|
||||
$: {
|
||||
alignmentHorizontal = correctAlignmentHorizontal($jsonAlignmentHorizontal, alignmentHorizontal);
|
||||
}
|
||||
|
||||
const jsonAlignmentVertical = rootCtx.getDerivedFromVars(json.text_alignment_vertical);
|
||||
let alignmentVertical: AlignmentVertical = 'center';
|
||||
$: {
|
||||
alignmentVertical = correctAlignmentVertical($jsonAlignmentVertical, alignmentVertical);
|
||||
}
|
||||
|
||||
const jsonKeyboardType = rootCtx.getDerivedFromVars(json.keyboard_type);
|
||||
const KEYBOARD_MAP: Record<KeyboardType, string> = {
|
||||
email: 'email',
|
||||
number: 'number',
|
||||
phone: 'tel',
|
||||
single_line_text: 'text',
|
||||
multi_line_text: 'text',
|
||||
uri: 'url'
|
||||
};
|
||||
let keyboardType = 'multi_line_text';
|
||||
let inputType = 'text';
|
||||
const isSupportInputMode = typeof document !== 'undefined' && 'inputMode' in document.createElement('input');
|
||||
let inputMode: HTMLAttributes<HTMLInputElement>['inputmode'] = undefined;
|
||||
$: {
|
||||
if ($jsonKeyboardType && $jsonKeyboardType in KEYBOARD_MAP) {
|
||||
inputType = KEYBOARD_MAP[$jsonKeyboardType as KeyboardType];
|
||||
@@ -177,17 +210,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonVisibleMaxLines = rootCtx.getDerivedFromVars(json.max_visible_lines);
|
||||
$: isMultiline = keyboardType === 'multi_line_text'/* && isPositiveNumber($jsonVisibleMaxLines) && $jsonVisibleMaxLines > 1*/;
|
||||
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
let maxHeight = '';
|
||||
let selfPadding: EdgeInsets | null = null;
|
||||
let padding = '';
|
||||
let verticalPadding = '';
|
||||
$: {
|
||||
if (isPositiveNumber($jsonVisibleMaxLines)) {
|
||||
maxHeight = `calc(${$jsonVisibleMaxLines * (lineHeight || 1.25) * (fontSize / 10) + 'em'} + ${pxToEmWithUnits(correctNonNegativeNumber($jsonPaddings?.top, 0) + correctNonNegativeNumber($jsonPaddings?.bottom, 0))})`;
|
||||
} else {
|
||||
maxHeight = '';
|
||||
}
|
||||
selfPadding = correctEdgeInsertsObject(($jsonPaddings) ? $jsonPaddings : undefined, selfPadding);
|
||||
padding = selfPadding ? edgeInsertsToCss({
|
||||
@@ -202,8 +231,6 @@
|
||||
}) : '';
|
||||
}
|
||||
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
let description = '';
|
||||
$: if ($jsonAccessibility?.description) {
|
||||
description = $jsonAccessibility.description;
|
||||
} else {
|
||||
@@ -212,8 +239,6 @@
|
||||
}));
|
||||
}
|
||||
|
||||
const jsonSelectAll = rootCtx.getDerivedFromVars(json.select_all_on_focus);
|
||||
|
||||
$: mods = {
|
||||
'highlight-color': Boolean(highlightColor),
|
||||
multiline: isMultiline,
|
||||
@@ -344,15 +369,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (input && inputMask) {
|
||||
if ($rawValueVariable) {
|
||||
inputMask.overrideRawValue($rawValueVariable);
|
||||
$valueVariable = value = contentEditableValue = inputMask.value;
|
||||
}
|
||||
$: if (input && json) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterFocusable(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
if (json.id) {
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerFocusable(json.id, {
|
||||
focus() {
|
||||
if (input) {
|
||||
@@ -361,11 +385,21 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (input && inputMask) {
|
||||
if ($rawValueVariable) {
|
||||
inputMask.overrideRawValue($rawValueVariable);
|
||||
$valueVariable = value = contentEditableValue = inputMask.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (json.id) {
|
||||
rootCtx.unregisterFocusable(json.id);
|
||||
if (prevId) {
|
||||
rootCtx.unregisterFocusable(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -38,10 +38,38 @@
|
||||
const rightClass = rootCtx.getCustomization('pagerRightClass');
|
||||
|
||||
const isDesktop = rootCtx.isDesktop;
|
||||
|
||||
const onScrollDebounced = debounce(onScroll, 50);
|
||||
|
||||
let prevId: string | undefined;
|
||||
|
||||
let pagerItemsWrapper: HTMLElement;
|
||||
let mounted = false;
|
||||
|
||||
let hasItemsError = false;
|
||||
|
||||
let currentItem = 0;
|
||||
let prevSelectedItem = 0;
|
||||
|
||||
let hasLayoutModeError = false;
|
||||
|
||||
let orientation: Orientation = 'horizontal';
|
||||
let itemSpacing = '';
|
||||
let padding = '';
|
||||
let sizeVal = '';
|
||||
|
||||
$: if (json) {
|
||||
itemSpacing = '';
|
||||
padding = '';
|
||||
sizeVal = '';
|
||||
}
|
||||
|
||||
$: jsonLayoutMode = rootCtx.getDerivedFromVars(json.layout_mode);
|
||||
$: jsonOrientation = rootCtx.getDerivedFromVars(json.orientation);
|
||||
$: jsonItemSpacing = rootCtx.getDerivedFromVars(json.item_spacing);
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
$: jsonRestrictParentScroll = rootCtx.getDerivedFromVars(json.restrict_parent_scroll);
|
||||
|
||||
$: {
|
||||
if (!json.items?.length || !Array.isArray(json.items)) {
|
||||
hasItemsError = true;
|
||||
@@ -73,12 +101,6 @@
|
||||
origJson: item
|
||||
};
|
||||
});
|
||||
|
||||
let currentItem = 0;
|
||||
let prevSelectedItem = 0;
|
||||
|
||||
let hasLayoutModeError = false;
|
||||
$: jsonLayoutMode = rootCtx.getDerivedFromVars(json.layout_mode);
|
||||
$: {
|
||||
if (!$jsonLayoutMode) {
|
||||
hasLayoutModeError = true;
|
||||
@@ -91,14 +113,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
let orientation: Orientation = 'horizontal';
|
||||
$: jsonOrientation = rootCtx.getDerivedFromVars(json.orientation);
|
||||
$: {
|
||||
orientation = correctGeneralOrientation($jsonOrientation, orientation);
|
||||
}
|
||||
|
||||
let itemSpacing = '';
|
||||
$: jsonItemSpacing = rootCtx.getDerivedFromVars(json.item_spacing);
|
||||
$: {
|
||||
const val = $jsonItemSpacing?.value;
|
||||
if (val && isNonNegativeNumber(val)) {
|
||||
@@ -106,16 +124,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
let padding = '';
|
||||
$: {
|
||||
padding = correctEdgeInserts($jsonPaddings, padding);
|
||||
}
|
||||
|
||||
$: jsonRestrictParentScroll = rootCtx.getDerivedFromVars(json.restrict_parent_scroll);
|
||||
|
||||
$: gridAuto = orientation === 'horizontal' ? 'grid-auto-columns' : 'grid-auto-rows';
|
||||
let sizeVal = '';
|
||||
|
||||
$: {
|
||||
if ($jsonLayoutMode?.type === 'fixed') {
|
||||
@@ -185,8 +198,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const onScrollDebounced = debounce(onScroll, 50);
|
||||
|
||||
$: pagers = rootCtx.getStore<Map<string, PagerData>>('pagers');
|
||||
|
||||
function pagerDataUpdate(size: number, currentItem: number): void {
|
||||
@@ -248,18 +259,26 @@
|
||||
scrollToPagerItem(nextItem);
|
||||
}
|
||||
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
rootCtx.registerInstance<SwitchElements>(json.id, {
|
||||
setCurrentItem(item: number) {
|
||||
if (item < 0 || item > items.length - 1) {
|
||||
throw new Error('Item is out of range in "set-current-item" action');
|
||||
}
|
||||
$: if (json) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
scrollToPagerItem(item);
|
||||
},
|
||||
setPreviousItem,
|
||||
setNextItem
|
||||
});
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerInstance<SwitchElements>(json.id, {
|
||||
setCurrentItem(item: number) {
|
||||
if (item < 0 || item > items.length - 1) {
|
||||
throw new Error('Item is out of range in "set-current-item" action');
|
||||
}
|
||||
|
||||
scrollToPagerItem(item);
|
||||
},
|
||||
setPreviousItem,
|
||||
setNextItem
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
@@ -281,8 +300,9 @@
|
||||
onDestroy(() => {
|
||||
mounted = false;
|
||||
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
rootCtx.unregisterInstance(json.id);
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -304,18 +324,16 @@
|
||||
bind:this={pagerItemsWrapper}
|
||||
on:scroll={onScrollDebounced}
|
||||
>
|
||||
{#key items}
|
||||
{#each items as item}
|
||||
<div class={css.pager__item}>
|
||||
<Unknown
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
layoutParams={layoutParams?.fakeElement ? { fakeElement: true } : undefined}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{/key}
|
||||
{#each items as item}
|
||||
<div class={css.pager__item}>
|
||||
<Unknown
|
||||
div={item.json}
|
||||
templateContext={item.templateContext}
|
||||
origJson={item.origJson}
|
||||
layoutParams={layoutParams?.fakeElement ? { fakeElement: true } : undefined}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if hasScrollLeft && shouldCheckArrows}
|
||||
|
||||
@@ -29,28 +29,61 @@
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
const variable = json.value_variable;
|
||||
let prevId: string | undefined;
|
||||
let select: HTMLSelectElement;
|
||||
|
||||
let hasError = false;
|
||||
if (!variable) {
|
||||
let selectText = '';
|
||||
let selfPadding: EdgeInsets | null = null;
|
||||
let padding = '';
|
||||
let hintColor = 'rgba(0,0,0,.45)';
|
||||
let fontSize = 12;
|
||||
let fontWeight: number | undefined = undefined;
|
||||
let fontFamily = '';
|
||||
let lineHeight: number | undefined = undefined;
|
||||
let letterSpacing = '';
|
||||
let textColor = '#000';
|
||||
let description = '';
|
||||
|
||||
$: if (json) {
|
||||
selfPadding = null;
|
||||
hintColor = 'rgba(0,0,0,.45)';
|
||||
fontSize = 12;
|
||||
fontWeight = undefined;
|
||||
fontFamily = '';
|
||||
lineHeight = undefined;
|
||||
letterSpacing = '';
|
||||
textColor = '#000';
|
||||
description = '';
|
||||
}
|
||||
|
||||
$: variable = json.value_variable;
|
||||
$: items = json.options;
|
||||
$: filteredItems = Array.isArray(items) && items.filter(it => typeof it.value === 'string') || [];
|
||||
|
||||
$: valueVariable = variable && rootCtx.getVariable(variable, 'string') || createVariable('temp', 'string', '');
|
||||
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
$: jsonHintText = rootCtx.getDerivedFromVars(json.hint_text);
|
||||
$: jsonHintColor = rootCtx.getDerivedFromVars(json.hint_color);
|
||||
$: jsonFontSize = rootCtx.getDerivedFromVars(json.font_size);
|
||||
$: jsonFontWeight = rootCtx.getDerivedFromVars(json.font_weight);
|
||||
$: jsonFontFamily = rootCtx.getDerivedFromVars(json.font_family);
|
||||
$: jsonLineHeight = rootCtx.getDerivedFromVars(json.line_height);
|
||||
$: jsonLetterSpacing = rootCtx.getDerivedFromVars(json.letter_spacing);
|
||||
$: jsonTextColor = rootCtx.getDerivedFromVars(json.text_color);
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
|
||||
$: if (!(Array.isArray(filteredItems) && filteredItems.length)) {
|
||||
rootCtx.logError(wrapError(new Error('Empty selection "items" in "select"')));
|
||||
}
|
||||
|
||||
$: if (variable) {
|
||||
hasError = false;
|
||||
} else {
|
||||
hasError = true;
|
||||
rootCtx.logError(wrapError(new Error('Missing "value_variable" in "select"')));
|
||||
}
|
||||
|
||||
let valueVariable = variable && rootCtx.getVariable(variable, 'string') || createVariable('temp', 'string', '');
|
||||
let value = '';
|
||||
$: {
|
||||
value = $valueVariable as string;
|
||||
}
|
||||
|
||||
const items = json.options;
|
||||
const filteredItems = Array.isArray(items) && items.filter(it => typeof it.value === 'string') || [];
|
||||
if (!(Array.isArray(filteredItems) && filteredItems.length)) {
|
||||
rootCtx.logError(wrapError(new Error('Empty selection "items" in "select"')));
|
||||
}
|
||||
|
||||
let selectText = '';
|
||||
$: {
|
||||
const item = filteredItems.find(it => {
|
||||
return it.value === $valueVariable;
|
||||
@@ -65,9 +98,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
let selfPadding: EdgeInsets | null = null;
|
||||
let padding = '';
|
||||
$: {
|
||||
selfPadding = correctEdgeInsertsObject(($jsonPaddings) ? $jsonPaddings : undefined, selfPadding);
|
||||
padding = selfPadding ? edgeInsertsToCss({
|
||||
@@ -78,25 +108,14 @@
|
||||
}) : '';
|
||||
}
|
||||
|
||||
const jsonHintText = rootCtx.getDerivedFromVars(json.hint_text);
|
||||
$: hint = $jsonHintText;
|
||||
|
||||
const jsonHintColor = rootCtx.getDerivedFromVars(json.hint_color);
|
||||
let hintColor = 'rgba(0,0,0,.45)';
|
||||
$: {
|
||||
hintColor = correctColor($jsonHintColor, 1, hintColor);
|
||||
}
|
||||
|
||||
const jsonFontSize = rootCtx.getDerivedFromVars(json.font_size);
|
||||
let fontSize = 12;
|
||||
$: {
|
||||
fontSize = correctPositiveNumber($jsonFontSize, fontSize);
|
||||
}
|
||||
|
||||
const jsonFontWeight = rootCtx.getDerivedFromVars(json.font_weight);
|
||||
const jsonFontFamily = rootCtx.getDerivedFromVars(json.font_family);
|
||||
let fontWeight: number | undefined = undefined;
|
||||
let fontFamily = '';
|
||||
$: {
|
||||
fontWeight = correctFontWeight($jsonFontWeight, fontWeight);
|
||||
if ($jsonFontFamily && typeof $jsonFontFamily === 'string') {
|
||||
@@ -108,8 +127,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonLineHeight = rootCtx.getDerivedFromVars(json.line_height);
|
||||
let lineHeight: number | undefined = undefined;
|
||||
$: {
|
||||
const val = $jsonLineHeight;
|
||||
if (isPositiveNumber(val)) {
|
||||
@@ -117,22 +134,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonLetterSpacing = rootCtx.getDerivedFromVars(json.letter_spacing);
|
||||
let letterSpacing = '';
|
||||
$: {
|
||||
if (isNumber($jsonLetterSpacing)) {
|
||||
letterSpacing = pxToEm($jsonLetterSpacing / fontSize * 10);
|
||||
}
|
||||
}
|
||||
|
||||
const jsonTextColor = rootCtx.getDerivedFromVars(json.text_color);
|
||||
let textColor = '#000';
|
||||
$: {
|
||||
textColor = correctColor($jsonTextColor, 1, textColor);
|
||||
}
|
||||
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
let description = '';
|
||||
$: if ($jsonAccessibility?.description) {
|
||||
description = $jsonAccessibility.description;
|
||||
} else {
|
||||
@@ -162,8 +173,14 @@
|
||||
'letter-spacing': letterSpacing
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
if (json.id) {
|
||||
$: if (json && select) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterFocusable(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerFocusable(json.id, {
|
||||
focus() {
|
||||
if (select) {
|
||||
@@ -172,11 +189,12 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (json.id) {
|
||||
rootCtx.unregisterFocusable(json.id);
|
||||
if (prevId) {
|
||||
rootCtx.unregisterFocusable(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -199,7 +217,7 @@
|
||||
>
|
||||
<span class={css['select__select-text']} style={makeStyle(innerStl)} aria-hidden="true">
|
||||
<!--Space holder should have height even it has no value-->
|
||||
{selectText || hint || ''}
|
||||
{selectText || $jsonHintText || ''}
|
||||
</span>
|
||||
|
||||
<select
|
||||
|
||||
@@ -22,8 +22,17 @@
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
$: jsonDelimiterStyle = rootCtx.getDerivedFromVars(json.delimiter_style);
|
||||
let orientation: Orientation = 'horizontal';
|
||||
// let background = correctColor('#14000000');
|
||||
let background = 'rgba(0,0,0,0.08)';
|
||||
|
||||
$: if (json) {
|
||||
orientation = 'horizontal';
|
||||
background = 'rgba(0,0,0,0.08)';
|
||||
}
|
||||
|
||||
$: jsonDelimiterStyle = rootCtx.getDerivedFromVars(json.delimiter_style);
|
||||
|
||||
$: {
|
||||
orientation = correctGeneralOrientation($jsonDelimiterStyle?.orientation, orientation);
|
||||
}
|
||||
@@ -40,8 +49,6 @@
|
||||
)
|
||||
);
|
||||
|
||||
// let background = correctColor('#14000000');
|
||||
let background = 'rgba(0,0,0,0.08)';
|
||||
$: {
|
||||
background = correctColor($jsonDelimiterStyle?.color, 1, background);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
<script lang="ts" context="module">
|
||||
const DEFAULT_DRAWABLE_STYLE: DrawableStyle = {
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
background: '#000'
|
||||
};
|
||||
const THUMB_MARK_SHAPES = [
|
||||
'rounded_rectangle',
|
||||
'circle'
|
||||
];
|
||||
const TRACK_SHAPES = [
|
||||
'rounded_rectangle'
|
||||
];
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy, onMount } from 'svelte';
|
||||
|
||||
@@ -25,38 +41,67 @@
|
||||
export let origJson: DivBase | undefined = undefined;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const DEFAULT_DRAWABLE_STYLE: DrawableStyle = {
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
background: '#000'
|
||||
};
|
||||
|
||||
const THUMB_MARK_SHAPES = ['rounded_rectangle', 'circle'];
|
||||
const TRACK_SHAPES = ['rounded_rectangle'];
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
const actionCtx = getContext<ActionCtxValue>(ACTION_CTX);
|
||||
|
||||
let prevId: string | undefined;
|
||||
let input: HTMLInputElement;
|
||||
let tracksInner: HTMLElement;
|
||||
let switchedTracks = false;
|
||||
let minValue = 0;
|
||||
let maxValue = 100;
|
||||
let thumbStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
let thumbSecondaryStyle = thumbStyle;
|
||||
let trackInactiveStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
let trackActiveStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
let markActiveTicks: number[];
|
||||
let markActiveStyle: DrawableStyle | null = null;
|
||||
let markInactiveTicks: number[];
|
||||
let markInactiveStyle: DrawableStyle | null = null;
|
||||
let textStyle: TransformedSliderTextStyle | undefined = undefined;
|
||||
let textSecondaryStyle: TransformedSliderTextStyle | undefined = textStyle;
|
||||
let description = '';
|
||||
let secondaryDescription = '';
|
||||
let hasError = false;
|
||||
|
||||
$: if (json) {
|
||||
thumbStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
thumbSecondaryStyle = thumbStyle;
|
||||
trackInactiveStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
trackActiveStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
markActiveStyle = null;
|
||||
markInactiveStyle = null;
|
||||
textStyle = undefined;
|
||||
textSecondaryStyle = undefined;
|
||||
description = '';
|
||||
secondaryDescription = '';
|
||||
}
|
||||
|
||||
$: firstVariable = json.thumb_value_variable;
|
||||
$: secondVariable = json.thumb_secondary_value_variable;
|
||||
|
||||
$: valueVariable = firstVariable && rootCtx.getVariable(firstVariable, 'integer') || createVariable('temp', 'integer', 0);
|
||||
$: value2Variable = secondVariable && rootCtx.getVariable(secondVariable, 'integer') || createVariable('temp', 'integer', 0);
|
||||
|
||||
$: jsonMinValue = rootCtx.getDerivedFromVars(json.min_value);
|
||||
$: jsonMaxValue = rootCtx.getDerivedFromVars(json.max_value);
|
||||
let minValue = 0;
|
||||
let maxValue = 100;
|
||||
$: jsonThumbStyle = rootCtx.getDerivedFromVars(json.thumb_style);
|
||||
$: jsonThumbSecondaryStyle = rootCtx.getDerivedFromVars(json.thumb_secondary_style);
|
||||
$: jsonTrackInactiveStyle = rootCtx.getDerivedFromVars(json.track_inactive_style);
|
||||
$: jsonTrackActiveStyle = rootCtx.getDerivedFromVars(json.track_active_style);
|
||||
$: jsonMarkActiveStyle = rootCtx.getDerivedFromVars(json.tick_mark_active_style);
|
||||
$: jsonMarkInactiveStyle = rootCtx.getDerivedFromVars(json.tick_mark_inactive_style);
|
||||
$: jsonTextStyle = rootCtx.getDerivedFromVars(json.thumb_text_style);
|
||||
$: jsonSecondaryTextStyle = rootCtx.getDerivedFromVars(json.thumb_secondary_text_style);
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
$: jsonSecondaryAccessibility = rootCtx.getDerivedFromVars(json.secondary_value_accessibility);
|
||||
|
||||
$: {
|
||||
minValue = correctNumber($jsonMinValue, minValue);
|
||||
maxValue = correctNumber($jsonMaxValue, maxValue);
|
||||
checkTicks();
|
||||
}
|
||||
|
||||
const firstVariable = json.thumb_value_variable;
|
||||
const secondVariable = json.thumb_secondary_value_variable;
|
||||
|
||||
let valueVariable = firstVariable && rootCtx.getVariable(firstVariable, 'integer') || createVariable('temp', 'integer', 0);
|
||||
let value2Variable = secondVariable && rootCtx.getVariable(secondVariable, 'integer') || createVariable('temp', 'integer', 0);
|
||||
|
||||
let value = clamp($valueVariable || 0, minValue, maxValue);
|
||||
let value2 = clamp($value2Variable || 0, minValue, maxValue);
|
||||
|
||||
@@ -74,26 +119,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonThumbStyle = rootCtx.getDerivedFromVars(json.thumb_style);
|
||||
let thumbStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
$: {
|
||||
thumbStyle = correctDrawableStyle($jsonThumbStyle, THUMB_MARK_SHAPES, thumbStyle);
|
||||
}
|
||||
|
||||
$: jsonThumbSecondaryStyle = rootCtx.getDerivedFromVars(json.thumb_secondary_style);
|
||||
let thumbSecondaryStyle = thumbStyle;
|
||||
$: {
|
||||
thumbSecondaryStyle = correctDrawableStyle($jsonThumbSecondaryStyle, THUMB_MARK_SHAPES, thumbStyle);
|
||||
}
|
||||
|
||||
$: jsonTrackInactiveStyle = rootCtx.getDerivedFromVars(json.track_inactive_style);
|
||||
let trackInactiveStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
$: {
|
||||
trackInactiveStyle = correctDrawableStyle($jsonTrackInactiveStyle, TRACK_SHAPES, trackInactiveStyle);
|
||||
}
|
||||
|
||||
$: jsonTrackActiveStyle = rootCtx.getDerivedFromVars(json.track_active_style);
|
||||
let trackActiveStyle = DEFAULT_DRAWABLE_STYLE;
|
||||
$: {
|
||||
trackActiveStyle = correctDrawableStyle($jsonTrackActiveStyle, TRACK_SHAPES, trackActiveStyle);
|
||||
}
|
||||
@@ -117,9 +154,6 @@
|
||||
return res;
|
||||
}
|
||||
|
||||
$: jsonMarkActiveStyle = rootCtx.getDerivedFromVars(json.tick_mark_active_style);
|
||||
let markActiveTicks: number[];
|
||||
let markActiveStyle: DrawableStyle | null = null;
|
||||
$: {
|
||||
let newStyle = correctDrawableStyle($jsonMarkActiveStyle, THUMB_MARK_SHAPES, DEFAULT_DRAWABLE_STYLE);
|
||||
|
||||
@@ -136,9 +170,6 @@
|
||||
markActiveTicks = [];
|
||||
}
|
||||
|
||||
$: jsonMarkInactiveStyle = rootCtx.getDerivedFromVars(json.tick_mark_inactive_style);
|
||||
let markInactiveTicks: number[];
|
||||
let markInactiveStyle: DrawableStyle | null = null;
|
||||
$: {
|
||||
let newStyle = correctDrawableStyle($jsonMarkInactiveStyle, THUMB_MARK_SHAPES, DEFAULT_DRAWABLE_STYLE);
|
||||
|
||||
@@ -155,20 +186,14 @@
|
||||
markInactiveTicks = [];
|
||||
}
|
||||
|
||||
$: jsonTextStyle = rootCtx.getDerivedFromVars(json.thumb_text_style);
|
||||
let textStyle: TransformedSliderTextStyle | undefined = undefined;
|
||||
$: {
|
||||
textStyle = correctSliderTextStyle($jsonTextStyle, textStyle);
|
||||
}
|
||||
|
||||
$: jsonSecondaryTextStyle = rootCtx.getDerivedFromVars(json.thumb_secondary_text_style);
|
||||
let textSecondaryStyle: TransformedSliderTextStyle | undefined = textStyle;
|
||||
$: {
|
||||
textSecondaryStyle = correctSliderTextStyle($jsonSecondaryTextStyle, textStyle);
|
||||
}
|
||||
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
let description = '';
|
||||
$: if ($jsonAccessibility?.description) {
|
||||
description = $jsonAccessibility.description;
|
||||
} else {
|
||||
@@ -177,8 +202,6 @@
|
||||
}));
|
||||
}
|
||||
|
||||
$: jsonSecondaryAccessibility = rootCtx.getDerivedFromVars(json.secondary_value_accessibility);
|
||||
let secondaryDescription = '';
|
||||
$: if ($jsonSecondaryAccessibility?.description) {
|
||||
secondaryDescription = $jsonSecondaryAccessibility.description;
|
||||
} else if (secondVariable) {
|
||||
@@ -187,7 +210,6 @@
|
||||
}));
|
||||
}
|
||||
|
||||
let hasError = false;
|
||||
$: {
|
||||
let newHasError = false;
|
||||
|
||||
@@ -313,10 +335,14 @@
|
||||
|
||||
const checkTicksDebounced = debounce(checkTicks, 50);
|
||||
|
||||
onMount(() => {
|
||||
checkTicks();
|
||||
$: if (json && input) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterFocusable(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
if (json.id) {
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerFocusable(json.id, {
|
||||
focus() {
|
||||
if (input) {
|
||||
@@ -325,11 +351,16 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
checkTicks();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (json.id) {
|
||||
rootCtx.unregisterFocusable(json.id);
|
||||
if (prevId) {
|
||||
rootCtx.unregisterFocusable(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -25,19 +25,50 @@
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
const stateCtx = getContext<StateCtxValue>(STATE_CTX);
|
||||
|
||||
let hasError = false;
|
||||
|
||||
let animationRoot: HTMLElement | undefined;
|
||||
let transitionChangeBoxes: Map<string, DOMRect> = new Map();
|
||||
let childrenIds = new Set<string>();
|
||||
|
||||
let childStateMap: Map<string, StateInterface> | null = null;
|
||||
let animationList: (AnimationItemWithMaxDuration | ChangeBoundsItem)[] = [];
|
||||
let childrenWithTransitionIn: ChildWithTransition[] = [];
|
||||
let childrenWithTransitionOut: ChildWithTransition[] = [];
|
||||
let childrenWithTransitionChange: ChildWithTransitionChange[] = [];
|
||||
|
||||
let prevStateId: string | undefined;
|
||||
$: stateId = json.div_id || json.id;
|
||||
let selectedId: string | undefined;
|
||||
let selectedState: State | null = null;
|
||||
$: jsonDefaultStateId = rootCtx.getJsonWithVars(json.default_state_id);
|
||||
$: stateVariableName = json.state_id_variable;
|
||||
$: stateVariable = stateVariableName ?
|
||||
rootCtx.getVariable(stateVariableName, 'string') :
|
||||
null;
|
||||
let inited = false;
|
||||
|
||||
$: if (json) {
|
||||
inited = false;
|
||||
}
|
||||
|
||||
$: if (stateId) {
|
||||
hasError = false;
|
||||
} else {
|
||||
hasError = true;
|
||||
rootCtx.logError(wrapError(new Error('Missing "id" prop for div "state"')));
|
||||
}
|
||||
|
||||
$: if (json) {
|
||||
childrenIds = new Set<string>();
|
||||
}
|
||||
|
||||
let hasError = false;
|
||||
$: items = json.states || [];
|
||||
$: parentOfItems = items.map(it => {
|
||||
return it.div;
|
||||
});
|
||||
|
||||
$: {
|
||||
if (!items?.length) {
|
||||
hasError = true;
|
||||
@@ -70,8 +101,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let childStateMap: Map<string, StateInterface> | null = null;
|
||||
|
||||
interface AnimationItem {
|
||||
json: DivBaseData;
|
||||
templateContext: TemplateContext;
|
||||
@@ -100,7 +129,6 @@
|
||||
resolvePromise?: (val?: void) => void;
|
||||
node: HTMLElement;
|
||||
}
|
||||
let animationList: (AnimationItemWithMaxDuration | ChangeBoundsItem)[] = [];
|
||||
|
||||
interface ChildWithTransition {
|
||||
json: DivBaseData;
|
||||
@@ -117,9 +145,6 @@
|
||||
node: HTMLElement;
|
||||
resolvePromise?: (val?: void) => void;
|
||||
}
|
||||
let childrenWithTransitionIn: ChildWithTransition[] = [];
|
||||
let childrenWithTransitionOut: ChildWithTransition[] = [];
|
||||
let childrenWithTransitionChange: ChildWithTransitionChange[] = [];
|
||||
|
||||
function haveFadeTransition(list: AnyTransition[]): boolean {
|
||||
return list.some(it => it.type === 'fade');
|
||||
@@ -163,8 +188,6 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
const stateId = json.div_id || json.id;
|
||||
|
||||
async function setState(stateId: string) {
|
||||
if (selectedId === stateId) {
|
||||
return;
|
||||
@@ -278,167 +301,166 @@
|
||||
rootCtx.setRunning('stateChange', false);
|
||||
}
|
||||
|
||||
if (!stateId) {
|
||||
hasError = true;
|
||||
rootCtx.logError(wrapError(new Error('Missing "id" prop for div "state"')));
|
||||
} else if (!layoutParams?.fakeElement) {
|
||||
stateCtx.registerInstance(stateId, {
|
||||
setState,
|
||||
getChild(id: string): StateInterface | undefined {
|
||||
if (childStateMap && childStateMap.has(id)) {
|
||||
return childStateMap.get(id);
|
||||
}
|
||||
function getChild(id: string): StateInterface | undefined {
|
||||
if (childStateMap && childStateMap.has(id)) {
|
||||
return childStateMap.get(id);
|
||||
}
|
||||
|
||||
rootCtx.logError(wrapError(new Error('Missing state block with id'), {
|
||||
rootCtx.logError(wrapError(new Error('Missing state block with id'), {
|
||||
additional: {
|
||||
id
|
||||
}
|
||||
}));
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$: if (json) {
|
||||
if (prevStateId) {
|
||||
stateCtx.unregisterInstance(prevStateId);
|
||||
prevStateId = undefined;
|
||||
}
|
||||
|
||||
if (stateId && !layoutParams?.fakeElement) {
|
||||
prevStateId = stateId;
|
||||
stateCtx.registerInstance(stateId, {
|
||||
setState,
|
||||
getChild
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setContext<StateCtxValue>(STATE_CTX, {
|
||||
registerInstance(id: string, block: StateInterface) {
|
||||
if (!childStateMap) {
|
||||
childStateMap = new Map();
|
||||
}
|
||||
|
||||
if (childStateMap.has(id)) {
|
||||
rootCtx.logError(wrapError(new Error('Duplicate state with id'), {
|
||||
additional: {
|
||||
id
|
||||
}
|
||||
}));
|
||||
return undefined;
|
||||
} else {
|
||||
childStateMap.set(id, block);
|
||||
}
|
||||
});
|
||||
|
||||
setContext<StateCtxValue>(STATE_CTX, {
|
||||
registerInstance(id: string, block: StateInterface) {
|
||||
if (!childStateMap) {
|
||||
childStateMap = new Map();
|
||||
}
|
||||
|
||||
if (childStateMap.has(id)) {
|
||||
rootCtx.logError(wrapError(new Error('Duplicate state with id'), {
|
||||
additional: {
|
||||
id
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
childStateMap.set(id, block);
|
||||
}
|
||||
},
|
||||
unregisterInstance(id: string) {
|
||||
childStateMap?.delete(id);
|
||||
},
|
||||
runVisibilityTransition(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: AppearanceTransition,
|
||||
node: HTMLElement,
|
||||
direction: 'in' | 'out'
|
||||
) {
|
||||
if (!animationRoot) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const rootBbox = animationRoot.getBoundingClientRect();
|
||||
const item: AnimationItem = getItemAnimation(
|
||||
rootBbox,
|
||||
{
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
},
|
||||
direction
|
||||
);
|
||||
|
||||
const maxDuration = calcMaxDuration(item.transitions);
|
||||
const itemWithMaxDuration: AnimationItemWithMaxDuration = {
|
||||
...item,
|
||||
maxDuration
|
||||
};
|
||||
animationList = [
|
||||
...animationList.filter(it => it.node !== item.node),
|
||||
itemWithMaxDuration
|
||||
];
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
itemWithMaxDuration.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
registerChildWithTransitionIn(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: AppearanceTransition,
|
||||
node: HTMLElement
|
||||
) {
|
||||
const item: ChildWithTransition = {
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
};
|
||||
childrenWithTransitionIn.push(item);
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
item.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
registerChildWithTransitionOut(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: AppearanceTransition,
|
||||
node: HTMLElement
|
||||
) {
|
||||
const item: ChildWithTransition = {
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
};
|
||||
childrenWithTransitionOut.push(item);
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
item.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
registerChildWithTransitionChange(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: TransitionChange,
|
||||
node: HTMLElement
|
||||
) {
|
||||
const id = json.id;
|
||||
|
||||
if (!id) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const item: ChildWithTransitionChange = {
|
||||
id,
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
};
|
||||
childrenWithTransitionChange.push(item);
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
item.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
hasTransitionChange(id?: string) {
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return transitionChangeBoxes.has(id);
|
||||
},
|
||||
registerChild(id: string): void {
|
||||
childrenIds.add(id);
|
||||
},
|
||||
unregisterChild(id: string): void {
|
||||
childrenIds.delete(id);
|
||||
},
|
||||
unregisterInstance(id: string) {
|
||||
childStateMap?.delete(id);
|
||||
},
|
||||
runVisibilityTransition(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: AppearanceTransition,
|
||||
node: HTMLElement,
|
||||
direction: 'in' | 'out'
|
||||
) {
|
||||
if (!animationRoot) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let selectedId: string | undefined;
|
||||
let selectedState: State | null = null;
|
||||
const jsonDefaultStateId = rootCtx.getJsonWithVars(json.default_state_id);
|
||||
const stateVariableName = json.state_id_variable;
|
||||
const stateVariable = stateVariableName ?
|
||||
rootCtx.getVariable(stateVariableName, 'string') :
|
||||
null;
|
||||
let inited = false;
|
||||
const rootBbox = animationRoot.getBoundingClientRect();
|
||||
const item: AnimationItem = getItemAnimation(
|
||||
rootBbox,
|
||||
{
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
},
|
||||
direction
|
||||
);
|
||||
|
||||
const maxDuration = calcMaxDuration(item.transitions);
|
||||
const itemWithMaxDuration: AnimationItemWithMaxDuration = {
|
||||
...item,
|
||||
maxDuration
|
||||
};
|
||||
animationList = [
|
||||
...animationList.filter(it => it.node !== item.node),
|
||||
itemWithMaxDuration
|
||||
];
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
itemWithMaxDuration.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
registerChildWithTransitionIn(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: AppearanceTransition,
|
||||
node: HTMLElement
|
||||
) {
|
||||
const item: ChildWithTransition = {
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
};
|
||||
childrenWithTransitionIn.push(item);
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
item.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
registerChildWithTransitionOut(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: AppearanceTransition,
|
||||
node: HTMLElement
|
||||
) {
|
||||
const item: ChildWithTransition = {
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
};
|
||||
childrenWithTransitionOut.push(item);
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
item.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
registerChildWithTransitionChange(
|
||||
json: DivBaseData,
|
||||
templateContext: TemplateContext,
|
||||
transitions: TransitionChange,
|
||||
node: HTMLElement
|
||||
) {
|
||||
const id = json.id;
|
||||
|
||||
if (!id) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const item: ChildWithTransitionChange = {
|
||||
id,
|
||||
json,
|
||||
templateContext,
|
||||
transitions,
|
||||
node
|
||||
};
|
||||
childrenWithTransitionChange.push(item);
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
item.resolvePromise = resolve;
|
||||
});
|
||||
},
|
||||
hasTransitionChange(id?: string) {
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return transitionChangeBoxes.has(id);
|
||||
},
|
||||
registerChild(id: string): void {
|
||||
childrenIds.add(id);
|
||||
},
|
||||
unregisterChild(id: string): void {
|
||||
childrenIds.delete(id);
|
||||
}
|
||||
});
|
||||
|
||||
function initDefaultState(items: State[]): void {
|
||||
if (inited) {
|
||||
return;
|
||||
@@ -470,7 +492,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
$: initDefaultState(items);
|
||||
$: !inited && initDefaultState(items);
|
||||
|
||||
function onOutro(item: AnimationItem | ChangeBoundsItem): void {
|
||||
animationList = animationList.filter(it => it !== item);
|
||||
@@ -481,8 +503,8 @@
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (stateId && !layoutParams?.fakeElement) {
|
||||
stateCtx.unregisterInstance(stateId);
|
||||
if (prevStateId) {
|
||||
stateCtx.unregisterInstance(prevStateId);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -499,7 +521,7 @@
|
||||
{replaceItems}
|
||||
>
|
||||
{#if selectedState?.div}
|
||||
{#key selectedState}
|
||||
{#key selectedId}
|
||||
<Unknown div={selectedState.div} templateContext={templateContext} />
|
||||
{/key}
|
||||
{/if}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import type { SwitchElements, Overflow } from '../../types/switch-elements';
|
||||
import type { TabItem } from '../../types/tabs';
|
||||
import type { MaybeMissing } from '../../expressions/json';
|
||||
import type { DivBaseData } from '../../types/base';
|
||||
import { ROOT_CTX, RootCtxValue } from '../../context/root';
|
||||
import Outer from '../utilities/Outer.svelte';
|
||||
import Unknown from '../utilities/Unknown.svelte';
|
||||
@@ -34,28 +35,98 @@
|
||||
import { correctEdgeInsertsObject } from '../../utils/correctEdgeInsertsObject';
|
||||
import { correctNonNegativeNumber } from '../../utils/correctNonNegativeNumber';
|
||||
import { edgeInsertsToCss } from '../../utils/edgeInsertsToCss';
|
||||
import { DivBaseData } from '../../types/base';
|
||||
|
||||
export let json: Partial<DivTabsData> = {};
|
||||
export let templateContext: TemplateContext;
|
||||
export let origJson: DivBase | undefined = undefined;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
const instId = rootCtx.genId('tabs');
|
||||
|
||||
let hasError = false;
|
||||
$: items = json.items || [];
|
||||
$: parentOfItems = items.map(it => {
|
||||
return it.div;
|
||||
});
|
||||
|
||||
interface ChildInfo {
|
||||
index: number;
|
||||
title: MaybeMissing<string> | undefined;
|
||||
title_click_action?: MaybeMissing<Action> | undefined;
|
||||
}
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
const instId = rootCtx.genId('tabs');
|
||||
|
||||
let prevId: string | undefined;
|
||||
let hasError = false;
|
||||
let childStore = writable<ChildInfo[]>([]);
|
||||
let childLayoutParams: LayoutParams = {};
|
||||
|
||||
let tabsElem: HTMLElement;
|
||||
let panelsWrapper: HTMLElement;
|
||||
let swiperElem: HTMLElement;
|
||||
let mods: Mods = {};
|
||||
|
||||
let tabFontSize = 12;
|
||||
let tabPaddings = '';
|
||||
let tabLineHeight = '';
|
||||
let tabLetterSpacing = '';
|
||||
let tabBorderRadius = '';
|
||||
let tabActiveFontWeight: number | undefined = undefined;
|
||||
let tabActiveFontFamily = '';
|
||||
let tabInactiveFontWeight: number | undefined = undefined;
|
||||
let tabInactiveFontFamily = '';
|
||||
let tabActiveTextColor = '';
|
||||
let tabInactiveTextColor = '';
|
||||
let tabActiveBackground = '';
|
||||
let tabInactiveBackground = '';
|
||||
let tabItemSpacing = 0;
|
||||
let separatorBackground = '';
|
||||
let separatorMargins = '';
|
||||
let titlePadding: EdgeInsets | null = null;
|
||||
let isSwipeInitialized = false;
|
||||
let isAnimated = false;
|
||||
let previousSelected: number | undefined;
|
||||
let showedPanels: boolean[] = [];
|
||||
let visiblePanels: boolean[] = [];
|
||||
let hidePanelsTimeout: number | null = null;
|
||||
let startCoords: Coords | null = null;
|
||||
let moveCoords: Coords | null = null;
|
||||
let swipeStartTime: number;
|
||||
let isSwipeStarted = false;
|
||||
let isSwipeCanceled = false;
|
||||
let startTransform: number;
|
||||
let currentTransform: number;
|
||||
|
||||
$: if (json) {
|
||||
tabFontSize = 12;
|
||||
tabPaddings = '';
|
||||
tabBorderRadius = '';
|
||||
tabActiveFontWeight = undefined;
|
||||
tabActiveFontFamily = '';
|
||||
tabInactiveFontWeight = undefined;
|
||||
tabInactiveFontFamily = '';
|
||||
tabActiveTextColor = '';
|
||||
tabInactiveTextColor = '';
|
||||
tabActiveBackground = '';
|
||||
tabInactiveBackground = '';
|
||||
tabItemSpacing = 0;
|
||||
separatorBackground = '';
|
||||
separatorMargins = '';
|
||||
titlePadding = null;
|
||||
}
|
||||
|
||||
$: items = json.items || [];
|
||||
$: parentOfItems = items.map(it => {
|
||||
return it.div;
|
||||
});
|
||||
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
$: jsonSelectedTab = rootCtx.getJsonWithVars(json.selected_tab);
|
||||
$: jsonTabStyle = rootCtx.getDerivedFromVars(json.tab_title_style);
|
||||
$: jsonSeparator = rootCtx.getDerivedFromVars(json.has_separator);
|
||||
$: jsonSeparatorColor = rootCtx.getDerivedFromVars(json.separator_color);
|
||||
$: jsonSeparatorPaddings = rootCtx.getDerivedFromVars(json.separator_paddings);
|
||||
$: jsonSwipeEnabled = rootCtx.getDerivedFromVars(json.switch_tabs_by_content_swipe_enabled);
|
||||
$: jsonRestrictParentScroll = rootCtx.getDerivedFromVars(json.restrict_parent_scroll);
|
||||
$: jsonTitlePaddings = rootCtx.getDerivedFromVars(json.title_paddings);
|
||||
|
||||
$: selected = jsonSelectedTab && Number(jsonSelectedTab) || 0;
|
||||
|
||||
$: if (Array.isArray(items) && items.length) {
|
||||
let children: ChildInfo[] = [];
|
||||
|
||||
@@ -106,9 +177,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
let childLayoutParams: LayoutParams = {};
|
||||
$: {
|
||||
let newLayoutParams: LayoutParams = {};
|
||||
|
||||
@@ -125,13 +193,6 @@
|
||||
childLayoutParams = assignIfDifferent(newLayoutParams, childLayoutParams);
|
||||
}
|
||||
|
||||
let tabsElem: HTMLElement;
|
||||
let panelsWrapper: HTMLElement;
|
||||
let swiperElem: HTMLElement;
|
||||
let mods: Mods = {};
|
||||
const jsonSelectedTab = rootCtx.getJsonWithVars(json.selected_tab);
|
||||
let selected = jsonSelectedTab && Number(jsonSelectedTab) || 0;
|
||||
|
||||
$: if (!hasError && (selected < 0 || selected >= items.length)) {
|
||||
rootCtx.logError(wrapError(new Error('Incorrect "selected_tab" prop for div "tabs"'), {
|
||||
additional: {
|
||||
@@ -151,16 +212,12 @@
|
||||
selected = $childStore[0]?.index || 0;
|
||||
}
|
||||
|
||||
$: jsonTabStyle = rootCtx.getDerivedFromVars(json.tab_title_style);
|
||||
$: tabStyle = $jsonTabStyle || {};
|
||||
|
||||
let tabFontSize = 12;
|
||||
$: {
|
||||
tabFontSize = correctPositiveNumber(tabStyle.font_size, tabFontSize);
|
||||
}
|
||||
|
||||
let tabPaddings = '';
|
||||
|
||||
$: {
|
||||
if (tabStyle.font_size || tabStyle.paddings) {
|
||||
const paddings: EdgeInsets = tabStyle.paddings || {
|
||||
@@ -181,7 +238,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let tabLineHeight = '';
|
||||
$: {
|
||||
const lineHeight = tabStyle.line_height;
|
||||
if (lineHeight !== undefined && isPositiveNumber(lineHeight)) {
|
||||
@@ -189,7 +245,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let tabLetterSpacing = '';
|
||||
$: {
|
||||
const letterSpacing = tabStyle.letter_spacing;
|
||||
if (letterSpacing !== undefined && isNonNegativeNumber(letterSpacing)) {
|
||||
@@ -197,7 +252,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let tabBorderRadius = '';
|
||||
$: {
|
||||
if (tabStyle.corner_radius || tabStyle.corners_radius || tabStyle.font_size) {
|
||||
const defaultRadius = tabStyle.corner_radius ?? 1000;
|
||||
@@ -215,8 +269,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let tabActiveFontWeight: number | undefined = undefined;
|
||||
let tabActiveFontFamily = '';
|
||||
$: {
|
||||
tabActiveFontWeight = correctFontWeight(
|
||||
tabStyle.active_font_weight || tabStyle.font_weight,
|
||||
@@ -231,8 +283,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let tabInactiveFontWeight: number | undefined = undefined;
|
||||
let tabInactiveFontFamily = '';
|
||||
$: {
|
||||
tabInactiveFontWeight = correctFontWeight(
|
||||
tabStyle.inactive_font_weight || tabStyle.font_weight,
|
||||
@@ -247,36 +297,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
let tabActiveTextColor = '';
|
||||
$: {
|
||||
tabActiveTextColor = correctColor(tabStyle.active_text_color, 1, tabActiveTextColor);
|
||||
}
|
||||
|
||||
let tabInactiveTextColor = '';
|
||||
$: {
|
||||
tabInactiveTextColor = correctColor(tabStyle.inactive_text_color, 1, tabInactiveTextColor);
|
||||
}
|
||||
|
||||
let tabActiveBackground = '';
|
||||
$: {
|
||||
tabActiveBackground = correctColor(tabStyle.active_background_color, 1, tabActiveBackground);
|
||||
}
|
||||
|
||||
let tabInactiveBackground = '';
|
||||
$: {
|
||||
tabInactiveBackground = correctColor(tabStyle.inactive_background_color, 1, tabInactiveBackground);
|
||||
}
|
||||
|
||||
let tabItemSpacing = 0;
|
||||
$: {
|
||||
tabItemSpacing = correctNonNegativeNumber(tabStyle.item_spacing, tabItemSpacing);
|
||||
}
|
||||
|
||||
$: jsonSeparator = rootCtx.getDerivedFromVars(json.has_separator);
|
||||
$: jsonSeparatorColor = rootCtx.getDerivedFromVars(json.separator_color);
|
||||
$: jsonSeparatorPaddings = rootCtx.getDerivedFromVars(json.separator_paddings);
|
||||
let separatorBackground = '';
|
||||
let separatorMargins = '';
|
||||
$: {
|
||||
if ($jsonSeparator) {
|
||||
if ($jsonSeparatorColor) {
|
||||
@@ -292,24 +332,14 @@
|
||||
margin: separatorMargins
|
||||
};
|
||||
|
||||
$: jsonSwipeEnabled = rootCtx.getDerivedFromVars(json.switch_tabs_by_content_swipe_enabled);
|
||||
$: isSwipeEnabled = typeof $jsonSwipeEnabled === 'undefined' ?
|
||||
true :
|
||||
Boolean($jsonSwipeEnabled);
|
||||
|
||||
$: jsonRestrictParentScroll = rootCtx.getDerivedFromVars(json.restrict_parent_scroll);
|
||||
|
||||
$: jsonTitlePaddings = rootCtx.getDerivedFromVars(json.title_paddings);
|
||||
let titlePadding: EdgeInsets | null = null;
|
||||
$: {
|
||||
titlePadding = correctEdgeInsertsObject($jsonTitlePaddings ? $jsonTitlePaddings : undefined, titlePadding);
|
||||
}
|
||||
|
||||
let isSwipeInitialized = false;
|
||||
let isAnimated = false;
|
||||
let previousSelected = selected;
|
||||
let showedPanels: boolean[] = [];
|
||||
let visiblePanels: boolean[] = [];
|
||||
function updateItems(_items: TabItem[]): void {
|
||||
if (hasError) {
|
||||
return;
|
||||
@@ -383,10 +413,10 @@
|
||||
function updateShowedPanels(around = false): void {
|
||||
const start = around ?
|
||||
Math.max(0, selected - 1) :
|
||||
Math.min(selected, previousSelected);
|
||||
Math.min(selected, previousSelected ?? selected);
|
||||
const end = around ?
|
||||
Math.min(items.length - 1, selected + 1) :
|
||||
Math.max(selected, previousSelected);
|
||||
Math.max(selected, previousSelected ?? selected);
|
||||
|
||||
showedPanels = showedPanels.map((isShowed, index) => isShowed || index >= start && index <= end);
|
||||
visiblePanels = visiblePanels.map((_, index) => index >= start && index <= end);
|
||||
@@ -401,8 +431,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let hidePanelsTimeout: number | null = null;
|
||||
|
||||
function hideNonVisiblePanels(): void {
|
||||
if (hidePanelsTimeout) {
|
||||
clearTimeout(hidePanelsTimeout);
|
||||
@@ -444,17 +472,9 @@
|
||||
|
||||
isSwipeInitialized = true;
|
||||
panelsWrapper.style.height = pxToEm(panelsWrapper.clientHeight);
|
||||
swiperElem.style.transform = `translate3d(${-previousSelected * 100}%,0,0)`;
|
||||
swiperElem.style.transform = `translate3d(${-(previousSelected ?? selected) * 100}%,0,0)`;
|
||||
}
|
||||
|
||||
let startCoords: Coords | null = null;
|
||||
let moveCoords: Coords | null = null;
|
||||
let swipeStartTime: number;
|
||||
let isSwipeStarted = false;
|
||||
let isSwipeCanceled = false;
|
||||
let startTransform: number;
|
||||
let currentTransform: number;
|
||||
|
||||
function onTouchStart(event: TouchEvent): void {
|
||||
const target = event.target as HTMLElement | null;
|
||||
const restrictClosest = target?.closest?.(`.${rootCss['root_restrict-scroll']}`);
|
||||
@@ -554,39 +574,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
rootCtx.registerInstance<SwitchElements>(json.id, {
|
||||
setCurrentItem(item: number) {
|
||||
if (item < 0 || item > items.length - 1) {
|
||||
throw new Error('Item is out of range in "set-current-item" action');
|
||||
$: if (json) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerInstance<SwitchElements>(json.id, {
|
||||
setCurrentItem(item: number) {
|
||||
if (item < 0 || item > items.length - 1) {
|
||||
throw new Error('Item is out of range in "set-current-item" action');
|
||||
}
|
||||
|
||||
setSelected(item);
|
||||
},
|
||||
setPreviousItem(overflow: Overflow) {
|
||||
let previousItem = selected - 1;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? items.length - 1 : selected;
|
||||
}
|
||||
|
||||
setSelected(previousItem);
|
||||
},
|
||||
setNextItem(overflow: Overflow) {
|
||||
let nextItem = selected + 1;
|
||||
|
||||
if (nextItem > items.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : selected;
|
||||
}
|
||||
|
||||
setSelected(nextItem);
|
||||
}
|
||||
|
||||
setSelected(item);
|
||||
},
|
||||
setPreviousItem(overflow: Overflow) {
|
||||
let previousItem = selected - 1;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? items.length - 1 : selected;
|
||||
}
|
||||
|
||||
setSelected(previousItem);
|
||||
},
|
||||
setNextItem(overflow: Overflow) {
|
||||
let nextItem = selected + 1;
|
||||
|
||||
if (nextItem > items.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : selected;
|
||||
}
|
||||
|
||||
setSelected(nextItem);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (json.id && !layoutParams?.fakeElement) {
|
||||
rootCtx.unregisterInstance(json.id);
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -34,14 +34,52 @@
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
$: jsonText = rootCtx.getDerivedFromVars(json.text);
|
||||
let text = '';
|
||||
$: {
|
||||
text = propToString($jsonText);
|
||||
let fontSize = 12;
|
||||
let lineHeight = 1.25;
|
||||
let customLineHeight = false;
|
||||
let maxHeight = '';
|
||||
let lineClamp: string | number = '';
|
||||
let multiline = false;
|
||||
let halign: AlignmentHorizontal = 'left';
|
||||
let valign: AlignmentVertical = 'top';
|
||||
let rootTextColor = '';
|
||||
let focusTextColor = '';
|
||||
let gradient = '';
|
||||
let selectable = false;
|
||||
|
||||
let renderList: ({
|
||||
text: string;
|
||||
textStyles: TextStyles;
|
||||
actions?: MaybeMissing<Action[]>;
|
||||
} | {
|
||||
image: {
|
||||
url: string;
|
||||
width: string;
|
||||
height: string;
|
||||
wrapperStyle: Style;
|
||||
svgFilterId: string;
|
||||
};
|
||||
})[] = [];
|
||||
let usedTintColors: [string, TintMode][] = [];
|
||||
|
||||
$: if (json) {
|
||||
fontSize = 12;
|
||||
lineHeight = 1.25;
|
||||
customLineHeight = false;
|
||||
maxHeight = '';
|
||||
lineClamp = '';
|
||||
multiline = false;
|
||||
halign = 'left';
|
||||
valign = 'top';
|
||||
rootTextColor = '';
|
||||
gradient = '';
|
||||
selectable = false;
|
||||
}
|
||||
|
||||
$: jsonText = rootCtx.getDerivedFromVars(json.text);
|
||||
$: jsonRanges = rootCtx.getDerivedFromVars(json.ranges);
|
||||
$: jsonImages = rootCtx.getDerivedFromVars(json.images);
|
||||
|
||||
$: jsonRootTextStyles = rootCtx.getDerivedFromVars({
|
||||
font_size: json.font_size,
|
||||
letter_spacing: json.letter_spacing,
|
||||
@@ -53,16 +91,25 @@
|
||||
line_height: json.line_height,
|
||||
text_shadow: json.text_shadow
|
||||
});
|
||||
|
||||
$: jsonTextSize = rootCtx.getDerivedFromVars(json.font_size);
|
||||
let fontSize = 12;
|
||||
$: jsonLineHeight = rootCtx.getDerivedFromVars(json.line_height);
|
||||
$: jsonMaxLines = rootCtx.getDerivedFromVars(json.max_lines);
|
||||
$: jsonHAlign = rootCtx.getDerivedFromVars(json.text_alignment_horizontal);
|
||||
$: jsonVAlign = rootCtx.getDerivedFromVars(json.text_alignment_vertical);
|
||||
$: jsonTextColor = rootCtx.getDerivedFromVars(json.text_color);
|
||||
$: jsonFocusTextColor = rootCtx.getDerivedFromVars(json.focused_text_color);
|
||||
$: jsonTruncate = rootCtx.getDerivedFromVars(json.truncate);
|
||||
$: jsonTextGradient = rootCtx.getDerivedFromVars(json.text_gradient);
|
||||
$: jsonSelectable = rootCtx.getDerivedFromVars(json.selectable);
|
||||
|
||||
$: {
|
||||
text = propToString($jsonText);
|
||||
}
|
||||
|
||||
$: {
|
||||
fontSize = correctPositiveNumber($jsonTextSize, fontSize);
|
||||
}
|
||||
|
||||
$: jsonLineHeight = rootCtx.getDerivedFromVars(json.line_height);
|
||||
let lineHeight = 1.25;
|
||||
let customLineHeight = false;
|
||||
$: {
|
||||
const newLineHeight = $jsonLineHeight;
|
||||
if (isPositiveNumber(newLineHeight)) {
|
||||
@@ -73,11 +120,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonMaxLines = rootCtx.getDerivedFromVars(json.max_lines);
|
||||
$: singleline = $jsonMaxLines === 1;
|
||||
let maxHeight = '';
|
||||
let lineClamp: string | number = '';
|
||||
let multiline = false;
|
||||
$: {
|
||||
let newMaxHeight = '';
|
||||
let newLineClamp: string | number = '';
|
||||
@@ -96,14 +139,10 @@
|
||||
multiline = newMultiline;
|
||||
}
|
||||
|
||||
let halign: AlignmentHorizontal = 'left';
|
||||
$: jsonHAlign = rootCtx.getDerivedFromVars(json.text_alignment_horizontal);
|
||||
$: {
|
||||
halign = correctAlignmentHorizontal($jsonHAlign, halign);
|
||||
}
|
||||
|
||||
let valign: AlignmentVertical = 'top';
|
||||
$: jsonVAlign = rootCtx.getDerivedFromVars(json.text_alignment_vertical);
|
||||
$: {
|
||||
valign = correctAlignmentVertical($jsonVAlign, valign);
|
||||
}
|
||||
@@ -115,12 +154,10 @@
|
||||
$jsonRanges[0].start === 0 && typeof $jsonRanges[0].end === 'number' && $jsonRanges[0].end >= text.length
|
||||
);
|
||||
|
||||
$: jsonTextColor = rootCtx.getDerivedFromVars(json.text_color);
|
||||
|
||||
$: isOnlyOneColorDefined = Boolean($jsonTextColor) !==
|
||||
Boolean($jsonRanges && $jsonRanges[0] && $jsonRanges[0].text_color);
|
||||
|
||||
let rootTextColor = '';
|
||||
$: {
|
||||
let newRootTextColor = '';
|
||||
|
||||
@@ -136,17 +173,12 @@
|
||||
rootTextColor = newRootTextColor;
|
||||
}
|
||||
|
||||
let focusTextColor = '';
|
||||
$: jsonFocusTextColor = rootCtx.getDerivedFromVars(json.focused_text_color);
|
||||
$: {
|
||||
focusTextColor = correctColor($jsonFocusTextColor, 1, focusTextColor);
|
||||
}
|
||||
|
||||
$: jsonTruncate = rootCtx.getDerivedFromVars(json.truncate);
|
||||
$: truncate = $jsonTruncate === 'none' ? 'none' : '';
|
||||
|
||||
$: jsonTextGradient = rootCtx.getDerivedFromVars(json.text_gradient);
|
||||
let gradient = '';
|
||||
$: {
|
||||
let newGradient = '';
|
||||
|
||||
@@ -160,27 +192,10 @@
|
||||
gradient = newGradient;
|
||||
}
|
||||
|
||||
$: jsonSelectable = rootCtx.getDerivedFromVars(json.selectable);
|
||||
let selectable = false;
|
||||
$: {
|
||||
selectable = correctBooleanInt($jsonSelectable, selectable);
|
||||
}
|
||||
|
||||
let renderList: ({
|
||||
text: string;
|
||||
textStyles: TextStyles;
|
||||
actions?: MaybeMissing<Action[]>;
|
||||
} | {
|
||||
image: {
|
||||
url: string;
|
||||
width: string;
|
||||
height: string;
|
||||
wrapperStyle: Style;
|
||||
svgFilterId: string;
|
||||
};
|
||||
})[] = [];
|
||||
let usedTintColors: [string, TintMode][] = [];
|
||||
|
||||
function updateRenderList(
|
||||
text: string,
|
||||
textRanges: MaybeMissing<TextRange[]> | undefined,
|
||||
@@ -403,6 +418,7 @@
|
||||
{#if 'text' in item}
|
||||
{#if item.text}
|
||||
<TextRangeView
|
||||
{json}
|
||||
text={item.text}
|
||||
rootFontSize={fontSize}
|
||||
textStyles={item.textStyles}
|
||||
@@ -432,6 +448,7 @@
|
||||
{/each}
|
||||
{:else}
|
||||
<TextRangeView
|
||||
{json}
|
||||
{text}
|
||||
rootFontSize={fontSize}
|
||||
textStyles={$jsonRootTextStyles}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { getContext } from 'svelte';
|
||||
import css from './TextRange.module.css';
|
||||
|
||||
import type { TextRange } from '../../types/text';
|
||||
import type { DivTextData, TextRange } from '../../types/text';
|
||||
import type { Action } from '../../../typings/common';
|
||||
import type { MaybeMissing } from '../../expressions/json';
|
||||
import Actionable from '../utilities/Actionable.svelte';
|
||||
@@ -18,6 +18,7 @@
|
||||
import { ROOT_CTX, RootCtxValue } from '../../context/root';
|
||||
import { shadowToCssFilter } from '../../utils/shadow';
|
||||
|
||||
export let json: Partial<DivTextData>;
|
||||
export let text: string;
|
||||
export let rootFontSize: number;
|
||||
export let textStyles: MaybeMissing<Partial<TextRange>> = {};
|
||||
@@ -27,6 +28,28 @@
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
let decoration = 'none';
|
||||
let fontSize = 12;
|
||||
let lineHeight = 1.25;
|
||||
let letterSpacing = '';
|
||||
let fontWeight: number | undefined = undefined;
|
||||
let fontFamily = '';
|
||||
let color = '';
|
||||
let border: {
|
||||
color: string;
|
||||
width: number;
|
||||
} | null = null;
|
||||
|
||||
$: if (json) {
|
||||
decoration = 'none';
|
||||
fontSize = 12;
|
||||
lineHeight = 1.25;
|
||||
letterSpacing = '';
|
||||
fontWeight = undefined;
|
||||
fontFamily = '';
|
||||
color = '';
|
||||
border = null;
|
||||
}
|
||||
|
||||
$: {
|
||||
let newDecoration = 'none';
|
||||
|
||||
@@ -43,27 +66,22 @@
|
||||
decoration = newDecoration;
|
||||
}
|
||||
|
||||
let fontSize = 12;
|
||||
$: {
|
||||
fontSize = correctPositiveNumber(textStyles.font_size, fontSize);
|
||||
}
|
||||
|
||||
let lineHeight = 1.25;
|
||||
$: {
|
||||
if (isPositiveNumber(textStyles.line_height)) {
|
||||
lineHeight = Number(textStyles.line_height) / fontSize;
|
||||
}
|
||||
}
|
||||
|
||||
let letterSpacing = '';
|
||||
$: {
|
||||
if (isNonNegativeNumber(textStyles.letter_spacing)) {
|
||||
letterSpacing = pxToEm(textStyles.letter_spacing);
|
||||
}
|
||||
}
|
||||
|
||||
let fontWeight: number | undefined = undefined;
|
||||
let fontFamily = '';
|
||||
$: {
|
||||
fontWeight = correctFontWeight(textStyles.font_weight, fontWeight);
|
||||
if (typeof textStyles.font_family === 'string' && textStyles.font_family) {
|
||||
@@ -75,7 +93,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let color = '';
|
||||
$: {
|
||||
color = correctColor(textStyles.text_color, 1, color);
|
||||
}
|
||||
@@ -84,10 +101,6 @@
|
||||
|
||||
$: bg = textStyles.background ? getBackground([textStyles.background]) : null;
|
||||
|
||||
let border: {
|
||||
color: string;
|
||||
width: number;
|
||||
} | null = null;
|
||||
$: if (
|
||||
textStyles.border?.stroke &&
|
||||
textStyles.border.stroke.color &&
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
<script lang="ts" context="module">
|
||||
const DEFAULT_ANIMATION: Animation = {
|
||||
name: 'set',
|
||||
items: [{
|
||||
name: 'translate'
|
||||
}, {
|
||||
name: 'fade'
|
||||
}]
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { afterUpdate, createEventDispatcher, getContext, onDestroy, onMount } from 'svelte';
|
||||
import { afterUpdate, getContext, onDestroy, onMount } from 'svelte';
|
||||
|
||||
import rootCss from '../Root.module.css';
|
||||
import css from './Tooltip.module.css';
|
||||
@@ -19,26 +30,10 @@
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
const DEFAULT_ANIMATION: Animation = {
|
||||
name: 'set',
|
||||
items: [{
|
||||
name: 'translate'
|
||||
}, {
|
||||
name: 'fade'
|
||||
}]
|
||||
};
|
||||
const isDesktop = rootCtx.isDesktop;
|
||||
|
||||
const creationTime = Date.now();
|
||||
|
||||
$: isDesktop = rootCtx.isDesktop;
|
||||
|
||||
$: position = rootCtx.getDerivedFromVars(data.position);
|
||||
$: offsetX = rootCtx.getDerivedFromVars(data.offset?.x?.value);
|
||||
$: offsetY = rootCtx.getDerivedFromVars(data.offset?.y?.value);
|
||||
|
||||
$: animationIn = rootCtx.getDerivedFromVars(data.animation_in);
|
||||
$: animationOut = rootCtx.getDerivedFromVars(data.animation_out);
|
||||
|
||||
let tooltipNode: HTMLElement;
|
||||
let visible = false;
|
||||
let tooltipX = '';
|
||||
@@ -47,6 +42,13 @@
|
||||
let tooltipHeight = '';
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
|
||||
$: position = rootCtx.getDerivedFromVars(data.position);
|
||||
$: offsetX = rootCtx.getDerivedFromVars(data.offset?.x?.value);
|
||||
$: offsetY = rootCtx.getDerivedFromVars(data.offset?.y?.value);
|
||||
|
||||
$: animationIn = rootCtx.getDerivedFromVars(data.animation_in);
|
||||
$: animationOut = rootCtx.getDerivedFromVars(data.animation_out);
|
||||
|
||||
$: mods = {
|
||||
visible
|
||||
};
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
<script lang="ts" context="module">
|
||||
const MIN_SWIPE_PX = 8;
|
||||
const MIN_LONG_TAP_DURATION = 400;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy, onMount, setContext } from 'svelte';
|
||||
|
||||
@@ -33,9 +38,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
const MIN_SWIPE_PX = 8;
|
||||
const MIN_LONG_TAP_DURATION = 400;
|
||||
|
||||
let node: HTMLElement;
|
||||
let href = '';
|
||||
let target: string | undefined = undefined;
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
<script lang="ts" context="module">
|
||||
const HORIZONTAL_ALIGN_TO_GENERAL = {
|
||||
left: 'start',
|
||||
center: 'center',
|
||||
right: 'end'
|
||||
};
|
||||
|
||||
const VERTICAL_ALIGN_TO_GENERAL = {
|
||||
top: 'start',
|
||||
center: 'center',
|
||||
bottom: 'end',
|
||||
baseline: 'baseline'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy, tick } from 'svelte';
|
||||
|
||||
import css from './Outer.module.css';
|
||||
|
||||
import type { DivBaseData } from '../../types/base';
|
||||
import type { DivBaseData, Extension } from '../../types/base';
|
||||
import type { Mods, Style } from '../../types/general';
|
||||
import type { DivActionableData } from '../../types/actionable';
|
||||
import type { LayoutParams } from '../../types/layoutParams';
|
||||
@@ -42,6 +57,7 @@
|
||||
import { isNonNegativeNumber } from '../../utils/isNonNegativeNumber';
|
||||
import { Truthy } from '../../utils/truthy';
|
||||
import { shadowToCssBoxShadow } from '../../utils/shadow';
|
||||
import { isDeepEqual } from '../../utils/isDeepEqual';
|
||||
import Actionable from './Actionable.svelte';
|
||||
import OuterBackground from './OuterBackground.svelte';
|
||||
|
||||
@@ -61,27 +77,132 @@
|
||||
export let replaceItems: ((items: (DivBaseData | undefined)[]) => void) | undefined = undefined;
|
||||
export let hasInnerFocusable = false;
|
||||
|
||||
const HORIZONTAL_ALIGN_TO_GENERAL = {
|
||||
left: 'start',
|
||||
center: 'center',
|
||||
right: 'end'
|
||||
};
|
||||
|
||||
const VERTICAL_ALIGN_TO_GENERAL = {
|
||||
top: 'start',
|
||||
center: 'center',
|
||||
bottom: 'end',
|
||||
baseline: 'baseline'
|
||||
};
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
const stateCtx = getContext<StateCtxValue>(STATE_CTX);
|
||||
const isPointerFocus = rootCtx.isPointerFocus;
|
||||
|
||||
let currentNode: HTMLElement;
|
||||
let attrs: Record<string, string> | undefined;
|
||||
let extensions: DivExtension[] | null = null;
|
||||
|
||||
let prevChilds: string[] = [];
|
||||
|
||||
let borderStyle: Style = {};
|
||||
let borderElemStyle: Style = {};
|
||||
let hasBorder = false;
|
||||
let strokeWidth = 1;
|
||||
let strokeColor = 'transparent';
|
||||
let cornerRadius = 0;
|
||||
let cornersRadius: CornersRadius = {
|
||||
'top-left': 0,
|
||||
'top-right': 0,
|
||||
'bottom-right': 0,
|
||||
'bottom-left': 0
|
||||
};
|
||||
let backgroundRadius = '';
|
||||
|
||||
let selfPadding: EdgeInsets | null = null;
|
||||
let margin = '';
|
||||
|
||||
let widthMods: Mods = {};
|
||||
let width: string | undefined;
|
||||
let widthMin: string | undefined;
|
||||
let widthMax: string | undefined;
|
||||
let widthNum = 0;
|
||||
let widthFlexGrow = 0;
|
||||
let widthFlexShrink = 0;
|
||||
let widthFill = false;
|
||||
let hasWidthError = false;
|
||||
|
||||
let heightMods: Mods = {};
|
||||
let height: string | undefined;
|
||||
let heightMin: string | undefined;
|
||||
let heightMax: string | undefined;
|
||||
let heightNum = 0;
|
||||
let heightFlexGrow = 0;
|
||||
let heightFlexShrink = 0;
|
||||
let heightFill = false;
|
||||
let hasHeightError = false;
|
||||
|
||||
let alpha = 1;
|
||||
let opacity: number | undefined;
|
||||
|
||||
let background: MaybeMissing<Background[]> | undefined;
|
||||
let backgroundStyle: Style;
|
||||
let hasSeparateBg: boolean;
|
||||
|
||||
let jsonTransitionTriggers = [];
|
||||
let hasStateChangeTrigger = false;
|
||||
let hasVisibilityChangeTrigger = false;
|
||||
|
||||
let stateChangingInProgress: boolean | undefined;
|
||||
let visibilityChangingInProgress: boolean | undefined;
|
||||
let transitionChangeInProgress: boolean | undefined;
|
||||
|
||||
let actions: MaybeMissing<Action>[] = [];
|
||||
let doubleTapActions: MaybeMissing<Action>[] = [];
|
||||
let longTapActions: MaybeMissing<Action>[] = [];
|
||||
let focusActions: MaybeMissing<Action>[] = [];
|
||||
let blurActions: MaybeMissing<Action>[] = [];
|
||||
|
||||
let actionAnimationList: MaybeMissing<AnyAnimation>[] = [];
|
||||
let actionAnimationTransition = '';
|
||||
let animationOpacityStart: number | undefined = undefined;
|
||||
let animationOpacityEnd: number | undefined = undefined;
|
||||
let animationScaleStart: number | undefined = undefined;
|
||||
let animationScaleEnd: number | undefined = undefined;
|
||||
|
||||
let isVisibilityInited = false;
|
||||
let visibility: Visibility = 'visible';
|
||||
|
||||
let pivotXNum = 0;
|
||||
let pivotYNum = 0;
|
||||
let transformOrigin: string | undefined;
|
||||
let transform: string | undefined;
|
||||
|
||||
let hasCustomFocus = false;
|
||||
|
||||
let prevExtensionsVal: Extension[] | undefined = undefined;
|
||||
|
||||
let dev: DevtoolResult | null = null;
|
||||
|
||||
$: if (json && layoutParams) {
|
||||
selfPadding = null;
|
||||
margin = '';
|
||||
alpha = 1;
|
||||
isVisibilityInited = false;
|
||||
visibility = 'visible';
|
||||
pivotXNum = 0;
|
||||
pivotYNum = 0;
|
||||
transformOrigin = undefined;
|
||||
transform = undefined;
|
||||
|
||||
jsonTransitionTriggers = layoutParams.fakeElement ?
|
||||
[] :
|
||||
(json.transition_triggers || ['state_change', 'visibility_change']);
|
||||
hasStateChangeTrigger = Boolean(jsonTransitionTriggers.indexOf('state_change') !== -1 && json.id);
|
||||
hasVisibilityChangeTrigger = Boolean(jsonTransitionTriggers.indexOf('visibility_change') !== -1 && json.id);
|
||||
}
|
||||
|
||||
$: jsonFocus = rootCtx.getDerivedFromVars(json.focus);
|
||||
$: jsonBorder = rootCtx.getDerivedFromVars(json.border);
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
$: jsonMargins = rootCtx.getDerivedFromVars(json.margins);
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonAlignmentHorizontal = rootCtx.getDerivedFromVars(json.alignment_horizontal);
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
$: jsonAlignmentVertical = rootCtx.getDerivedFromVars(json.alignment_vertical);
|
||||
$: jsonAlpha = rootCtx.getDerivedFromVars(json.alpha);
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
$: jsonBackground = rootCtx.getDerivedFromVars(json.background);
|
||||
$: jsonAction = rootCtx.getDerivedFromVars(json.action);
|
||||
$: jsonActions = rootCtx.getDerivedFromVars(json.actions);
|
||||
$: jsonDoubleTapActions = rootCtx.getDerivedFromVars(json.doubletap_actions);
|
||||
$: jsonLongTapActions = rootCtx.getDerivedFromVars(json.longtap_actions);
|
||||
$: jsonActionAnimation = rootCtx.getDerivedFromVars(json.action_animation);
|
||||
$: jsonVisibility = rootCtx.getDerivedFromVars(json.visibility);
|
||||
$: jsonTransform = rootCtx.getDerivedFromVars(json.transform);
|
||||
|
||||
$: {
|
||||
prevChilds.forEach(id => {
|
||||
rootCtx.unregisterParentOf(id);
|
||||
@@ -121,22 +242,6 @@
|
||||
replaceItems(newItems);
|
||||
}
|
||||
|
||||
$: jsonFocus = rootCtx.getDerivedFromVars(json.focus);
|
||||
|
||||
$: jsonBorder = rootCtx.getDerivedFromVars(json.border);
|
||||
let borderStyle: Style = {};
|
||||
let borderElemStyle: Style = {};
|
||||
let hasBorder = false;
|
||||
let strokeWidth = 1;
|
||||
let strokeColor = 'transparent';
|
||||
let cornerRadius = 0;
|
||||
let cornersRadius: CornersRadius = {
|
||||
'top-left': 0,
|
||||
'top-right': 0,
|
||||
'bottom-right': 0,
|
||||
'bottom-left': 0
|
||||
};
|
||||
let backgroundRadius = '';
|
||||
$: {
|
||||
const border = hasCustomFocus && $jsonFocus?.border ? $jsonFocus.border : $jsonBorder;
|
||||
let newBorderStyle: Style = {};
|
||||
@@ -195,8 +300,6 @@
|
||||
backgroundRadius = newBackgroundRadius;
|
||||
}
|
||||
|
||||
$: jsonPaddings = rootCtx.getDerivedFromVars(json.paddings);
|
||||
let selfPadding: EdgeInsets | null = null;
|
||||
$: {
|
||||
selfPadding = correctEdgeInsertsObject(
|
||||
($jsonPaddings && !customPaddings) ?
|
||||
@@ -208,23 +311,9 @@
|
||||
|
||||
$: padding = edgeInsertsToCss(sumEdgeInsets(selfPadding, additionalPaddings));
|
||||
|
||||
$: jsonMargins = rootCtx.getDerivedFromVars(json.margins);
|
||||
let margin = '';
|
||||
$: {
|
||||
margin = correctEdgeInserts($jsonMargins, margin);
|
||||
}
|
||||
|
||||
$: jsonWidth = rootCtx.getDerivedFromVars(json.width);
|
||||
$: jsonAlignmentHorizontal = rootCtx.getDerivedFromVars(json.alignment_horizontal);
|
||||
let widthMods: Mods = {};
|
||||
let width: string | undefined;
|
||||
let widthMin: string | undefined;
|
||||
let widthMax: string | undefined;
|
||||
let widthNum = 0;
|
||||
let widthFlexGrow = 0;
|
||||
let widthFlexShrink = 0;
|
||||
let widthFill = false;
|
||||
let hasWidthError = false;
|
||||
$: {
|
||||
let widthType: 'parent' | 'content' | undefined = undefined;
|
||||
let newWidth: string | undefined = undefined;
|
||||
@@ -314,17 +403,6 @@
|
||||
hasWidthError = newWidthError;
|
||||
}
|
||||
|
||||
$: jsonHeight = rootCtx.getDerivedFromVars(json.height);
|
||||
$: jsonAlignmentVertical = rootCtx.getDerivedFromVars(json.alignment_vertical);
|
||||
let heightMods: Mods = {};
|
||||
let height: string | undefined;
|
||||
let heightMin: string | undefined;
|
||||
let heightMax: string | undefined;
|
||||
let heightNum = 0;
|
||||
let heightFlexGrow = 0;
|
||||
let heightFlexShrink = 0;
|
||||
let heightFill = false;
|
||||
let hasHeightError = false;
|
||||
$: {
|
||||
let heightType: 'parent' | 'content' | undefined = undefined;
|
||||
let newHeight: string | undefined = undefined;
|
||||
@@ -429,15 +507,11 @@
|
||||
`${layoutParams.gridArea.y + 1}/${layoutParams.gridArea.x + 1}/span ${layoutParams.gridArea.rowSpan}/span ${layoutParams.gridArea.colSpan}` :
|
||||
undefined;
|
||||
|
||||
$: jsonAlpha = rootCtx.getDerivedFromVars(json.alpha);
|
||||
let alpha = 1;
|
||||
let opacity: number | undefined;
|
||||
$: {
|
||||
alpha = correctAlpha($jsonAlpha, alpha);
|
||||
opacity = alpha === 1 ? undefined : alpha;
|
||||
}
|
||||
|
||||
$: jsonAccessibility = rootCtx.getDerivedFromVars(json.accessibility);
|
||||
$: {
|
||||
attrs = undefined;
|
||||
if ($jsonAccessibility && !customDescription && $jsonAccessibility.description) {
|
||||
@@ -446,10 +520,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonBackground = rootCtx.getDerivedFromVars(json.background);
|
||||
let background: MaybeMissing<Background[]> | undefined;
|
||||
let backgroundStyle: Style;
|
||||
let hasSeparateBg: boolean;
|
||||
$: {
|
||||
background = hasCustomFocus && $jsonFocus?.background ? $jsonFocus.background : $jsonBackground;
|
||||
backgroundStyle = {};
|
||||
@@ -470,15 +540,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonTransitionTriggers = layoutParams.fakeElement ?
|
||||
[] :
|
||||
(json.transition_triggers || ['state_change', 'visibility_change']);
|
||||
const hasStateChangeTrigger = jsonTransitionTriggers.indexOf('state_change') !== -1 && json.id;
|
||||
const hasVisibilityChangeTrigger = jsonTransitionTriggers.indexOf('visibility_change') !== -1 && json.id;
|
||||
|
||||
let stateChangingInProgress: boolean | undefined;
|
||||
let visibilityChangingInProgress: boolean | undefined;
|
||||
let transitionChangeInProgress: boolean | undefined;
|
||||
$: {
|
||||
stateChangingInProgress = undefined;
|
||||
if (hasStateChangeTrigger && json.transition_in && rootCtx.isRunning('stateChange')) {
|
||||
@@ -495,15 +556,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: jsonAction = rootCtx.getDerivedFromVars(json.action);
|
||||
$: jsonActions = rootCtx.getDerivedFromVars(json.actions);
|
||||
$: jsonDoubleTapActions = rootCtx.getDerivedFromVars(json.doubletap_actions);
|
||||
$: jsonLongTapActions = rootCtx.getDerivedFromVars(json.longtap_actions);
|
||||
let actions: MaybeMissing<Action>[] = [];
|
||||
let doubleTapActions: MaybeMissing<Action>[] = [];
|
||||
let longTapActions: MaybeMissing<Action>[] = [];
|
||||
let focusActions: MaybeMissing<Action>[] = [];
|
||||
let blurActions: MaybeMissing<Action>[] = [];
|
||||
$: {
|
||||
let newActions = $jsonActions || $jsonAction && [$jsonAction] || [];
|
||||
let newDoubleTapActions = $jsonDoubleTapActions || [];
|
||||
@@ -555,13 +607,6 @@
|
||||
blurActions = newBlurActions;
|
||||
}
|
||||
|
||||
$: jsonActionAnimation = rootCtx.getDerivedFromVars(json.action_animation);
|
||||
let actionAnimationList: MaybeMissing<AnyAnimation>[] = [];
|
||||
let actionAnimationTransition = '';
|
||||
let animationOpacityStart: number | undefined = undefined;
|
||||
let animationOpacityEnd: number | undefined = undefined;
|
||||
let animationScaleStart: number | undefined = undefined;
|
||||
let animationScaleEnd: number | undefined = undefined;
|
||||
$: {
|
||||
if ($jsonActionAnimation) {
|
||||
actionAnimationList = flattenAnimation($jsonActionAnimation as Animation);
|
||||
@@ -602,9 +647,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let isVisibilityInited = false;
|
||||
let visibility: Visibility = 'visible';
|
||||
$: jsonVisibility = rootCtx.getDerivedFromVars(json.visibility);
|
||||
$: {
|
||||
const prevVisibility = visibility;
|
||||
const nextVisibility = correctVisibility($jsonVisibility, visibility);
|
||||
@@ -659,6 +701,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
function unmountExtensions(): void {
|
||||
if (extensions && currentNode) {
|
||||
const ctx = rootCtx.getExtensionContext();
|
||||
extensions.forEach(it => {
|
||||
it.unmountView?.(currentNode, ctx);
|
||||
});
|
||||
extensions = null;
|
||||
}
|
||||
}
|
||||
|
||||
$: if (json && currentNode && !isDeepEqual(json.extensions, prevExtensionsVal)) {
|
||||
unmountExtensions();
|
||||
|
||||
if (Array.isArray(json.extensions)) {
|
||||
const ctx = rootCtx.getExtensionContext();
|
||||
extensions = json.extensions.map(it => {
|
||||
const instance = rootCtx.getExtension(it.id, it.params);
|
||||
|
||||
if (instance) {
|
||||
instance.mountView?.(currentNode, ctx);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}).filter(Truthy);
|
||||
}
|
||||
prevExtensionsVal = json.extensions;
|
||||
}
|
||||
|
||||
function updateDevtool(): void {
|
||||
if (dev) {
|
||||
dev.update({
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: if (json && origJson && templateContext) {
|
||||
updateDevtool();
|
||||
}
|
||||
|
||||
$: mods = {
|
||||
...widthMods,
|
||||
...heightMods,
|
||||
@@ -675,11 +759,6 @@
|
||||
'has-custom-focus': Boolean(hasCustomFocus && json.focus)
|
||||
};
|
||||
|
||||
$: jsonTransform = rootCtx.getDerivedFromVars(json.transform);
|
||||
let pivotXNum = 0;
|
||||
let pivotYNum = 0;
|
||||
let transformOrigin: string | undefined;
|
||||
let transform: string | undefined;
|
||||
$: {
|
||||
if ($jsonTransform && $jsonTransform.rotation !== undefined) {
|
||||
const pivotX = $jsonTransform.pivot_x || {
|
||||
@@ -797,8 +876,6 @@
|
||||
rootCtx.registerTooltip(node, tooltip);
|
||||
});
|
||||
|
||||
let dev: DevtoolResult | null = null;
|
||||
|
||||
if (devtool && !layoutParams.fakeElement) {
|
||||
dev = devtool(node, {
|
||||
json,
|
||||
@@ -808,31 +885,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(json.extensions)) {
|
||||
const ctx = rootCtx.getExtensionContext();
|
||||
extensions = json.extensions.map(it => {
|
||||
const instance = rootCtx.getExtension(it.id, it.params);
|
||||
|
||||
if (instance) {
|
||||
instance.mountView?.(node, ctx);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}).filter(Truthy);
|
||||
}
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
if (id) {
|
||||
stateCtx.unregisterChild(id);
|
||||
}
|
||||
if (extensions) {
|
||||
const ctx = rootCtx.getExtensionContext();
|
||||
extensions.forEach(it => {
|
||||
it.unmountView?.(node, ctx);
|
||||
});
|
||||
extensions = null;
|
||||
}
|
||||
if (dev) {
|
||||
dev.destroy();
|
||||
}
|
||||
@@ -840,9 +897,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
let hasCustomFocus: boolean;
|
||||
$: isPointerFocus = rootCtx.isPointerFocus;
|
||||
|
||||
function focusHandler() {
|
||||
if (!json.focus) {
|
||||
return;
|
||||
@@ -873,6 +927,8 @@
|
||||
json.tooltips?.forEach(tooltip => {
|
||||
rootCtx.unregisterTooltip(tooltip);
|
||||
});
|
||||
|
||||
unmountExtensions();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy } from 'svelte';
|
||||
import type { Unsubscriber } from 'svelte/store';
|
||||
|
||||
import css from './Video.module.css';
|
||||
|
||||
@@ -24,12 +25,53 @@
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
|
||||
const rootCtx = getContext<RootCtxValue>(ROOT_CTX);
|
||||
|
||||
let prevId: string | undefined;
|
||||
let hasError = false;
|
||||
let isSelfVariableSet = false;
|
||||
let videoElem: HTMLVideoElement;
|
||||
|
||||
const jsonSource = rootCtx.getDerivedFromVars(json.video_sources);
|
||||
let sources: PreparedVideoSource[] = [];
|
||||
let loop = false;
|
||||
let autoplay = false;
|
||||
let muted = false;
|
||||
let poster: string | undefined = undefined;
|
||||
let scale = 'fit';
|
||||
let aspectPaddingBottom = '0';
|
||||
let elapsedVariableUnsubscriber: Unsubscriber | undefined;
|
||||
|
||||
$: if (json) {
|
||||
loop = false;
|
||||
autoplay = false;
|
||||
muted = false;
|
||||
poster = undefined;
|
||||
scale = 'fit';
|
||||
}
|
||||
|
||||
$: elapsedVariableName = json.elapsed_time_variable;
|
||||
$: elapsedVariable = elapsedVariableName && rootCtx.getVariable(elapsedVariableName, 'integer') || createVariable('temp', 'integer', 0);
|
||||
|
||||
$: if (elapsedVariable) {
|
||||
if (elapsedVariableUnsubscriber) {
|
||||
elapsedVariableUnsubscriber();
|
||||
}
|
||||
elapsedVariableUnsubscriber = elapsedVariable.subscribe(val => {
|
||||
if (isSelfVariableSet) {
|
||||
isSelfVariableSet = false;
|
||||
return;
|
||||
}
|
||||
if (videoElem) {
|
||||
videoElem.currentTime = Number(val) / 1000;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$: jsonSource = rootCtx.getDerivedFromVars(json.video_sources);
|
||||
$: jsonRepeatable = rootCtx.getDerivedFromVars(json.repeatable);
|
||||
$: jsonAutostart = rootCtx.getDerivedFromVars(json.autostart);
|
||||
$: jsonMuted = rootCtx.getDerivedFromVars(json.muted);
|
||||
$: jsonPreview = rootCtx.getDerivedFromVars(json.preview);
|
||||
$: jsonScale = rootCtx.getDerivedFromVars(json.scale);
|
||||
$: jsonAspect = rootCtx.getDerivedFromVars(json.aspect);
|
||||
|
||||
$: {
|
||||
sources = correctVideoSource($jsonSource, sources);
|
||||
@@ -42,30 +84,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
const jsonRepeatable = rootCtx.getDerivedFromVars(json.repeatable);
|
||||
let loop = false;
|
||||
$: loop = correctBooleanInt($jsonRepeatable, loop);
|
||||
|
||||
const jsonAutostart = rootCtx.getDerivedFromVars(json.autostart);
|
||||
let autoplay = false;
|
||||
$: autoplay = correctBooleanInt($jsonAutostart, autoplay);
|
||||
|
||||
const jsonMuted = rootCtx.getDerivedFromVars(json.muted);
|
||||
let muted = false;
|
||||
$: muted = correctBooleanInt($jsonMuted, muted);
|
||||
|
||||
const jsonPreview = rootCtx.getDerivedFromVars(json.preview);
|
||||
let poster: string | undefined = undefined;
|
||||
$: poster = typeof $jsonPreview === 'string' ? prepareBase64($jsonPreview) : poster;
|
||||
|
||||
$: jsonScale = rootCtx.getDerivedFromVars(json.scale);
|
||||
let scale = 'fit';
|
||||
$: {
|
||||
scale = videoSize($jsonScale) || scale;
|
||||
}
|
||||
|
||||
$: jsonAspect = rootCtx.getDerivedFromVars(json.aspect);
|
||||
let aspectPaddingBottom = '0';
|
||||
$: {
|
||||
const newRatio = $jsonAspect?.ratio;
|
||||
if (newRatio && isPositiveNumber(newRatio)) {
|
||||
@@ -75,38 +105,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
const elapsedVariableName = json.elapsed_time_variable;
|
||||
let elapsedVariable = elapsedVariableName && rootCtx.getVariable(elapsedVariableName, 'integer') || createVariable('temp', 'integer', 0);
|
||||
|
||||
elapsedVariable.subscribe(val => {
|
||||
if (isSelfVariableSet) {
|
||||
isSelfVariableSet = false;
|
||||
return;
|
||||
$: if (json) {
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
if (videoElem) {
|
||||
videoElem.currentTime = Number(val) / 1000;
|
||||
}
|
||||
});
|
||||
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
rootCtx.registerInstance<VideoElements>(json.id, {
|
||||
pause() {
|
||||
videoElem?.pause();
|
||||
},
|
||||
start() {
|
||||
const res = videoElem?.play();
|
||||
if (res) {
|
||||
res.catch(err => {
|
||||
rootCtx.logError(wrapError(new Error('Video playing error'), {
|
||||
level: 'error',
|
||||
additional: {
|
||||
originalText: String(err)
|
||||
}
|
||||
}));
|
||||
});
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
prevId = json.id;
|
||||
rootCtx.registerInstance<VideoElements>(json.id, {
|
||||
pause() {
|
||||
videoElem?.pause();
|
||||
},
|
||||
start() {
|
||||
const res = videoElem?.play();
|
||||
if (res) {
|
||||
res.catch(err => {
|
||||
rootCtx.logError(wrapError(new Error('Video playing error'), {
|
||||
level: 'error',
|
||||
additional: {
|
||||
originalText: String(err)
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: mods = {
|
||||
@@ -150,8 +175,14 @@
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (json.id && !hasError && !layoutParams?.fakeElement) {
|
||||
rootCtx.unregisterInstance(json.id);
|
||||
if (prevId) {
|
||||
rootCtx.unregisterInstance(prevId);
|
||||
prevId = undefined;
|
||||
}
|
||||
|
||||
if (elapsedVariableUnsubscriber) {
|
||||
elapsedVariableUnsubscriber();
|
||||
elapsedVariableUnsubscriber = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -62,20 +62,17 @@ export interface RootCtxValue {
|
||||
customComponents: Map<string, CustomComponentDescription> | undefined;
|
||||
|
||||
// Devtool
|
||||
registerComponent?({
|
||||
componentDevtool?({
|
||||
type,
|
||||
node,
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
}: {
|
||||
type: 'mount' | 'update' | 'destroy';
|
||||
node: HTMLElement;
|
||||
json: Partial<DivBaseData>;
|
||||
origJson: DivBase | undefined;
|
||||
templateContext: TemplateContext;
|
||||
}): void;
|
||||
unregisterComponent?({
|
||||
node
|
||||
}: {
|
||||
node: HTMLElement;
|
||||
}): void;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,15 @@ import type { DivBase, TemplateContext } from '../../typings/common';
|
||||
import type { DivBaseData } from '../types/base';
|
||||
|
||||
export interface DevtoolResult {
|
||||
update({
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
}: {
|
||||
json: Partial<DivBaseData>;
|
||||
origJson?: DivBase | undefined;
|
||||
templateContext: TemplateContext;
|
||||
}): void;
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
@@ -17,7 +26,8 @@ function devtoolReal(node: HTMLElement, {
|
||||
templateContext: TemplateContext;
|
||||
rootCtx: RootCtxValue;
|
||||
}): DevtoolResult {
|
||||
rootCtx.registerComponent?.({
|
||||
rootCtx.componentDevtool?.({
|
||||
type: 'mount',
|
||||
node,
|
||||
json,
|
||||
origJson,
|
||||
@@ -25,8 +35,31 @@ function devtoolReal(node: HTMLElement, {
|
||||
});
|
||||
|
||||
return {
|
||||
update({
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
}: {
|
||||
json: Partial<DivBaseData>;
|
||||
origJson?: DivBase | undefined;
|
||||
templateContext: TemplateContext;
|
||||
}) {
|
||||
rootCtx.componentDevtool?.({
|
||||
type: 'update',
|
||||
node,
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
});
|
||||
},
|
||||
destroy() {
|
||||
rootCtx.unregisterComponent?.({ node });
|
||||
rootCtx.componentDevtool?.({
|
||||
type: 'destroy',
|
||||
node,
|
||||
json,
|
||||
origJson,
|
||||
templateContext
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,3 +12,5 @@ export function constStore<T>(val: T): Readable<T> {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const constUndefStore = constStore(undefined);
|
||||
|
||||
@@ -18,6 +18,7 @@ import type { CustomComponentDescription } from './custom';
|
||||
|
||||
export interface DivkitDebugInstance extends DivkitInstance {
|
||||
getDebugVariables(): Map<string, Variable>;
|
||||
getDebugAllVariables(): Map<string, Variable>;
|
||||
}
|
||||
|
||||
export function render(opts: {
|
||||
|
||||
+4
-4
@@ -228,14 +228,11 @@ export type StatCallback = (details: {
|
||||
export type CustomActionCallback = (action: Action & { url: string }) => void;
|
||||
|
||||
export type ComponentCallback = (details: {
|
||||
type: 'mount';
|
||||
type: 'mount' | 'update' | 'destroy';
|
||||
node: HTMLElement;
|
||||
json: DivBase;
|
||||
origJson: DivBase | undefined;
|
||||
templateContext: TemplateContext;
|
||||
} | {
|
||||
type: 'destroy';
|
||||
node: HTMLElement;
|
||||
}) => void;
|
||||
|
||||
export interface WrappedError extends Error {
|
||||
@@ -256,7 +253,10 @@ export type FetchInit = RequestInit | ((url: string) => RequestInit);
|
||||
export interface DivkitInstance {
|
||||
$destroy(): void;
|
||||
execAction(action: Action | VisibilityAction): void;
|
||||
/** @deprecated */
|
||||
setTheme(theme: Theme): void;
|
||||
/** Experimental */
|
||||
setData(json: DivJson): void;
|
||||
}
|
||||
|
||||
export type Platform = 'desktop' | 'touch' | 'auto';
|
||||
|
||||
Reference in New Issue
Block a user