@gunkin/uiify 0.0.2-alpha → 0.0.3-alpha

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.
@@ -199,10 +199,25 @@
199
199
  block-size: var( --uiify-virtual-scroll-total-size, calc(var(--uiify-virtual-scroll-count, 0) * var(--uiify-virtual-scroll-row-height)) );
200
200
  }
201
201
  [data-uiify-virtual-scroll] [data-part=row] {
202
+ --uiify-row-position: var( --uiify-row-offset, calc( (var(--uiify-range-start, 0) + var(--uiify-slot-index, 0)) * var(--uiify-virtual-scroll-row-height) ) );
202
203
  position: absolute;
203
204
  inset-inline: 0;
204
205
  block-size: var(--uiify-row-height, var(--uiify-virtual-scroll-row-height));
205
- translate: 0 var( --uiify-row-offset, calc( (var(--uiify-range-start, 0) + var(--uiify-slot-index, 0)) * var(--uiify-virtual-scroll-row-height) ) );
206
+ translate: 0 var(--uiify-row-position);
207
+ }
208
+ [data-uiify-virtual-scroll][data-orientation=horizontal] {
209
+ overflow: auto hidden;
210
+ }
211
+ [data-uiify-virtual-scroll][data-orientation=horizontal] > [data-part=spacer] {
212
+ block-size: 100%;
213
+ inline-size: var( --uiify-virtual-scroll-total-size, calc(var(--uiify-virtual-scroll-count, 0) * var(--uiify-virtual-scroll-row-height)) );
214
+ }
215
+ [data-uiify-virtual-scroll][data-orientation=horizontal] > [data-part=spacer] > [data-part=row] {
216
+ inset-block: 0;
217
+ inset-inline: var(--uiify-row-position) auto;
218
+ block-size: auto;
219
+ inline-size: var(--uiify-row-height, var(--uiify-virtual-scroll-row-height));
220
+ translate: none;
206
221
  }
207
222
  }
