Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/run-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/setup-node@v4
with:
node-version: 16
cache: "npm"
Expand All @@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/setup-node@v4
with:
node-version: 16
cache: "npm"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,4 @@ demo/_data/version.yml
outjs/
declaration/
dist/

38 changes: 38 additions & 0 deletions core-packages-link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable */

/**
* 프레임워크 컴포넌트를 디버깅할 때 코어 바닐라 로직을 수정하면서 확인할 필요가 있을 때,
* 이 스크립트를 이용하면 바닐라 로직 수정사항이 프레임워크 컴포넌트 로컬 데모환경에도 반영된다.
*
* 인자로 프레임워크 컴포넌트 패키지의 루트 디렉토리를 제공하면 된다.
*
* 사용 예시: node core-package-link.js react-flicking
*/

const { execSync } = require("child_process");
const path = require("path");
const fs = require("fs");

const args = process.argv.slice(2);
const targetDir = args[0];

if (!targetDir) {
console.error("❌ 디렉토리명을 인자로 입력하세요.");
process.exit(1);
}

const fullPath = path.resolve(process.cwd(), 'packages', targetDir);
if (!fs.existsSync(fullPath)) {
console.error(`❌ 디렉토리 없음: ${fullPath}`);
process.exit(1);
}

function run(cmd, cwd = process.cwd()) {
console.log(`\n▶️ Running: ${cmd} (in ${cwd})`);
execSync(cmd, { stdio: "inherit", cwd });
}

run("npm run build");
run("npm link");
run(`npm link '@egjs/flicking'`, fullPath);
run("npm run build", fullPath);
252 changes: 252 additions & 0 deletions debug/state-api/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flicking Basic Demo</title>
<link rel="stylesheet" href="../../dist/flicking.css" />
<style>
#container {
display: flex;
flex-direction: column;
align-items: center;
}
#nav-wrapper {
display: flex;
align-items: center;
}
.flicking-viewport {
width: 500px;
height: 300px;
/* margin: 0 auto; */
border: 1px solid black;
}
.flicking-camera {
display: flex;
}
.flicking-panel {
align-items: flex-end;
border-radius: 5px;
box-sizing: border-box;
display: flex;
/* height: 200px; */
justify-content: flex-start;
margin-top: 10px;
margin-bottom: 10px;
margin-right: 10px;
position: relative;
width: 200px;
background-color: aliceblue;
justify-content: center;
align-items: center;
}
.navigation-btn {
text-align: center;
margin: 0 5px;
padding: 5px 10px;
height: 50px;
}
#pagination {
display: flex;
}
.pagination-num {
background-color: beige;
margin: 5px;
width: 30px;
height: 30px;
text-align: center;
}
.pagination-num.active {
background-color: yellowgreen;
}
#progress-bar {
width: 600px;
height: 20px;
border-radius: 20px;
background-color: #e0e0e0;
overflow: hidden;
}
#progress-fill {
height: 100%;
width: 0%; /* 초기에는 0% 채워짐 */
background-color: #4caf50; /* 채워지는 색 */
transition: width 0.3s ease; /* 부드럽게 변화 */
}
#scroll-progress-bar {
width: 600px;
height: 20px;
border-radius: 20px;
background-color: #e0e0e0;
overflow: hidden;
}
#scroll-progress-fill {
height: 100%;
width: 0%; /* 초기에는 0% 채워짐 */
background-color: #2196f3; /* 채워지는 색 */
transition: width 0.3s ease; /* 부드럽게 변화 */
}
</style>
</head>
<body>
<div id="container">
<div id="nav-wrapper">
<button class="navigation-btn" id="prev">Previous</button>
<div class="flicking-viewport">
<div class="flicking-camera">
<div class="flicking-panel" style="width: 500px;">x0</div>
<div class="flicking-panel">x1</div>
<div class="flicking-panel">x2</div>
<div class="flicking-panel">x3</div>
<div class="flicking-panel">x4</div>
</div>
</div>
<button class="navigation-btn" id="next">Next</button>
</div>
<div id="pagination"></div>
<div id="progress-bar">
<div id="progress-fill"></div>
</div>
<div id="scroll-progress-bar">
<div id="scroll-progress-fill"></div>
</div>
</div>

