Skip to content

DataContainer — Changelog

v0.4.0 (2026-06-24)

TL;DR

Perubahan:

  • 🔥 Breaking: PageConfig restrukturisasi — perPage, isFrontEndPreferCursor, dan paginationMode dihapus, diganti setup: PageSetup | null (Breaking)
  • 🔥 Breaking: PaginationIntent.preferCursor dihapus (Breaking)
  • ✨ New: declarePagination() — deklarasi intent pagination frontend secara eksplisit (Medium)
  • ✨ New: submitSearch() — set search dan reset pagination ke halaman 1 dalam satu panggilan (Medium)
  • 🔧 Improved: mapFromResponse tidak lagi override mode atau perPage jika page.setup sudah di-set (Medium)
  • 🐛 Fixed: deteksi mode 'simple' salah terdeteksi sebagai 'cursor' saat backend mengirim next_cursor: null (Low)

Impact: 🔴 Breaking: 2 | ✨ New: 2 | 🟢 Medium: 2 | 🔵 Low: 1

Backward Compatible: ❌ Tidak

🔴 Breaking Changes

PageConfig: perPage, isFrontEndPreferCursor, dan paginationMode dihapus, setup ditambahkan

page.perPage, page.isFrontEndPreferCursor, dan page.paginationMode tidak lagi ada di PageConfig. Ketiganya digantikan oleh field baru page.setup: PageSetup | null yang menjadi satu-satunya sumber konfigurasi dan mode pagination. Mode dibaca via page.setup?.mode.

ts
// Before (v0.3.x) - Tidak berlaku lagi
container.page.perPage = 15;
container.page.isFrontEndPreferCursor = true;

// After (v0.4.0)
container.declarePagination({ mode: 'cursor', perPage: 15 });
// atau lewat QueryIntent saat konstruksi
useDataContainer(filter, { pagination: { mode: 'cursor', perPage: 15 } });

Fix:

  1. Ganti page.paginationModepage.setup?.mode
  2. Ganti page.perPagepage.setup?.perPage untuk membaca, declarePagination() untuk menulis
  3. Hapus semua akses ke page.isFrontEndPreferCursor — gunakan declarePagination({ mode: 'cursor' }) sebagai gantinya
  4. Update type annotation yang referensi PageConfig secara langsung

Affected: Semua code yang membaca atau menulis page.paginationMode, page.perPage, atau page.isFrontEndPreferCursor.

PaginationIntent.preferCursor dihapus

Field preferCursor pada PaginationIntent (QueryIntent) tidak lagi tersedia.

ts
// Before (v0.3.x) - Tidak berlaku lagi
useDataContainer(filter, {
    pagination: { mode: 'lengthAware', preferCursor: true }
});

// After (v0.4.0) - set mode secara eksplisit
useDataContainer(filter, {
    pagination: { mode: 'cursor' }
});

Fix: Hapus preferCursor dari semua QueryIntent, set mode: 'cursor' secara langsung.

✨ New

declarePagination()

Method baru declarePagination({ mode, perPage? }) untuk mendeklarasikan intent pagination frontend setelah konstruksi. Ini adalah satu-satunya cara yang diizinkan untuk menulis page.setup post-construct — page.setup bersifat convention-immutable dan tidak boleh diubah langsung atau lewat setPage().

Poin utama:

  • Set page.setup dan page.paginationMode sekaligus — efektif segera untuk URL generation
  • Harus dipanggil sebelum fetch pertama jika tidak menggunakan QueryIntent
  • perPage opsional — jika tidak di-set, perPage tidak dikirim ke backend (backend gunakan default-nya)

Lihat: declarePagination()

🟢 Medium Impact

Peningkatan:

  • mapFromResponse via applyResponsePagination kini membaca page.setup sebelum memproses response. Jika setup sudah di-set: mode tidak di-detect ulang dari response, perPage tidak ditimpa, hanya field state (cursor, page number, total, hasMore) yang diupdate. Jika setup null: perilaku lama (auto-detect dari response).

New:

  • submitSearch(value?) menggabungkan update nilai search dan reset pagination ke halaman 1 dalam satu panggilan. Sebelumnya, set container.search secara langsung tidak mereset halaman, sehingga user yang sedang di halaman X bisa mendapat nol hasil saat search baru tidak mencapai halaman tersebut. Reset page.numeric.current ke 1 dan page.cursor.direction ke 'next' secara otomatis. Setter container.search tetap berfungsi untuk binding v-model.

🔵 Low Impact

