@june24/expo-pdf-reader 0.1.27 → 0.1.28
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.
|
@@ -95,6 +95,8 @@ class ExpoPdfReaderView(
|
|
|
95
95
|
private var windowStart = 0 // pageEntries[0]-н absolute page index
|
|
96
96
|
private var chunkLoading = false // chunk дуусах хүртэл дахин trigger хийхгүй
|
|
97
97
|
private var currentViewWidth = 0 // chunk load-д дахин хэрэглэнэ
|
|
98
|
+
/** Thumbnail panel нээх/хаах зэргээр RN өргөн өөрчлөгдөнө — reflow-ийн суурь */
|
|
99
|
+
private var lastHostWidthForPdf = 0
|
|
98
100
|
private var loadingFooter: View? = null
|
|
99
101
|
|
|
100
102
|
companion object {
|
|
@@ -133,41 +135,51 @@ class ExpoPdfReaderView(
|
|
|
133
135
|
private var maxZoom = 5.0f
|
|
134
136
|
private var currentZoom = 1.0f
|
|
135
137
|
|
|
138
|
+
/** RN / Drawer зэрэг дээд scroll хуудас pinch-ийг scroll болгож идэвхжүүлэхээс сэргийлнэ */
|
|
139
|
+
private fun propagateDisallowInterceptFrom(view: View, disallow: Boolean) {
|
|
140
|
+
var p: ViewParent? = view.parent
|
|
141
|
+
while (p is ViewGroup) {
|
|
142
|
+
p.requestDisallowInterceptTouchEvent(disallow)
|
|
143
|
+
p = p.parent
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
136
147
|
/**
|
|
137
|
-
* continuous / twoup / twoupcontinuous — pinch
|
|
138
|
-
*
|
|
148
|
+
* continuous / twoup / twoupcontinuous — pinch-ийг [dispatchTouchEvent]-ийн эхэнд дуудаж
|
|
149
|
+
* 2 хурууны POINTER_DOWN canvas-д баригдахаас өмнө хүлээнэ. Zoom хийсэн ч босоо scroll хэвээр (зөвхөн pinch үед scroll intercept унтрана).
|
|
139
150
|
*/
|
|
140
151
|
private inner class ZoomableScrollView(ctx: Context) : ScrollView(ctx) {
|
|
141
|
-
/** ScrollView-д [isScrollEnabled] байхгүй тул: false үед босоо scroll (super) ажиллахгүй. */
|
|
142
|
-
var allowVerticalScrollFromTouch = true
|
|
143
152
|
|
|
144
153
|
private val pinch = ScaleGestureDetector(
|
|
145
154
|
ctx,
|
|
146
155
|
object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
|
147
156
|
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
|
|
148
157
|
if (activeTool != null) return false
|
|
158
|
+
stopNestedScroll()
|
|
159
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomableScrollView, true)
|
|
149
160
|
parent?.requestDisallowInterceptTouchEvent(true)
|
|
150
161
|
return true
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
|
154
165
|
if (activeTool != null) return false
|
|
155
|
-
applyZoom(
|
|
166
|
+
applyZoom(
|
|
167
|
+
(currentZoom * detector.scaleFactor).coerceIn(minZoom, maxZoom),
|
|
168
|
+
detector.focusX,
|
|
169
|
+
detector.focusY
|
|
170
|
+
)
|
|
156
171
|
return true
|
|
157
172
|
}
|
|
158
173
|
|
|
159
174
|
override fun onScaleEnd(detector: ScaleGestureDetector) {
|
|
160
175
|
parent?.requestDisallowInterceptTouchEvent(false)
|
|
176
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomableScrollView, false)
|
|
161
177
|
}
|
|
162
178
|
}
|
|
163
179
|
)
|
|
164
|
-
private var panLastX = 0f
|
|
165
|
-
private var panLastY = 0f
|
|
166
180
|
|
|
167
181
|
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
|
168
182
|
if (activeTool != null) return super.onInterceptTouchEvent(ev)
|
|
169
|
-
// 2+ хуруу эсвэл pinch эхэлсэн үед ScrollView босоо scroll intercept хийхгүй (scroll + zoom өрсөлдөнө)
|
|
170
|
-
if (!allowVerticalScrollFromTouch) return false
|
|
171
183
|
if (ev.pointerCount > 1 || pinch.isInProgress) return false
|
|
172
184
|
return super.onInterceptTouchEvent(ev)
|
|
173
185
|
}
|
|
@@ -179,8 +191,14 @@ class ExpoPdfReaderView(
|
|
|
179
191
|
stopNestedScroll()
|
|
180
192
|
}
|
|
181
193
|
if (pinch.isInProgress || ev.pointerCount > 1) {
|
|
194
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomableScrollView, true)
|
|
182
195
|
parent?.requestDisallowInterceptTouchEvent(true)
|
|
183
196
|
}
|
|
197
|
+
if (ev.actionMasked == MotionEvent.ACTION_UP ||
|
|
198
|
+
ev.actionMasked == MotionEvent.ACTION_CANCEL
|
|
199
|
+
) {
|
|
200
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomableScrollView, false)
|
|
201
|
+
}
|
|
184
202
|
}
|
|
185
203
|
return super.dispatchTouchEvent(ev)
|
|
186
204
|
}
|
|
@@ -190,23 +208,6 @@ class ExpoPdfReaderView(
|
|
|
190
208
|
if (pinch.isInProgress || ev.pointerCount > 1) {
|
|
191
209
|
return true
|
|
192
210
|
}
|
|
193
|
-
if (currentZoom > 1.02f) {
|
|
194
|
-
when (ev.actionMasked) {
|
|
195
|
-
MotionEvent.ACTION_DOWN -> {
|
|
196
|
-
panLastX = ev.x
|
|
197
|
-
panLastY = ev.y
|
|
198
|
-
}
|
|
199
|
-
MotionEvent.ACTION_MOVE -> {
|
|
200
|
-
val dx = ev.x - panLastX
|
|
201
|
-
val dy = ev.y - panLastY
|
|
202
|
-
panLastX = ev.x
|
|
203
|
-
panLastY = ev.y
|
|
204
|
-
applyContainerPanDelta(dx, dy)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return true
|
|
208
|
-
}
|
|
209
|
-
if (!allowVerticalScrollFromTouch) return true
|
|
210
211
|
return super.onTouchEvent(ev)
|
|
211
212
|
}
|
|
212
213
|
}
|
|
@@ -244,13 +245,18 @@ class ExpoPdfReaderView(
|
|
|
244
245
|
override fun onScrollStateChanged(rv: RecyclerView, newState: Int) {
|
|
245
246
|
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
|
246
247
|
val lm = rv.layoutManager as? LinearLayoutManager ?: return
|
|
247
|
-
|
|
248
|
-
|
|
248
|
+
var pos = lm.findFirstCompletelyVisibleItemPosition()
|
|
249
|
+
if (pos < 0) pos = lm.findFirstVisibleItemPosition()
|
|
250
|
+
if (pos < 0) return
|
|
249
251
|
if (pos != currentPageIndex) {
|
|
250
252
|
currentPageIndex = pos
|
|
251
253
|
// Хуудас солигдоход zoom-г reset хийнэ
|
|
252
254
|
(pager as? ZoomRecyclerView)?.resetZoom()
|
|
253
255
|
onPageChange(mapOf("currentPage" to pos, "totalPage" to totalPages))
|
|
256
|
+
} else {
|
|
257
|
+
// scrollToPage() нь currentPageIndex-ийг урьдчилан тохируулдаг тул энд орохгүй —
|
|
258
|
+
// гэхдээ zoom transform + Fabric layout-оос хуудас шинэчлэгдэхгүй үлдэхээс сэргийлнэ
|
|
259
|
+
(pager as? ZoomRecyclerView)?.resetZoom()
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
262
|
}
|
|
@@ -268,8 +274,32 @@ class ExpoPdfReaderView(
|
|
|
268
274
|
startLoad(it)
|
|
269
275
|
}
|
|
270
276
|
}
|
|
271
|
-
//
|
|
272
|
-
|
|
277
|
+
// RN: thumbnail panel нээх/хаахад өргөн өөрчлөгдөнө; Fabric child requestLayout сул → reflow шаардлагатай
|
|
278
|
+
if (renderer != null && isLayoutReady && lastHostWidthForPdf > 0 && width > 0) {
|
|
279
|
+
val dw = kotlin.math.abs(width - lastHostWidthForPdf)
|
|
280
|
+
if (dw > 4) {
|
|
281
|
+
post { reflowForHostWidthChange() }
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Хостын өргөн өөрчлөгдсөний дараа PDF-ийг шинэ өргөнөөр дахин тохируулна */
|
|
287
|
+
private fun reflowForHostWidthChange() {
|
|
288
|
+
val w = width.takeIf { it > 0 } ?: return
|
|
289
|
+
if (renderer == null) return
|
|
290
|
+
if (lastHostWidthForPdf > 0 && kotlin.math.abs(w - lastHostWidthForPdf) <= 4) return
|
|
291
|
+
lastHostWidthForPdf = w
|
|
292
|
+
currentViewWidth = w
|
|
293
|
+
when (displayMode) {
|
|
294
|
+
"single" -> {
|
|
295
|
+
forcePagerLayout()
|
|
296
|
+
singleAdapter?.notifyDataSetChanged()
|
|
297
|
+
forcePagerLayout()
|
|
298
|
+
val p = currentPageIndex.coerceIn(0, maxOf(0, totalPages - 1))
|
|
299
|
+
post { scrollToPage(p, smooth = false) }
|
|
300
|
+
}
|
|
301
|
+
else -> triggerRender()
|
|
302
|
+
}
|
|
273
303
|
}
|
|
274
304
|
|
|
275
305
|
override fun onDetachedFromWindow() {
|
|
@@ -536,25 +566,46 @@ class ExpoPdfReaderView(
|
|
|
536
566
|
// Zoom
|
|
537
567
|
// ─────────────────────────────────────────────────────────────────────────
|
|
538
568
|
|
|
539
|
-
|
|
569
|
+
/**
|
|
570
|
+
* Scroll mode: pivot (0,0) + translation — pinch төв (focus) тогтвортой үлдэхийн тулд translation-ийг
|
|
571
|
+
* scrollX/scrollY-тай нийлүүлэн шинэчилнэ (ZoomRecyclerView-тай ижил математик).
|
|
572
|
+
*/
|
|
573
|
+
private fun applyZoom(
|
|
574
|
+
newZoom: Float,
|
|
575
|
+
pinchFocusX: Float = Float.NaN,
|
|
576
|
+
pinchFocusY: Float = Float.NaN
|
|
577
|
+
) {
|
|
578
|
+
val prevZoom = currentZoom
|
|
540
579
|
currentZoom = newZoom.coerceIn(minZoom, maxZoom)
|
|
541
580
|
container.pivotX = 0f
|
|
542
581
|
container.pivotY = 0f
|
|
543
|
-
|
|
544
|
-
container.scaleY = currentZoom
|
|
582
|
+
|
|
545
583
|
if (displayMode != "single") {
|
|
546
584
|
if (currentZoom <= 1.02f) {
|
|
547
|
-
scrollView.allowVerticalScrollFromTouch = true
|
|
548
585
|
container.translationX = 0f
|
|
549
586
|
container.translationY = 0f
|
|
550
|
-
} else {
|
|
551
|
-
|
|
587
|
+
} else if (!pinchFocusX.isNaN() && !pinchFocusY.isNaN() && prevZoom > 0.01f) {
|
|
588
|
+
val af = currentZoom / prevZoom
|
|
589
|
+
if (kotlin.math.abs(af - 1f) > 1e-5f) {
|
|
590
|
+
val scrX = scrollView.scrollX.toFloat()
|
|
591
|
+
val scrY = scrollView.scrollY.toFloat()
|
|
592
|
+
val tx = container.translationX
|
|
593
|
+
val ty = container.translationY
|
|
594
|
+
val contentFx = pinchFocusX + scrX
|
|
595
|
+
val contentFy = pinchFocusY + scrY
|
|
596
|
+
container.translationX = contentFx - (contentFx - tx) * af
|
|
597
|
+
container.translationY = contentFy - (contentFy - ty) * af
|
|
598
|
+
}
|
|
552
599
|
}
|
|
553
600
|
}
|
|
601
|
+
container.scaleX = currentZoom
|
|
602
|
+
container.scaleY = currentZoom
|
|
603
|
+
if (displayMode != "single" && currentZoom > 1.02f) {
|
|
604
|
+
clampContainerTranslationsInPlace()
|
|
605
|
+
}
|
|
554
606
|
}
|
|
555
607
|
|
|
556
|
-
|
|
557
|
-
private fun applyContainerPanDelta(dx: Float, dy: Float) {
|
|
608
|
+
private fun clampContainerTranslationsInPlace() {
|
|
558
609
|
val ch = container.height.toFloat()
|
|
559
610
|
val cw = container.width.toFloat()
|
|
560
611
|
if (ch <= 0f || cw <= 0f) return
|
|
@@ -562,8 +613,8 @@ class ExpoPdfReaderView(
|
|
|
562
613
|
val scaledW = cw * currentZoom
|
|
563
614
|
val vw = scrollView.width.toFloat()
|
|
564
615
|
val vh = scrollView.height.toFloat()
|
|
565
|
-
var tx = container.translationX
|
|
566
|
-
var ty = container.translationY
|
|
616
|
+
var tx = container.translationX
|
|
617
|
+
var ty = container.translationY
|
|
567
618
|
if (scaledW <= vw) tx = 0f else tx = tx.coerceIn(vw - scaledW, 0f)
|
|
568
619
|
if (scaledH <= vh) ty = 0f else ty = ty.coerceIn(vh - scaledH, 0f)
|
|
569
620
|
container.translationX = tx
|
|
@@ -662,10 +713,17 @@ class ExpoPdfReaderView(
|
|
|
662
713
|
|
|
663
714
|
private fun scrollToPage(pageIndex: Int, smooth: Boolean = true) {
|
|
664
715
|
if (displayMode == "single") {
|
|
665
|
-
|
|
666
|
-
else pager.scrollToPosition(pageIndex)
|
|
716
|
+
pager.stopScroll()
|
|
667
717
|
currentPageIndex = pageIndex
|
|
668
718
|
onPageChange(mapOf("currentPage" to pageIndex, "totalPage" to totalPages))
|
|
719
|
+
// scrollToPosition нь заримдаа layout/bind хойшлуулна (RN Fabric); post + forcePagerLayout
|
|
720
|
+
pager.post {
|
|
721
|
+
if (smooth) pager.smoothScrollToPosition(pageIndex)
|
|
722
|
+
else pager.scrollToPosition(pageIndex)
|
|
723
|
+
forcePagerLayout()
|
|
724
|
+
singleAdapter?.notifyItemChanged(pageIndex)
|
|
725
|
+
(pager as? ZoomRecyclerView)?.resetZoom()
|
|
726
|
+
}
|
|
669
727
|
return
|
|
670
728
|
}
|
|
671
729
|
if (pageEntries.isEmpty()) return
|
|
@@ -743,7 +801,6 @@ class ExpoPdfReaderView(
|
|
|
743
801
|
container.scaleY = 1f
|
|
744
802
|
container.translationX = 0f
|
|
745
803
|
container.translationY = 0f
|
|
746
|
-
scrollView.allowVerticalScrollFromTouch = true
|
|
747
804
|
container.removeAllViews()
|
|
748
805
|
pageEntries.clear()
|
|
749
806
|
loadingFooter = null
|
|
@@ -771,6 +828,7 @@ class ExpoPdfReaderView(
|
|
|
771
828
|
"height" to (this@ExpoPdfReaderView.height / density).toDouble()
|
|
772
829
|
)
|
|
773
830
|
)
|
|
831
|
+
lastHostWidthForPdf = this@ExpoPdfReaderView.width.takeIf { it > 0 } ?: viewWidth
|
|
774
832
|
}
|
|
775
833
|
}
|
|
776
834
|
|
|
@@ -1307,7 +1365,11 @@ class ExpoPdfReaderView(
|
|
|
1307
1365
|
private fun safeCloseRenderer() {
|
|
1308
1366
|
try { renderer?.close(); fileDescriptor?.close() }
|
|
1309
1367
|
catch (_: Exception) { }
|
|
1310
|
-
finally {
|
|
1368
|
+
finally {
|
|
1369
|
+
renderer = null
|
|
1370
|
+
fileDescriptor = null
|
|
1371
|
+
lastHostWidthForPdf = 0
|
|
1372
|
+
}
|
|
1311
1373
|
}
|
|
1312
1374
|
|
|
1313
1375
|
private suspend fun resolveFile(url: String): File = withContext(pdfDispatcher) {
|
|
@@ -1447,6 +1509,14 @@ class ExpoPdfReaderView(
|
|
|
1447
1509
|
|
|
1448
1510
|
private val zoomDetector = ScaleGestureDetector(context,
|
|
1449
1511
|
object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
|
1512
|
+
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
|
|
1513
|
+
if (activeTool != null) return false
|
|
1514
|
+
stopScroll()
|
|
1515
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomRecyclerView, true)
|
|
1516
|
+
parent?.requestDisallowInterceptTouchEvent(true)
|
|
1517
|
+
return true
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1450
1520
|
override fun onScale(d: ScaleGestureDetector): Boolean {
|
|
1451
1521
|
val newScale = (currentScale * d.scaleFactor).coerceIn(minZoom, maxZoom)
|
|
1452
1522
|
val af = newScale / currentScale
|
|
@@ -1457,6 +1527,11 @@ class ExpoPdfReaderView(
|
|
|
1457
1527
|
clampAndApply()
|
|
1458
1528
|
return true
|
|
1459
1529
|
}
|
|
1530
|
+
|
|
1531
|
+
override fun onScaleEnd(detector: ScaleGestureDetector) {
|
|
1532
|
+
parent?.requestDisallowInterceptTouchEvent(false)
|
|
1533
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomRecyclerView, false)
|
|
1534
|
+
}
|
|
1460
1535
|
}
|
|
1461
1536
|
)
|
|
1462
1537
|
|
|
@@ -1467,8 +1542,14 @@ class ExpoPdfReaderView(
|
|
|
1467
1542
|
stopScroll()
|
|
1468
1543
|
}
|
|
1469
1544
|
if (ev.pointerCount > 1 || zoomDetector.isInProgress) {
|
|
1545
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomRecyclerView, true)
|
|
1470
1546
|
parent?.requestDisallowInterceptTouchEvent(true)
|
|
1471
1547
|
}
|
|
1548
|
+
if (ev.actionMasked == MotionEvent.ACTION_UP ||
|
|
1549
|
+
ev.actionMasked == MotionEvent.ACTION_CANCEL
|
|
1550
|
+
) {
|
|
1551
|
+
this@ExpoPdfReaderView.propagateDisallowInterceptFrom(this@ZoomRecyclerView, false)
|
|
1552
|
+
}
|
|
1472
1553
|
}
|
|
1473
1554
|
return super.dispatchTouchEvent(ev)
|
|
1474
1555
|
}
|
|
@@ -56,6 +56,8 @@ final class ExpoPdfReaderView: ExpoView {
|
|
|
56
56
|
// Zoom range: minZoom=1.0 (fit width), maxZoom=5.0 → pinch-to-zoom дэмжинэ
|
|
57
57
|
private var minZoom: CGFloat = 1.0
|
|
58
58
|
private var maxZoom: CGFloat = 5.0
|
|
59
|
+
/// RN thumbnail panel нээх/хаахад bounds өргөн өөрчлөгдөнө — scaleToFit дахин хийх суурь
|
|
60
|
+
private var lastHostWidthForPdf: CGFloat = 0
|
|
59
61
|
|
|
60
62
|
required init(appContext: AppContext? = nil) {
|
|
61
63
|
super.init(appContext: appContext)
|
|
@@ -164,11 +166,31 @@ final class ExpoPdfReaderView: ExpoView {
|
|
|
164
166
|
super.layoutSubviews()
|
|
165
167
|
pdfView.frame = bounds
|
|
166
168
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
guard let document = pdfView.document, document.pageCount > 0 else { return }
|
|
170
|
+
let w = bounds.width
|
|
171
|
+
guard w > 1 else { return }
|
|
172
|
+
|
|
173
|
+
// Анх: зөвхөн scaleFactor идэвхгүй үед fit (өмнөх зан)
|
|
174
|
+
if lastHostWidthForPdf <= 0 {
|
|
175
|
+
lastHostWidthForPdf = w
|
|
176
|
+
if pdfView.scaleFactor == 0 {
|
|
177
|
+
scaleToFitWidth()
|
|
178
|
+
}
|
|
179
|
+
return
|
|
171
180
|
}
|
|
181
|
+
|
|
182
|
+
// Thumbnail / side panel нээх эсвэл хаахад өргөн өөрчлөгдөнө → fit width дахин (жижиг үлдэхээс сэргийлнэ)
|
|
183
|
+
let dw = abs(w - lastHostWidthForPdf)
|
|
184
|
+
guard dw > 4 else { return }
|
|
185
|
+
|
|
186
|
+
let maxIdx = max(0, document.pageCount - 1)
|
|
187
|
+
let idx = min(max(0, lastPageIndex), maxIdx)
|
|
188
|
+
lastHostWidthForPdf = w
|
|
189
|
+
scaleToFitWidth()
|
|
190
|
+
if let page = document.page(at: idx) {
|
|
191
|
+
pdfView.go(to: page)
|
|
192
|
+
}
|
|
193
|
+
requestDisplayUpdate()
|
|
172
194
|
}
|
|
173
195
|
|
|
174
196
|
/// Custom hitTest:
|
|
@@ -198,6 +220,7 @@ final class ExpoPdfReaderView: ExpoView {
|
|
|
198
220
|
|
|
199
221
|
func load(url: URL) {
|
|
200
222
|
if pdfView.document?.documentURL == url { return }
|
|
223
|
+
lastHostWidthForPdf = 0
|
|
201
224
|
if let document = PDFDocument(url: url) {
|
|
202
225
|
pdfView.document = document
|
|
203
226
|
// New document → start from first page logically
|
|
@@ -209,6 +232,7 @@ final class ExpoPdfReaderView: ExpoView {
|
|
|
209
232
|
// Defer scaling until the view has correct bounds
|
|
210
233
|
DispatchQueue.main.async {
|
|
211
234
|
self.scaleToFitWidth()
|
|
235
|
+
self.lastHostWidthForPdf = self.bounds.width
|
|
212
236
|
// Document load хийгдсэний дараа pending annotation-уудыг load хийх
|
|
213
237
|
if let pending = self.pendingAnnotations {
|
|
214
238
|
self.pendingAnnotations = nil
|
|
@@ -286,6 +310,7 @@ final class ExpoPdfReaderView: ExpoView {
|
|
|
286
310
|
self.pdfView.go(to: page)
|
|
287
311
|
}
|
|
288
312
|
self.scaleToFitWidth()
|
|
313
|
+
self.lastHostWidthForPdf = self.bounds.width
|
|
289
314
|
}
|
|
290
315
|
}
|
|
291
316
|
|
package/package.json
CHANGED