<div class="add">
<button id="prepend">prepend</button>
<button id="append">append</button>
<button id="add-random">add random</button>
</div>
<div class="remove">
<button id="remove-first">remove first</button>
<button id="remove-last">remove last</button>
<button id="remove-random">remove random</button>
</div>

<script src="../../dist/flicking.pkgd.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
const flicking = new Flicking(".flicking-viewport", {renderOnlyVisible: true});
const { connectFlickingStateApi } = Flicking;
const reactiveObj = connectFlickingStateApi(flicking);
const {
isReachStart,
isReachEnd,
totalPanelCount,
currentPanelIndex,
moveTo,
} = reactiveObj;

// Navigation buttons
const prevButton = document.getElementById("prev");
const nextButton = document.getElementById("next");

// 비활성화 여부 초기화
prevButton.disabled = isReachStart;
nextButton.disabled = isReachEnd;

// 반응형과 엮기
reactiveObj.subscribe("isReachStart", (nextValue) => {
prevButton.disabled = nextValue;
});
reactiveObj.subscribe("isReachEnd", (nextValue) => {
nextButton.disabled = nextValue;
});

// 이벤트 리스너 등록
prevButton.addEventListener("click", () => {
flicking.prev();
});

nextButton.addEventListener("click", () => {
flicking.next();
});

// 패널이 동적으로 추가되거나 삭제되었을 때도 잘 동작해야함.

let appendNum = 100;
let prependNum = -1;

const appendButton = document.getElementById("append");
const prependButton = document.getElementById("prepend");
const addRandomButton = document.getElementById("add-random");

const getRandomInt = (min, max) => {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
return Math.floor(
Math.random() * (maxFloored - minCeiled) + minCeiled
);
};
appendButton.addEventListener("click", () => {
flicking.append(`<div class="flicking-panel">x${appendNum}</div>`);
appendNum++;
});
prependButton.addEventListener("click", () => {
flicking.prepend(`<div class="flicking-panel">x${prependNum}</div>`);
prependNum--;
});
addRandomButton.addEventListener("click", () => {
const randomN = getRandomInt(0, flicking.panelCount);
flicking.insert(
randomN,
`<div class="flicking-panel">random ${randomN}</div>`
);
});

const removeFirstButton = document.getElementById("remove-first");
const removeLastButton = document.getElementById("remove-last");
const removeRandomButton = document.getElementById("remove-random");

removeFirstButton.addEventListener("click", () => {
flicking.remove(0);
});

// active panel을 지우는 경우 포커스가 가장 처음으로 돌아가는 현상이 있음.
removeLastButton.addEventListener("click", () => {
flicking.remove(flicking.panelCount - 1);
});
removeRandomButton.addEventListener("click", () => {
const randomN = getRandomInt(0, flicking.panelCount);
flicking.remove(randomN);
});

const paginationElement = document.getElementById("pagination");
const progressFillElement = document.getElementById("progress-fill");

const pageNums = Array.from({ length: totalPanelCount }, (_, i) => {
const div = document.createElement("div");
div.className = `pagination-num ${
i === currentPanelIndex ? "active" : ""
}`;
div.textContent = `${i}`;

div.addEventListener("click", (e) => {
moveTo(i);
});
return div;
});

paginationElement.append(...pageNums);

reactiveObj.subscribe("currentPanelIndex", (nextValue) => {
pageNums.forEach((v, i) => {
v.classList.remove("active");
if (i === nextValue) {
v.classList.add("active");
}
});
});

reactiveObj.subscribe("indexProgress", (nextValue) => {
progressFillElement.style.width = `${nextValue}%`;
});


const scrollProgressFillElement = document.getElementById("scroll-progress-fill");
reactiveObj.subscribe("scrollProgress", (nextValue) => {
scrollProgressFillElement.style.width = `${nextValue}%`;
});
});
</script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Flicking extends Component