Bug Fixes:

  • Fix deteksi pagination mode 'simple': sebelumnya salah terdeteksi sebagai 'cursor' saat backend mengirim next_cursor: null dan previous_cursor: null secara eksplisit (seperti pola laresponse). Deteksi kini mengecek nilai truthy, bukan hanya keberadaan key.

v0.3.1 (2026-04-22)

TL;DR

Perubahan:

  • 🔥 Breaking: sort.sortDir berubah dari 'a'/'d' menjadi 'asc'/'desc' (Breaking) — nilai yang tersimpan sekarang selalu longform
  • ✨ New: setSortAsc() dan setSortDesc() (Medium) — Shorthand eksplisit untuk set sort direction
  • 🔧 Improved: SortDirection type + normalisasi setSort() (Medium) — Input fleksibel, output konsisten
  • 🔵 Low: 'regular' alias untuk PaginationIntent.mode (Low) — Alternatif dari 'lengthAware'

Impact: 🔴 Breaking: 1 | ✨ New: 1 | 🟢 Medium: 1 | 🔵 Low: 1

Backward Compatible: ❌ Tidak

🔴 Breaking Changes

sort.sortDir: nilai berubah dari 'a'/'d' menjadi 'asc'/'desc'

sort.sortDir kini selalu disimpan dalam format panjang. Sebelumnya nilai yang tersimpan adalah shorthand 'a' atau 'd'. URL params tidak berubah — sortDir di URL sudah 'asc'/'desc' sejak sebelumnya.

ts
// Before (v0.3.0) - Tidak berlaku lagi
container.sort.sortDir === 'a'

// After (v0.3.1) - Wajib longform
container.sort.sortDir === 'asc'

Fix:

  1. Search & replace sort.sortDir === 'a'sort.sortDir === 'asc'
  2. Search & replace sort.sortDir === 'd'sort.sortDir === 'desc'
  3. Update pola toggle: container.setSort(field, container.sort.sortDir === 'asc' ? 'desc' : 'asc') — atau gunakan setSortAsc/setSortDesc

Affected: Semua code yang membaca sort.sortDir untuk conditional logic atau toggle direction.

✨ New

setSortAsc() dan setSortDesc()

Dua shorthand baru untuk set sort direction secara eksplisit tanpa harus pass direction string ke setSort(). Keduanya menerima optional parameter sortBy — jika di-pass, field sort juga ikut berubah; jika tidak, hanya direction yang berubah.

Poin utama:

  • setSortAsc(field?) — set ascending, opsional ganti field
  • setSortDesc(field?) — set descending, opsional ganti field
  • setSort() tetap tersedia dan tidak berubah

Lihat: Sort Methods

🟢 Medium Impact

Peningkatan:

  • setSort() sekarang menerima 6 format input via SortDirection: 'a', 'asc', 1, 'd', 'desc', -1 — auto-normalisasi ke 'asc'/'desc' sebelum disimpan

🔵 Low Impact

Perubahan:

  • PaginationIntent.mode kini menerima 'regular' sebagai alias 'lengthAware' — dinormalisasi sebelum disimpan, page.paginationMode tetap selalu 'lengthAware'

v0.3.0 (2026-04-22)

TL;DR

Perubahan:

  • ✨ New: modifyFilter() (High) — Update beberapa key filter sekaligus tanpa setFilter() berulang
  • ✨ New: isUsingFilter() (High) — Cek apakah applied filter berbeda dari initial filter
  • 🔧 Improved: resetFilterToInit() dan resetFilterToApplied() (Medium) — Sekarang support partial reset via parameter paths
  • 🐛 Fixed: reset() mutasi snapshot _lastData (Low) — Sekarang menggunakan structuredClone untuk isolasi yang benar

Impact: ✨ New: 2 | 🟡 High: 2 | 🟢 Medium: 1 | 🔵 Low: 1

Backward Compatible: ✅ Ya

✨ New

modifyFilter()

Method baru modifyFilter(partial) memungkinkan update beberapa key filter sekaligus dengan menerima object partial — sebagai alternatif ergonomis dari memanggil setFilter() berkali-kali. Key yang tidak ada di partial tidak akan disentuh, sehingga aman untuk pre-fill sebagian field dari query params atau preset tertentu.

Poin utama:

  • Update banyak key dalam satu panggilan
  • Hanya key yang disertakan yang berubah
  • Tetap di lapisan draft — perlu applyFilter() setelahnya

Lihat: modifyFilter()

isUsingFilter()