208
223
  /*# sourceMappingURL=behavior.css.map */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/behavior.css"],"sourcesContent":["/* Behavioral rules for @gunkin/uiify/components — zero visual opinion.\n * Import is required: @import \"@gunkin/uiify/components/behavior.css\";\n * Cascade order: consumer app layer wins without specificity fights. */\n@layer ui.reset, ui.behavior, ui.tokens, ui.theme, app;\n\n@layer ui.behavior {\n [popover]:not(:popover-open) {\n display: none;\n }\n\n /* Native modal dialogs: wheel/touch scrolling inside the dialog must not chain to the page behind it. */\n dialog:modal {\n overscroll-behavior: contain;\n }\n\n /* Closed dialogs stay hidden even when author CSS sets display. */\n dialog:not([open]) {\n display: none;\n }\n\n [data-anchor]:not([data-positioning]) {\n anchor-name: var(--uiify-anchor, attr(data-anchor type(<custom-ident>)));\n }\n\n [data-positioning=\"native\"] {\n position: fixed;\n inset: auto;\n margin: 0;\n position-try-fallbacks: flip-block, flip-inline;\n }\n\n [data-positioning=\"native\"][data-anchor] {\n position-anchor: var(--uiify-anchor, attr(data-anchor type(<custom-ident>)));\n }\n\n [data-positioning=\"native\"][data-side=\"top\"] {\n position-area: top;\n margin-block-end: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"right\"] {\n position-area: right;\n margin-inline-start: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"bottom\"] {\n position-area: bottom;\n margin-block-start: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"left\"] {\n position-area: left;\n margin-inline-end: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"top\"][data-align=\"start\"] {\n position-area: top span-right;\n justify-self: start;\n }\n\n [data-positioning=\"native\"][data-side=\"top\"][data-align=\"end\"] {\n position-area: top span-left;\n justify-self: end;\n }\n\n [data-positioning=\"native\"][data-side=\"bottom\"][data-align=\"start\"] {\n position-area: bottom span-right;\n justify-self: start;\n }\n\n [data-positioning=\"native\"][data-side=\"bottom\"][data-align=\"end\"] {\n position-area: bottom span-left;\n justify-self: end;\n }\n\n [data-positioning=\"native\"][data-side=\"right\"][data-align=\"start\"] {\n align-self: start;\n position-area: right span-bottom;\n }\n\n [data-positioning=\"native\"][data-side=\"right\"][data-align=\"end\"] {\n align-self: end;\n position-area: right span-top;\n }\n\n [data-positioning=\"native\"][data-side=\"left\"][data-align=\"start\"] {\n align-self: start;\n position-area: left span-bottom;\n }\n\n [data-positioning=\"native\"][data-side=\"left\"][data-align=\"end\"] {\n align-self: end;\n position-area: left span-top;\n }\n\n /*\n * Local open-state hooks. Top layer does not change DOM ancestry, so a scope\n * that directly contains its surface can read the native state. Consumers\n * style with the selector or with the variable; neither is a second source of truth.\n *\n * Compound roots and their public trigger parts share one component identity plus\n * `data-part`, so native state stays readable without a second scope convention.\n */\n [data-uiify-modal][data-part=\"root\"]:has(> [data-uiify-modal][data-part=\"content\"][open])\n > [data-uiify-modal][data-part=\"trigger\"],\n [data-uiify-alert-modal][data-part=\"root\"]:has(\n > [data-uiify-alert-modal][data-part=\"content\"][open]\n )\n > [data-uiify-alert-modal][data-part=\"trigger\"],\n [data-uiify-popup][data-part=\"root\"]:has(> [data-uiify-popup][data-part=\"content\"]:popover-open)\n > [data-uiify-popup][data-part=\"trigger\"] {\n --uiify-trigger-open: 1;\n }\n\n [data-uiify-accordion] > [data-part=\"item\"][data-disabled] > summary,\n [data-uiify-collapsible][data-disabled] > summary {\n cursor: not-allowed;\n pointer-events: none;\n }\n\n /* Customizable select: opts the control and its picker into the browser's\n base styles so the picker becomes a styleable, top-layer popover with\n implicit anchor positioning. Behavior only — no visual opinion. Engines\n without support ignore this and keep the classic OS picker, which stays\n fully functional. */\n [data-uiify-select],\n [data-uiify-select]::picker(select) {\n appearance: base-select;\n }\n\n [data-uiify-tabs] > [data-part=\"item\"] > [data-part=\"control\"] {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n /* stylelint-disable-next-line property-no-deprecated -- kept for older browser support alongside clip-path */\n clip: rect(0, 0, 0, 0);\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n\n [data-uiify-tabs] > [data-part=\"item\"] > [data-part=\"panel\"] {\n display: none;\n }\n\n [data-uiify-tabs] > [data-part=\"item\"] > [data-part=\"control\"]:checked ~ [data-part=\"panel\"] {\n display: block;\n }\n\n [data-uiify-stepper] > [data-part=\"step\"] > [data-part=\"panel\"] {\n display: none;\n }\n\n [data-uiify-stepper] > [data-part=\"step\"] > [data-part=\"control\"]:checked ~ [data-part=\"panel\"] {\n display: block;\n }\n\n [data-uiify-tabs] [data-part=\"trigger\"][data-disabled] {\n cursor: not-allowed;\n pointer-events: none;\n }\n\n [data-uiify-spinner][data-state=\"delayed\"] {\n animation-name: uiify-spinner-show;\n animation-duration: 0s;\n animation-delay: attr(data-delay type(<time>), 0s);\n animation-fill-mode: forwards;\n visibility: hidden;\n }\n\n @keyframes uiify-spinner-show {\n to {\n visibility: visible;\n }\n }\n\n [data-uiify-breadcrumb] [data-part=\"ellipsis\"] > ol {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"] {\n display: grid;\n min-inline-size: 0;\n min-block-size: 0;\n gap: var(--uiify-carousel-gap, 0);\n scroll-behavior: auto;\n }\n\n [data-uiify-carousel][data-axis=\"inline\"] > [data-part=\"viewport\"] {\n grid-auto-flow: column;\n grid-auto-columns: var(--uiify-carousel-slide-size, 100%);\n overflow-inline: auto;\n overflow-block: hidden;\n scroll-snap-type: inline mandatory;\n }\n\n [data-uiify-carousel][data-axis=\"block\"] > [data-part=\"viewport\"] {\n grid-auto-flow: row;\n grid-auto-rows: var(--uiify-carousel-slide-size, 100%);\n overflow-block: auto;\n overflow-inline: hidden;\n scroll-snap-type: block mandatory;\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"] > [data-part=\"slide\"] {\n min-inline-size: 0;\n min-block-size: 0;\n scroll-snap-align: start;\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"]:focus-visible,\n [data-uiify-carousel] > button[data-part=\"controls\"]:focus-visible,\n [data-uiify-carousel] > [data-part=\"dots\"] > a:focus-visible {\n outline: auto;\n }\n\n @media (prefers-reduced-motion: no-preference) {\n [data-uiify-carousel] > [data-part=\"viewport\"] {\n scroll-behavior: smooth;\n }\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"][data-dragging] {\n scroll-behavior: auto;\n scroll-snap-type: none;\n }\n\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced] > [data-part=\"viewport\"] {\n grid-auto-flow: row;\n grid-template-columns: 100%;\n grid-auto-columns: auto;\n overflow: hidden;\n scroll-snap-type: none;\n touch-action: pan-y pinch-zoom;\n }\n\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced]\n > [data-part=\"viewport\"]\n > [data-part=\"slide\"] {\n grid-area: 1 / 1;\n opacity: 0;\n pointer-events: none;\n }\n\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced]\n > [data-part=\"viewport\"]\n > [data-part=\"slide\"][data-state=\"active\"] {\n opacity: 1;\n pointer-events: auto;\n }\n\n @media (prefers-reduced-motion: no-preference) {\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced]\n > [data-part=\"viewport\"]\n > [data-part=\"slide\"] {\n transition: opacity var(--uiify-carousel-fade-duration, 300ms) ease;\n }\n }\n\n [data-uiify-virtual-scroll] {\n --uiify-virtual-scroll-row-height: 64px;\n\n overflow-y: auto;\n }\n\n [data-uiify-virtual-scroll] > [data-part=\"spacer\"] {\n position: relative;\n block-size: var(\n --uiify-virtual-scroll-total-size,\n calc(var(--uiify-virtual-scroll-count, 0) * var(--uiify-virtual-scroll-row-height))\n );\n }\n\n [data-uiify-virtual-scroll] [data-part=\"row\"] {\n position: absolute;\n inset-inline: 0;\n block-size: var(--uiify-row-height, var(--uiify-virtual-scroll-row-height));\n translate: 0\n var(\n --uiify-row-offset,\n calc(\n (var(--uiify-range-start, 0) + var(--uiify-slot-index, 0)) *\n var(--uiify-virtual-scroll-row-height)\n )\n );\n }\n}\n"],"mappings":"AAGA;AAEA;AACE,GAAC,QAAQ,KAAK;AACZ,aAAS;AACX;AAGA,QAAM;AACJ,yBAAqB;AACvB;AAGA,QAAM,KAAK,CAAC;AACV,aAAS;AACX;AAEA,GAAC,YAAY,KAAK,CAAC;AACjB,iBAAa,IAAI,cAAc,EAAE,KAAK,YAAY,KAAK,CAAC,YAAY;AACtE;AAEA,GAAC;AACC,cAAU;AACV,WAAO;AACP,YAAQ;AACR,4BAAwB,UAAU,EAAE;AACtC;AAEA,GAAC,wBAA0B,CAAC;AAC1B,qBAAiB,IAAI,cAAc,EAAE,KAAK,YAAY,KAAK,CAAC,YAAY;AAC1E;AAEA,GAAC,wBAA0B,CAAC;AAC1B,mBAAe;AACf,sBAAkB,IAAI,qBAAqB,EAAE;AAC/C;AAEA,GAAC,wBAA0B,CAAC;AAC1B,mBAAe;AACf,yBAAqB,IAAI,qBAAqB,EAAE;AAClD;AAEA,GAAC,wBAA0B,CAAC;AAC1B,mBAAe;AACf,wBAAoB,IAAI,qBAAqB,EAAE;AACjD;AAEA,GAAC,wBAA0B,CAAC;AAC1B,mBAAe;AACf,uBAAmB,IAAI,qBAAqB,EAAE;AAChD;AAEA,GAAC,wBAA0B,CAAC,cAAgB,CAAC;AAC3C,mBAAe,IAAI;AACnB,kBAAc;AAChB;AAEA,GAAC,wBAA0B,CAAC,cAAgB,CAAC;AAC3C,mBAAe,IAAI;AACnB,kBAAc;AAChB;AAEA,GAAC,wBAA0B,CAAC,iBAAmB,CAAC;AAC9C,mBAAe,OAAO;AACtB,kBAAc;AAChB;AAEA,GAAC,wBAA0B,CAAC,iBAAmB,CAAC;AAC9C,mBAAe,OAAO;AACtB,kBAAc;AAChB;AAEA,GAAC,wBAA0B,CAAC,gBAAkB,CAAC;AAC7C,gBAAY;AACZ,mBAAe,MAAM;AACvB;AAEA,GAAC,wBAA0B,CAAC,gBAAkB,CAAC;AAC7C,gBAAY;AACZ,mBAAe,MAAM;AACvB;AAEA,GAAC,wBAA0B,CAAC,eAAiB,CAAC;AAC5C,gBAAY;AACZ,mBAAe,KAAK;AACtB;AAEA,GAAC,wBAA0B,CAAC,eAAiB,CAAC;AAC5C,gBAAY;AACZ,mBAAe,KAAK;AACtB;AAUA,GAAC,iBAAiB,CAAC,eAAiB,KAAK,EAAE,CAAC,iBAAiB,CAAC,kBAAoB,CAAC,OACjF,EAAE,CAAC,iBAAiB,CAAC;AAAA,EACvB,CAAC,uBAAuB,CAAC,eAAiB,KACtC,EAAE,CAAC,uBAAuB,CAAC,kBAAoB,CAAC,OAElD,EAAE,CAAC,uBAAuB,CAAC;AAAA,EAC7B,CAAC,iBAAiB,CAAC,eAAiB,KAAK,EAAE,CAAC,iBAAiB,CAAC,kBAAoB,eAChF,EAAE,CAAC,iBAAiB,CAAC;AACrB,0BAAsB;AACxB;AAEA,GAAC,sBAAsB,EAAE,CAAC,eAAiB,CAAC,eAAe,EAAE;AAAA,EAC7D,CAAC,uBAAuB,CAAC,eAAe,EAAE;AACxC,YAAQ;AACR,oBAAgB;AAClB;AAOA,GAAC;AAAA,EACD,CAAC,kBAAkB,SAAS;AAC1B,gBAAY;AACd;AAEA,GAAC,iBAAiB,EAAE,CAAC,gBAAkB,EAAE,CAAC;AACxC,cAAU;AACV,WAAO;AACP,YAAQ;AACR,aAAS;AACT,YAAQ;AACR,cAAU;AAEV,UAAM,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACpB,eAAW,MAAM;AACjB,iBAAa;AACb,YAAQ;AACV;AAEA,GAAC,iBAAiB,EAAE,CAAC,gBAAkB,EAAE,CAAC;AACxC,aAAS;AACX;AAEA,GAAC,iBAAiB,EAAE,CAAC,gBAAkB,EAAE,CAAC,kBAAoB,SAAS,EAAE,CAAC;AACxE,aAAS;AACX;AAEA,GAAC,oBAAoB,EAAE,CAAC,gBAAkB,EAAE,CAAC;AAC3C,aAAS;AACX;AAEA,GAAC,oBAAoB,EAAE,CAAC,gBAAkB,EAAE,CAAC,kBAAoB,SAAS,EAAE,CAAC;AAC3E,aAAS;AACX;AAEA,GAAC,iBAAiB,CAAC,kBAAoB,CAAC;AACtC,YAAQ;AACR,oBAAgB;AAClB;AAEA,GAAC,mBAAmB,CAAC;AACnB,oBAAgB;AAChB,wBAAoB;AACpB,qBAAiB,KAAK,WAAW,KAAK,CAAC,IAAI,EAAE,EAAE;AAC/C,yBAAqB;AACrB,gBAAY;AACd;AAEA,aAPkB;AAQhB;AACE,kBAAY;AACd;AACF;AAEA,GAAC,uBAAuB,CAAC,oBAAsB,EAAE;AAC/C,gBAAY;AACZ,YAAQ;AACR,aAAS;AACX;AAEA,GAAC,qBAAqB,EAAE,CAAC;AACvB,aAAS;AACT,qBAAiB;AACjB,oBAAgB;AAChB,SAAK,IAAI,oBAAoB,EAAE;AAC/B,qBAAiB;AACnB;AAEA,GAAC,oBAAoB,CAAC,kBAAoB,EAAE,CAAC;AAC3C,oBAAgB;AAChB,uBAAmB,IAAI,2BAA2B,EAAE;AACpD,qBAAiB;AACjB,oBAAgB;AAChB,sBAAkB,OAAO;AAC3B;AAEA,GAAC,oBAAoB,CAAC,iBAAmB,EAAE,CAAC;AAC1C,oBAAgB;AAChB,oBAAgB,IAAI,2BAA2B,EAAE;AACjD,oBAAgB;AAChB,qBAAiB;AACjB,sBAAkB,MAAM;AAC1B;AAEA,GAAC,qBAAqB,EAAE,CAAC,oBAAsB,EAAE,CAAC;AAChD,qBAAiB;AACjB,oBAAgB;AAChB,uBAAmB;AACrB;AAEA,GAAC,qBAAqB,EAAE,CAAC,mBAAqB;AAAA,EAC9C,CAAC,qBAAqB,EAAE,MAAM,CAAC,mBAAqB;AAAA,EACpD,CAAC,qBAAqB,EAAE,CAAC,gBAAkB,EAAE,CAAC;AAC5C,aAAS;AACX;AAEA,UAAO,wBAAyB;AAC9B,KAAC,qBAAqB,EAAE,CAAC;AACvB,uBAAiB;AACnB;AACF;AAEA,GAAC,qBAAqB,EAAE,CAAC,mBAAqB,CAAC;AAC7C,qBAAiB;AACjB,sBAAkB;AACpB;AAEA,GAAC,oBAAoB,CAAC,eAAiB,CAAC,eAAe,EAAE,CAAC;AACxD,oBAAgB;AAChB,2BAAuB;AACvB,uBAAmB;AACnB,cAAU;AACV,sBAAkB;AAClB,kBAAc,MAAM;AACtB;AAEA,GAAC,oBAAoB,CAAC,eAAiB,CAAC,eACtC,EAAE,CAAC,oBACH,EAAE,CAAC;AACH,eAAW,EAAE,EAAE;AACf,aAAS;AACT,oBAAgB;AAClB;AAEA,GAAC,oBAAoB,CAAC,eAAiB,CAAC,eACtC,EAAE,CAAC,oBACH,EAAE,CAAC,gBAAkB,CAAC;AACtB,aAAS;AACT,oBAAgB;AAClB;AAEA,UAAO,wBAAyB;AAC9B,KAAC,oBAAoB,CAAC,eAAiB,CAAC,eACtC,EAAE,CAAC,oBACH,EAAE,CAAC;AACH,kBAAY,QAAQ,IAAI,8BAA8B,EAAE,OAAO;AACjE;AACF;AAEA,GAAC;AACC,uCAAmC;AAEnC,gBAAY;AACd;AAEA,GAAC,2BAA2B,EAAE,CAAC;AAC7B,cAAU;AACV,gBAAY,KACV,iCAAiC,EACjC,KAAK,IAAI,4BAA4B,EAAE,GAAG,EAAE,IAAI;AAEpD;AAEA,GAAC,2BAA2B,CAAC;AAC3B,cAAU;AACV,kBAAc;AACd,gBAAY,IAAI,kBAAkB,EAAE,IAAI;AACxC,eAAW,EACT,KACE,kBAAkB,EAClB,MACE,CAAC,IAAI,mBAAmB,EAAE,GAAG,EAAE,IAAI,kBAAkB,EAAE,IAAI,EACzD,IAAI;AAGd;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/components/behavior.css"],"sourcesContent":["/* Behavioral rules for @gunkin/uiify/components — zero visual opinion.\n * Import is required: @import \"@gunkin/uiify/components/behavior.css\";\n * Cascade order: consumer app layer wins without specificity fights. */\n@layer ui.reset, ui.behavior, ui.tokens, ui.theme, app;\n\n@layer ui.behavior {\n [popover]:not(:popover-open) {\n display: none;\n }\n\n /* Native modal dialogs: wheel/touch scrolling inside the dialog must not chain to the page behind it. */\n dialog:modal {\n overscroll-behavior: contain;\n }\n\n /* Closed dialogs stay hidden even when author CSS sets display. */\n dialog:not([open]) {\n display: none;\n }\n\n [data-anchor]:not([data-positioning]) {\n anchor-name: var(--uiify-anchor, attr(data-anchor type(<custom-ident>)));\n }\n\n [data-positioning=\"native\"] {\n position: fixed;\n inset: auto;\n margin: 0;\n position-try-fallbacks: flip-block, flip-inline;\n }\n\n [data-positioning=\"native\"][data-anchor] {\n position-anchor: var(--uiify-anchor, attr(data-anchor type(<custom-ident>)));\n }\n\n [data-positioning=\"native\"][data-side=\"top\"] {\n position-area: top;\n margin-block-end: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"right\"] {\n position-area: right;\n margin-inline-start: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"bottom\"] {\n position-area: bottom;\n margin-block-start: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"left\"] {\n position-area: left;\n margin-inline-end: var(--uiify-anchor-offset, 0);\n }\n\n [data-positioning=\"native\"][data-side=\"top\"][data-align=\"start\"] {\n position-area: top span-right;\n justify-self: start;\n }\n\n [data-positioning=\"native\"][data-side=\"top\"][data-align=\"end\"] {\n position-area: top span-left;\n justify-self: end;\n }\n\n [data-positioning=\"native\"][data-side=\"bottom\"][data-align=\"start\"] {\n position-area: bottom span-right;\n justify-self: start;\n }\n\n [data-positioning=\"native\"][data-side=\"bottom\"][data-align=\"end\"] {\n position-area: bottom span-left;\n justify-self: end;\n }\n\n [data-positioning=\"native\"][data-side=\"right\"][data-align=\"start\"] {\n align-self: start;\n position-area: right span-bottom;\n }\n\n [data-positioning=\"native\"][data-side=\"right\"][data-align=\"end\"] {\n align-self: end;\n position-area: right span-top;\n }\n\n [data-positioning=\"native\"][data-side=\"left\"][data-align=\"start\"] {\n align-self: start;\n position-area: left span-bottom;\n }\n\n [data-positioning=\"native\"][data-side=\"left\"][data-align=\"end\"] {\n align-self: end;\n position-area: left span-top;\n }\n\n /*\n * Local open-state hooks. Top layer does not change DOM ancestry, so a scope\n * that directly contains its surface can read the native state. Consumers\n * style with the selector or with the variable; neither is a second source of truth.\n *\n * Compound roots and their public trigger parts share one component identity plus\n * `data-part`, so native state stays readable without a second scope convention.\n */\n [data-uiify-modal][data-part=\"root\"]:has(> [data-uiify-modal][data-part=\"content\"][open])\n > [data-uiify-modal][data-part=\"trigger\"],\n [data-uiify-alert-modal][data-part=\"root\"]:has(\n > [data-uiify-alert-modal][data-part=\"content\"][open]\n )\n > [data-uiify-alert-modal][data-part=\"trigger\"],\n [data-uiify-popup][data-part=\"root\"]:has(> [data-uiify-popup][data-part=\"content\"]:popover-open)\n > [data-uiify-popup][data-part=\"trigger\"] {\n --uiify-trigger-open: 1;\n }\n\n [data-uiify-accordion] > [data-part=\"item\"][data-disabled] > summary,\n [data-uiify-collapsible][data-disabled] > summary {\n cursor: not-allowed;\n pointer-events: none;\n }\n\n /* Customizable select: opts the control and its picker into the browser's\n base styles so the picker becomes a styleable, top-layer popover with\n implicit anchor positioning. Behavior only — no visual opinion. Engines\n without support ignore this and keep the classic OS picker, which stays\n fully functional. */\n [data-uiify-select],\n [data-uiify-select]::picker(select) {\n appearance: base-select;\n }\n\n [data-uiify-tabs] > [data-part=\"item\"] > [data-part=\"control\"] {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n /* stylelint-disable-next-line property-no-deprecated -- kept for older browser support alongside clip-path */\n clip: rect(0, 0, 0, 0);\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n\n [data-uiify-tabs] > [data-part=\"item\"] > [data-part=\"panel\"] {\n display: none;\n }\n\n [data-uiify-tabs] > [data-part=\"item\"] > [data-part=\"control\"]:checked ~ [data-part=\"panel\"] {\n display: block;\n }\n\n [data-uiify-stepper] > [data-part=\"step\"] > [data-part=\"panel\"] {\n display: none;\n }\n\n [data-uiify-stepper] > [data-part=\"step\"] > [data-part=\"control\"]:checked ~ [data-part=\"panel\"] {\n display: block;\n }\n\n [data-uiify-tabs] [data-part=\"trigger\"][data-disabled] {\n cursor: not-allowed;\n pointer-events: none;\n }\n\n [data-uiify-spinner][data-state=\"delayed\"] {\n animation-name: uiify-spinner-show;\n animation-duration: 0s;\n animation-delay: attr(data-delay type(<time>), 0s);\n animation-fill-mode: forwards;\n visibility: hidden;\n }\n\n @keyframes uiify-spinner-show {\n to {\n visibility: visible;\n }\n }\n\n [data-uiify-breadcrumb] [data-part=\"ellipsis\"] > ol {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"] {\n display: grid;\n min-inline-size: 0;\n min-block-size: 0;\n gap: var(--uiify-carousel-gap, 0);\n scroll-behavior: auto;\n }\n\n [data-uiify-carousel][data-axis=\"inline\"] > [data-part=\"viewport\"] {\n grid-auto-flow: column;\n grid-auto-columns: var(--uiify-carousel-slide-size, 100%);\n overflow-inline: auto;\n overflow-block: hidden;\n scroll-snap-type: inline mandatory;\n }\n\n [data-uiify-carousel][data-axis=\"block\"] > [data-part=\"viewport\"] {\n grid-auto-flow: row;\n grid-auto-rows: var(--uiify-carousel-slide-size, 100%);\n overflow-block: auto;\n overflow-inline: hidden;\n scroll-snap-type: block mandatory;\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"] > [data-part=\"slide\"] {\n min-inline-size: 0;\n min-block-size: 0;\n scroll-snap-align: start;\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"]:focus-visible,\n [data-uiify-carousel] > button[data-part=\"controls\"]:focus-visible,\n [data-uiify-carousel] > [data-part=\"dots\"] > a:focus-visible {\n outline: auto;\n }\n\n @media (prefers-reduced-motion: no-preference) {\n [data-uiify-carousel] > [data-part=\"viewport\"] {\n scroll-behavior: smooth;\n }\n }\n\n [data-uiify-carousel] > [data-part=\"viewport\"][data-dragging] {\n scroll-behavior: auto;\n scroll-snap-type: none;\n }\n\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced] > [data-part=\"viewport\"] {\n grid-auto-flow: row;\n grid-template-columns: 100%;\n grid-auto-columns: auto;\n overflow: hidden;\n scroll-snap-type: none;\n touch-action: pan-y pinch-zoom;\n }\n\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced]\n > [data-part=\"viewport\"]\n > [data-part=\"slide\"] {\n grid-area: 1 / 1;\n opacity: 0;\n pointer-events: none;\n }\n\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced]\n > [data-part=\"viewport\"]\n > [data-part=\"slide\"][data-state=\"active\"] {\n opacity: 1;\n pointer-events: auto;\n }\n\n @media (prefers-reduced-motion: no-preference) {\n [data-uiify-carousel][data-mode=\"fade\"][data-enhanced]\n > [data-part=\"viewport\"]\n > [data-part=\"slide\"] {\n transition: opacity var(--uiify-carousel-fade-duration, 300ms) ease;\n }\n }\n\n [data-uiify-virtual-scroll] {\n --uiify-virtual-scroll-row-height: 64px;\n\n overflow-y: auto;\n }\n\n [data-uiify-virtual-scroll] > [data-part=\"spacer\"] {\n position: relative;\n block-size: var(\n --uiify-virtual-scroll-total-size,\n calc(var(--uiify-virtual-scroll-count, 0) * var(--uiify-virtual-scroll-row-height))\n );\n }\n\n [data-uiify-virtual-scroll] [data-part=\"row\"] {\n --uiify-row-position: var(\n --uiify-row-offset,\n calc(\n (var(--uiify-range-start, 0) + var(--uiify-slot-index, 0)) *\n var(--uiify-virtual-scroll-row-height)\n )\n );\n\n position: absolute;\n inset-inline: 0;\n block-size: var(--uiify-row-height, var(--uiify-virtual-scroll-row-height));\n translate: 0 var(--uiify-row-position);\n }\n\n /* Horizontal: the row size runs along the inline axis. Rows sit at a logical\n inline offset so RTL needs no direction selector; child combinators keep a\n vertical list nested inside a horizontal row on the vertical rules. */\n [data-uiify-virtual-scroll][data-orientation=\"horizontal\"] {\n overflow: auto hidden;\n }\n\n [data-uiify-virtual-scroll][data-orientation=\"horizontal\"] > [data-part=\"spacer\"] {\n block-size: 100%;\n inline-size: var(\n --uiify-virtual-scroll-total-size,\n calc(var(--uiify-virtual-scroll-count, 0) * var(--uiify-virtual-scroll-row-height))\n );\n }\n\n [data-uiify-virtual-scroll][data-orientation=\"horizontal\"]\n > [data-part=\"spacer\"]\n > [data-part=\"row\"] {\n inset-block: 0;\n inset-inline: var(--uiify-row-position) auto;\n block-size: auto;\n inline-size: var(--uiify-row-height, var(--uiify-virtual-scroll-row-height));\n translate: none;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualScroll.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/VirtualScroll.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,YAAY,EAClB,MAAM,OAAO,CAAC;AAoCf,OAAO,KAAK,EAEV,iBAAiB,EACjB,qBAAqB,EAItB,MAAM,YAAY,CAAC;AAwBpB,wBAAgB,aAAa,CAAC,CAAC,SAAS,iBAAiB,EACvD,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC9B,YAAY,CAgdd;yBAlde,aAAa"}
1
+ {"version":3,"file":"VirtualScroll.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/VirtualScroll.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,YAAY,EAClB,MAAM,OAAO,CAAC;AAqCf,OAAO,KAAK,EAEV,iBAAiB,EACjB,qBAAqB,EAItB,MAAM,YAAY,CAAC;AAwBpB,wBAAgB,aAAa,CAAC,CAAC,SAAS,iBAAiB,EACvD,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC9B,YAAY,CA4cd;yBA9ce,aAAa"}
@@ -10,6 +10,7 @@ import {
10
10
  import { flushSync } from "react-dom";
11
11
  import { useResizeObserver } from "@gunkin/uiify/hooks";
12
12
  import { resolveVirtualScrollAnchorAdjustment } from "./virtual-scroll-anchor.js";
13
+ import { readScrollOffset, writeScrollOffset } from "./virtual-scroll-axis.js";
13
14
  import {
14
15
  createVirtualScrollIosScroll,
15
16
  detectTouchScrollEnvironment
@@ -64,6 +65,7 @@ function VirtualScroll(props) {
64
65
  items,
65
66
  height = 600,
66
67
  rowHeight = VIRTUAL_SCROLL_ROW_HEIGHT,
68
+ orientation = "vertical",
67
69
  overscan = VIRTUAL_SCROLL_OVERSCAN,
68
70
  className,
69
71
  testId,
@@ -78,8 +80,9 @@ function VirtualScroll(props) {
78
80
  isScrollingResetDelay = VIRTUAL_SCROLL_SCROLL_RESET_DELAY
79
81
  } = props;
80
82
  const dynamicLayout = estimateRowHeight !== void 0;
83
+ const horizontal = orientation === "horizontal";
81
84
  const ref = useRef(null);
82
- const scrollTopRef = useRef(0);
85
+ const scrollOffsetRef = useRef(0);
83
86
  const itemsRef = useRef(items);
84
87
  itemsRef.current = items;
85
88
  const smoothRafRef = useRef(0);
@@ -94,7 +97,7 @@ function VirtualScroll(props) {
94
97
  const [rangeVersion, setRangeVersion] = useState(0);
95
98
  const [measurementVersion, setMeasurementVersion] = useState(0);
96
99
  const measuredSize = useResizeObserver(ref);
97
- const viewportHeight = measuredSize?.height ?? height;
100
+ const viewportSize = (horizontal ? measuredSize?.width : measuredSize?.height) ?? height;
98
101
  const measurementStoreRef = useRef(
99
102
  createVirtualScrollMeasurementStore({
100
103
  itemCount: items.length,
@@ -108,29 +111,31 @@ function VirtualScroll(props) {
108
111
  const scrollOptionsRef = useRef({
109
112
  dynamicLayout,
110
113
  itemCount: items.length,
114
+ orientation,
111
115
  overscan,
112
116
  rowHeight,
113
- viewportHeight
117
+ viewportSize
114
118
  });
115
119
  scrollOptionsRef.current = {
116
120
  dynamicLayout,
117
121
  itemCount: items.length,
122
+ orientation,
118
123
  overscan,
119
124
  rowHeight,
120
- viewportHeight
125
+ viewportSize
121
126
  };
122
127
  const onRangeChangeRef = useRef(onRangeChange);
123
128
  onRangeChangeRef.current = onRangeChange;
124
129
  const onScrollStateChangeRef = useRef(onScrollStateChange);
125
130
  onScrollStateChangeRef.current = onScrollStateChange;
126
131
  const computeRange = () => {
127
- const { dynamicLayout: dynamicLayout2, itemCount, overscan: overscan2, rowHeight: rowHeight2, viewportHeight: viewportHeight2 } = scrollOptionsRef.current;
128
- const scrollTop = scrollTopRef.current;
132
+ const { dynamicLayout: dynamicLayout2, itemCount, overscan: overscan2, rowHeight: rowHeight2, viewportSize: viewportSize2 } = scrollOptionsRef.current;
133
+ const scrollTop = scrollOffsetRef.current;
129
134
  if (dynamicLayout2) {
130
135
  const store = measurementStoreRef.current;
131
136
  return computeDynamicVirtualScrollRange({
132
137
  scrollTop,
133
- viewportHeight: viewportHeight2,
138
+ viewportHeight: viewportSize2,
134
139
  itemCount,
135
140
  overscan: overscan2,
136
141
  findStartIndex: store.findStartIndex,
@@ -140,7 +145,7 @@ function VirtualScroll(props) {
140
145
  }
141
146
  return computeVirtualScrollRange({
142
147
  scrollTop,
143
- viewportHeight: viewportHeight2,
148
+ viewportHeight: viewportSize2,
144
149
  itemCount,
145
150
  rowHeight: rowHeight2,
146
151
  overscan: overscan2
@@ -160,19 +165,19 @@ function VirtualScroll(props) {
160
165
  syncRangeFromScrollRef.current = () => {
161
166
  const element = ref.current;
162
167
  if (!element) return;
163
- const scrollTop = element.scrollTop;
168
+ const scrollOffset = readScrollOffset(element, scrollOptionsRef.current.orientation);
164
169
  const previousRange = computeRange();
165
- scrollTopRef.current = scrollTop;
170
+ scrollOffsetRef.current = scrollOffset;
166
171
  const nextRange = computeRange();
167
172
  if (rangesEqual(previousRange, nextRange)) return;
168
173
  emitRangeChange(nextRange);
169
- const { dynamicLayout: dynamicLayout2, itemCount, viewportHeight: viewportHeight2, rowHeight: rowHeight2, overscan: overscan2 } = scrollOptionsRef.current;
174
+ const { dynamicLayout: dynamicLayout2, itemCount, viewportSize: viewportSize2, rowHeight: rowHeight2, overscan: overscan2 } = scrollOptionsRef.current;
170
175
  const slotCount2 = computeActiveVirtualScrollSlotCount(
171
176
  itemCount,
172
177
  nextRange.start,
173
178
  Math.max(
174
179
  nextRange.end - nextRange.start,
175
- computeVirtualScrollSlotCount(viewportHeight2, rowHeight2, overscan2)
180
+ computeVirtualScrollSlotCount(viewportSize2, rowHeight2, overscan2)
176
181
  )
177
182
  );
178
183
  const store = measurementStoreRef.current;
@@ -196,7 +201,8 @@ function VirtualScroll(props) {
196
201
  applyScrollDeltaRef.current = (delta) => {
197
202
  const element = ref.current;
198
203
  if (!element || delta === 0) return;
199
- element.scrollTop += delta;
204
+ const { orientation: orientation2 } = scrollOptionsRef.current;
205
+ writeScrollOffset(element, orientation2, readScrollOffset(element, orientation2) + delta, "auto");
200
206
  syncRangeFromScrollRef.current();
201
207
  };
202
208
  const applyScrollOffset = (offset, behavior) => {
@@ -204,15 +210,10 @@ function VirtualScroll(props) {
204
210
  if (!element) return;
205
211
  const store = measurementStoreRef.current;
206
212
  const totalSize2 = dynamicLayout ? store.getTotalSize() : items.length * rowHeight;
207
- const clamped = clampScrollOffset(offset, totalSize2, viewportHeight);
208
- const resolved = resolveScrollBehavior(behavior);
209
- if (typeof element.scrollTo === "function") {
210
- element.scrollTo({ top: clamped, behavior: resolved });
211
- } else {
212
- element.scrollTop = clamped;
213
- }
213
+ const clamped = clampScrollOffset(offset, totalSize2, viewportSize);
214
+ writeScrollOffset(element, orientation, clamped, resolveScrollBehavior(behavior));
214
215
  syncRangeFromScrollRef.current();
215
- if (isSmoothScrollActive(behavior ?? "auto", element.scrollTop, clamped)) {
216
+ if (isSmoothScrollActive(behavior ?? "auto", readScrollOffset(element, orientation), clamped)) {
216
217
  if (smoothRafRef.current !== 0) cancelAnimationFrame(smoothRafRef.current);
217
218
  const tick = () => {
218
219
  syncRangeFromScrollRef.current();
@@ -221,7 +222,7 @@ function VirtualScroll(props) {
221
222
  smoothRafRef.current = 0;
222
223
  return;
223
224
  }
224
- if (isSmoothScrollActive("smooth", node.scrollTop, clamped)) {
225
+ if (isSmoothScrollActive("smooth", readScrollOffset(node, orientation), clamped)) {
225
226
  smoothRafRef.current = requestAnimationFrame(tick);
226
227
  return;
227
228
  }
@@ -253,8 +254,8 @@ function VirtualScroll(props) {
253
254
  index,
254
255
  normalized.align,
255
256
  metrics,
256
- scrollOptionsRef.current.viewportHeight,
257
- scrollTopRef.current
257
+ scrollOptionsRef.current.viewportSize,
258
+ scrollOffsetRef.current
258
259
  );
259
260
  applyScrollOffsetRef.current(offset, normalized.behavior);
260
261
  },
@@ -264,7 +265,7 @@ function VirtualScroll(props) {
264
265
  scrollToEnd(options) {
265
266
  const store = measurementStoreRef.current;
266
267
  const totalSize2 = dynamicLayout ? store.getTotalSize() : scrollOptionsRef.current.itemCount * scrollOptionsRef.current.rowHeight;
267
- const offset = Math.max(0, totalSize2 - scrollOptionsRef.current.viewportHeight);
268
+ const offset = Math.max(0, totalSize2 - scrollOptionsRef.current.viewportSize);
268
269
  applyScrollOffsetRef.current(offset, normalizeScrollBehaviorOptions(options));
269
270
  }
270
271
  }),
@@ -284,9 +285,9 @@ function VirtualScroll(props) {
284
285
  if (items.length === 0) return 0;
285
286
  return Math.max(
286
287
  range.end - range.start,
287
- computeVirtualScrollSlotCount(viewportHeight, rowHeight, overscan)
288
+ computeVirtualScrollSlotCount(viewportSize, rowHeight, overscan)
288
289
  );
289
- }, [items.length, overscan, range.end, range.start, rowHeight, viewportHeight]);
290
+ }, [items.length, overscan, range.end, range.start, rowHeight, viewportSize]);
290
291
  const rowSlots = useMemo(
291
292
  () => buildRowSlots(items, range.start, slotCount),
292
293
  [items, range.start, slotCount]
@@ -297,7 +298,7 @@ function VirtualScroll(props) {
297
298
  const rowOffset = store.getRowOffset(index);
298
299
  if (!store.setMeasuredHeight(itemId, index, height2)) return;
299
300
  const adjustment = computeScrollAdjustmentForRowResize({
300
- scrollTop: scrollTopRef.current,
301
+ scrollTop: scrollOffsetRef.current,
301
302
  rowOffset,
302
303
  previousHeight,
303
304
  nextHeight: height2
@@ -327,12 +328,13 @@ function VirtualScroll(props) {
327
328
  if (!Number.isInteger(index)) continue;
328
329
  const itemId = itemsRef.current[index]?.id;
329
330
  if (itemId === void 0) continue;
330
- handleRowMeasureRef.current(index, itemId, entry.contentRect.height);
331
+ const size = horizontal ? entry.contentRect.width : entry.contentRect.height;
332
+ handleRowMeasureRef.current(index, itemId, size);
331
333
  }
332
334
  });
333
335
  fragment.observeUsing(observer);
334
336
  return () => fragment.unobserveUsing(observer);
335
- }, [dynamicLayout]);
337
+ }, [dynamicLayout, horizontal]);
336
338
  useEffect(() => {
337
339
  const element = ref.current;
338
340
  if (!element) return;
@@ -379,40 +381,33 @@ function VirtualScroll(props) {
379
381
  const store = measurementStoreRef.current;
380
382
  const nextTotalSize = dynamicLayout ? store.getTotalSize() : items.length * rowHeight;
381
383
  const previous = anchorSnapshotRef.current;
384
+ const scrollOffset = element ? readScrollOffset(element, orientation) : scrollOffsetRef.current;
382
385
  const nextSnapshot = {
383
386
  firstItemId: items[0]?.id,
384
387
  itemCount: items.length,
385
388
  totalSize: nextTotalSize,
386
- scrollTop: element?.scrollTop ?? scrollTopRef.current
387
- // banned-read-ok: anchor snapshot reads native position.
389
+ scrollTop: scrollOffset
388
390
  };
389
391
  const adjustment = resolveVirtualScrollAnchorAdjustment({
390
392
  anchor,
391
393
  followAppend,
392
- viewportHeight,
394
+ viewportHeight: viewportSize,
393
395
  previous,
394
396
  next: nextSnapshot
395
397
  });
396
398
  if (adjustment && element) {
397
- if (adjustment.behavior === "smooth" && typeof element.scrollTo === "function") {
398
- element.scrollTo({
399
- top: element.scrollTop + adjustment.delta,
400
- // banned-read-ok: retain the anchored viewport.
401
- behavior: "smooth"
402
- });
403
- } else {
404
- element.scrollTop += adjustment.delta;
405
- }
399
+ writeScrollOffset(element, orientation, scrollOffset + adjustment.delta, adjustment.behavior);
406
400
  syncRangeFromScrollRef.current();
407
401
  }
408
402
  anchorSnapshotRef.current = nextSnapshot;
409
- }, [anchor, followAppend, items, dynamicLayout, rowHeight, viewportHeight]);
403
+ }, [anchor, followAppend, items, dynamicLayout, orientation, rowHeight, viewportSize]);
410
404
  useEffect(() => {
411
405
  emitRangeChange(range);
412
406
  }, [range]);
413
407
  const scrollportStyle = {
414
408
  height,
415
- overflowY: "auto",
409
+ overflowX: horizontal ? "auto" : void 0,
410
+ overflowY: horizontal ? "hidden" : "auto",
416
411
  "--uiify-virtual-scroll-count": items.length,
417
412
  "--uiify-virtual-scroll-row-height": `${rowHeight}px`,
418
413
  ...dynamicLayout ? { "--uiify-virtual-scroll-total-size": `${totalSize}px` } : {}
@@ -427,6 +422,7 @@ function VirtualScroll(props) {
427
422
  "data-testid": testId,
428
423
  "data-uiify-virtual-scroll": "",
429
424
  "data-dynamic-layout": dynamicLayout ? "" : void 0,
425
+ "data-orientation": orientation,
430
426
  role,
431
427
  className,
432
428
  style: scrollportStyle,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/virtual-scroll/VirtualScroll.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FragmentInstance,\n type ReactElement,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { useResizeObserver } from \"@gunkin/uiify/hooks\";\nimport { resolveVirtualScrollAnchorAdjustment } from \"./virtual-scroll-anchor.js\";\nimport {\n createVirtualScrollIosScroll,\n detectTouchScrollEnvironment,\n} from \"./virtual-scroll-ios.js\";\nimport {\n computeScrollAdjustmentForRowResize,\n createVirtualScrollMeasurementStore,\n} from \"./virtual-scroll-measurements.js\";\nimport {\n computeDynamicVirtualScrollRange,\n computeVirtualScrollRange,\n rangesEqual,\n toVirtualScrollRangeChange,\n} from \"./virtual-scroll-range.js\";\nimport {\n computeActiveVirtualScrollSlotCount,\n computeVirtualScrollSlotCount,\n VirtualScrollRowShell,\n} from \"./VirtualScrollRowShell.js\";\nimport {\n clampScrollOffset,\n computeScrollOffsetForIndex,\n isSmoothScrollActive,\n normalizeScrollBehaviorOptions,\n normalizeScrollToIndexOptions,\n resolveScrollBehavior,\n} from \"./virtual-scroll-scroll.js\";\nimport {\n createVirtualScrollScrollState,\n supportsScrollEndEvent,\n} from \"./virtual-scroll-scroll-state.js\";\nimport { applyVirtualScrollRangeToDom } from \"./virtual-scroll-scroll-sync.js\";\nimport type {\n VirtualScrollHandle,\n VirtualScrollItem,\n VirtualScrollOwnProps,\n VirtualScrollRowSlot,\n VirtualScrollScrollBehaviorOptions,\n VirtualScrollScrollToIndexOptions,\n} from \"./types.js\";\nimport { VirtualScrollRowItem } from \"./VirtualScrollRowItem.js\";\nimport {\n VIRTUAL_SCROLL_OVERSCAN,\n VIRTUAL_SCROLL_ROW_HEIGHT,\n VIRTUAL_SCROLL_SCROLL_RESET_DELAY,\n} from \"./types.js\";\n\nfunction buildRowSlots<T extends VirtualScrollItem>(\n items: readonly T[],\n rangeStart: number,\n slotCount: number,\n): readonly VirtualScrollRowSlot<T>[] {\n const activeSlotCount = computeActiveVirtualScrollSlotCount(items.length, rangeStart, slotCount);\n return Array.from({ length: activeSlotCount }, (_, slotIndex) => {\n const index = rangeStart + slotIndex;\n return {\n index,\n item: items[index] ?? null,\n slotIndex,\n };\n });\n}\n\nexport function VirtualScroll<T extends VirtualScrollItem>(\n props: VirtualScrollOwnProps<T>,\n): ReactElement {\n const {\n items,\n height = 600,\n rowHeight = VIRTUAL_SCROLL_ROW_HEIGHT,\n overscan = VIRTUAL_SCROLL_OVERSCAN,\n className,\n testId,\n renderRow,\n scrollRef,\n estimateRowHeight,\n onRangeChange,\n role = \"list\",\n anchor = \"start\",\n followAppend = false,\n onScrollStateChange,\n isScrollingResetDelay = VIRTUAL_SCROLL_SCROLL_RESET_DELAY,\n } = props;\n\n const dynamicLayout = estimateRowHeight !== undefined;\n const ref = useRef<HTMLDivElement>(null);\n const scrollTopRef = useRef(0);\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const smoothRafRef = useRef(0);\n const lastRangeChangeRef = useRef<string>(\"\");\n const measuredHeightsRef = useRef(new Map<string, number>());\n const anchorSnapshotRef = useRef({\n firstItemId: items[0]?.id,\n itemCount: items.length,\n totalSize: 0,\n scrollTop: 0,\n });\n\n const [rangeVersion, setRangeVersion] = useState(0);\n const [measurementVersion, setMeasurementVersion] = useState(0);\n\n const measuredSize = useResizeObserver(ref);\n const viewportHeight = measuredSize?.height ?? height;\n\n const measurementStoreRef = useRef(\n createVirtualScrollMeasurementStore({\n itemCount: items.length,\n defaultRowHeight: rowHeight,\n ...(estimateRowHeight ? { estimateRowHeight } : {}),\n measuredHeights: measuredHeightsRef.current,\n itemIdAtIndex: (index) => itemsRef.current[index]?.id,\n }),\n );\n\n measurementStoreRef.current.syncItemCount(items.length);\n\n const scrollOptionsRef = useRef({\n dynamicLayout,\n itemCount: items.length,\n overscan,\n rowHeight,\n viewportHeight,\n });\n scrollOptionsRef.current = {\n dynamicLayout,\n itemCount: items.length,\n overscan,\n rowHeight,\n viewportHeight,\n };\n\n const onRangeChangeRef = useRef(onRangeChange);\n onRangeChangeRef.current = onRangeChange;\n\n const onScrollStateChangeRef = useRef(onScrollStateChange);\n onScrollStateChangeRef.current = onScrollStateChange;\n\n const computeRange = (): ReturnType<typeof computeVirtualScrollRange> => {\n const { dynamicLayout, itemCount, overscan, rowHeight, viewportHeight } =\n scrollOptionsRef.current;\n const scrollTop = scrollTopRef.current;\n\n if (dynamicLayout) {\n const store = measurementStoreRef.current;\n return computeDynamicVirtualScrollRange({\n scrollTop,\n viewportHeight,\n itemCount,\n overscan,\n findStartIndex: store.findStartIndex,\n findEndIndex: store.findEndIndex,\n getRowOffset: store.getRowOffset,\n });\n }\n\n return computeVirtualScrollRange({\n scrollTop,\n viewportHeight,\n itemCount,\n rowHeight,\n overscan,\n });\n };\n\n const emitRangeChange = (range: ReturnType<typeof computeVirtualScrollRange>): void => {\n const callback = onRangeChangeRef.current;\n if (!callback) return;\n const payload = toVirtualScrollRangeChange(range);\n const signature = `${payload.overscanStart}:${payload.overscanEnd}`;\n if (signature === lastRangeChangeRef.current) return;\n lastRangeChangeRef.current = signature;\n callback(payload);\n };\n\n const syncRangeFromScrollRef = useRef(() => {});\n\n syncRangeFromScrollRef.current = () => {\n const element = ref.current;\n if (!element) return;\n\n const scrollTop = element.scrollTop; // banned-read-ok: scroll position drives the virtual range.\n const previousRange = computeRange();\n scrollTopRef.current = scrollTop;\n\n const nextRange = computeRange();\n if (rangesEqual(previousRange, nextRange)) return;\n\n emitRangeChange(nextRange);\n\n const { dynamicLayout, itemCount, viewportHeight, rowHeight, overscan } =\n scrollOptionsRef.current;\n const slotCount = computeActiveVirtualScrollSlotCount(\n itemCount,\n nextRange.start,\n Math.max(\n nextRange.end - nextRange.start,\n computeVirtualScrollSlotCount(viewportHeight, rowHeight, overscan),\n ),\n );\n const store = measurementStoreRef.current;\n\n // Write range CSS vars on the scroll handler so rows move in the same frame as scrollTop.\n applyVirtualScrollRangeToDom(element, nextRange, {\n dynamicLayout,\n slotCount,\n getRowOffset: store.getRowOffset.bind(store),\n });\n\n // Commit the visible slice synchronously so content matches scroll position on large jumps.\n flushSync(() => {\n setRangeVersion((version) => version + 1);\n });\n };\n\n const iosControllerRef = useRef(\n createVirtualScrollIosScroll({\n enabled: detectTouchScrollEnvironment(),\n resetDelay: isScrollingResetDelay,\n }),\n );\n\n const applyScrollDeltaRef = useRef((_delta: number) => {});\n\n applyScrollDeltaRef.current = (delta: number) => {\n const element = ref.current;\n if (!element || delta === 0) return;\n element.scrollTop += delta; // banned-read-ok: preserve the viewport while rows resize.\n syncRangeFromScrollRef.current();\n };\n\n const applyScrollOffset = (\n offset: number,\n behavior: VirtualScrollScrollBehaviorOptions[\"behavior\"],\n ): void => {\n const element = ref.current;\n if (!element) return;\n\n const store = measurementStoreRef.current;\n const totalSize = dynamicLayout ? store.getTotalSize() : items.length * rowHeight;\n const clamped = clampScrollOffset(offset, totalSize, viewportHeight);\n const resolved = resolveScrollBehavior(behavior);\n\n if (typeof element.scrollTo === \"function\") {\n element.scrollTo({ top: clamped, behavior: resolved });\n } else {\n element.scrollTop = clamped; // banned-read-ok: native scroll fallback for this viewport.\n }\n syncRangeFromScrollRef.current();\n\n if (isSmoothScrollActive(behavior ?? \"auto\", element.scrollTop, clamped)) {\n // banned-read-ok: poll native smooth-scroll completion.\n if (smoothRafRef.current !== 0) cancelAnimationFrame(smoothRafRef.current);\n const tick = (): void => {\n syncRangeFromScrollRef.current();\n const node = ref.current;\n if (!node) {\n smoothRafRef.current = 0;\n return;\n }\n if (isSmoothScrollActive(\"smooth\", node.scrollTop, clamped)) {\n // banned-read-ok: poll native smooth-scroll completion.\n smoothRafRef.current = requestAnimationFrame(tick);\n return;\n }\n smoothRafRef.current = 0;\n };\n smoothRafRef.current = requestAnimationFrame(tick);\n }\n };\n\n const applyScrollOffsetRef = useRef(\n (_offset: number, _behavior: VirtualScrollScrollBehaviorOptions[\"behavior\"]) => {},\n );\n\n applyScrollOffsetRef.current = applyScrollOffset;\n\n useImperativeHandle(\n scrollRef,\n (): VirtualScrollHandle => ({\n get element() {\n return ref.current;\n },\n scrollToIndex(index: number, options?: VirtualScrollScrollToIndexOptions): void {\n const normalized = normalizeScrollToIndexOptions(options);\n const store = measurementStoreRef.current;\n const metrics = {\n getRowOffset: store.getRowOffset.bind(store),\n getRowHeight: store.getRowHeight.bind(store),\n getTotalSize: store.getTotalSize.bind(store),\n };\n const offset = computeScrollOffsetForIndex(\n index,\n normalized.align,\n metrics,\n scrollOptionsRef.current.viewportHeight,\n scrollTopRef.current,\n );\n applyScrollOffsetRef.current(offset, normalized.behavior);\n },\n scrollToOffset(offset: number, options?: VirtualScrollScrollBehaviorOptions): void {\n applyScrollOffsetRef.current(offset, normalizeScrollBehaviorOptions(options));\n },\n scrollToEnd(options?: VirtualScrollScrollBehaviorOptions): void {\n const store = measurementStoreRef.current;\n const totalSize = dynamicLayout\n ? store.getTotalSize()\n : scrollOptionsRef.current.itemCount * scrollOptionsRef.current.rowHeight;\n const offset = Math.max(0, totalSize - scrollOptionsRef.current.viewportHeight);\n applyScrollOffsetRef.current(offset, normalizeScrollBehaviorOptions(options));\n },\n }),\n [dynamicLayout],\n );\n\n const range = useMemo(() => {\n void rangeVersion;\n void measurementVersion;\n return computeRange();\n }, [rangeVersion, measurementVersion]);\n\n const totalSize = useMemo(() => {\n void measurementVersion;\n if (dynamicLayout) return measurementStoreRef.current.getTotalSize();\n return items.length * rowHeight;\n }, [dynamicLayout, items.length, measurementVersion, rowHeight]);\n\n const slotCount = useMemo(() => {\n if (items.length === 0) return 0;\n return Math.max(\n range.end - range.start,\n computeVirtualScrollSlotCount(viewportHeight, rowHeight, overscan),\n );\n }, [items.length, overscan, range.end, range.start, rowHeight, viewportHeight]);\n\n const rowSlots = useMemo(\n () => buildRowSlots(items, range.start, slotCount),\n [items, range.start, slotCount],\n );\n\n const handleRowMeasureRef = useRef((index: number, itemId: string, height: number) => {\n const store = measurementStoreRef.current;\n const previousHeight = store.getRowHeight(index);\n const rowOffset = store.getRowOffset(index);\n if (!store.setMeasuredHeight(itemId, index, height)) return;\n\n const adjustment = computeScrollAdjustmentForRowResize({\n scrollTop: scrollTopRef.current,\n rowOffset,\n previousHeight,\n nextHeight: height,\n });\n\n if (adjustment > 0) {\n const ios = iosControllerRef.current;\n if (ios.isTouchScrolling()) {\n ios.queueAdjustment(adjustment);\n } else {\n applyScrollDeltaRef.current(adjustment);\n }\n }\n\n setMeasurementVersion((version) => version + 1);\n });\n\n const rowsFragmentRef = useRef<FragmentInstance>(null);\n\n // One ResizeObserver for the whole pooled row set. React keeps the\n // subscription in sync as slots mount and unmount — pinned by\n // core/fragment-instance.test.tsx. Fixed layout never measures rows, so no\n // observer is created there at all.\n useEffect(() => {\n if (!dynamicLayout) return;\n const fragment = rowsFragmentRef.current;\n if (!fragment || typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const target = entry.target;\n if (!(target instanceof HTMLElement)) continue;\n const raw = target.dataset[\"uiifyRowIndex\"];\n if (raw === undefined) continue;\n const index = Number(raw);\n if (!Number.isInteger(index)) continue;\n const itemId = itemsRef.current[index]?.id;\n if (itemId === undefined) continue;\n handleRowMeasureRef.current(index, itemId, entry.contentRect.height);\n }\n });\n\n fragment.observeUsing(observer);\n return () => fragment.unobserveUsing(observer);\n }, [dynamicLayout]);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const scrollState = createVirtualScrollScrollState({\n resetDelay: isScrollingResetDelay,\n supportsScrollEnd: supportsScrollEndEvent(),\n onChange: (isScrolling) => {\n onScrollStateChangeRef.current?.({ isScrolling });\n if (!isScrolling) {\n iosControllerRef.current.flushAdjustments(applyScrollDeltaRef.current);\n }\n },\n });\n\n let onScroll: (() => void) | null = null;\n let onScrollEnd: (() => void) | null = null;\n const ios = iosControllerRef.current;\n const onTouchStart = (): void => ios.onTouchStart();\n const onTouchEnd = (): void => ios.onTouchEnd();\n\n onScroll = () => {\n scrollState.notifyScroll();\n syncRangeFromScrollRef.current();\n };\n element.addEventListener(\"scroll\", onScroll, { passive: true });\n if (supportsScrollEndEvent()) {\n onScrollEnd = () => {\n scrollState.notifyScrollEnd();\n syncRangeFromScrollRef.current();\n };\n element.addEventListener(\"scrollend\", onScrollEnd, { passive: true });\n }\n element.addEventListener(\"touchstart\", onTouchStart, { passive: true });\n element.addEventListener(\"touchend\", onTouchEnd, { passive: true });\n\n return () => {\n if (smoothRafRef.current !== 0) cancelAnimationFrame(smoothRafRef.current);\n if (onScroll) element.removeEventListener(\"scroll\", onScroll);\n if (onScrollEnd) element.removeEventListener(\"scrollend\", onScrollEnd);\n element.removeEventListener(\"touchstart\", onTouchStart);\n element.removeEventListener(\"touchend\", onTouchEnd);\n scrollState.dispose();\n };\n }, [isScrollingResetDelay]);\n\n useEffect(() => {\n const element = ref.current;\n const store = measurementStoreRef.current;\n const nextTotalSize = dynamicLayout ? store.getTotalSize() : items.length * rowHeight;\n const previous = anchorSnapshotRef.current;\n const nextSnapshot = {\n firstItemId: items[0]?.id,\n itemCount: items.length,\n totalSize: nextTotalSize,\n scrollTop: element?.scrollTop ?? scrollTopRef.current, // banned-read-ok: anchor snapshot reads native position.\n };\n\n const adjustment = resolveVirtualScrollAnchorAdjustment({\n anchor,\n followAppend,\n viewportHeight,\n previous,\n next: nextSnapshot,\n });\n\n if (adjustment && element) {\n if (adjustment.behavior === \"smooth\" && typeof element.scrollTo === \"function\") {\n element.scrollTo({\n top: element.scrollTop + adjustment.delta, // banned-read-ok: retain the anchored viewport.\n behavior: \"smooth\",\n });\n } else {\n element.scrollTop += adjustment.delta; // banned-read-ok: retain the anchored viewport.\n }\n syncRangeFromScrollRef.current();\n }\n\n anchorSnapshotRef.current = nextSnapshot;\n }, [anchor, followAppend, items, dynamicLayout, rowHeight, viewportHeight]);\n\n useEffect(() => {\n emitRangeChange(range);\n }, [range]);\n\n const scrollportStyle = {\n height,\n overflowY: \"auto\",\n \"--uiify-virtual-scroll-count\": items.length,\n \"--uiify-virtual-scroll-row-height\": `${rowHeight}px`,\n ...(dynamicLayout ? { \"--uiify-virtual-scroll-total-size\": `${totalSize}px` } : {}),\n } as CSSProperties;\n\n const spacerStyle = dynamicLayout\n ? undefined\n : ({\n \"--uiify-range-start\": range.start,\n } as CSSProperties);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n data-uiify-virtual-scroll=\"\"\n data-dynamic-layout={dynamicLayout ? \"\" : undefined}\n role={role}\n className={className}\n style={scrollportStyle}\n >\n <div data-part=\"spacer\" style={spacerStyle}>\n {rowSlots.map((slot) => {\n const store = measurementStoreRef.current;\n const rowOffset = dynamicLayout ? store.getRowOffset(slot.index) : undefined;\n const measuredRowHeight = dynamicLayout ? store.getRowHeight(slot.index) : undefined;\n\n return (\n <VirtualScrollRowShell\n key={`slot-${slot.slotIndex}`}\n slotIndex={slot.slotIndex}\n index={slot.index}\n itemCount={items.length}\n listRole={role}\n dynamicLayout={dynamicLayout}\n {...(rowOffset !== undefined ? { rowOffset } : {})}\n {...(measuredRowHeight !== undefined ? { rowHeight: measuredRowHeight } : {})}\n >\n {slot.item ? (\n <VirtualScrollRowItem item={slot.item} index={slot.index} renderRow={renderRow} />\n ) : null}\n </VirtualScrollRowShell>\n );\n })}\n </div>\n </div>\n );\n}\nVirtualScroll.displayName = \"VirtualScroll\";\n"],"mappings":"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","names":["dynamicLayout","overscan","rowHeight","viewportHeight","range","slotCount","totalSize","height"]}
1
+ {"version":3,"sources":["../../../src/components/virtual-scroll/VirtualScroll.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FragmentInstance,\n type ReactElement,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { useResizeObserver } from \"@gunkin/uiify/hooks\";\nimport { resolveVirtualScrollAnchorAdjustment } from \"./virtual-scroll-anchor.js\";\nimport { readScrollOffset, writeScrollOffset } from \"./virtual-scroll-axis.js\";\nimport {\n createVirtualScrollIosScroll,\n detectTouchScrollEnvironment,\n} from \"./virtual-scroll-ios.js\";\nimport {\n computeScrollAdjustmentForRowResize,\n createVirtualScrollMeasurementStore,\n} from \"./virtual-scroll-measurements.js\";\nimport {\n computeDynamicVirtualScrollRange,\n computeVirtualScrollRange,\n rangesEqual,\n toVirtualScrollRangeChange,\n} from \"./virtual-scroll-range.js\";\nimport {\n computeActiveVirtualScrollSlotCount,\n computeVirtualScrollSlotCount,\n VirtualScrollRowShell,\n} from \"./VirtualScrollRowShell.js\";\nimport {\n clampScrollOffset,\n computeScrollOffsetForIndex,\n isSmoothScrollActive,\n normalizeScrollBehaviorOptions,\n normalizeScrollToIndexOptions,\n resolveScrollBehavior,\n} from \"./virtual-scroll-scroll.js\";\nimport {\n createVirtualScrollScrollState,\n supportsScrollEndEvent,\n} from \"./virtual-scroll-scroll-state.js\";\nimport { applyVirtualScrollRangeToDom } from \"./virtual-scroll-scroll-sync.js\";\nimport type {\n VirtualScrollHandle,\n VirtualScrollItem,\n VirtualScrollOwnProps,\n VirtualScrollRowSlot,\n VirtualScrollScrollBehaviorOptions,\n VirtualScrollScrollToIndexOptions,\n} from \"./types.js\";\nimport { VirtualScrollRowItem } from \"./VirtualScrollRowItem.js\";\nimport {\n VIRTUAL_SCROLL_OVERSCAN,\n VIRTUAL_SCROLL_ROW_HEIGHT,\n VIRTUAL_SCROLL_SCROLL_RESET_DELAY,\n} from \"./types.js\";\n\nfunction buildRowSlots<T extends VirtualScrollItem>(\n items: readonly T[],\n rangeStart: number,\n slotCount: number,\n): readonly VirtualScrollRowSlot<T>[] {\n const activeSlotCount = computeActiveVirtualScrollSlotCount(items.length, rangeStart, slotCount);\n return Array.from({ length: activeSlotCount }, (_, slotIndex) => {\n const index = rangeStart + slotIndex;\n return {\n index,\n item: items[index] ?? null,\n slotIndex,\n };\n });\n}\n\nexport function VirtualScroll<T extends VirtualScrollItem>(\n props: VirtualScrollOwnProps<T>,\n): ReactElement {\n const {\n items,\n height = 600,\n rowHeight = VIRTUAL_SCROLL_ROW_HEIGHT,\n orientation = \"vertical\",\n overscan = VIRTUAL_SCROLL_OVERSCAN,\n className,\n testId,\n renderRow,\n scrollRef,\n estimateRowHeight,\n onRangeChange,\n role = \"list\",\n anchor = \"start\",\n followAppend = false,\n onScrollStateChange,\n isScrollingResetDelay = VIRTUAL_SCROLL_SCROLL_RESET_DELAY,\n } = props;\n\n const dynamicLayout = estimateRowHeight !== undefined;\n const horizontal = orientation === \"horizontal\";\n const ref = useRef<HTMLDivElement>(null);\n const scrollOffsetRef = useRef(0);\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const smoothRafRef = useRef(0);\n const lastRangeChangeRef = useRef<string>(\"\");\n const measuredHeightsRef = useRef(new Map<string, number>());\n const anchorSnapshotRef = useRef({\n firstItemId: items[0]?.id,\n itemCount: items.length,\n totalSize: 0,\n scrollTop: 0,\n });\n\n const [rangeVersion, setRangeVersion] = useState(0);\n const [measurementVersion, setMeasurementVersion] = useState(0);\n\n const measuredSize = useResizeObserver(ref);\n const viewportSize = (horizontal ? measuredSize?.width : measuredSize?.height) ?? height;\n\n const measurementStoreRef = useRef(\n createVirtualScrollMeasurementStore({\n itemCount: items.length,\n defaultRowHeight: rowHeight,\n ...(estimateRowHeight ? { estimateRowHeight } : {}),\n measuredHeights: measuredHeightsRef.current,\n itemIdAtIndex: (index) => itemsRef.current[index]?.id,\n }),\n );\n\n measurementStoreRef.current.syncItemCount(items.length);\n\n const scrollOptionsRef = useRef({\n dynamicLayout,\n itemCount: items.length,\n orientation,\n overscan,\n rowHeight,\n viewportSize,\n });\n scrollOptionsRef.current = {\n dynamicLayout,\n itemCount: items.length,\n orientation,\n overscan,\n rowHeight,\n viewportSize,\n };\n\n const onRangeChangeRef = useRef(onRangeChange);\n onRangeChangeRef.current = onRangeChange;\n\n const onScrollStateChangeRef = useRef(onScrollStateChange);\n onScrollStateChangeRef.current = onScrollStateChange;\n\n const computeRange = (): ReturnType<typeof computeVirtualScrollRange> => {\n const { dynamicLayout, itemCount, overscan, rowHeight, viewportSize } =\n scrollOptionsRef.current;\n const scrollTop = scrollOffsetRef.current;\n\n if (dynamicLayout) {\n const store = measurementStoreRef.current;\n return computeDynamicVirtualScrollRange({\n scrollTop,\n viewportHeight: viewportSize,\n itemCount,\n overscan,\n findStartIndex: store.findStartIndex,\n findEndIndex: store.findEndIndex,\n getRowOffset: store.getRowOffset,\n });\n }\n\n return computeVirtualScrollRange({\n scrollTop,\n viewportHeight: viewportSize,\n itemCount,\n rowHeight,\n overscan,\n });\n };\n\n const emitRangeChange = (range: ReturnType<typeof computeVirtualScrollRange>): void => {\n const callback = onRangeChangeRef.current;\n if (!callback) return;\n const payload = toVirtualScrollRangeChange(range);\n const signature = `${payload.overscanStart}:${payload.overscanEnd}`;\n if (signature === lastRangeChangeRef.current) return;\n lastRangeChangeRef.current = signature;\n callback(payload);\n };\n\n const syncRangeFromScrollRef = useRef(() => {});\n\n syncRangeFromScrollRef.current = () => {\n const element = ref.current;\n if (!element) return;\n\n const scrollOffset = readScrollOffset(element, scrollOptionsRef.current.orientation);\n const previousRange = computeRange();\n scrollOffsetRef.current = scrollOffset;\n\n const nextRange = computeRange();\n if (rangesEqual(previousRange, nextRange)) return;\n\n emitRangeChange(nextRange);\n\n const { dynamicLayout, itemCount, viewportSize, rowHeight, overscan } =\n scrollOptionsRef.current;\n const slotCount = computeActiveVirtualScrollSlotCount(\n itemCount,\n nextRange.start,\n Math.max(\n nextRange.end - nextRange.start,\n computeVirtualScrollSlotCount(viewportSize, rowHeight, overscan),\n ),\n );\n const store = measurementStoreRef.current;\n\n // Write range CSS vars on the scroll handler so rows move in the same frame as the scroll offset.\n applyVirtualScrollRangeToDom(element, nextRange, {\n dynamicLayout,\n slotCount,\n getRowOffset: store.getRowOffset.bind(store),\n });\n\n // Commit the visible slice synchronously so content matches scroll position on large jumps.\n flushSync(() => {\n setRangeVersion((version) => version + 1);\n });\n };\n\n const iosControllerRef = useRef(\n createVirtualScrollIosScroll({\n enabled: detectTouchScrollEnvironment(),\n resetDelay: isScrollingResetDelay,\n }),\n );\n\n const applyScrollDeltaRef = useRef((_delta: number) => {});\n\n applyScrollDeltaRef.current = (delta: number) => {\n const element = ref.current;\n if (!element || delta === 0) return;\n // Preserve the viewport while rows resize.\n const { orientation } = scrollOptionsRef.current;\n writeScrollOffset(element, orientation, readScrollOffset(element, orientation) + delta, \"auto\");\n syncRangeFromScrollRef.current();\n };\n\n const applyScrollOffset = (\n offset: number,\n behavior: VirtualScrollScrollBehaviorOptions[\"behavior\"],\n ): void => {\n const element = ref.current;\n if (!element) return;\n\n const store = measurementStoreRef.current;\n const totalSize = dynamicLayout ? store.getTotalSize() : items.length * rowHeight;\n const clamped = clampScrollOffset(offset, totalSize, viewportSize);\n writeScrollOffset(element, orientation, clamped, resolveScrollBehavior(behavior));\n syncRangeFromScrollRef.current();\n\n if (isSmoothScrollActive(behavior ?? \"auto\", readScrollOffset(element, orientation), clamped)) {\n if (smoothRafRef.current !== 0) cancelAnimationFrame(smoothRafRef.current);\n const tick = (): void => {\n syncRangeFromScrollRef.current();\n const node = ref.current;\n if (!node) {\n smoothRafRef.current = 0;\n return;\n }\n if (isSmoothScrollActive(\"smooth\", readScrollOffset(node, orientation), clamped)) {\n smoothRafRef.current = requestAnimationFrame(tick);\n return;\n }\n smoothRafRef.current = 0;\n };\n smoothRafRef.current = requestAnimationFrame(tick);\n }\n };\n\n const applyScrollOffsetRef = useRef(\n (_offset: number, _behavior: VirtualScrollScrollBehaviorOptions[\"behavior\"]) => {},\n );\n\n applyScrollOffsetRef.current = applyScrollOffset;\n\n useImperativeHandle(\n scrollRef,\n (): VirtualScrollHandle => ({\n get element() {\n return ref.current;\n },\n scrollToIndex(index: number, options?: VirtualScrollScrollToIndexOptions): void {\n const normalized = normalizeScrollToIndexOptions(options);\n const store = measurementStoreRef.current;\n const metrics = {\n getRowOffset: store.getRowOffset.bind(store),\n getRowHeight: store.getRowHeight.bind(store),\n getTotalSize: store.getTotalSize.bind(store),\n };\n const offset = computeScrollOffsetForIndex(\n index,\n normalized.align,\n metrics,\n scrollOptionsRef.current.viewportSize,\n scrollOffsetRef.current,\n );\n applyScrollOffsetRef.current(offset, normalized.behavior);\n },\n scrollToOffset(offset: number, options?: VirtualScrollScrollBehaviorOptions): void {\n applyScrollOffsetRef.current(offset, normalizeScrollBehaviorOptions(options));\n },\n scrollToEnd(options?: VirtualScrollScrollBehaviorOptions): void {\n const store = measurementStoreRef.current;\n const totalSize = dynamicLayout\n ? store.getTotalSize()\n : scrollOptionsRef.current.itemCount * scrollOptionsRef.current.rowHeight;\n const offset = Math.max(0, totalSize - scrollOptionsRef.current.viewportSize);\n applyScrollOffsetRef.current(offset, normalizeScrollBehaviorOptions(options));\n },\n }),\n [dynamicLayout],\n );\n\n const range = useMemo(() => {\n void rangeVersion;\n void measurementVersion;\n return computeRange();\n }, [rangeVersion, measurementVersion]);\n\n const totalSize = useMemo(() => {\n void measurementVersion;\n if (dynamicLayout) return measurementStoreRef.current.getTotalSize();\n return items.length * rowHeight;\n }, [dynamicLayout, items.length, measurementVersion, rowHeight]);\n\n const slotCount = useMemo(() => {\n if (items.length === 0) return 0;\n return Math.max(\n range.end - range.start,\n computeVirtualScrollSlotCount(viewportSize, rowHeight, overscan),\n );\n }, [items.length, overscan, range.end, range.start, rowHeight, viewportSize]);\n\n const rowSlots = useMemo(\n () => buildRowSlots(items, range.start, slotCount),\n [items, range.start, slotCount],\n );\n\n const handleRowMeasureRef = useRef((index: number, itemId: string, height: number) => {\n const store = measurementStoreRef.current;\n const previousHeight = store.getRowHeight(index);\n const rowOffset = store.getRowOffset(index);\n if (!store.setMeasuredHeight(itemId, index, height)) return;\n\n const adjustment = computeScrollAdjustmentForRowResize({\n scrollTop: scrollOffsetRef.current,\n rowOffset,\n previousHeight,\n nextHeight: height,\n });\n\n if (adjustment > 0) {\n const ios = iosControllerRef.current;\n if (ios.isTouchScrolling()) {\n ios.queueAdjustment(adjustment);\n } else {\n applyScrollDeltaRef.current(adjustment);\n }\n }\n\n setMeasurementVersion((version) => version + 1);\n });\n\n const rowsFragmentRef = useRef<FragmentInstance>(null);\n\n // One ResizeObserver for the whole pooled row set. React keeps the\n // subscription in sync as slots mount and unmount — pinned by\n // core/fragment-instance.test.tsx. Fixed layout never measures rows, so no\n // observer is created there at all.\n useEffect(() => {\n if (!dynamicLayout) return;\n const fragment = rowsFragmentRef.current;\n if (!fragment || typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const target = entry.target;\n if (!(target instanceof HTMLElement)) continue;\n const raw = target.dataset[\"uiifyRowIndex\"];\n if (raw === undefined) continue;\n const index = Number(raw);\n if (!Number.isInteger(index)) continue;\n const itemId = itemsRef.current[index]?.id;\n if (itemId === undefined) continue;\n const size = horizontal ? entry.contentRect.width : entry.contentRect.height;\n handleRowMeasureRef.current(index, itemId, size);\n }\n });\n\n fragment.observeUsing(observer);\n return () => fragment.unobserveUsing(observer);\n }, [dynamicLayout, horizontal]);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const scrollState = createVirtualScrollScrollState({\n resetDelay: isScrollingResetDelay,\n supportsScrollEnd: supportsScrollEndEvent(),\n onChange: (isScrolling) => {\n onScrollStateChangeRef.current?.({ isScrolling });\n if (!isScrolling) {\n iosControllerRef.current.flushAdjustments(applyScrollDeltaRef.current);\n }\n },\n });\n\n let onScroll: (() => void) | null = null;\n let onScrollEnd: (() => void) | null = null;\n const ios = iosControllerRef.current;\n const onTouchStart = (): void => ios.onTouchStart();\n const onTouchEnd = (): void => ios.onTouchEnd();\n\n onScroll = () => {\n scrollState.notifyScroll();\n syncRangeFromScrollRef.current();\n };\n element.addEventListener(\"scroll\", onScroll, { passive: true });\n if (supportsScrollEndEvent()) {\n onScrollEnd = () => {\n scrollState.notifyScrollEnd();\n syncRangeFromScrollRef.current();\n };\n element.addEventListener(\"scrollend\", onScrollEnd, { passive: true });\n }\n element.addEventListener(\"touchstart\", onTouchStart, { passive: true });\n element.addEventListener(\"touchend\", onTouchEnd, { passive: true });\n\n return () => {\n if (smoothRafRef.current !== 0) cancelAnimationFrame(smoothRafRef.current);\n if (onScroll) element.removeEventListener(\"scroll\", onScroll);\n if (onScrollEnd) element.removeEventListener(\"scrollend\", onScrollEnd);\n element.removeEventListener(\"touchstart\", onTouchStart);\n element.removeEventListener(\"touchend\", onTouchEnd);\n scrollState.dispose();\n };\n }, [isScrollingResetDelay]);\n\n useEffect(() => {\n const element = ref.current;\n const store = measurementStoreRef.current;\n const nextTotalSize = dynamicLayout ? store.getTotalSize() : items.length * rowHeight;\n const previous = anchorSnapshotRef.current;\n const scrollOffset = element ? readScrollOffset(element, orientation) : scrollOffsetRef.current;\n const nextSnapshot = {\n firstItemId: items[0]?.id,\n itemCount: items.length,\n totalSize: nextTotalSize,\n scrollTop: scrollOffset,\n };\n\n const adjustment = resolveVirtualScrollAnchorAdjustment({\n anchor,\n followAppend,\n viewportHeight: viewportSize,\n previous,\n next: nextSnapshot,\n });\n\n if (adjustment && element) {\n // Retain the anchored viewport.\n writeScrollOffset(element, orientation, scrollOffset + adjustment.delta, adjustment.behavior);\n syncRangeFromScrollRef.current();\n }\n\n anchorSnapshotRef.current = nextSnapshot;\n }, [anchor, followAppend, items, dynamicLayout, orientation, rowHeight, viewportSize]);\n\n useEffect(() => {\n emitRangeChange(range);\n }, [range]);\n\n const scrollportStyle = {\n height,\n overflowX: horizontal ? \"auto\" : undefined,\n overflowY: horizontal ? \"hidden\" : \"auto\",\n \"--uiify-virtual-scroll-count\": items.length,\n \"--uiify-virtual-scroll-row-height\": `${rowHeight}px`,\n ...(dynamicLayout ? { \"--uiify-virtual-scroll-total-size\": `${totalSize}px` } : {}),\n } as CSSProperties;\n\n const spacerStyle = dynamicLayout\n ? undefined\n : ({\n \"--uiify-range-start\": range.start,\n } as CSSProperties);\n\n return (\n <div\n ref={ref}\n data-testid={testId}\n data-uiify-virtual-scroll=\"\"\n data-dynamic-layout={dynamicLayout ? \"\" : undefined}\n data-orientation={orientation}\n role={role}\n className={className}\n style={scrollportStyle}\n >\n <div data-part=\"spacer\" style={spacerStyle}>\n {rowSlots.map((slot) => {\n const store = measurementStoreRef.current;\n const rowOffset = dynamicLayout ? store.getRowOffset(slot.index) : undefined;\n const measuredRowHeight = dynamicLayout ? store.getRowHeight(slot.index) : undefined;\n\n return (\n <VirtualScrollRowShell\n key={`slot-${slot.slotIndex}`}\n slotIndex={slot.slotIndex}\n index={slot.index}\n itemCount={items.length}\n listRole={role}\n dynamicLayout={dynamicLayout}\n {...(rowOffset !== undefined ? { rowOffset } : {})}\n {...(measuredRowHeight !== undefined ? { rowHeight: measuredRowHeight } : {})}\n >\n {slot.item ? (\n <VirtualScrollRowItem item={slot.item} index={slot.index} renderRow={renderRow} />\n ) : null}\n </VirtualScrollRowShell>\n );\n })}\n </div>\n </div>\n );\n}\nVirtualScroll.displayName = \"VirtualScroll\";\n"],"mappings":"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","names":["dynamicLayout","overscan","rowHeight","viewportSize","range","slotCount","orientation","totalSize","height"]}
@@ -1,4 +1,4 @@
1
1
  export { VirtualScroll } from "./VirtualScroll.js";
2
- export type { VirtualScrollAnchor, VirtualScrollHandle, VirtualScrollItem, VirtualScrollListRole, VirtualScrollOwnProps, VirtualScrollRangeChange, VirtualScrollRowSlot, VirtualScrollScrollAlign, VirtualScrollScrollBehavior, VirtualScrollScrollBehaviorOptions, VirtualScrollScrollState, VirtualScrollScrollToIndexOptions, } from "./types.js";
2
+ export type { VirtualScrollAnchor, VirtualScrollHandle, VirtualScrollItem, VirtualScrollListRole, VirtualScrollOrientation, VirtualScrollOwnProps, VirtualScrollRangeChange, VirtualScrollRowSlot, VirtualScrollScrollAlign, VirtualScrollScrollBehavior, VirtualScrollScrollBehaviorOptions, VirtualScrollScrollState, VirtualScrollScrollToIndexOptions, } from "./types.js";
3
3
  export { VIRTUAL_SCROLL_ANCHOR_THRESHOLD, VIRTUAL_SCROLL_OVERSCAN, VIRTUAL_SCROLL_ROW_HEIGHT, VIRTUAL_SCROLL_SCROLL_RESET_DELAY, } from "./types.js";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC3B,kCAAkC,EAClC,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,EACvB,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC3B,kCAAkC,EAClC,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,EACvB,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/virtual-scroll/index.ts"],"sourcesContent":["export { VirtualScroll } from \"./VirtualScroll.js\";\nexport type {\n VirtualScrollAnchor,\n VirtualScrollHandle,\n VirtualScrollItem,\n VirtualScrollListRole,\n VirtualScrollOwnProps,\n VirtualScrollRangeChange,\n VirtualScrollRowSlot,\n VirtualScrollScrollAlign,\n VirtualScrollScrollBehavior,\n VirtualScrollScrollBehaviorOptions,\n VirtualScrollScrollState,\n VirtualScrollScrollToIndexOptions,\n} from \"./types.js\";\nexport {\n VIRTUAL_SCROLL_ANCHOR_THRESHOLD,\n VIRTUAL_SCROLL_OVERSCAN,\n VIRTUAL_SCROLL_ROW_HEIGHT,\n VIRTUAL_SCROLL_SCROLL_RESET_DELAY,\n} from \"./types.js\";\n"],"mappings":"AAAA,SAAS,qBAAqB;AAe9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/virtual-scroll/index.ts"],"sourcesContent":["export { VirtualScroll } from \"./VirtualScroll.js\";\nexport type {\n VirtualScrollAnchor,\n VirtualScrollHandle,\n VirtualScrollItem,\n VirtualScrollListRole,\n VirtualScrollOrientation,\n VirtualScrollOwnProps,\n VirtualScrollRangeChange,\n VirtualScrollRowSlot,\n VirtualScrollScrollAlign,\n VirtualScrollScrollBehavior,\n VirtualScrollScrollBehaviorOptions,\n VirtualScrollScrollState,\n VirtualScrollScrollToIndexOptions,\n} from \"./types.js\";\nexport {\n VIRTUAL_SCROLL_ANCHOR_THRESHOLD,\n VIRTUAL_SCROLL_OVERSCAN,\n VIRTUAL_SCROLL_ROW_HEIGHT,\n VIRTUAL_SCROLL_SCROLL_RESET_DELAY,\n} from \"./types.js\";\n"],"mappings":"AAAA,SAAS,qBAAqB;AAgB9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
@@ -12,6 +12,8 @@ export interface VirtualScrollItem {
12
12
  }
13
13
  export type VirtualScrollListRole = "list" | "grid";
14
14
  export type VirtualScrollAnchor = "start" | "end";
15
+ /** Scroll axis. Row size props (`rowHeight`, `estimateRowHeight`) measure along this axis. */
16
+ export type VirtualScrollOrientation = "vertical" | "horizontal";
15
17
  export type VirtualScrollScrollAlign = "start" | "center" | "end" | "auto";
16
18
  export type VirtualScrollScrollBehavior = "auto" | "instant" | "smooth";
17
19
  export interface VirtualScrollScrollBehaviorOptions {
@@ -41,8 +43,11 @@ export interface VirtualScrollHandle {
41
43
  }
42
44
  export interface VirtualScrollOwnProps<T extends VirtualScrollItem> {
43
45
  readonly items: readonly T[];
46
+ /** Scrollport height; also the viewport extent used before the first resize measurement. */
44
47
  readonly height?: number;
48
+ /** Fixed item size along the scroll axis — row height when vertical, item width when horizontal. */
45
49
  readonly rowHeight?: number;
50
+ readonly orientation?: VirtualScrollOrientation;
46
51
  readonly overscan?: number;
47
52
  readonly className?: string;
48
53
  readonly testId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/virtual-scroll/types.ts"],"sourcesContent":["import type { ReactNode, Ref } from \"react\";\n\n/** Fixed row height — default for scroll math when `estimateRowHeight` is omitted. */\nexport const VIRTUAL_SCROLL_ROW_HEIGHT = 64;\n\n/** Overscan rows above and below the viewport to avoid flicker during fast scroll. */\nexport const VIRTUAL_SCROLL_OVERSCAN = 5;\n\n/** Default delay before treating scroll as settled when `scrollend` is unavailable. */\nexport const VIRTUAL_SCROLL_SCROLL_RESET_DELAY = 150;\n\n/** Distance from list bottom treated as \"pinned to end\" for anchor/follow. */\nexport const VIRTUAL_SCROLL_ANCHOR_THRESHOLD = 1;\n\nexport interface VirtualScrollItem {\n readonly id: string;\n}\n\nexport type VirtualScrollListRole = \"list\" | \"grid\";\n\nexport type VirtualScrollAnchor = \"start\" | \"end\";\n\nexport type VirtualScrollScrollAlign = \"start\" | \"center\" | \"end\" | \"auto\";\n\nexport type VirtualScrollScrollBehavior = \"auto\" | \"instant\" | \"smooth\";\n\nexport interface VirtualScrollScrollBehaviorOptions {\n readonly behavior?: VirtualScrollScrollBehavior;\n}\n\nexport interface VirtualScrollScrollToIndexOptions extends VirtualScrollScrollBehaviorOptions {\n readonly align?: VirtualScrollScrollAlign;\n}\n\nexport interface VirtualScrollRangeChange {\n /** First visible row index (no overscan). */\n readonly startIndex: number;\n /** Last visible row index, inclusive (no overscan). */\n readonly endIndex: number;\n /** First rendered row index including overscan. */\n readonly overscanStart: number;\n /** Last rendered row index, inclusive, including overscan. */\n readonly overscanEnd: number;\n}\n\nexport interface VirtualScrollScrollState {\n readonly isScrolling: boolean;\n}\n\nexport interface VirtualScrollHandle {\n readonly element: HTMLDivElement | null;\n scrollToIndex(index: number, options?: VirtualScrollScrollToIndexOptions): void;\n scrollToOffset(offset: number, options?: VirtualScrollScrollBehaviorOptions): void;\n scrollToEnd(options?: VirtualScrollScrollBehaviorOptions): void;\n}\n\nexport interface VirtualScrollOwnProps<T extends VirtualScrollItem> {\n readonly items: readonly T[];\n readonly height?: number;\n readonly rowHeight?: number;\n readonly overscan?: number;\n readonly className?: string;\n readonly testId?: string;\n readonly renderRow: (item: T, index: number) => ReactNode;\n readonly scrollRef?: Ref<VirtualScrollHandle>;\n readonly estimateRowHeight?: (index: number) => number;\n readonly onRangeChange?: (range: VirtualScrollRangeChange) => void;\n readonly role?: VirtualScrollListRole;\n readonly anchor?: VirtualScrollAnchor;\n readonly followAppend?: boolean | \"smooth\";\n readonly onScrollStateChange?: (state: VirtualScrollScrollState) => void;\n readonly isScrollingResetDelay?: number;\n}\n\nexport interface VirtualScrollRowSlot<T extends VirtualScrollItem> {\n readonly slotIndex: number;\n readonly index: number;\n readonly item: T | null;\n}\n"],"mappings":"AAGO,MAAM,4BAA4B;AAGlC,MAAM,0BAA0B;AAGhC,MAAM,oCAAoC;AAG1C,MAAM,kCAAkC;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/virtual-scroll/types.ts"],"sourcesContent":["import type { ReactNode, Ref } from \"react\";\n\n/** Fixed row height — default for scroll math when `estimateRowHeight` is omitted. */\nexport const VIRTUAL_SCROLL_ROW_HEIGHT = 64;\n\n/** Overscan rows above and below the viewport to avoid flicker during fast scroll. */\nexport const VIRTUAL_SCROLL_OVERSCAN = 5;\n\n/** Default delay before treating scroll as settled when `scrollend` is unavailable. */\nexport const VIRTUAL_SCROLL_SCROLL_RESET_DELAY = 150;\n\n/** Distance from list bottom treated as \"pinned to end\" for anchor/follow. */\nexport const VIRTUAL_SCROLL_ANCHOR_THRESHOLD = 1;\n\nexport interface VirtualScrollItem {\n readonly id: string;\n}\n\nexport type VirtualScrollListRole = \"list\" | \"grid\";\n\nexport type VirtualScrollAnchor = \"start\" | \"end\";\n\n/** Scroll axis. Row size props (`rowHeight`, `estimateRowHeight`) measure along this axis. */\nexport type VirtualScrollOrientation = \"vertical\" | \"horizontal\";\n\nexport type VirtualScrollScrollAlign = \"start\" | \"center\" | \"end\" | \"auto\";\n\nexport type VirtualScrollScrollBehavior = \"auto\" | \"instant\" | \"smooth\";\n\nexport interface VirtualScrollScrollBehaviorOptions {\n readonly behavior?: VirtualScrollScrollBehavior;\n}\n\nexport interface VirtualScrollScrollToIndexOptions extends VirtualScrollScrollBehaviorOptions {\n readonly align?: VirtualScrollScrollAlign;\n}\n\nexport interface VirtualScrollRangeChange {\n /** First visible row index (no overscan). */\n readonly startIndex: number;\n /** Last visible row index, inclusive (no overscan). */\n readonly endIndex: number;\n /** First rendered row index including overscan. */\n readonly overscanStart: number;\n /** Last rendered row index, inclusive, including overscan. */\n readonly overscanEnd: number;\n}\n\nexport interface VirtualScrollScrollState {\n readonly isScrolling: boolean;\n}\n\nexport interface VirtualScrollHandle {\n readonly element: HTMLDivElement | null;\n scrollToIndex(index: number, options?: VirtualScrollScrollToIndexOptions): void;\n scrollToOffset(offset: number, options?: VirtualScrollScrollBehaviorOptions): void;\n scrollToEnd(options?: VirtualScrollScrollBehaviorOptions): void;\n}\n\nexport interface VirtualScrollOwnProps<T extends VirtualScrollItem> {\n readonly items: readonly T[];\n /** Scrollport height; also the viewport extent used before the first resize measurement. */\n readonly height?: number;\n /** Fixed item size along the scroll axis — row height when vertical, item width when horizontal. */\n readonly rowHeight?: number;\n readonly orientation?: VirtualScrollOrientation;\n readonly overscan?: number;\n readonly className?: string;\n readonly testId?: string;\n readonly renderRow: (item: T, index: number) => ReactNode;\n readonly scrollRef?: Ref<VirtualScrollHandle>;\n readonly estimateRowHeight?: (index: number) => number;\n readonly onRangeChange?: (range: VirtualScrollRangeChange) => void;\n readonly role?: VirtualScrollListRole;\n readonly anchor?: VirtualScrollAnchor;\n readonly followAppend?: boolean | \"smooth\";\n readonly onScrollStateChange?: (state: VirtualScrollScrollState) => void;\n readonly isScrollingResetDelay?: number;\n}\n\nexport interface VirtualScrollRowSlot<T extends VirtualScrollItem> {\n readonly slotIndex: number;\n readonly index: number;\n readonly item: T | null;\n}\n"],"mappings":"AAGO,MAAM,4BAA4B;AAGlC,MAAM,0BAA0B;AAGhC,MAAM,oCAAoC;AAG1C,MAAM,kCAAkC;","names":[]}
@@ -0,0 +1,9 @@
1
+ import type { VirtualScrollOrientation } from "./types.js";
2
+ /**
3
+ * Logical scroll offset along the list axis. RTL `scrollLeft` runs from 0 to
4
+ * `-max`, so its magnitude is the distance from the inline-start edge.
5
+ */
6
+ export declare function readScrollOffset(element: HTMLElement, orientation: VirtualScrollOrientation): number;
7
+ /** Move the scrollport to a logical offset along the list axis. */
8
+ export declare function writeScrollOffset(element: HTMLElement, orientation: VirtualScrollOrientation, offset: number, behavior: ScrollBehavior): void;
9
+ //# sourceMappingURL=virtual-scroll-axis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-scroll-axis.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-scroll/virtual-scroll-axis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,wBAAwB,GACpC,MAAM,CAIR;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,wBAAwB,EACrC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,GACvB,IAAI,CAWN"}
@@ -0,0 +1,18 @@
1
+ function readScrollOffset(element, orientation) {
2
+ return orientation === "horizontal" ? Math.abs(element.scrollLeft) : element.scrollTop;
3
+ }
4
+ function writeScrollOffset(element, orientation, offset, behavior) {
5
+ if (orientation === "horizontal") {
6
+ const left = element.matches(":dir(rtl)") ? -offset : offset;
7
+ if (typeof element.scrollTo === "function") element.scrollTo({ left, behavior });
8
+ else element.scrollLeft = left;
9
+ return;
10
+ }
11
+ if (typeof element.scrollTo === "function") element.scrollTo({ top: offset, behavior });
12
+ else element.scrollTop = offset;
13
+ }
14
+ export {
15
+ readScrollOffset,
16
+ writeScrollOffset
17
+ };
18
+ //# sourceMappingURL=virtual-scroll-axis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/virtual-scroll/virtual-scroll-axis.ts"],"sourcesContent":["import type { VirtualScrollOrientation } from \"./types.js\";\n\n/**\n * Logical scroll offset along the list axis. RTL `scrollLeft` runs from 0 to\n * `-max`, so its magnitude is the distance from the inline-start edge.\n */\nexport function readScrollOffset(\n element: HTMLElement,\n orientation: VirtualScrollOrientation,\n): number {\n return orientation === \"horizontal\"\n ? Math.abs(element.scrollLeft) // banned-read-ok: scroll position drives the virtual range.\n : element.scrollTop; // banned-read-ok: scroll position drives the virtual range.\n}\n\n/** Move the scrollport to a logical offset along the list axis. */\nexport function writeScrollOffset(\n element: HTMLElement,\n orientation: VirtualScrollOrientation,\n offset: number,\n behavior: ScrollBehavior,\n): void {\n if (orientation === \"horizontal\") {\n // `:dir()` resolves from the DOM `dir` attribute — no style or layout read.\n const left = element.matches(\":dir(rtl)\") ? -offset : offset;\n if (typeof element.scrollTo === \"function\") element.scrollTo({ left, behavior });\n else element.scrollLeft = left; // banned-read-ok: native scroll fallback for this viewport.\n return;\n }\n\n if (typeof element.scrollTo === \"function\") element.scrollTo({ top: offset, behavior });\n else element.scrollTop = offset; // banned-read-ok: native scroll fallback for this viewport.\n}\n"],"mappings":"AAMO,SAAS,iBACd,SACA,aACQ;AACR,SAAO,gBAAgB,eACnB,KAAK,IAAI,QAAQ,UAAU,IAC3B,QAAQ;AACd;AAGO,SAAS,kBACd,SACA,aACA,QACA,UACM;AACN,MAAI,gBAAgB,cAAc;AAEhC,UAAM,OAAO,QAAQ,QAAQ,WAAW,IAAI,CAAC,SAAS;AACtD,QAAI,OAAO,QAAQ,aAAa,WAAY,SAAQ,SAAS,EAAE,MAAM,SAAS,CAAC;AAAA,QAC1E,SAAQ,aAAa;AAC1B;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,aAAa,WAAY,SAAQ,SAAS,EAAE,KAAK,QAAQ,SAAS,CAAC;AAAA,MACjF,SAAQ,YAAY;AAC3B;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gunkin/uiify",
3
- "version": "0.0.2-alpha",
3
+ "version": "0.0.3-alpha",
4
4
  "description": "Native-first, accessible React 19 components that work before hydration.",
5
5
  "keywords": [
6
6
  "accessibility",