<div className="container">
<div className="row mb-2"><div className="col col--4"><strong>Properties</strong></div><div className="col col--4"><strong>Methods</strong></div><div className="col col--4"><strong>Events</strong></div></div>
<div className="row"><div className="col col--4"><a href="#VERSION">VERSION</a><span className="badge badge--info margin-left--sm">static</span><br/><a href="#control">control</a><br/><a href="#camera">camera</a><br/><a href="#renderer">renderer</a><br/><a href="#viewport">viewport</a><br/><a href="#initialized">initialized</a><br/><a href="#circularEnabled">circularEnabled</a><br/><a href="#virtualEnabled">virtualEnabled</a><br/><a href="#index">index</a><br/><a href="#element">element</a><br/><a href="#currentPanel">currentPanel</a><br/><a href="#panels">panels</a><br/><a href="#panelCount">panelCount</a><br/><a href="#visiblePanels">visiblePanels</a><br/><a href="#animating">animating</a><br/><a href="#holding">holding</a><br/><a href="#activePlugins">activePlugins</a><br/><a href="#align">align</a><br/><a href="#defaultIndex">defaultIndex</a><br/><a href="#horizontal">horizontal</a><br/><a href="#circular">circular</a><br/><a href="#circularFallback">circularFallback</a><br/><a href="#bound">bound</a><br/><a href="#adaptive">adaptive</a><br/><a href="#panelsPerView">panelsPerView</a><br/><a href="#noPanelStyleOverride">noPanelStyleOverride</a><br/><a href="#resizeOnContentsReady">resizeOnContentsReady</a><br/><a href="#nested">nested</a><br/><a href="#needPanelThreshold">needPanelThreshold</a><br/><a href="#preventEventsBeforeInit">preventEventsBeforeInit</a><br/><a href="#deceleration">deceleration</a><br/><a href="#easing">easing</a><br/><a href="#duration">duration</a><br/><a href="#inputType">inputType</a><br/><a href="#moveType">moveType</a><br/><a href="#threshold">threshold</a><br/><a href="#dragThreshold">dragThreshold</a><br/><a href="#interruptable">interruptable</a><br/><a href="#bounce">bounce</a><br/><a href="#iOSEdgeSwipeThreshold">iOSEdgeSwipeThreshold</a><br/><a href="#preventClickOnDrag">preventClickOnDrag</a><br/><a href="#preventDefaultOnDrag">preventDefaultOnDrag</a><br/><a href="#disableOnInit">disableOnInit</a><br/><a href="#changeOnHold">changeOnHold</a><br/><a href="#renderOnlyVisible">renderOnlyVisible</a><br/><a href="#virtual">virtual</a><br/><a href="#autoInit">autoInit</a><br/><a href="#autoResize">autoResize</a><br/><a href="#useResizeObserver">useResizeObserver</a><br/><a href="#resizeDebounce">resizeDebounce</a><br/><a href="#maxResizeDebounce">maxResizeDebounce</a><br/><a href="#useFractionalSize">useFractionalSize</a><br/><a href="#externalRenderer">externalRenderer</a><br/><a href="#renderExternal">renderExternal</a></div><div className="col col--4"><a href="#init">init</a><br/><a href="#destroy">destroy</a><br/><a href="#prev">prev</a><br/><a href="#next">next</a><br/><a href="#moveTo">moveTo</a><br/><a href="#updateAnimation">updateAnimation</a><br/><a href="#stopAnimation">stopAnimation</a><br/><a href="#getPanel">getPanel</a><br/><a href="#enableInput">enableInput</a><br/><a href="#disableInput">disableInput</a><br/><a href="#getStatus">getStatus</a><br/><a href="#setStatus">setStatus</a><br/><a href="#addPlugins">addPlugins</a><br/><a href="#removePlugins">removePlugins</a><br/><a href="#resize">resize</a><br/><a href="#append">append</a><br/><a href="#prepend">prepend</a><br/><a href="#insert">insert</a><br/><a href="#remove">remove</a></div><div className="col col--4"><a href="#event-ready">ready</a><br/><a href="#event-beforeResize">beforeResize</a><br/><a href="#event-afterResize">afterResize</a><br/><a href="#event-holdStart">holdStart</a><br/><a href="#event-holdEnd">holdEnd</a><br/><a href="#event-moveStart">moveStart</a><br/><a href="#event-move">move</a><br/><a href="#event-moveEnd">moveEnd</a><br/><a href="#event-willChange">willChange</a><br/><a href="#event-changed">changed</a><br/><a href="#event-willRestore">willRestore</a><br/><a href="#event-restored">restored</a><br/><a href="#event-select">select</a><br/><a href="#event-needPanel">needPanel</a><br/><a href="#event-visibleChange">visibleChange</a><br/><a href="#event-reachEdge">reachEdge</a><br/><a href="#event-panelChange">panelChange</a></div></div>
<div className="row"><div className="col col--4"><a href="#VERSION">VERSION</a><span className="badge badge--info margin-left--sm">static</span><br/><a href="#control">control</a><br/><a href="#camera">camera</a><br/><a href="#renderer">renderer</a><br/><a href="#viewport">viewport</a><br/><a href="#autoResizer">autoResizer</a><br/><a href="#initialized">initialized</a><br/><a href="#circularEnabled">circularEnabled</a><br/><a href="#virtualEnabled">virtualEnabled</a><br/><a href="#index">index</a><br/><a href="#element">element</a><br/><a href="#currentPanel">currentPanel</a><br/><a href="#panels">panels</a><br/><a href="#panelCount">panelCount</a><br/><a href="#visiblePanels">visiblePanels</a><br/><a href="#animating">animating</a><br/><a href="#holding">holding</a><br/><a href="#activePlugins">activePlugins</a><br/><a href="#align">align</a><br/><a href="#defaultIndex">defaultIndex</a><br/><a href="#horizontal">horizontal</a><br/><a href="#circular">circular</a><br/><a href="#circularFallback">circularFallback</a><br/><a href="#bound">bound</a><br/><a href="#adaptive">adaptive</a><br/><a href="#panelsPerView">panelsPerView</a><br/><a href="#noPanelStyleOverride">noPanelStyleOverride</a><br/><a href="#resizeOnContentsReady">resizeOnContentsReady</a><br/><a href="#nested">nested</a><br/><a href="#needPanelThreshold">needPanelThreshold</a><br/><a href="#preventEventsBeforeInit">preventEventsBeforeInit</a><br/><a href="#deceleration">deceleration</a><br/><a href="#easing">easing</a><br/><a href="#duration">duration</a><br/><a href="#inputType">inputType</a><br/><a href="#moveType">moveType</a><br/><a href="#threshold">threshold</a><br/><a href="#dragThreshold">dragThreshold</a><br/><a href="#interruptable">interruptable</a><br/><a href="#bounce">bounce</a><br/><a href="#iOSEdgeSwipeThreshold">iOSEdgeSwipeThreshold</a><br/><a href="#preventClickOnDrag">preventClickOnDrag</a><br/><a href="#preventDefaultOnDrag">preventDefaultOnDrag</a><br/><a href="#disableOnInit">disableOnInit</a><br/><a href="#changeOnHold">changeOnHold</a><br/><a href="#renderOnlyVisible">renderOnlyVisible</a><br/><a href="#virtual">virtual</a><br/><a href="#autoInit">autoInit</a><br/><a href="#autoResize">autoResize</a><br/><a href="#useResizeObserver">useResizeObserver</a><br/><a href="#observePanelResize">observePanelResize</a><br/><a href="#resizeDebounce">resizeDebounce</a><br/><a href="#maxResizeDebounce">maxResizeDebounce</a><br/><a href="#useFractionalSize">useFractionalSize</a><br/><a href="#externalRenderer">externalRenderer</a><br/><a href="#renderExternal">renderExternal</a><br/><a href="#optimizeSizeUpdate">optimizeSizeUpdate</a></div><div className="col col--4"><a href="#init">init</a><br/><a href="#destroy">destroy</a><br/><a href="#prev">prev</a><br/><a href="#next">next</a><br/><a href="#moveTo">moveTo</a><br/><a href="#updateAnimation">updateAnimation</a><br/><a href="#stopAnimation">stopAnimation</a><br/><a href="#getPanel">getPanel</a><br/><a href="#enableInput">enableInput</a><br/><a href="#disableInput">disableInput</a><br/><a href="#getStatus">getStatus</a><br/><a href="#setStatus">setStatus</a><br/><a href="#addPlugins">addPlugins</a><br/><a href="#removePlugins">removePlugins</a><br/><a href="#resize">resize</a><br/><a href="#append">append</a><br/><a href="#prepend">prepend</a><br/><a href="#insert">insert</a><br/><a href="#remove">remove</a></div><div className="col col--4"><a href="#event-ready">ready</a><br/><a href="#event-beforeResize">beforeResize</a><br/><a href="#event-afterResize">afterResize</a><br/><a href="#event-holdStart">holdStart</a><br/><a href="#event-holdEnd">holdEnd</a><br/><a href="#event-moveStart">moveStart</a><br/><a href="#event-move">move</a><br/><a href="#event-moveEnd">moveEnd</a><br/><a href="#event-willChange">willChange</a><br/><a href="#event-changed">changed</a><br/><a href="#event-willRestore">willRestore</a><br/><a href="#event-restored">restored</a><br/><a href="#event-select">select</a><br/><a href="#event-needPanel">needPanel</a><br/><a href="#event-visibleChange">visibleChange</a><br/><a href="#event-reachEdge">reachEdge</a><br/><a href="#event-panelChange">panelChange</a></div></div>
</div>

## constructor
Expand Down Expand Up @@ -124,6 +124,14 @@ Flicking.VERSION; // ex) 4.0.0
**See**:
- [Viewport](Viewport)

### autoResizer {#autoResizer}

<div>
<span className="badge badge--warning">readonly</span>
</div>

현재 Flicking에 활성화된 [AutoResizer](AutoResizer) 인스턴스

### initialized {#initialized}

<div>
Expand Down Expand Up @@ -821,6 +829,14 @@ autoResize 옵션 사용시 [ResizeObserver](https://developer.mozilla.org/en-US
**See**:
- [useResizeObserver ( Options )](https://naver.github.io/egjs-flicking/Options#useresizeobserver)

### observePanelResize {#observePanelResize}

<div>

</div>

이 옵션을 활성화할 경우, [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)를 사용하여 패널 엘리먼트의 크기를 추적합니다.<br />이 옵션은 `useResizeObserver` 옵션이 활성화된 경우에만 사용할 수 있습니다.<br />이 옵션은 패널 엘리먼트의 크기가 변경될 경우 resize 이벤트가 발생하도록 보장합니다.

### resizeDebounce {#resizeDebounce}

<div>
Expand Down Expand Up @@ -886,6 +902,18 @@ autoResize 옵션 사용시 [ResizeObserver](https://developer.mozilla.org/en-US

**Default**: null

### optimizeSizeUpdate {#optimizeSizeUpdate}

<div>

</div>

optimizeSizeUpdate는 autoResize가 true일 때만 동작합니다.<br />기본적으로 autoResize는 뷰포트의 width와 height 변화를 모두 감지하여 패널들의 사이즈를 업데이트합니다.<br />이 옵션을 활성화하면 플리킹 방향에 따라 필요한 차원(horizontal → width, vertical → height)에 대해서만 사이즈를 업데이트합니다.<br />내부 패널의 높이가 서로 다를 때, 플리킹 중 과도한 리사이징으로 인한 깜빡임 현상을 줄이는 데 유용합니다.

**Type**: boolean

**Default**: false

## Methods

### init {#init}
Expand Down
Loading