Method baru yang mengembalikan true jika applied filter saat ini berbeda dari initial filter. Berbeda dengan hasUnappliedFilterChanges() yang membandingkan draft vs applied — isUsingFilter() membandingkan applied vs initial, cocok untuk conditional rendering indikator "filter aktif" atau tombol "Hapus Filter".

Poin utama:

  • Deteksi apakah ada filter aktif yang sudah di-apply
  • Cocok untuk badge indikator atau tombol reset filter
  • Perbandingan terhadap initialFilter, bukan draft

Lihat: isUsingFilter()

🟢 Medium Impact

Peningkatan:

  • resetFilterToInit() dan resetFilterToApplied() sekarang menerima optional parameter paths (string atau string[]) untuk reset sebagian field filter saja, bukan seluruh filter

🔵 Low Impact

Bug Fixes:

  • Fix reset(): snapshot _lastData dimutasi saat restore — sekarang menggunakan structuredClone untuk isolasi yang benar

v0.2.0 (2026-04-09)

TL;DR

Perubahan:

  • 🔥 Breaking: dataLength() menjadi getDataLength() (Breaking) — rename untuk konsistensi penamaan getter
  • ✨ New: navigatePage(), nextPage(), prevPage() (High) — Kontrol navigasi halaman tanpa override seluruh object pagination
  • 📝 Docs: Inline docs untuk semua method (Low)

Impact: 🔴 Breaking: 1 | ✨ New: 1 | 🟡 High: 1 | 🔵 Low: 1

Backward Compatible: ❌ Tidak

🔴 Breaking Changes

dataLength() diubah menjadi getDataLength()

Rename untuk menyelaraskan konvensi penamaan getter di seluruh API.

ts
// Before (v0.1.x) - Tidak berlaku lagi
container.dataLength()

// After (v0.2.0)
container.getDataLength()

Fix: Search & replace semua container.dataLength()container.getDataLength().

✨ New

Tiga method baru untuk navigasi halaman tanpa harus override seluruh object pagination via setPage(). navigatePage(target) menerima number atau string 'next'/'prev'; nextPage() dan prevPage() adalah shorthand-nya.

Poin utama:

  • Navigasi halaman tanpa menyentuh konfigurasi pagination lainnya
  • Support numerik dan cursor pagination
  • nextPage()/prevPage() sebagai shorthand umum

Lihat: Pagination Methods

🔵 Low Impact

Perubahan:

  • Inline JSDoc ditambahkan untuk semua method

v0.1.1 (2025-12-26)

TL;DR

Perubahan:

  • 🔥 Breaking: loadStatus berubah dari Ref menjadi getter/setter (Breaking) — tidak perlu .value di script
  • ✨ New: Parameter queryIntent (High) — Initialize state dari URL/router untuk deep linking dan SSR
  • 🎨 Refactor: File structure reorganization (Low) — types.ts dipindah ke types/index.ts
  • 📦 Dependencies: Build scripts + rimraf (Low)

Impact: 🔴 Breaking: 1 | ✨ New: 1 | 🟡 High: 1 | 🔵 Low: 2

Backward Compatible: ❌ Tidak

🔴 Breaking Changes

loadStatus: Ref → getter/setter

Property loadStatus tidak lagi berupa Ref. Access di <script> berubah; di <template> tetap sama.

ts
// Before (v0.1.0) - Tidak berlaku lagi
container.loadStatus.value = 0;
if (container.loadStatus.value === 1) { }

// After (v0.1.1)
container.loadStatus = 0;
if (container.loadStatus === 1) { }

Fix:

  1. Search & replace semua container.loadStatus.valuecontainer.loadStatus di <script> sections
  2. Template code tidak perlu diubah

Affected: Semua code yang mengakses loadStatus di script setup.

✨ New

Parameter queryIntent

useDataContainer() sekarang menerima optional second parameter untuk initialize pagination, sort, dan search state dari URL query params atau router state. Memungkinkan deep linking, shareable URLs, dan SSR hydration tanpa fetch dua kali.

Poin utama:

  • Initialize page, sort, dan search dari URL dalam satu panggilan
  • Support semua pagination modes di QueryIntent
  • Backward compatible — parameter optional

Lihat: QueryIntent dan Example 6

🔵 Low Impact

Perubahan:

  • File structure: src/types.ts dipindah ke src/types/index.ts
  • Build scripts: tambah clean, build:watch, preview
  • Dependency: tambah rimraf@^6.1.2 untuk cross-platform clean script