@egjs/flicking
Version:
Everyday 30 million people experience. It's reliable, flexible and extendable carousel.
1 lines • 534 kB
Source Map (JSON)
{"version":3,"file":"flicking.pkgd.js","sources":["../src/const/error.ts","../src/const/external.ts","../src/utils.ts","../src/core/FlickingError.ts","../src/core/Viewport.ts","../src/core/AutoResizer.ts","../src/core/panel/provider/VanillaElementProvider.ts","../src/core/panel/provider/VirtualElementProvider.ts","../src/core/VirtualManager.ts","../src/const/axes.ts","../src/control/states/State.ts","../src/control/states/IdleState.ts","../src/control/states/HoldingState.ts","../src/control/states/DraggingState.ts","../src/control/states/AnimatingState.ts","../src/control/states/DisabledState.ts","../src/control/StateMachine.ts","../src/control/AxesController.ts","../src/control/Control.ts","../src/core/AnchorPoint.ts","../src/control/SnapControl.ts","../src/control/FreeControl.ts","../src/control/StrictControl.ts","../src/control/index.ts","../src/camera/mode/CameraMode.ts","../src/camera/mode/LinearCameraMode.ts","../src/camera/mode/CircularCameraMode.ts","../src/camera/mode/BoundCameraMode.ts","../src/camera/Camera.ts","../src/camera/index.ts","../src/renderer/Renderer.ts","../src/renderer/VanillaRenderer.ts","../src/renderer/ExternalRenderer.ts","../src/core/panel/Panel.ts","../src/renderer/strategy/NormalRenderingStrategy.ts","../src/core/panel/VirtualPanel.ts","../src/renderer/strategy/VirtualRenderingStrategy.ts","../src/renderer/index.ts","../src/Flicking.ts","../src/core/index.ts","../src/cfc/withFlickingMethods.ts","../src/cfc/sync.ts","../src/cfc/getRenderingPanels.ts","../src/cfc/getDefaultCameraTransform.ts","../src/index.umd.ts"],"sourcesContent":["/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\n\n/**\n * Error codes of {@link FlickingError}. Below are the conditions where each error code occurs.\n * @ko {@link FlickingError}의 에러 코드. 아래는 각각의 에러 코드가 발생하는 조건입니다.\n * @name ERROR_CODE\n * @constant\n * @type object\n * @property {number} WRONG_TYPE Parameter type is wrong<ko>패러미터의 타입이 잘못되었을 경우</ko>\n * @property {number} ELEMENT_NOT_FOUND Element is not found inside page with the given CSS selector<ko>주어진 CSS selector로 페이지 내에서 해당 엘리먼트를 찾지 못했을 경우</ko>\n * @property {number} VAL_MUST_NOT_NULL Expected non-null value, but given `null` or `undefined`<ko>값을 기대했으나, `null`이나 `undefined`를 받은 경우</ko>\n * @property {number} NOT_ATTACHED_TO_FLICKING When Flicking's component is not initialized (i.e. {@link Flicking#init} is not called)<ko>Flicking 내부 컴포넌트가 초기화되지 않은 경우 ({@link Flicking#init}이 호출되지 않은 경우)</ko>\n * @property {number} WRONG_OPTION One of the options is wrong<ko>옵션들 중 잘못된 값이 있을 때</ko>\n * @property {number} INDEX_OUT_OF_RANGE When the given index is out of possible range<ko>인덱스가 주어진 범위를 벗어난 경우</ko>\n * @property {number} POSITION_NOT_REACHABLE When {@link Control#moveToPosition}'s position parameter is out of possible range.<ko>{@link Control#moveToPosition}의 `position` 패러미터가 도달 가능한 범위를 벗어난 경우</ko>\n * @property {number} TRANSFORM_NOT_SUPPORTED CSS `transform` property is not available(<=IE8) <ko>CSS `transform` 속성을 사용할 수 없는 경우(<=IE8)</ko>\n * @property {number} STOP_CALLED_BY_USER When the event's `stop()` is called by user.<ko>사용자에 의해 이벤트의 `stop()`이 호출된 경우</ko>\n * @property {number} ANIMATION_INTERRUPTED When the animation is interrupted by user.<ko>사용자에 의해 애니메이션이 중단된 경우</ko>\n * @property {number} ANIMATION_ALREADY_PLAYING When the animation is already playing.<ko>현재 애니메이션이 이미 진행중인 경우</ko>\n * @property {number} NOT_ALLOWED_IN_FRAMEWORK When the non-allowed method is called from frameworks (React, Angular, Vue...)\n * <ko>프레임워크(React, Angular, Vue ...)에서 사용 불가능한 메소드를 호출했을 경우</ko>\n * @property {number} NOT_INITIALIZED When the {@link Flicking#init} is not called before but is needed<ko>{@link Flicking#init}의 호출이 필요하나, 아직 호출되지 않았을 경우</ko>\n * @property {number} NO_ACTIVE When there're no active panel that flicking has selected. This may be due to the absence of any panels<ko>현재 Flicking이 선택한 패널이 없을 경우. 일반적으로 패널이 하나도 없는 경우에 발생할 수 있습니다</ko>\n * @property {number} NOT_ALLOWED_IN_VIRTUAL When the non-allowed method is called while the virtual option is enabled<ko>virtual 옵션이 활성화된 상태에서 사용 불가능한 메소드가 호출되었을 경우</ko>\n */\nexport const CODE = {\n WRONG_TYPE: 0,\n ELEMENT_NOT_FOUND: 1,\n VAL_MUST_NOT_NULL: 2,\n NOT_ATTACHED_TO_FLICKING: 3,\n WRONG_OPTION: 4,\n INDEX_OUT_OF_RANGE: 5,\n POSITION_NOT_REACHABLE: 6,\n TRANSFORM_NOT_SUPPORTED: 7,\n STOP_CALLED_BY_USER: 8,\n ANIMATION_INTERRUPTED: 9,\n ANIMATION_ALREADY_PLAYING: 10,\n NOT_ALLOWED_IN_FRAMEWORK: 11,\n NOT_INITIALIZED: 12,\n NO_ACTIVE: 13,\n NOT_ALLOWED_IN_VIRTUAL: 14\n} as const;\n\nexport const MESSAGE = {\n WRONG_TYPE: (wrongVal: any, correctTypes: string[]) => `${wrongVal}(${typeof wrongVal}) is not a ${correctTypes.map(type => `\"${type}\"`).join(\" or \")}.`,\n ELEMENT_NOT_FOUND: (selector: string) => `Element with selector \"${selector}\" not found.`,\n VAL_MUST_NOT_NULL: (val: any, name: string) => `${name} should be provided. Given: ${val}`,\n NOT_ATTACHED_TO_FLICKING: \"This module is not attached to the Flicking instance. \\\"init()\\\" should be called first.\",\n WRONG_OPTION: (optionName: string, val: any) => `Option \"${optionName}\" is not in correct format, given: ${val}`,\n INDEX_OUT_OF_RANGE: (val: number, min: number, max: number) => `Index \"${val}\" is out of range: should be between ${min} and ${max}.`,\n POSITION_NOT_REACHABLE: (position: number) => `Position \"${position}\" is not reachable.`,\n TRANSFORM_NOT_SUPPORTED: \"Browser does not support CSS transform.\",\n STOP_CALLED_BY_USER: \"Event stop() is called by user.\",\n ANIMATION_INTERRUPTED: \"Animation is interrupted by user input.\",\n ANIMATION_ALREADY_PLAYING: \"Animation is already playing.\",\n NOT_ALLOWED_IN_FRAMEWORK: \"This behavior is not allowed in the frameworks like React, Vue, or Angular.\",\n NOT_INITIALIZED: \"Flicking is not initialized yet, call init() first.\",\n NO_ACTIVE: \"There's no active panel that Flicking has selected. This may be due to the absence of any panels.\",\n NOT_ALLOWED_IN_VIRTUAL: \"This behavior is not allowed when the virtual option is enabled\"\n} as const;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nexport { CODE as ERROR_CODE } from \"./error\";\n\n/**\n * Event type object with event name strings of {@link Flicking}\n * @ko {@link Flicking}의 이벤트 이름 문자열들을 담은 객체\n * @type {object}\n * @property {\"holdStart\"} HOLD_START holdStart event<ko>holdStart 이벤트</ko>\n * @property {\"holdEnd\"} HOLD_END holdEnd event<ko>holdEnd 이벤트</ko>\n * @property {\"moveStart\"} MOVE_START moveStart event<ko>moveStart 이벤트</ko>\n * @property {\"move\"} MOVE move event<ko>move 이벤트</ko>\n * @property {\"moveEnd\"} MOVE_END moveEnd event<ko>moveEnd 이벤트</ko>\n * @property {\"willChange\"} WILL_CHANGE willChange event<ko>willChange 이벤트</ko>\n * @property {\"changed\"} CHANGED changed event<ko>changed 이벤트</ko>\n * @property {\"willRestore\"} WILL_RESTORE willRestore event<ko>willRestore 이벤트</ko>\n * @property {\"restored\"} RESTORED restored event<ko>restored 이벤트</ko>\n * @property {\"select\"} SELECT select event<ko>select 이벤트</ko>\n * @property {\"needPanel\"} NEED_PANEL needPanel event<ko>needPanel 이벤트</ko>\n * @property {\"panelChange\"} PANEL_CHANGE panelChange event<ko>panelChange 이벤트</ko>\n * @example\n * ```ts\n * import { EVENTS } from \"@egjs/flicking\";\n * EVENTS.MOVE_START; // \"moveStart\"\n * ```\n */\nexport const EVENTS = {\n READY: \"ready\",\n BEFORE_RESIZE: \"beforeResize\",\n AFTER_RESIZE: \"afterResize\",\n HOLD_START: \"holdStart\",\n HOLD_END: \"holdEnd\",\n MOVE_START: \"moveStart\",\n MOVE: \"move\",\n MOVE_END: \"moveEnd\",\n WILL_CHANGE: \"willChange\",\n CHANGED: \"changed\",\n WILL_RESTORE: \"willRestore\",\n RESTORED: \"restored\",\n SELECT: \"select\",\n NEED_PANEL: \"needPanel\",\n VISIBLE_CHANGE: \"visibleChange\",\n REACH_EDGE: \"reachEdge\",\n PANEL_CHANGE: \"panelChange\"\n} as const;\n\n/**\n * An object with all possible predefined literal string for the {@link Flicking#align align} option\n * @ko {@link Flicking#align align} 옵션에 사용되는 미리 정의된 리터럴 상수들을 담고 있는 객체\n * @type {object}\n * @property {\"prev\"} PREV left/top align<ko>좌/상 정렬</ko>\n * @property {\"center\"} CENTER center align<ko>중앙 정렬</ko>\n * @property {\"next\"} NEXT right/bottom align<ko>우/하 정렬</ko>\n */\nexport const ALIGN = {\n PREV: \"prev\",\n CENTER: \"center\",\n NEXT: \"next\"\n} as const;\n\n/**\n * An object of directions\n * @ko 방향을 나타내는 값들을 담고 있는 객체\n * @type {object}\n * @property {\"PREV\"} PREV \"left\" when {@link Flicking#horizontal horizontal} is true, and \"top\" when {@link Flicking#horizontal horizontal} is false\n * <ko>{@link Flicking#horizontal horizontal}가 `true`일 경우 왼쪽, {@link Flicking#horizontal horizontal}가 `false`일 경우 위쪽을 의미합니다</ko>\n * @property {\"NEXT\"} NEXT \"right\" when {@link Flicking#horizontal horizontal} is true, and \"bottom\" when {@link Flicking#horizontal horizontal} is false\n * <ko>{@link Flicking#horizontal horizontal}가 `true`일 경우 오른쪽, {@link Flicking#horizontal horizontal}가 `false`일 경우 아래쪽을 의미합니다</ko>\n * @property {null} NONE This value usually means it's the same position<ko>주로 제자리인 경우를 의미합니다</ko>\n */\nexport const DIRECTION = {\n PREV: \"PREV\",\n NEXT: \"NEXT\",\n NONE: null\n} as const;\n\n/**\n * An object with all possible {@link Flicking#moveType moveType}s\n * @ko Flicking이 제공하는 {@link Flicking#moveType moveType}들을 담고 있는 객체\n * @type {object}\n * @property {\"snap\"} SNAP Flicking's {@link Flicking#moveType moveType} that enables {@link SnapControl} as a Flicking's {@link Flicking#control control}\n * <ko>Flicking의 {@link Flicking#control control}을 {@link SnapControl}로 설정하게 하는 {@link Flicking#moveType moveType}</ko>\n * @property {\"freeScroll\"} FREE_SCROLL Flicking's {@link Flicking#moveType moveType} that enables {@link FreeControl} as a Flicking's {@link Flicking#control control}\n * <ko>Flicking의 {@link Flicking#control control}을 {@link FreeControl}로 설정하게 하는 {@link Flicking#moveType moveType}</ko>\n * @property {\"strict\"} STRICT Flicking's {@link Flicking#moveType moveType} that enables {@link StrictControl} as a Flicking's {@link Flicking#control control}\n * <ko>Flicking의 {@link Flicking#control control}을 {@link StrictControl}로 설정하게 하는 {@link Flicking#moveType moveType}</ko>\n */\nexport const MOVE_TYPE = {\n SNAP: \"snap\",\n FREE_SCROLL: \"freeScroll\",\n STRICT: \"strict\"\n} as const;\n\nexport const CLASS = {\n VERTICAL: \"vertical\",\n HIDDEN: \"flicking-hidden\",\n DEFAULT_VIRTUAL: \"flicking-panel\"\n};\n\n/**\n * An object with all possible {@link Flicking#circularFallback circularFallback}s\n * @ko Flicking의 {@link Flicking#circularFallback circularFallback}에 설정 가능한 값들을 담고 있는 객체\n * @type {object}\n * @property {string} LINEAR \"linear\"\n * @property {string} BOUND \"bound\"\n */\nexport const CIRCULAR_FALLBACK = {\n LINEAR: \"linear\",\n BOUND: \"bound\"\n} as const;\n\n/**\n * An object for identifying {@link https://developer.mozilla.org/en-US/docs/Web/CSS/direction direction} CSS property applied to the camera element(`.flicking-camera`)\n * @ko 카메라 엘리먼트(`.flicking-camera`)에 적용된 {@link https://developer.mozilla.org/en-US/docs/Web/CSS/direction direction} CSS 속성을 구분하기 위한 객체\n * @type {object}\n * @property {string} LTR \"ltr\"\n * @property {string} RTL \"rtl\"\n */\nexport const ORDER = {\n LTR: \"ltr\",\n RTL: \"rtl\"\n} as const;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport Flicking, { FlickingOptions } from \"./Flicking\";\nimport FlickingError from \"./core/FlickingError\";\nimport * as ERROR from \"./const/error\";\nimport { ALIGN, DIRECTION } from \"./const/external\";\nimport { LiteralUnion, Merged, ValueOf } from \"./type/internal\";\nimport { ElementLike } from \"./type/external\";\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport const merge = <From extends object, To extends object>(target: From, ...sources: To[]): Merged<From, To> => {\n sources.forEach(source => {\n Object.keys(source).forEach(key => {\n target[key] = source[key] as unknown;\n });\n });\n\n return target as Merged<From, To>;\n};\n\nexport const getElement = (el: HTMLElement | string | null, parent?: HTMLElement): HTMLElement => {\n let targetEl: HTMLElement | null = null;\n\n if (isString(el)) {\n const parentEl = parent ? parent : document;\n const queryResult = parentEl.querySelector(el);\n if (!queryResult) {\n throw new FlickingError(ERROR.MESSAGE.ELEMENT_NOT_FOUND(el), ERROR.CODE.ELEMENT_NOT_FOUND);\n }\n targetEl = queryResult as HTMLElement;\n } else if (el && el.nodeType === Node.ELEMENT_NODE) {\n targetEl = el;\n }\n\n if (!targetEl) {\n throw new FlickingError(ERROR.MESSAGE.WRONG_TYPE(el, [\"HTMLElement\", \"string\"]), ERROR.CODE.WRONG_TYPE);\n }\n\n return targetEl;\n};\n\nexport const checkExistence = (value: any, nameOnErrMsg: string) => {\n if (value == null) {\n throw new FlickingError(ERROR.MESSAGE.VAL_MUST_NOT_NULL(value, nameOnErrMsg), ERROR.CODE.VAL_MUST_NOT_NULL);\n }\n};\n\nexport const clamp = (x: number, min: number, max: number) => Math.max(Math.min(x, max), min);\n\nexport const getFlickingAttached = (val: Flicking | null): Flicking => {\n if (!val) {\n throw new FlickingError(ERROR.MESSAGE.NOT_ATTACHED_TO_FLICKING, ERROR.CODE.NOT_ATTACHED_TO_FLICKING);\n }\n\n return val;\n};\n\nexport const toArray = <T>(iterable: ArrayLike<T>): T[] => [].slice.call(iterable) as T[];\n\nexport const parseAlign = (align: LiteralUnion<ValueOf<typeof ALIGN>> | number, size: number): number => {\n let alignPoint: number | null;\n if (isString(align)) {\n switch (align) {\n case ALIGN.PREV:\n alignPoint = 0;\n break;\n case ALIGN.CENTER:\n alignPoint = 0.5 * size;\n break;\n case ALIGN.NEXT:\n alignPoint = size;\n break;\n default:\n alignPoint = parseArithmeticSize(align, size);\n if (alignPoint == null) {\n throw new FlickingError(ERROR.MESSAGE.WRONG_OPTION(\"align\", align), ERROR.CODE.WRONG_OPTION);\n }\n }\n } else {\n alignPoint = align as number;\n }\n\n return alignPoint;\n};\n\nexport const parseBounce = (bounce: FlickingOptions[\"bounce\"], size: number): number[] => {\n let parsedBounce: Array<number | null>;\n\n if (Array.isArray(bounce)) {\n parsedBounce = (bounce as string[]).map(val => parseArithmeticSize(val, size));\n } else {\n const parsedVal = parseArithmeticSize(bounce, size);\n\n parsedBounce = [parsedVal, parsedVal];\n }\n\n return parsedBounce.map(val => {\n if (val == null) {\n throw new FlickingError(ERROR.MESSAGE.WRONG_OPTION(\"bounce\", bounce), ERROR.CODE.WRONG_OPTION);\n }\n return val;\n });\n};\n\nexport const parseArithmeticSize = (cssValue: number | string, base: number): number | null => {\n const parsed = parseArithmeticExpression(cssValue);\n\n if (parsed == null) return null;\n\n return parsed.percentage * base + parsed.absolute;\n};\n\nexport const parseArithmeticExpression = (cssValue: number | string): { percentage: number; absolute: number } | null => {\n const cssRegex = /(?:(\\+|\\-)\\s*)?(\\d+(?:\\.\\d+)?(%|px)?)/g;\n\n if (typeof cssValue === \"number\") {\n return { percentage: 0, absolute: cssValue };\n }\n\n const parsed = {\n percentage: 0,\n absolute: 0\n };\n let idx = 0;\n let matchResult = cssRegex.exec(cssValue);\n while (matchResult != null) {\n let sign = matchResult[1];\n const value = matchResult[2];\n const unit = matchResult[3];\n const parsedValue = parseFloat(value);\n\n if (idx <= 0) {\n sign = sign || \"+\";\n }\n\n // Return default value for values not in good form\n if (!sign) {\n return null;\n }\n\n const signMultiplier = sign === \"+\" ? 1 : -1;\n\n if (unit === \"%\") {\n parsed.percentage += signMultiplier * (parsedValue / 100);\n } else {\n parsed.absolute += signMultiplier * parsedValue;\n }\n\n // Match next occurrence\n ++idx;\n matchResult = cssRegex.exec(cssValue);\n }\n\n // None-matched\n if (idx === 0) {\n return null;\n }\n\n return parsed;\n};\n\nexport const parseCSSSizeValue = (val: string | number): string => isString(val) ? val : `${val}px`;\n\nexport const parsePanelAlign = (align: FlickingOptions[\"align\"]) => typeof align === \"object\"\n ? (align as { panel: string | number }).panel\n : align;\n\nexport const getDirection = (start: number, end: number): ValueOf<typeof DIRECTION> => {\n if (start === end) return DIRECTION.NONE;\n return start < end ? DIRECTION.NEXT : DIRECTION.PREV;\n};\n\nexport const parseElement = (element: ElementLike | ElementLike[]): HTMLElement[] => {\n if (!Array.isArray(element)) {\n element = [element];\n }\n\n const elements: HTMLElement[] = [];\n element.forEach(el => {\n if (isString(el)) {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = el;\n\n elements.push(...toArray(tempDiv.children) as HTMLElement[]);\n while (tempDiv.firstChild) {\n tempDiv.removeChild(tempDiv.firstChild);\n }\n } else if (el && el.nodeType === Node.ELEMENT_NODE) {\n elements.push(el);\n } else {\n throw new FlickingError(ERROR.MESSAGE.WRONG_TYPE(el, [\"HTMLElement\", \"string\"]), ERROR.CODE.WRONG_TYPE);\n }\n });\n\n return elements;\n};\n\nexport const getMinusCompensatedIndex = (idx: number, max: number) => idx < 0 ? clamp(idx + max, 0, max) : clamp(idx, 0, max);\n\nexport const includes = <T>(array: T[], target: any): target is T => {\n for (const val of array) {\n if (val === target) return true;\n }\n return false;\n};\n\nexport const isString = (val: any): val is string => typeof val === \"string\";\n\nexport const circulatePosition = (pos: number, min: number, max: number) => {\n const size = max - min;\n\n if (pos < min) {\n const offset = (min - pos) % size;\n pos = max - offset;\n } else if (pos > max) {\n const offset = (pos - max) % size;\n pos = min + offset;\n }\n\n return pos;\n};\n\nexport const find = <T>(array: T[], checker: (val: T) => boolean): T | null => {\n for (const val of array) {\n if (checker(val)) {\n return val;\n }\n }\n\n return null;\n};\n\nexport const findRight = <T>(array: T[], checker: (val: T) => boolean): T | null => {\n for (let idx = array.length - 1; idx >= 0; idx--) {\n const val = array[idx];\n if (checker(val)) {\n return val;\n }\n }\n\n return null;\n};\n\nexport const findIndex = <T>(array: T[], checker: (val: T) => boolean): number => {\n for (let idx = 0; idx < array.length; idx++) {\n if (checker(array[idx])) {\n return idx;\n }\n }\n\n return -1;\n};\n\nexport const getProgress = (pos: number, prev: number, next: number) => (pos - prev) / (next - prev);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\nexport const getStyle = (el: HTMLElement): CSSStyleDeclaration => window.getComputedStyle(el) || (el as any).currentStyle as CSSStyleDeclaration;\n\nexport const setSize = (el: HTMLElement, { width, height }: Partial<{\n width: number | string;\n height: number | string;\n}>) => {\n if (width != null) {\n if (isString(width)) {\n el.style.width = width;\n } else {\n el.style.width = `${width}px`;\n }\n }\n if (height != null) {\n if (isString(height)) {\n el.style.height = height;\n } else {\n el.style.height = `${height}px`;\n }\n }\n};\n\nexport const isBetween = (val: number, min: number, max: number) => val >= min && val <= max;\n\nexport const circulateIndex = (index: number, max: number): number => {\n if (index >= max) {\n return index % max;\n } else if (index < 0) {\n return getMinusCompensatedIndex((index + 1) % max - 1, max);\n } else {\n return index;\n }\n};\n\nexport const range = (end: number): number[] => {\n const arr = new Array(end);\n\n for (let i = 0; i < end; i++) {\n arr[i] = i;\n }\n\n return arr;\n};\n\nexport const getElementSize = ({\n el,\n horizontal,\n useFractionalSize,\n useOffset,\n style\n}: {\n el: HTMLElement;\n horizontal: boolean;\n useFractionalSize: boolean;\n useOffset: boolean;\n style: CSSStyleDeclaration;\n}): number => {\n let size = 0;\n if (useFractionalSize) {\n const baseSize = parseFloat(horizontal ? style.width : style.height) || 0;\n const isBorderBoxSizing = style.boxSizing === \"border-box\";\n const border = horizontal\n ? parseFloat(style.borderLeftWidth || \"0\") + parseFloat(style.borderRightWidth || \"0\")\n : parseFloat(style.borderTopWidth || \"0\") + parseFloat(style.borderBottomWidth || \"0\");\n\n if (isBorderBoxSizing) {\n size = useOffset\n ? baseSize\n : baseSize - border;\n } else {\n const padding = horizontal\n ? parseFloat(style.paddingLeft || \"0\") + parseFloat(style.paddingRight || \"0\")\n : parseFloat(style.paddingTop || \"0\") + parseFloat(style.paddingBottom || \"0\");\n\n size = useOffset\n ? baseSize + padding + border\n : baseSize + padding;\n }\n } else {\n const sizeStr = horizontal ? \"Width\" : \"Height\";\n\n size = useOffset\n ? el[`offset${sizeStr}`]\n : el[`client${sizeStr}`];\n }\n\n return Math.max(size, 0);\n};\n\nexport const setPrototypeOf = Object.setPrototypeOf || ((obj, proto) => {\n obj.__proto__ = proto;\n return obj;\n});\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport { setPrototypeOf } from \"../utils\";\n\n/**\n * Special type of known error that {@link Flicking} throws.\n * @ko Flicking 내부에서 알려진 오류 발생시 throw되는 에러\n * @property {number} code Error code<ko>에러 코드</ko>\n * @property {string} message Error message<ko>에러 메시지</ko>\n * @see {@link ERROR_CODE ERROR_CODE}\n * @example\n * ```ts\n * import Flicking, { FlickingError, ERROR_CODES } from \"@egjs/flicking\";\n * try {\n * const flicking = new Flicking(\".flicking-viewport\")\n * } catch (e) {\n * if (e instanceof FlickingError && e.code === ERROR_CODES.ELEMENT_NOT_FOUND) {\n * console.error(\"Element not found\")\n * }\n * }\n * ```\n */\nclass FlickingError extends Error {\n public code: number;\n\n /**\n * @param message Error message<ko>에러 메시지</ko>\n * @param code Error code<ko>에러 코드</ko>\n */\n public constructor(message: string, code: number) {\n super(message);\n\n setPrototypeOf(this, FlickingError.prototype);\n this.name = \"FlickingError\";\n this.code = code;\n }\n}\n\nexport default FlickingError;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport Flicking from \"../Flicking\";\nimport { getElementSize, getStyle, isString } from \"../utils\";\n\n/**\n * A component that manages viewport size\n * @ko 뷰포트 크기 정보를 담당하는 컴포넌트\n */\nclass Viewport {\n private _flicking: Flicking;\n private _el: HTMLElement;\n private _width: number;\n private _height: number;\n private _isBorderBoxSizing: boolean;\n private _padding: {\n left: number;\n right: number;\n top: number;\n bottom: number;\n };\n\n /**\n * A viewport(root) element\n * @ko 뷰포트(root) 엘리먼트\n * @type {HTMLElement}\n * @readonly\n */\n public get element() { return this._el; }\n\n /**\n * Viewport width, without paddings\n * @ko 뷰포트 너비\n * @type {number}\n * @readonly\n */\n public get width() { return this._width - this._padding.left - this._padding.right; }\n /**\n * Viewport height, without paddings\n * @ko 뷰포트 높이\n * @type {number}\n * @readonly\n */\n public get height() { return this._height - this._padding.top - this._padding.bottom; }\n /**\n * Viewport paddings\n * @ko 뷰포트 CSS padding 값\n * @type {object}\n * @property {number} left CSS `padding-left`\n * @property {number} right CSS `padding-right`\n * @property {number} top CSS `padding-top`\n * @property {number} bottom CSS `padding-bottom`\n * @readonly\n */\n public get padding() { return this._padding; }\n\n /**\n * @param el A viewport element<ko>뷰포트 엘리먼트</ko>\n */\n public constructor(flicking: Flicking, el: HTMLElement) {\n this._flicking = flicking;\n this._el = el;\n this._width = 0;\n this._height = 0;\n this._padding = {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n };\n this._isBorderBoxSizing = false;\n }\n\n /**\n * Change viewport's size.\n * This will change the actual size of `.flicking-viewport` element by changing its CSS width/height property\n * @ko 뷰포트 크기를 변경합니다.\n * `.flicking-viewport` 엘리먼트에 해당 크기의 CSS width/height를 적용합니다\n * @param {object} [size] New viewport size<ko>새 뷰포트 크기</ko>\n * @param {number|string} [size.width] CSS string or number(in px)<ko>CSS 문자열 또는 숫자(px)</ko>\n * @param {number|string} [size.height] CSS string or number(in px)<ko>CSS 문자열 또는 숫자(px)</ko>\n */\n public setSize({\n width,\n height\n }: Partial<{\n width: number | string;\n height: number | string;\n }>) {\n const el = this._el;\n const padding = this._padding;\n const isBorderBoxSizing = this._isBorderBoxSizing;\n\n if (width != null) {\n if (isString(width)) {\n el.style.width = width;\n } else {\n const newWidth = isBorderBoxSizing\n ? width + padding.left + padding.right\n : width;\n el.style.width = `${newWidth}px`;\n }\n }\n if (height != null) {\n if (isString(height)) {\n el.style.height = height;\n } else {\n const newHeight = isBorderBoxSizing\n ? height + padding.top + padding.bottom\n : height;\n el.style.height = `${newHeight}px`;\n }\n }\n this.resize();\n }\n\n /**\n * Update width/height to the current viewport element's size\n * @ko 현재 뷰포트 엘리먼트의 크기로 너비/높이를 업데이트합니다\n */\n public resize() {\n const el = this._el;\n const elStyle = getStyle(el);\n const {\n useFractionalSize\n } = this._flicking;\n\n this._width = getElementSize({\n el,\n horizontal: true,\n useFractionalSize,\n useOffset: false,\n style: elStyle\n });\n this._height = getElementSize({\n el,\n horizontal: false,\n useFractionalSize,\n useOffset: false,\n style: elStyle\n });\n\n this._padding = {\n left: elStyle.paddingLeft ? parseFloat(elStyle.paddingLeft) : 0,\n right: elStyle.paddingRight ? parseFloat(elStyle.paddingRight) : 0,\n top: elStyle.paddingTop ? parseFloat(elStyle.paddingTop) : 0,\n bottom: elStyle.paddingBottom ? parseFloat(elStyle.paddingBottom) : 0\n };\n this._isBorderBoxSizing = elStyle.boxSizing === \"border-box\";\n }\n}\n\nexport default Viewport;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport Flicking from \"../Flicking\";\n\nclass AutoResizer {\n private _flicking: Flicking;\n private _enabled: boolean;\n private _resizeObserver: ResizeObserver | null;\n private _resizeTimer: number;\n private _maxResizeDebounceTimer: number;\n\n public get enabled() { return this._enabled; }\n\n public constructor(flicking: Flicking) {\n this._flicking = flicking;\n this._enabled = false;\n this._resizeObserver = null;\n this._resizeTimer = -1;\n this._maxResizeDebounceTimer = -1;\n }\n\n public enable(): this {\n const flicking = this._flicking;\n const viewport = flicking.viewport;\n\n if (this._enabled) {\n this.disable();\n }\n\n if (flicking.useResizeObserver && !!window.ResizeObserver) {\n const viewportSizeNot0 = viewport.width !== 0 || viewport.height !== 0;\n\n const resizeObserver = viewportSizeNot0\n ? new ResizeObserver(this._skipFirstResize)\n : new ResizeObserver(this._onResize);\n\n resizeObserver.observe(flicking.viewport.element);\n\n this._resizeObserver = resizeObserver;\n } else {\n window.addEventListener(\"resize\", this._onResize);\n }\n\n this._enabled = true;\n\n return this;\n }\n\n public disable(): this {\n if (!this._enabled) return this;\n\n const resizeObserver = this._resizeObserver;\n if (resizeObserver) {\n resizeObserver.disconnect();\n this._resizeObserver = null;\n } else {\n window.removeEventListener(\"resize\", this._onResize);\n }\n\n this._enabled = false;\n\n return this;\n }\n\n private _onResize = () => {\n const flicking = this._flicking;\n const resizeDebounce = flicking.resizeDebounce;\n const maxResizeDebounce = flicking.maxResizeDebounce;\n\n if (resizeDebounce <= 0) {\n void flicking.resize();\n } else {\n if (this._maxResizeDebounceTimer <= 0) {\n if (maxResizeDebounce > 0 && maxResizeDebounce >= resizeDebounce) {\n this._maxResizeDebounceTimer = window.setTimeout(this._doScheduledResize, maxResizeDebounce);\n }\n }\n\n if (this._resizeTimer > 0) {\n clearTimeout(this._resizeTimer);\n this._resizeTimer = 0;\n }\n\n this._resizeTimer = window.setTimeout(this._doScheduledResize, resizeDebounce);\n }\n };\n\n private _doScheduledResize = () => {\n clearTimeout(this._resizeTimer);\n clearTimeout(this._maxResizeDebounceTimer);\n\n this._maxResizeDebounceTimer = -1;\n this._resizeTimer = -1;\n\n void this._flicking.resize();\n };\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n private _skipFirstResize = (() => {\n let isFirstResize = true;\n\n return (() => {\n if (isFirstResize) {\n isFirstResize = false;\n return;\n }\n this._onResize();\n });\n })();\n}\n\nexport default AutoResizer;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport Flicking from \"../../../Flicking\";\n\nimport ElementProvider from \"./ElementProvider\";\n\n/**\n * @internal\n */\nclass VanillaElementProvider implements ElementProvider {\n private _element: HTMLElement;\n private _rendered: boolean;\n\n public get element() { return this._element; }\n public get rendered() { return this._rendered; }\n\n public constructor(element: HTMLElement) {\n this._element = element;\n this._rendered = true;\n }\n\n public show(flicking: Flicking): void {\n const el = this.element;\n const cameraEl = flicking.camera.element;\n\n if (el.parentElement !== cameraEl) {\n cameraEl.appendChild(el);\n this._rendered = true;\n }\n }\n\n public hide(flicking: Flicking): void {\n const el = this.element;\n const cameraEl = flicking.camera.element;\n\n if (el.parentElement === cameraEl) {\n cameraEl.removeChild(el);\n this._rendered = false;\n }\n }\n}\n\nexport default VanillaElementProvider;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport Flicking from \"../../../Flicking\";\nimport VirtualPanel from \"../VirtualPanel\";\n\nimport ElementProvider from \"./ElementProvider\";\n\n/**\n * @internal\n */\nclass VirtualElementProvider implements ElementProvider {\n private _flicking: Flicking;\n private _panel: VirtualPanel;\n\n public get element() { return this._virtualElement.nativeElement; }\n public get rendered() { return this._virtualElement.visible; }\n\n private get _virtualElement() {\n const flicking = this._flicking;\n const elIndex = this._panel.elementIndex;\n const virtualElements = flicking.virtual.elements;\n\n return virtualElements[elIndex];\n }\n\n public constructor(flicking: Flicking) {\n this._flicking = flicking;\n }\n\n public init(panel: VirtualPanel) {\n this._panel = panel;\n }\n\n public show(): void {\n // DO_NOTHING\n // Actual element visibility is controlled by VirtualManager\n }\n\n public hide(): void {\n // DO_NOTHING\n // Actual element visibility is controlled by VirtualManager\n }\n}\n\nexport default VirtualElementProvider;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport Flicking from \"../Flicking\";\nimport { range } from \"../utils\";\nimport { CLASS } from \"../const/external\";\n\nimport VirtualPanel from \"./panel/VirtualPanel\";\n\nexport interface VirtualOptions {\n renderPanel: (panel: VirtualPanel, index: number) => string;\n initialPanelCount: number;\n cache?: boolean;\n panelClass?: string;\n}\n\n/**\n * A manager class to add / remove virtual panels\n */\nclass VirtualManager {\n private _flicking: Flicking;\n\n private _renderPanel: (panel: VirtualPanel, index: number) => string;\n private _initialPanelCount: number;\n private _cache: boolean;\n private _panelClass: string;\n\n private _elements: Array<{ nativeElement: HTMLElement; visible: boolean }>;\n\n public get elements() { return this._elements; }\n\n // Options\n /**\n * A rendering function for the panel element's innerHTML\n * @ko 패널 엘리먼트의 innerHTML을 렌더링하는 함수\n * @type {function}\n * @param {VirtualPanel} panel Instance of the panel<ko>패널 인스턴스</ko>\n * @param {number} index Index of the panel<ko>패널 인덱스</ko>\n * @default \"() => {}\"\n */\n public get renderPanel() { return this._renderPanel; }\n /**\n * Initial panel count to render\n * @ko 최초로 렌더링할 패널의 개수\n * @readonly\n * @type {number}\n * @default -1\n */\n public get initialPanelCount() { return this._initialPanelCount; }\n /**\n * Whether to cache rendered panel's innerHTML\n * @ko 렌더링된 패널의 innerHTML 정보를 캐시할지 여부\n * @type {boolean}\n * @default false\n */\n public get cache() { return this._cache; }\n /**\n * The class name that will be applied to rendered panel elements\n * @ko 렌더링되는 패널 엘리먼트에 적용될 클래스 이름\n * @type {string}\n * @default \"flicking-panel\"\n */\n public get panelClass() { return this._panelClass; }\n\n public set renderPanel(val: VirtualOptions[\"renderPanel\"]) {\n this._renderPanel = val;\n this._flicking.renderer.panels.forEach((panel: VirtualPanel) => panel.uncacheRenderResult());\n }\n\n public set cache(val: NonNullable<VirtualOptions[\"cache\"]>) { this._cache = val; }\n public set panelClass(val: NonNullable<VirtualOptions[\"panelClass\"]>) { this._panelClass = val; }\n\n public constructor(flicking: Flicking, options: VirtualOptions | null) {\n this._flicking = flicking;\n\n this._renderPanel = options?.renderPanel ?? (() => \"\");\n this._initialPanelCount = options?.initialPanelCount ?? -1;\n this._cache = options?.cache ?? false;\n this._panelClass = options?.panelClass ?? CLASS.DEFAULT_VIRTUAL;\n\n this._elements = [];\n }\n\n public init() {\n const flicking = this._flicking;\n\n if (!flicking.virtualEnabled) return;\n\n if (!flicking.externalRenderer && !flicking.renderExternal) {\n this._initVirtualElements();\n }\n\n const virtualElements = flicking.camera.children;\n this._elements = virtualElements.map(el => ({ nativeElement: el, visible: true }));\n }\n\n public show(index: number) {\n const el = this._elements[index];\n const nativeEl = el.nativeElement;\n\n el.visible = true;\n\n if (nativeEl.style.display) {\n nativeEl.style.display = \"\";\n }\n }\n\n public hide(index: number) {\n const el = this._elements[index];\n const nativeEl = el.nativeElement;\n\n el.visible = false;\n nativeEl.style.display = \"none\";\n }\n\n /**\n * Add new virtual panels at the end of the list\n * @ko 새로운 가상 패널들을 리스트의 끝에 추가합니다\n * @param {number} count The number of panels to add<ko>추가할 패널의 개수</ko>\n * @returns {Array<VirtualPanel>} The new panels added<ko>새롭게 추가된 패널들</ko>\n */\n public append(count: number = 1): VirtualPanel[] {\n const flicking = this._flicking;\n\n return this.insert(flicking.panels.length, count);\n }\n\n /**\n * Add new virtual panels at the start of the list\n * @ko 새로운 가상 패널들을 리스트의 시작에 추가합니다\n * @param {number} count The number of panels to add<ko>추가할 패널의 개수</ko>\n * @returns {Array<VirtualPanel>} The new panels added<ko>새롭게 추가된 패널들</ko>\n */\n public prepend(count: number = 1): VirtualPanel[] {\n return this.insert(0, count);\n }\n\n /**\n * Add new virtual panels at the given index\n * @ko 새로운 가상 패널들을 주어진 인덱스에 추가합니다\n * @param {number} count The number of panels to add<ko>추가할 패널의 개수</ko>\n * @returns {Array<VirtualPanel>} The new panels added<ko>새롭게 추가된 패널들</ko>\n */\n public insert(index: number, count: number = 1): VirtualPanel[] {\n if (count <= 0) return [];\n\n const flicking = this._flicking;\n\n return flicking.renderer.batchInsert({ index, elements: range(count), hasDOMInElements: false }) as VirtualPanel[];\n }\n\n /**\n * Remove panels at the given index\n * @ko 주어진 인덱스에서 패널들을 삭제합니다\n * @param {number} count The number of panels to remove<ko>삭제할 패널의 개수</ko>\n * @returns {Array<VirtualPanel>} The panels removed<ko>삭제된 패널들</ko>\n */\n public remove(index: number, count: number): VirtualPanel[] {\n if (count <= 0) return [];\n\n const flicking = this._flicking;\n\n return flicking.renderer.batchRemove({ index, deleteCount: count, hasDOMInElements: false }) as VirtualPanel[];\n }\n\n private _initVirtualElements() {\n const flicking = this._flicking;\n const cameraElement = flicking.camera.element;\n const panelsPerView = flicking.panelsPerView;\n const fragment = document.createDocumentFragment();\n\n const newElements = range(panelsPerView + 1).map(idx => {\n const panelEl = document.createElement(\"div\");\n panelEl.className = this._panelClass;\n panelEl.dataset.elementIndex = idx.toString();\n return panelEl;\n });\n\n newElements.forEach(el => {\n fragment.appendChild(el);\n });\n\n cameraElement.appendChild(fragment);\n }\n}\n\nexport default VirtualManager;\n","/**\n * All possible @egjs/axes event keys\n * @internal\n */\nexport const EVENT = {\n HOLD: \"hold\",\n CHANGE: \"change\",\n RELEASE: \"release\",\n ANIMATION_END: \"animationEnd\",\n FINISH: \"finish\"\n} as const;\n\n/**\n * An Axis key that Flicking uses\n * @internal\n */\nexport const POSITION_KEY = \"flick\";\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { OnAnimationEnd, OnChange, OnFinish, OnHold, OnRelease } from \"@egjs/axes\";\nimport { ComponentEvent } from \"@egjs/component\";\n\nimport Flicking from \"../../Flicking\";\nimport Panel from \"../../core/panel/Panel\";\nimport { EVENTS } from \"../../const/external\";\nimport * as AXES from \"../../const/axes\";\nimport { circulatePosition, getDirection } from \"../../utils\";\n\nexport enum STATE_TYPE {\n IDLE,\n HOLDING,\n DRAGGING,\n ANIMATING,\n DISABLED\n}\n\n/**\n * A component that shows the current status of the user input or the animation\n * @ko 현재 사용자 입력 또는 애니메이션 상태를 나타내는 컴포넌트\n * @internal\n */\nabstract class State {\n /**\n * Whether user is clicking or touching\n * @ko 현재 사용자가 클릭/터치중인지 여부\n * @type {boolean}\n * @readonly\n */\n public abstract readonly holding: boolean;\n /**\n * Whether Flicking's animating\n * @ko 현재 애니메이션 동작 여부\n * @type {boolean}\n * @readonly\n */\n public abstract readonly animating: boolean;\n\n protected _delta: number = 0;\n protected _targetPanel: Panel | null = null;\n\n /**\n * A sum of delta values of change events from the last hold event of Axes\n * @ko 이전 hold이벤트부터 change에 의해 발생한 이동 delta값의 합산\n * @type {number}\n * @readonly\n */\n public get delta() { return this._delta; }\n\n /**\n * A panel to set as {@link Control#activePanel} after the animation is finished\n * @ko 애니메이션 종료시 {@link Control#activePanel}로 설정할 패널\n * @type {number}\n * @readonly\n */\n public get targetPanel() { return this._targetPanel; }\n\n public set targetPanel(val: Panel | null) { this._targetPanel = val; }\n\n /**\n * An callback which is called when state has changed to this state\n * @ko 현재 상태로 돌입했을때 호출되는 콜백 함수\n * @param {State} prevState An previous state<ko>이전 상태값</ko>\n * @return {void}\n */\n public onEnter(prevState: State): void {\n this._delta = prevState._delta;\n this._targetPanel = prevState._targetPanel;\n }\n\n /**\n * An event handler for Axes's {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:hold hold} event\n * @ko Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:hold hold} 이벤트 핸들러\n * @param {object} [ctx] Event context<ko>이벤트 콘텍스트</ko>\n * @param {Flicking} [ctx.flicking] An instance of Flicking<ko>Flicking 인스턴스</ko>\n * @param {object} [ctx.axesEvent] A {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:hold hold} event of Axes\n * <ko>Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:hold hold} 이벤트</ko>\n * @param {function} [ctx.transitTo] A function for changing current state to other state<ko>다른 상태로 변경하기 위한 함수</ko>\n * @return {void}\n */\n public onHold(ctx: {\n flicking: Flicking;\n axesEvent: OnHold;\n transitTo: (nextState: STATE_TYPE) => State;\n }): void {\n // DO NOTHING\n }\n\n /**\n * An event handler for Axes's {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:change change} event\n * @ko Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:change change} 이벤트 핸들러\n * @param {object} [ctx] Event context<ko>이벤트 콘텍스트</ko>\n * @param {Flicking} [ctx.flicking] An instance of Flicking<ko>Flicking 인스턴스</ko>\n * @param {object} [ctx.axesEvent] A {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:change change} event of Axes\n * <ko>Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:change change} 이벤트</ko>\n * @param {function} [ctx.transitTo] A function for changing current state to other state<ko>다른 상태로 변경하기 위한 함수</ko>\n * @return {void}\n */\n public onChange(ctx: {\n flicking: Flicking;\n axesEvent: OnChange;\n transitTo: (nextState: STATE_TYPE) => State;\n }): void {\n // DO NOTHING\n }\n\n /**\n * An event handler for Axes's {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:release release} event\n * @ko Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:release release} 이벤트 핸들러\n * @param {object} [ctx] Event context<ko>이벤트 콘텍스트</ko>\n * @param {Flicking} [ctx.flicking] An instance of Flicking<ko>Flicking 인스턴스</ko>\n * @param {object} [ctx.axesEvent] A {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:release release} event of Axes\n * <ko>Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:release release} 이벤트</ko>\n * @param {function} [ctx.transitTo] A function for changing current state to other state<ko>다른 상태로 변경하기 위한 함수</ko>\n * @return {void}\n */\n public onRelease(ctx: {\n flicking: Flicking;\n axesEvent: OnRelease;\n transitTo: (nextState: STATE_TYPE) => State;\n }): void {\n // DO NOTHING\n }\n\n /**\n * An event handler for Axes's {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:animationEnd animationEnd} event\n * @ko Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:animationEnd animationEnd} 이벤트 핸들러\n * @param {object} [ctx] Event context<ko>이벤트 콘텍스트</ko>\n * @param {Flicking} [ctx.flicking] An instance of Flicking<ko>Flicking 인스턴스</ko>\n * @param {object} [ctx.axesEvent] A {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:animationEnd animationEnd} event of Axes\n * <ko>Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:animationEnd animationEnd} 이벤트</ko>\n * @param {function} [ctx.transitTo] A function for changing current state to other state<ko>다른 상태로 변경하기 위한 함수</ko>\n * @return {void}\n */\n public onAnimationEnd(ctx: {\n flicking: Flicking;\n axesEvent: OnAnimationEnd;\n transitTo: (nextState: STATE_TYPE) => State;\n }): void {\n // DO NOTHING\n }\n\n /**\n * An event handler for Axes's {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:finish finish} event\n * @ko Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:finish finish} 이벤트 핸들러\n * @param {object} [ctx] Event context<ko>이벤트 콘텍스트</ko>\n * @param {Flicking} [ctx.flicking] An instance of Flicking<ko>Flicking 인스턴스</ko>\n * @param {object} [ctx.axesEvent] A {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:finish finish} event of Axes<ko>Axes의 {@link https://naver.github.io/egjs-axes/release/latest/doc/eg.Axes.html#event:finish finish} 이벤트</ko>\n * @param {function} [ctx.transitTo] A function for changing current state to other state<ko>다른 상태로 변경하기 위한 함수</ko>\n * @return {void}\n */\n public onFinish(ctx: {\n flicking: Flicking;\n axesEvent: OnFinish;\n transitTo: (nextState: STATE_TYPE) => State;\n }): void {\n // DO NOTHING\n }\n\n protected _moveToChangedPosition(ctx: Parameters<State[\"onChange\"]>[0]): void {\n const { flicking, axesEvent, transitTo } = ctx;\n const delta = axesEvent.delta[AXES.POSITION_KEY];\n\n if (!delta) {\n return;\n }\n\n this._delta += delta;\n\n const camera = flicking.camera;\n const prevPosition = camera.position;\n const position = axesEvent.pos[AXES.POSITION_KEY];\n const newPosition = flicking.circularEnabled\n ? circulatePosition(position, camera.range.min, camera.range.max)\n : position;\n\n camera.lookAt(newPosition);\n\n const moveEvent = new ComponentEvent(EVENTS.MOVE, {\n isTrusted: axesEvent.isTrusted,\n holding: this.holding,\n direction: getDirection(0, axesEvent.delta[AXES.POSITION_KEY]),\n axesEvent\n });\n\n flicking.trigger(moveEvent);\n\n if (moveEvent.isCanceled()) {\n // Return to previous position\n camera.lookAt(prevPosition);\n transitTo(STATE_TYPE.DISABLED);\n }\n }\n}\n\nexport default State;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport { ComponentEvent } from \"@egjs/component\";\n\nimport { EVENTS } from \"../../const/external\";\nimport { getDirection } from \"../../utils\";\n\nimport State, { STATE_TYPE } from \"./State\";\n\n/**\n * A default state when there's no user input and no animation's playing\n * @ko 사용자의 입력이 없고, 애니메이션이 동작하고있지 않은 기본 상태\n * @internal\n */\nclass IdleState extends State {\n /**\n * Whether user is clicking or touching\n * @ko 현재 사용자가 클릭/터치중인지 여부\n * @type {false}\n * @readonly\n */\n public readonly holding = false;\n /**\n * Whether Flicking's animating\n * @ko 현재 애니메이션 동작 여부\n * @type {false}\n * @readonly\n */\n public readonly animating = false;\n\n public onEnter() {\n this._delta = 0;\n this._targetPanel = null;\n }\n\n public onHold(ctx: Parameters<State[\"onHold\"]>[0]): void {\n // Shouldn't do any action until any panels on flicking area\n const { flicking, axesEvent, transitTo } = ctx;\n\n if (flicking.renderer.panelCount <= 0) {\n transitTo(STATE_TYPE.DISABLED);\n return;\n }\n\n const holdStartEvent = new ComponentEvent(EVENTS.HOLD_START, {\n axesEvent\n });\n\n flicking.trigger(holdStartEvent);\n\n if (holdStartEvent.isCanceled()) {\n transitTo(STATE_TYPE.DISABLED);\n } else {\n transitTo(STATE_TYPE.HOLDING);\n }\n }\n\n // By methods call\n public onChange(ctx: Parameters<State[\"onChange\"]>[0]): void {\n const { flicking, axesEvent, transitTo } = ctx;\n const controller = flicking.control.controller;\n const animatingContext = controller.animatingContext;\n\n const moveStartEvent = new ComponentEvent(EVENTS.MOVE_START, {\n isTrusted: axesEvent.isTrusted,\n holding: this.holding,\n direction: getDirection(animatingContext.start, animatingContext.end),\n axesEvent\n });\n flicking.trigger(moveStartEvent);\n\n if (moveStartEvent.isCanceled()) {\n transitTo(STATE_TYPE.DISABLED);\n } else {\n // Trigger AnimatingState's onChange, to trigger \"move\" event immediately\n transitTo(STATE_TYPE.ANIMATING).onChange(ctx);\n }\n }\n}\n\nexport default IdleState;\n","/*\n * Copyright (c) 2015 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport { OnRelease } from \"@egjs/axes\";\nimport { ComponentEvent } from \"@egjs/component\";\n\nimport Panel from \"../../core/panel/Panel\";\nimport { EVENTS } from \"../../const/external\";\nimport { getDirection } from \"../../utils\";\n\nimport State, { STATE_TYPE } from \"./State\";\n\n/**\n * A state that activates when user's holding the Flicking area, but not moved a single pixel yet\n * @ko 사용자의 입력이 시작되었으나, 아직 움직이지는 않은 상태\n * @internal\n */\nclass HoldingState extends State {\n /**\n * Whether user is clicking or touching\n * @ko 현재 사용자가 클릭/터치중인지 여부\n * @type {true}\n * @readonly\n */\n public readonly holding = true;\n /**\n * Whether Flicking's animating\n * @ko 현재 애니메이션 동작 여부\n * @type {false}\n * @readonly\n */\n public readonly animating = false;\n\n private _releaseEvent: OnRelease | null = null;\n\n public onChange(ctx: Parameters<State[\"onChange\"]>[0]): void {\n const { flicking, axesEvent, transitTo } = ctx;\n\n const inputEvent = axesEvent.inputEvent as { offsetX: