@egjs/flicking 4.13.2-beta.0 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,75 @@
1
+ /* eslint-disable */
2
+
3
+ /**
4
+ * 프레임워크 컴포넌트를 디버깅할 때 코어 바닐라 로직을 수정하면서 확인할 필요가 있을 때,
5
+ * 이 스크립트를 이용하면 바닐라 로직 수정사항이 프레임워크 컴포넌트 로컬 데모환경에도 반영된다.
6
+ * 다만, 바닐라 로직 수정 이후 리액트 데모에 핫 모듈 리로딩까지는 되지 않는다.
7
+ * 따라서 수정 사항들을 추가적으로 반영해주려면 바닐라를 다시 빌드해야 한다. 링크는 다시 하지 않아도 된다.
8
+ *
9
+ * 인자로 프레임워크 컴포넌트 패키지의 루트 디렉토리를 제공하면 된다.
10
+ * 인자를 제공하지 않으면 packages 하위의 전체 프레임워크 패키지에 대해 링크를 시도한다.
11
+ *
12
+ * 사용 예시: node core-package-link.js react-flicking
13
+ *
14
+ *
15
+ * 개발 흐름:
16
+ * 1. 이 스크립트를 실행
17
+ * 2. 바닐라 로직 수정 후 빌드 수행
18
+ * 3. 프레임워크 컴포넌트의 데모를 실행 (바닐라 로직 변경사항이 반영됨)
19
+ * 4. 바닐라 로직 추가 수정 후 빌드 수행
20
+ * 5. 프레임워크 컴포넌트의 데모를 새로고침 (바닐라 로직 변경사항이 반영됨)
21
+ * - 원래는 새로고침만 하면 되야 하지만 타입 에러가 발생하는 경우가 있어 데모를 중지하고 다시 실행해야 할 수도 있다.
22
+ *
23
+ *
24
+ */
25
+
26
+
27
+
28
+ function run(cmd, cwd = process.cwd()) {
29
+ console.log(`\n▶️ Running: ${cmd} (in ${cwd})`);
30
+ execSync(cmd, { stdio: "inherit", cwd });
31
+ }
32
+
33
+ const { execSync } = require("child_process");
34
+ const path = require("path");
35
+ const fs = require("fs");
36
+
37
+ const frameworks = [
38
+ "ngx-flicking",
39
+ "preact-flicking",
40
+ "react-flicking",
41
+ "vue-flicking",
42
+ "vue3-flicking",
43
+ "svelte-flicking",
44
+ ];
45
+
46
+ const args = process.argv.slice(2);
47
+ const targetDir = args[0];
48
+
49
+ if (!targetDir) {
50
+ console.log(
51
+ "❗️ 디렉토리명을 인자로 입력하지 않았습니다. 전체 프레임워크에 대해 링크를 시도합니다."
52
+ );
53
+ run("npm run build");
54
+ run("npm link");
55
+ frameworks.forEach((target) => {
56
+ const fullPath = path.resolve(process.cwd(), "packages", target);
57
+ if (!fs.existsSync(fullPath)) {
58
+ console.error(`❌ 디렉토리 없음: ${fullPath}`);
59
+ process.exit(1);
60
+ }
61
+ run(`npm link '@egjs/flicking'`, fullPath);
62
+ });
63
+ } else {
64
+ const fullPath = path.resolve(process.cwd(), "packages", targetDir);
65
+ if (!fs.existsSync(fullPath)) {
66
+ console.error(`❌ 디렉토리 없음: ${fullPath}`);
67
+ process.exit(1);
68
+ }
69
+
70
+ run("npm run build");
71
+ run("npm link");
72
+ run(`npm link '@egjs/flicking'`, fullPath);
73
+ }
74
+
75
+
@@ -0,0 +1,240 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Flicking Basic Demo</title>
7
+ <link rel="stylesheet" href="../../dist/flicking.css" />
8
+ <style>
9
+ #container {
10
+ display: flex;
11
+ flex-direction: column;
12
+ align-items: center;
13
+ }
14
+ #nav-wrapper {
15
+ display: flex;
16
+ align-items: center;
17
+ }
18
+ .flicking-viewport {
19
+ width: 500px;
20
+ height: 300px;
21
+ /* margin: 0 auto; */
22
+ border: 1px solid black;
23
+ }
24
+ .flicking-camera {
25
+ display: flex;
26
+ }
27
+ .flicking-panel {
28
+ align-items: flex-end;
29
+ border-radius: 5px;
30
+ box-sizing: border-box;
31
+ display: flex;
32
+ /* height: 200px; */
33
+ justify-content: flex-start;
34
+ margin-top: 10px;
35
+ margin-bottom: 10px;
36
+ margin-right: 10px;
37
+ position: relative;
38
+ width: 200px;
39
+ background-color: aliceblue;
40
+ justify-content: center;
41
+ align-items: center;
42
+ }
43
+ .navigation-btn {
44
+ text-align: center;
45
+ margin: 0 5px;
46
+ padding: 5px 10px;
47
+ height: 50px;
48
+ }
49
+ #pagination {
50
+ display: flex;
51
+ }
52
+ .pagination-num {
53
+ background-color: beige;
54
+ margin: 5px;
55
+ width: 30px;
56
+ height: 30px;
57
+ text-align: center;
58
+ }
59
+ .pagination-num.active {
60
+ background-color: yellowgreen;
61
+ }
62
+ #scroll-progress-bar {
63
+ width: 600px;
64
+ height: 20px;
65
+ border-radius: 20px;
66
+ background-color: #e0e0e0;
67
+ overflow: hidden;
68
+ }
69
+ #scroll-progress-fill {
70
+ height: 100%;
71
+ width: 0%; /* 초기에는 0% 채워짐 */
72
+ background-color: #2196f3; /* 채워지는 색 */
73
+ transition: width 0.3s ease; /* 부드럽게 변화 */
74
+ }
75
+ </style>
76
+ </head>
77
+ <body>
78
+ <div id="container">
79
+ <div id="nav-wrapper">
80
+ <button class="navigation-btn" id="prev">Previous</button>
81
+ <div class="flicking-viewport">
82
+ <div class="flicking-camera">
83
+ <div class="flicking-panel" style="width: 500px">x0</div>
84
+ <div class="flicking-panel">x1</div>
85
+ <div class="flicking-panel">x2</div>
86
+ <div class="flicking-panel">x3</div>
87
+ <div class="flicking-panel">x4</div>
88
+ </div>
89
+ </div>
90
+ <button class="navigation-btn" id="next">Next</button>
91
+ </div>
92
+ <div id="pagination"></div>
93
+ <div id="scroll-progress-bar">
94
+ <div id="scroll-progress-fill"></div>
95
+ </div>
96
+ </div>
97
+
98
+ <div class="add">
99
+ <button id="prepend">prepend</button>
100
+ <button id="append">append</button>
101
+ <button id="add-random">add random</button>
102
+ </div>
103
+ <div class="remove">
104
+ <button id="remove-first">remove first</button>
105
+ <button id="remove-last">remove last</button>
106
+ <button id="remove-random">remove random</button>
107
+ </div>
108
+
109
+ <script src="../../dist/flicking.pkgd.js"></script>
110
+ <script>
111
+ document.addEventListener("DOMContentLoaded", () => {
112
+ const flicking = new Flicking(".flicking-viewport", {
113
+ renderOnlyVisible: true,
114
+ // circular: true
115
+ // horizontal: false
116
+ // align: 'center',
117
+ defaultIndex: 2,
118
+ });
119
+ const { connectFlickingReactiveAPI } = Flicking;
120
+ const reactiveObj = connectFlickingReactiveAPI(flicking);
121
+ const {
122
+ isReachStart,
123
+ isReachEnd,
124
+ totalPanelCount,
125
+ currentPanelIndex,
126
+ moveTo,
127
+ progress,
128
+ } = reactiveObj;
129
+
130
+ // Navigation buttons
131
+ const prevButton = document.getElementById("prev");
132
+ const nextButton = document.getElementById("next");
133
+
134
+ // 비활성화 여부 초기화
135
+ prevButton.disabled = isReachStart;
136
+ nextButton.disabled = isReachEnd;
137
+
138
+ // 반응형과 엮기
139
+ reactiveObj.subscribe("isReachStart", (nextValue) => {
140
+ prevButton.disabled = nextValue;
141
+ });
142
+ reactiveObj.subscribe("isReachEnd", (nextValue) => {
143
+ nextButton.disabled = nextValue;
144
+ });
145
+
146
+ // 이벤트 리스너 등록
147
+ prevButton.addEventListener("click", () => {
148
+ flicking.prev();
149
+ });
150
+
151
+ nextButton.addEventListener("click", () => {
152
+ flicking.next();
153
+ });
154
+
155
+ // 패널이 동적으로 추가되거나 삭제되었을 때도 잘 동작해야함.
156
+
157
+ let appendNum = 100;
158
+ let prependNum = -1;
159
+
160
+ const appendButton = document.getElementById("append");
161
+ const prependButton = document.getElementById("prepend");
162
+ const addRandomButton = document.getElementById("add-random");
163
+
164
+ const getRandomInt = (min, max) => {
165
+ const minCeiled = Math.ceil(min);
166
+ const maxFloored = Math.floor(max);
167
+ return Math.floor(
168
+ Math.random() * (maxFloored - minCeiled) + minCeiled
169
+ );
170
+ };
171
+ appendButton.addEventListener("click", () => {
172
+ flicking.append(`<div class="flicking-panel">x${appendNum}</div>`);
173
+ appendNum++;
174
+ });
175
+ prependButton.addEventListener("click", () => {
176
+ flicking.prepend(`<div class="flicking-panel">x${prependNum}</div>`);
177
+ prependNum--;
178
+ });
179
+ addRandomButton.addEventListener("click", () => {
180
+ const randomN = getRandomInt(0, flicking.panelCount);
181
+ flicking.insert(
182
+ randomN,
183
+ `<div class="flicking-panel">random ${randomN}</div>`
184
+ );
185
+ });
186
+
187
+ const removeFirstButton = document.getElementById("remove-first");
188
+ const removeLastButton = document.getElementById("remove-last");
189
+ const removeRandomButton = document.getElementById("remove-random");
190
+
191
+ removeFirstButton.addEventListener("click", () => {
192
+ flicking.remove(0);
193
+ });
194
+
195
+ removeLastButton.addEventListener("click", () => {
196
+ flicking.remove(flicking.panelCount - 1);
197
+ });
198
+ removeRandomButton.addEventListener("click", () => {
199
+ const randomN = getRandomInt(0, flicking.panelCount);
200
+ flicking.remove(randomN);
201
+ });
202
+
203
+ const paginationElement = document.getElementById("pagination");
204
+
205
+ const pageNums = Array.from({ length: totalPanelCount }, (_, i) => {
206
+ const div = document.createElement("div");
207
+ div.className = `pagination-num ${
208
+ i === currentPanelIndex ? "active" : ""
209
+ }`;
210
+ div.textContent = `${i}`;
211
+
212
+ div.addEventListener("click", (e) => {
213
+ moveTo(i);
214
+ });
215
+ return div;
216
+ });
217
+
218
+ paginationElement.append(...pageNums);
219
+
220
+ reactiveObj.subscribe("currentPanelIndex", (nextValue) => {
221
+ pageNums.forEach((v, i) => {
222
+ v.classList.remove("active");
223
+ if (i === nextValue) {
224
+ v.classList.add("active");
225
+ }
226
+ });
227
+ });
228
+
229
+ const scrollProgressFillElement = document.getElementById(
230
+ "scroll-progress-fill"
231
+ );
232
+ scrollProgressFillElement.style.width = `${progress}%`;
233
+
234
+ reactiveObj.subscribe("progress", (nextValue) => {
235
+ scrollProgressFillElement.style.width = `${nextValue}%`;
236
+ });
237
+ });
238
+ </script>
239
+ </body>
240
+ </html>
@@ -1,5 +1,6 @@
1
1
  import Component from "@egjs/component";
2
2
  import Viewport from "./core/Viewport";
3
+ import AutoResizer from "./core/AutoResizer";
3
4
  import { Panel } from "./core/panel";
4
5
  import VirtualManager, { VirtualOptions } from "./core/VirtualManager";
5
6
  import { Control } from "./control";
@@ -65,9 +66,11 @@ export interface FlickingOptions {
65
66
  autoResize: boolean;
66
67
  useResizeObserver: boolean;
67
68
  resizeDebounce: number;
69
+ observePanelResize: boolean;
68
70
  maxResizeDebounce: number;
69
71
  useFractionalSize: boolean;
70
72
  externalRenderer: ExternalRenderer | null;
73
+ optimizeSizeUpdate: boolean;
71
74
  renderExternal: {
72
75
  renderer: new (options: RendererOptions) => ExternalRenderer;
73
76
  rendererOptions: RendererOptions;
@@ -114,16 +117,20 @@ declare class Flicking extends Component<FlickingEvents> {
114
117
  private _autoResize;
115
118
  private _useResizeObserver;
116
119
  private _resizeDebounce;
120
+ private _observePanelResize;
117
121
  private _maxResizeDebounce;
118
122
  private _useFractionalSize;
119
123
  private _externalRenderer;
120
124
  private _renderExternal;
125
+ private _optimizeSizeUpdate;
121
126
  private _initialized;
122
127
  private _plugins;
128
+ private _isResizing;
123
129
  get control(): Control;
124
130
  get camera(): Camera;
125
131
  get renderer(): Renderer;
126
132
  get viewport(): Viewport;
133
+ get autoResizer(): AutoResizer;
127
134
  get initialized(): boolean;
128
135
  get circularEnabled(): boolean;
129
136
  get virtualEnabled(): boolean;
@@ -171,6 +178,7 @@ declare class Flicking extends Component<FlickingEvents> {
171
178
  get autoInit(): boolean;
172
179
  get autoResize(): FlickingOptions["autoResize"];
173
180
  get useResizeObserver(): FlickingOptions["useResizeObserver"];
181
+ get observePanelResize(): FlickingOptions["observePanelResize"];
174
182
  get resizeDebounce(): number;
175
183
  get maxResizeDebounce(): number;
176
184
  get useFractionalSize(): boolean;
@@ -179,6 +187,7 @@ declare class Flicking extends Component<FlickingEvents> {
179
187
  renderer: new (options: RendererOptions) => ExternalRenderer;
180
188
  rendererOptions: RendererOptions;
181
189
  };
190
+ get optimizeSizeUpdate(): FlickingOptions["optimizeSizeUpdate"];
182
191
  set align(val: FlickingOptions["align"]);
183
192
  set defaultIndex(val: FlickingOptions["defaultIndex"]);
184
193
  set horizontal(val: FlickingOptions["horizontal"]);
@@ -208,7 +217,9 @@ declare class Flicking extends Component<FlickingEvents> {
208
217
  set renderOnlyVisible(val: FlickingOptions["renderOnlyVisible"]);
209
218
  set autoResize(val: FlickingOptions["autoResize"]);
210
219
  set useResizeObserver(val: FlickingOptions["useResizeObserver"]);
211
- constructor(root: HTMLElement | string, { align, defaultIndex, horizontal, circular, circularFallback, bound, adaptive, panelsPerView, noPanelStyleOverride, resizeOnContentsReady, nested, needPanelThreshold, preventEventsBeforeInit, deceleration, duration, easing, inputType, moveType, threshold, dragThreshold, interruptable, bounce, iOSEdgeSwipeThreshold, preventClickOnDrag, preventDefaultOnDrag, disableOnInit, changeOnHold, renderOnlyVisible, virtual, autoInit, autoResize, useResizeObserver, resizeDebounce, maxResizeDebounce, useFractionalSize, externalRenderer, renderExternal }?: Partial<FlickingOptions>);
220
+ set observePanelResize(val: FlickingOptions["observePanelResize"]);
221
+ set optimizeSizeUpdate(val: FlickingOptions["optimizeSizeUpdate"]);
222
+ constructor(root: HTMLElement | string, { align, defaultIndex, horizontal, circular, circularFallback, bound, adaptive, panelsPerView, noPanelStyleOverride, resizeOnContentsReady, nested, needPanelThreshold, preventEventsBeforeInit, deceleration, duration, easing, inputType, moveType, threshold, dragThreshold, interruptable, bounce, iOSEdgeSwipeThreshold, preventClickOnDrag, preventDefaultOnDrag, disableOnInit, changeOnHold, renderOnlyVisible, virtual, autoInit, autoResize, useResizeObserver, resizeDebounce, observePanelResize, maxResizeDebounce, useFractionalSize, externalRenderer, renderExternal, optimizeSizeUpdate }?: Partial<FlickingOptions>);
212
223
  init(): Promise<void>;
213
224
  destroy(): void;
214
225
  prev(duration?: number): Promise<void>;
@@ -40,6 +40,6 @@ declare abstract class Control {
40
40
  newActivePanel: Panel;
41
41
  axesEvent?: OnRelease;
42
42
  }): Promise<void>;
43
- protected _getPosition(panel: Panel, direction?: ValueOf<typeof DIRECTION>): number;
43
+ private _getPosition;
44
44
  }
45
45
  export default Control;
@@ -8,7 +8,12 @@ declare class AutoResizer {
8
8
  get enabled(): boolean;
9
9
  constructor(flicking: Flicking);
10
10
  enable(): this;
11
+ observePanels(): this;
12
+ unobservePanels(): this;
13
+ observe(element: HTMLElement): this;
14
+ unobserve(element: HTMLElement): this;
11
15
  disable(): this;
16
+ private _onResizeWrapper;
12
17
  private _onResize;
13
18
  private _doScheduledResize;
14
19
  private _skipFirstResize;
@@ -9,6 +9,7 @@ export * from "./renderer";
9
9
  export * from "./const/external";
10
10
  export * from "./cfc";
11
11
  export * from "./utils";
12
+ export * from "./reactive";
12
13
  export * from "./type/event";
13
14
  export * from "./type/external";
14
15
  export type { FlickingOptions, FlickingEvents, CrossFlickingOptions };
@@ -0,0 +1,25 @@
1
+ import { ReactiveObject, ReactiveSetupAdapter } from "@cfcs/core";
2
+ import Flicking from "../Flicking";
3
+ export declare type FlickingReactiveObject = ReactiveObject<FlickingReactiveState & FlickingReactiveMethod>;
4
+ export interface FlickingReactiveState {
5
+ isReachStart: boolean;
6
+ isReachEnd: boolean;
7
+ totalPanelCount: number;
8
+ currentPanelIndex: number;
9
+ progress: number;
10
+ indexProgress: number;
11
+ }
12
+ export interface FlickingReactiveMethod {
13
+ moveTo: (i: number) => Promise<void>;
14
+ }
15
+ export interface FlickingReactiveData {
16
+ flicking?: Flicking;
17
+ options?: FlickingReactiveAPIOptions;
18
+ }
19
+ export interface FlickingReactiveAPIOptions {
20
+ defaultIndex?: number;
21
+ totalPanelCount?: number;
22
+ }
23
+ declare const flickingReactiveAPIAdapter: ReactiveSetupAdapter<FlickingReactiveObject, FlickingReactiveState, "moveTo", FlickingReactiveData>;
24
+ declare const connectFlickingReactiveAPI: (flicking: Flicking, options?: FlickingReactiveAPIOptions) => ReactiveObject<FlickingReactiveState & FlickingReactiveMethod>;
25
+ export { flickingReactiveAPIAdapter, connectFlickingReactiveAPI };