@typlog/ui 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/addons.js CHANGED
@@ -1,492 +1,1840 @@
1
- import { defineComponent, computed, openBlock, createBlock, unref, normalizeClass, withCtx, createCommentVNode, renderSlot, createElementBlock, createElementVNode, toDisplayString, Fragment, renderList, createVNode, ref, onMounted, withDirectives, withKeys, mergeProps, withModifiers, vShow, createTextVNode, normalizeStyle, useTemplateRef, onBeforeUnmount } from "vue";
1
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onScopeDispose, openBlock, ref, renderList, renderSlot, shallowRef, toDisplayString, triggerRef, unref, useTemplateRef, watch, withCtx } from "vue";
2
+ import { Primitive } from "reka-ui";
2
3
  import { Icon } from "@iconify/vue";
3
- import { Primitive, injectDialogRootContext } from "reka-ui";
4
- import { buildPropsClass, TextField, Button, Tooltip, Pagination } from "./components";
5
- const BRAND_ICONS = {
6
- google: "logos:google-icon",
7
- facebook: "simple-icons:facebook",
8
- x: "simple-icons:x",
9
- github: "simple-icons:github",
10
- apple: "simple-icons:apple",
11
- slack: "logos:slack-icon",
12
- figma: "logos:figma"
4
+ import { Button, TextField, buildPropsClass } from "@typlog/ui";
5
+ //#region src/addons/button/SocialButton.vue?vue&type=script&setup=true&lang.ts
6
+ var BRAND_ICONS = {
7
+ google: "logos:google-icon",
8
+ facebook: "simple-icons:facebook",
9
+ x: "simple-icons:x",
10
+ github: "simple-icons:github",
11
+ apple: "simple-icons:apple",
12
+ slack: "logos:slack-icon",
13
+ figma: "logos:figma"
13
14
  };
14
- const _sfc_main$3 = /* @__PURE__ */ defineComponent({
15
- __name: "SocialButton",
16
- props: {
17
- brand: {},
18
- variant: { default: "classic" },
19
- radius: {},
20
- size: { default: "2" },
21
- disabled: { type: Boolean },
22
- asChild: { type: Boolean },
23
- as: { default: "button" }
24
- },
25
- setup(__props) {
26
- const props = __props;
27
- const resetClass = buildPropsClass(props, ["size", "brand", "variant"]);
28
- const brandIcon = computed(() => {
29
- return BRAND_ICONS[props.brand];
30
- });
31
- return (_ctx, _cache) => {
32
- return openBlock(), createBlock(unref(Primitive), {
33
- class: normalizeClass(["ui-Button ui-SocialButton", unref(resetClass)]),
34
- "as-child": props.asChild,
35
- as: props.as,
36
- "data-radius": props.radius,
37
- "data-disabled": props.disabled ? true : void 0
38
- }, {
39
- default: withCtx(() => [
40
- brandIcon.value ? (openBlock(), createBlock(unref(Icon), {
41
- key: 0,
42
- icon: brandIcon.value
43
- }, null, 8, ["icon"])) : createCommentVNode("", true),
44
- renderSlot(_ctx.$slots, "default")
45
- ]),
46
- _: 3
47
- }, 8, ["class", "as-child", "as", "data-radius", "data-disabled"]);
48
- };
49
- }
15
+ //#endregion
16
+ //#region src/addons/button/SocialButton.vue
17
+ var SocialButton_default = /* @__PURE__ */ defineComponent({
18
+ __name: "SocialButton",
19
+ props: {
20
+ brand: {},
21
+ variant: { default: "classic" },
22
+ radius: {},
23
+ size: { default: "2" },
24
+ disabled: { type: Boolean },
25
+ asChild: { type: Boolean },
26
+ as: { default: "button" }
27
+ },
28
+ setup(__props) {
29
+ const props = __props;
30
+ const resetClass = buildPropsClass(props, [
31
+ "size",
32
+ "brand",
33
+ "variant"
34
+ ]);
35
+ const brandIcon = computed(() => {
36
+ return BRAND_ICONS[props.brand];
37
+ });
38
+ return (_ctx, _cache) => {
39
+ return openBlock(), createBlock(unref(Primitive), {
40
+ class: normalizeClass(["ui-Button ui-SocialButton", unref(resetClass)]),
41
+ "as-child": props.asChild,
42
+ as: props.as,
43
+ "data-radius": props.radius,
44
+ "data-disabled": props.disabled ? true : void 0
45
+ }, {
46
+ default: withCtx(() => [brandIcon.value ? (openBlock(), createBlock(unref(Icon), {
47
+ key: 0,
48
+ icon: brandIcon.value
49
+ }, null, 8, ["icon"])) : createCommentVNode("", true), renderSlot(_ctx.$slots, "default")]),
50
+ _: 3
51
+ }, 8, [
52
+ "class",
53
+ "as-child",
54
+ "as",
55
+ "data-radius",
56
+ "data-disabled"
57
+ ]);
58
+ };
59
+ }
50
60
  });
51
- const _hoisted_1$1 = {
52
- type: "button",
53
- class: "ui-IconifySample"
61
+ //#endregion
62
+ //#region ../../node_modules/.pnpm/@tanstack+virtual-core@3.17.8/node_modules/@tanstack/virtual-core/dist/esm/lazy-measurements.js
63
+ function createLazyMeasurementsView(count, flat, getItemKey) {
64
+ const cache = new Array(count);
65
+ return new Proxy(cache, { get(target, prop, receiver) {
66
+ if (typeof prop === "string") {
67
+ const c = prop.charCodeAt(0);
68
+ if (c >= 48 && c <= 57) {
69
+ const i = +prop;
70
+ if (Number.isInteger(i) && i >= 0 && i < count) {
71
+ let v = target[i];
72
+ if (!v) {
73
+ const s = flat[i * 2];
74
+ v = target[i] = {
75
+ index: i,
76
+ key: getItemKey(i),
77
+ start: s,
78
+ size: flat[i * 2 + 1],
79
+ end: s + flat[i * 2 + 1],
80
+ lane: 0
81
+ };
82
+ }
83
+ return v;
84
+ }
85
+ }
86
+ if (prop === "length") return count;
87
+ }
88
+ return Reflect.get(target, prop, receiver);
89
+ } });
90
+ }
91
+ //#endregion
92
+ //#region ../../node_modules/.pnpm/@tanstack+virtual-core@3.17.8/node_modules/@tanstack/virtual-core/dist/esm/utils.js
93
+ function memo(getDeps, fn, opts) {
94
+ let deps = opts.initialDeps ?? [];
95
+ let result;
96
+ let isInitial = true;
97
+ function memoizedFunction() {
98
+ var _a;
99
+ const debugEnabled = process.env.NODE_ENV !== "production" && !!opts.key && !!((_a = opts.debug) == null ? void 0 : _a.call(opts));
100
+ let depTime = 0;
101
+ if (debugEnabled) depTime = Date.now();
102
+ const newDeps = getDeps();
103
+ if (!(newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep))) return result;
104
+ deps = newDeps;
105
+ let resultTime = 0;
106
+ if (debugEnabled) resultTime = Date.now();
107
+ result = fn(...newDeps);
108
+ if (debugEnabled) {
109
+ const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
110
+ const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
111
+ const resultFpsPercentage = resultEndTime / 16;
112
+ const pad = (str, num) => {
113
+ str = String(str);
114
+ while (str.length < num) str = " " + str;
115
+ return str;
116
+ };
117
+ console.info(`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`, `
118
+ font-size: .6rem;
119
+ font-weight: bold;
120
+ color: hsl(${Math.max(0, Math.min(120 - 120 * resultFpsPercentage, 120))}deg 100% 31%);`, opts == null ? void 0 : opts.key);
121
+ }
122
+ if ((opts == null ? void 0 : opts.onChange) && !(isInitial && opts.skipInitialOnChange)) opts.onChange(result);
123
+ isInitial = false;
124
+ return result;
125
+ }
126
+ memoizedFunction.updateDeps = (newDeps) => {
127
+ deps = newDeps;
128
+ };
129
+ return memoizedFunction;
130
+ }
131
+ function notUndefined(value, msg) {
132
+ if (value === void 0) throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ""}`);
133
+ else return value;
134
+ }
135
+ var approxEqual = (a, b) => Math.abs(a - b) < 1.01;
136
+ var debounce = (targetWindow, fn, ms) => {
137
+ let timeoutId;
138
+ return Object.assign(function(...args) {
139
+ targetWindow.clearTimeout(timeoutId);
140
+ timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);
141
+ }, { cancel: () => {
142
+ targetWindow.clearTimeout(timeoutId);
143
+ } });
54
144
  };
55
- const _hoisted_2$1 = { class: "ui-IconifySampleInfo" };
56
- const _hoisted_3$1 = { class: "ui-IconifySampleIcons" };
57
- const _sfc_main$2 = /* @__PURE__ */ defineComponent({
58
- __name: "IconifySample",
59
- props: {
60
- prefix: {},
61
- category: {},
62
- name: {},
63
- samples: {},
64
- total: {},
65
- license: {}
66
- },
67
- setup(__props) {
68
- const props = __props;
69
- return (_ctx, _cache) => {
70
- return openBlock(), createElementBlock("button", _hoisted_1$1, [
71
- createElementVNode("div", _hoisted_2$1, [
72
- createElementVNode("strong", null, toDisplayString(props.name), 1),
73
- createElementVNode("span", null, toDisplayString(props.license.title), 1),
74
- createElementVNode("span", null, toDisplayString(props.total) + " icons", 1)
75
- ]),
76
- createElementVNode("div", _hoisted_3$1, [
77
- (openBlock(true), createElementBlock(Fragment, null, renderList(props.samples, (icon) => {
78
- return openBlock(), createElementBlock("span", { key: icon }, [
79
- createVNode(unref(Icon), {
80
- icon: props.prefix + ":" + icon
81
- }, null, 8, ["icon"])
82
- ]);
83
- }), 128))
84
- ])
85
- ]);
86
- };
87
- }
88
- });
89
- const _hoisted_1 = { class: "ui-IconifyCollection" };
90
- const _hoisted_2 = { class: "ui-IconifyCollectionGroups" };
91
- const _hoisted_3 = { class: "ui-IconifyCollectionGroupsHead" };
92
- const _hoisted_4 = { class: "ui-IconifyCollectionForm" };
93
- const _hoisted_5 = { class: "mb-2" };
94
- const _hoisted_6 = { class: "font-medium" };
95
- const _hoisted_7 = { class: "text-sm ml-1" };
96
- const _hoisted_8 = { class: "ui-IconifyCollectionSampleGrid" };
97
- const _hoisted_9 = {
98
- key: 0,
99
- class: "ui-IconifyCollectionIcons"
145
+ //#endregion
146
+ //#region ../../node_modules/.pnpm/@tanstack+virtual-core@3.17.8/node_modules/@tanstack/virtual-core/dist/esm/index.js
147
+ var _isIOSResult;
148
+ var isIOSWebKit = () => {
149
+ if (_isIOSResult !== void 0) return _isIOSResult;
150
+ if (typeof navigator === "undefined") return _isIOSResult = false;
151
+ if (/iP(hone|od|ad)/.test(navigator.userAgent)) return _isIOSResult = true;
152
+ const mtp = navigator.maxTouchPoints;
153
+ return _isIOSResult = navigator.platform === "MacIntel" && mtp !== void 0 && mtp > 0;
154
+ };
155
+ var getRect = (element) => {
156
+ const { offsetWidth, offsetHeight } = element;
157
+ return {
158
+ width: offsetWidth,
159
+ height: offsetHeight
160
+ };
161
+ };
162
+ var defaultKeyExtractor = (index) => index;
163
+ var defaultRangeExtractor = (range) => {
164
+ const start = Math.max(range.startIndex - range.overscan, 0);
165
+ const len = Math.min(range.endIndex + range.overscan, range.count - 1) - start + 1;
166
+ const arr = new Array(len);
167
+ for (let i = 0; i < len; i++) arr[i] = start + i;
168
+ return arr;
100
169
  };
101
- const _hoisted_10 = { class: "ui-IconifyCollectionForm" };
102
- const _hoisted_11 = {
103
- key: 0,
104
- class: "ui-IconifyCollectionSuffixes"
170
+ var observeElementRect = (instance, cb) => {
171
+ const element = instance.scrollElement;
172
+ if (!element) return;
173
+ const targetWindow = instance.targetWindow;
174
+ if (!targetWindow) return;
175
+ const handler = (rect) => {
176
+ const { width, height } = rect;
177
+ cb({
178
+ width: Math.round(width),
179
+ height: Math.round(height)
180
+ });
181
+ };
182
+ handler(getRect(element));
183
+ if (!targetWindow.ResizeObserver) return () => {};
184
+ const observer = new targetWindow.ResizeObserver((entries) => {
185
+ const run = () => {
186
+ const entry = entries[0];
187
+ if (entry == null ? void 0 : entry.borderBoxSize) {
188
+ const box = entry.borderBoxSize[0];
189
+ if (box) {
190
+ handler({
191
+ width: box.inlineSize,
192
+ height: box.blockSize
193
+ });
194
+ return;
195
+ }
196
+ }
197
+ handler(getRect(element));
198
+ };
199
+ instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
200
+ });
201
+ observer.observe(element, { box: "border-box" });
202
+ return () => {
203
+ observer.unobserve(element);
204
+ };
105
205
  };
106
- const _hoisted_12 = ["onClick"];
107
- const fetchCollections = async () => {
108
- const apiLink = "https://api.iconify.design/collections";
109
- const resp = await fetch(apiLink);
110
- const data = await resp.json();
111
- const cache = {};
112
- Object.keys(data).forEach((prefix) => {
113
- const item = data[prefix];
114
- if (item.hidden) {
115
- return;
116
- }
117
- if (!cache[item.category]) {
118
- cache[item.category] = [];
119
- }
120
- cache[item.category].push({ ...item, prefix });
121
- });
122
- const collections = [];
123
- Object.keys(cache).forEach((category) => {
124
- collections.push({
125
- category,
126
- items: cache[category]
127
- });
128
- });
129
- return collections;
206
+ var addEventListenerOptions = { passive: true };
207
+ var supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
208
+ var observeOffset = (instance, cb, readOffset) => {
209
+ const element = instance.scrollElement;
210
+ if (!element) return;
211
+ const targetWindow = instance.targetWindow;
212
+ if (!targetWindow) return;
213
+ const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
214
+ let offset = 0;
215
+ const fallback = registerScrollendEvent ? null : debounce(targetWindow, () => cb(offset, false), instance.options.isScrollingResetDelay);
216
+ const createHandler = (isScrolling) => () => {
217
+ offset = readOffset(element);
218
+ fallback?.();
219
+ cb(offset, isScrolling);
220
+ };
221
+ const handler = createHandler(true);
222
+ const endHandler = createHandler(false);
223
+ element.addEventListener("scroll", handler, addEventListenerOptions);
224
+ if (registerScrollendEvent) element.addEventListener("scrollend", endHandler, addEventListenerOptions);
225
+ return () => {
226
+ element.removeEventListener("scroll", handler);
227
+ if (registerScrollendEvent) element.removeEventListener("scrollend", endHandler);
228
+ fallback?.cancel();
229
+ };
130
230
  };
131
- const searchIcons = async (query) => {
132
- const apiLink = `https://api.iconify.design/search?query=${encodeURIComponent(query)}&limit=999`;
133
- const resp = await fetch(apiLink);
134
- const data = await resp.json();
135
- return data.icons;
231
+ var observeElementOffset = (instance, cb) => observeOffset(instance, cb, (el) => {
232
+ const { horizontal, isRtl } = instance.options;
233
+ return horizontal ? el.scrollLeft * (isRtl && -1 || 1) : el.scrollTop;
234
+ });
235
+ var measureElement = (element, entry, instance) => {
236
+ if (instance.options.useCachedMeasurements) {
237
+ const index = instance.indexFromElement(element);
238
+ const key = instance.options.getItemKey(index);
239
+ return instance.itemSizeCache.get(key) ?? instance.options.estimateSize(index);
240
+ }
241
+ if (entry == null ? void 0 : entry.borderBoxSize) {
242
+ const box = entry.borderBoxSize[0];
243
+ if (box) return Math.round(box[instance.options.horizontal ? "inlineSize" : "blockSize"]);
244
+ }
245
+ if (!entry) {
246
+ const index = instance.indexFromElement(element);
247
+ const key = instance.options.getItemKey(index);
248
+ const cachedSize = instance.itemSizeCache.get(key);
249
+ if (cachedSize !== void 0) return cachedSize;
250
+ }
251
+ return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
252
+ };
253
+ var scrollWithAdjustments = (offset, { adjustments = 0, behavior }, instance) => {
254
+ var _a, _b;
255
+ (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null || _b.call(_a, {
256
+ [instance.options.horizontal ? "left" : "top"]: offset + adjustments,
257
+ behavior
258
+ });
136
259
  };
137
- const fetchCollectionIcons = async (prefix) => {
138
- const apiLink = `https://api.iconify.design/collection?prefix=${encodeURIComponent(prefix)}&chars=true&aliases=true`;
139
- const resp = await fetch(apiLink);
140
- const data = await resp.json();
141
- return data;
260
+ var elementScroll = scrollWithAdjustments;
261
+ var Virtualizer = class {
262
+ constructor(opts) {
263
+ this.unsubs = [];
264
+ this.scrollElement = null;
265
+ this.targetWindow = null;
266
+ this.isScrolling = false;
267
+ this.scrollState = null;
268
+ this.measurementsCache = [];
269
+ this._flatMeasurements = null;
270
+ this.itemSizeCache = /* @__PURE__ */ new Map();
271
+ this.itemSizeCacheVersion = 0;
272
+ this.laneAssignments = /* @__PURE__ */ new Map();
273
+ this.pendingMin = null;
274
+ this.prevLanes = void 0;
275
+ this.lanesChangedFlag = false;
276
+ this.lanesSettling = false;
277
+ this.pendingScrollAnchor = null;
278
+ this.scrollRect = null;
279
+ this.scrollOffset = null;
280
+ this.scrollDirection = null;
281
+ this.scrollAdjustments = 0;
282
+ this._iosDeferredAdjustment = 0;
283
+ this._iosTouching = false;
284
+ this._iosJustTouchEnded = false;
285
+ this._iosTouchEndTimerId = null;
286
+ this._intendedScrollOffset = null;
287
+ this.elementsCache = /* @__PURE__ */ new Map();
288
+ this.now = () => {
289
+ var _a, _b, _c;
290
+ return ((_c = (_b = (_a = this.targetWindow) == null ? void 0 : _a.performance) == null ? void 0 : _b.now) == null ? void 0 : _c.call(_b)) ?? Date.now();
291
+ };
292
+ this.observer = /* @__PURE__ */ (() => {
293
+ let _ro = null;
294
+ const get = () => {
295
+ if (_ro) return _ro;
296
+ if (!this.targetWindow || !this.targetWindow.ResizeObserver) return null;
297
+ return _ro = new this.targetWindow.ResizeObserver((entries) => {
298
+ entries.forEach((entry) => {
299
+ const run = () => {
300
+ const node = entry.target;
301
+ const index = this.indexFromElement(node);
302
+ if (!node.isConnected) {
303
+ this.observer.unobserve(node);
304
+ for (const [cacheKey, cachedNode] of this.elementsCache) if (cachedNode === node) {
305
+ this.elementsCache.delete(cacheKey);
306
+ break;
307
+ }
308
+ return;
309
+ }
310
+ if (!this.isIndexInRange(index)) return;
311
+ if (this.shouldMeasureDuringScroll(index)) this.resizeItem(index, this.options.measureElement(node, entry, this));
312
+ };
313
+ this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
314
+ });
315
+ });
316
+ };
317
+ return {
318
+ disconnect: () => {
319
+ var _a;
320
+ (_a = get()) == null || _a.disconnect();
321
+ _ro = null;
322
+ },
323
+ observe: (target) => {
324
+ var _a;
325
+ return (_a = get()) == null ? void 0 : _a.observe(target, { box: "border-box" });
326
+ },
327
+ unobserve: (target) => {
328
+ var _a;
329
+ return (_a = get()) == null ? void 0 : _a.unobserve(target);
330
+ }
331
+ };
332
+ })();
333
+ this.range = null;
334
+ this.setOptions = (opts2) => {
335
+ var _a, _b;
336
+ const merged = {
337
+ debug: false,
338
+ initialOffset: 0,
339
+ overscan: 1,
340
+ paddingStart: 0,
341
+ paddingEnd: 0,
342
+ scrollPaddingStart: 0,
343
+ scrollPaddingEnd: 0,
344
+ horizontal: false,
345
+ getItemKey: defaultKeyExtractor,
346
+ rangeExtractor: defaultRangeExtractor,
347
+ onChange: () => {},
348
+ measureElement,
349
+ initialRect: {
350
+ width: 0,
351
+ height: 0
352
+ },
353
+ scrollMargin: 0,
354
+ gap: 0,
355
+ indexAttribute: "data-index",
356
+ initialMeasurementsCache: [],
357
+ lanes: 1,
358
+ anchorTo: "start",
359
+ followOnAppend: false,
360
+ scrollEndThreshold: 1,
361
+ isScrollingResetDelay: 150,
362
+ enabled: true,
363
+ isRtl: false,
364
+ useScrollendEvent: false,
365
+ useAnimationFrameWithResizeObserver: false,
366
+ laneAssignmentMode: "estimate",
367
+ useCachedMeasurements: false
368
+ };
369
+ for (const key in opts2) {
370
+ const v = opts2[key];
371
+ if (v !== void 0) merged[key] = v;
372
+ }
373
+ const prevOptions = this.options;
374
+ let anchor = null;
375
+ let followOnAppend = null;
376
+ let edgeKeysChanged = false;
377
+ if (prevOptions !== void 0 && prevOptions.enabled && merged.enabled && merged.anchorTo === "end" && this.scrollElement !== null) {
378
+ const prevCount = prevOptions.count;
379
+ const nextCount = merged.count;
380
+ const measurements = this.getMeasurements();
381
+ const prevFirstKey = prevCount > 0 ? ((_a = measurements[0]) == null ? void 0 : _a.key) ?? prevOptions.getItemKey(0) : null;
382
+ const prevLastKey = prevCount > 0 ? ((_b = measurements[prevCount - 1]) == null ? void 0 : _b.key) ?? prevOptions.getItemKey(prevCount - 1) : null;
383
+ if (nextCount !== prevCount || prevCount > 0 && nextCount > 0 && (merged.getItemKey(0) !== prevFirstKey || merged.getItemKey(nextCount - 1) !== prevLastKey)) {
384
+ edgeKeysChanged = true;
385
+ const item = prevCount > 0 ? this.getVirtualItemForOffset(this.getScrollOffset()) ?? measurements[0] : null;
386
+ if (item) anchor = [item.key, this.getScrollOffset() - item.start];
387
+ const behavior = merged.followOnAppend === true ? "auto" : merged.followOnAppend || null;
388
+ if (behavior && nextCount > prevCount && this.isAtEnd(prevOptions.scrollEndThreshold) && (prevCount === 0 || merged.getItemKey(nextCount - 1) !== prevLastKey)) followOnAppend = behavior;
389
+ }
390
+ }
391
+ this.options = merged;
392
+ if (edgeKeysChanged) {
393
+ this.pendingMin = 0;
394
+ this.itemSizeCacheVersion++;
395
+ }
396
+ let anchorResolved = false;
397
+ let anchorDelta = 0;
398
+ if (anchor && this.scrollOffset !== null) {
399
+ const [anchorKey, anchorOffset] = anchor;
400
+ const newMeasurements = this.getMeasurements();
401
+ const { count, getItemKey } = this.options;
402
+ let idx = 0;
403
+ while (idx < count && getItemKey(idx) !== anchorKey) idx++;
404
+ if (idx < count) {
405
+ const anchorItem = newMeasurements[idx];
406
+ if (anchorItem) {
407
+ const newOffset = Math.max(0, anchorItem.start + anchorOffset);
408
+ if (newOffset !== this.scrollOffset) {
409
+ anchorDelta = newOffset - this.scrollOffset;
410
+ this.scrollOffset = newOffset;
411
+ anchorResolved = true;
412
+ }
413
+ }
414
+ }
415
+ }
416
+ if (anchorResolved || followOnAppend) this.pendingScrollAnchor = [
417
+ anchorResolved ? anchor[0] : null,
418
+ anchorResolved ? anchor[1] : 0,
419
+ followOnAppend,
420
+ anchorDelta
421
+ ];
422
+ };
423
+ this.notify = (sync) => {
424
+ var _a, _b;
425
+ (_b = (_a = this.options).onChange) == null || _b.call(_a, this, sync);
426
+ };
427
+ this.maybeNotify = memo(() => {
428
+ this.calculateRange();
429
+ return [
430
+ this.isScrolling,
431
+ this.range ? this.range.startIndex : null,
432
+ this.range ? this.range.endIndex : null
433
+ ];
434
+ }, (isScrolling) => {
435
+ this.notify(isScrolling);
436
+ }, {
437
+ key: process.env.NODE_ENV !== "production" && "maybeNotify",
438
+ debug: () => this.options.debug,
439
+ initialDeps: [
440
+ this.isScrolling,
441
+ this.range ? this.range.startIndex : null,
442
+ this.range ? this.range.endIndex : null
443
+ ]
444
+ });
445
+ this.cleanup = () => {
446
+ this.unsubs.filter(Boolean).forEach((d) => d());
447
+ this.unsubs = [];
448
+ this.observer.disconnect();
449
+ if (this.rafId != null && this.targetWindow) {
450
+ this.targetWindow.cancelAnimationFrame(this.rafId);
451
+ this.rafId = null;
452
+ }
453
+ this.scrollState = null;
454
+ this.isScrolling = false;
455
+ this.scrollDirection = null;
456
+ this._iosDeferredAdjustment = 0;
457
+ this._iosTouching = false;
458
+ this._iosJustTouchEnded = false;
459
+ this.scrollElement = null;
460
+ this.targetWindow = null;
461
+ };
462
+ this._didMount = () => {
463
+ return () => {
464
+ this.cleanup();
465
+ };
466
+ };
467
+ this._willUpdate = () => {
468
+ var _a;
469
+ const scrollElement = this.options.enabled ? this.options.getScrollElement() : null;
470
+ if (this.scrollElement !== scrollElement) {
471
+ this.cleanup();
472
+ if (!scrollElement) {
473
+ this.maybeNotify();
474
+ return;
475
+ }
476
+ this.scrollElement = scrollElement;
477
+ if (this.scrollElement && "ownerDocument" in this.scrollElement) this.targetWindow = this.scrollElement.ownerDocument.defaultView;
478
+ else this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null;
479
+ this.elementsCache.forEach((cached) => {
480
+ this.observer.observe(cached);
481
+ });
482
+ this.unsubs.push(this.options.observeElementRect(this, (rect) => {
483
+ this.scrollRect = rect;
484
+ this.maybeNotify();
485
+ }));
486
+ this.unsubs.push(this.options.observeElementOffset(this, (offset, isScrolling) => {
487
+ if (isScrolling && this._intendedScrollOffset === null && offset === this.scrollOffset) return;
488
+ if (this._intendedScrollOffset !== null && Math.abs(offset - this._intendedScrollOffset) < 1.5) offset = this._intendedScrollOffset;
489
+ this._intendedScrollOffset = null;
490
+ this.scrollAdjustments = 0;
491
+ const prevOffset = this.getScrollOffset();
492
+ this.scrollDirection = isScrolling ? prevOffset === offset ? this.scrollDirection : prevOffset < offset ? "forward" : "backward" : null;
493
+ this.scrollOffset = offset;
494
+ this.isScrolling = isScrolling;
495
+ this._flushIosDeferredIfReady();
496
+ if (this.scrollState) this.scheduleScrollReconcile();
497
+ this.maybeNotify();
498
+ }));
499
+ if ("addEventListener" in this.scrollElement) {
500
+ const scrollEl = this.scrollElement;
501
+ const onTouchStart = () => {
502
+ this._iosTouching = true;
503
+ this._iosJustTouchEnded = false;
504
+ if (this._iosTouchEndTimerId !== null && this.targetWindow != null) {
505
+ this.targetWindow.clearTimeout(this._iosTouchEndTimerId);
506
+ this._iosTouchEndTimerId = null;
507
+ }
508
+ };
509
+ const onTouchEnd = () => {
510
+ this._iosTouching = false;
511
+ if (!isIOSWebKit() || this.targetWindow == null) return;
512
+ this._iosJustTouchEnded = true;
513
+ this._iosTouchEndTimerId = this.targetWindow.setTimeout(() => {
514
+ this._iosJustTouchEnded = false;
515
+ this._iosTouchEndTimerId = null;
516
+ this._flushIosDeferredIfReady();
517
+ }, 150);
518
+ };
519
+ scrollEl.addEventListener("touchstart", onTouchStart, addEventListenerOptions);
520
+ scrollEl.addEventListener("touchend", onTouchEnd, addEventListenerOptions);
521
+ this.unsubs.push(() => {
522
+ scrollEl.removeEventListener("touchstart", onTouchStart);
523
+ scrollEl.removeEventListener("touchend", onTouchEnd);
524
+ if (this._iosTouchEndTimerId !== null && this.targetWindow != null) {
525
+ this.targetWindow.clearTimeout(this._iosTouchEndTimerId);
526
+ this._iosTouchEndTimerId = null;
527
+ }
528
+ });
529
+ }
530
+ this._scrollToOffset(this.getScrollOffset(), {
531
+ adjustments: void 0,
532
+ behavior: void 0
533
+ });
534
+ }
535
+ const anchor = this.pendingScrollAnchor;
536
+ this.pendingScrollAnchor = null;
537
+ if (anchor && this.scrollElement && this.options.enabled) {
538
+ const [key, _offset, followOnAppend, anchorDelta] = anchor;
539
+ if (key !== null && !followOnAppend) {
540
+ if (isIOSWebKit() && (this.isScrolling || this._iosTouching || this._iosJustTouchEnded)) {
541
+ if (anchorDelta !== 0) this._iosDeferredAdjustment += anchorDelta;
542
+ } else this._scrollToOffset(this.getScrollOffset(), {
543
+ adjustments: void 0,
544
+ behavior: void 0
545
+ });
546
+ }
547
+ if (followOnAppend) this.scrollToEnd({ behavior: followOnAppend });
548
+ }
549
+ };
550
+ this._flushIosDeferredIfReady = () => {
551
+ if (this._iosDeferredAdjustment === 0) return;
552
+ if (this.isScrolling) return;
553
+ if (this._iosTouching) return;
554
+ if (this._iosJustTouchEnded) return;
555
+ const cur = this.getScrollOffset();
556
+ const max = this.getMaxScrollOffset();
557
+ if (cur < 0 || cur > max) return;
558
+ if (this._iosDeferredAdjustment < 0 && cur >= max - 1) {
559
+ this._iosDeferredAdjustment = 0;
560
+ return;
561
+ }
562
+ const delta = this._iosDeferredAdjustment;
563
+ this._iosDeferredAdjustment = 0;
564
+ this._scrollToOffset(cur, {
565
+ adjustments: this.scrollAdjustments += delta,
566
+ behavior: void 0
567
+ });
568
+ };
569
+ this.rafId = null;
570
+ this.getSize = () => {
571
+ if (!this.options.enabled) {
572
+ this.scrollRect = null;
573
+ return 0;
574
+ }
575
+ this.scrollRect = this.scrollRect ?? this.options.initialRect;
576
+ return this.scrollRect[this.options.horizontal ? "width" : "height"];
577
+ };
578
+ this.getScrollOffset = () => {
579
+ if (!this.options.enabled) {
580
+ this.scrollOffset = null;
581
+ return 0;
582
+ }
583
+ this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === "function" ? this.options.initialOffset() : this.options.initialOffset);
584
+ return this.scrollOffset;
585
+ };
586
+ this.getMeasurementOptions = memo(() => [
587
+ this.options.count,
588
+ this.options.paddingStart,
589
+ this.options.scrollMargin,
590
+ this.options.getItemKey,
591
+ this.options.enabled,
592
+ this.options.lanes,
593
+ this.options.laneAssignmentMode,
594
+ this.options.gap
595
+ ], (count, paddingStart, scrollMargin, getItemKey, enabled, lanes, laneAssignmentMode, gap) => {
596
+ if (this.prevLanes !== void 0 && this.prevLanes !== lanes) this.lanesChangedFlag = true;
597
+ this.prevLanes = lanes;
598
+ this.pendingMin = null;
599
+ return {
600
+ count,
601
+ paddingStart,
602
+ scrollMargin,
603
+ getItemKey,
604
+ enabled,
605
+ lanes,
606
+ laneAssignmentMode,
607
+ gap
608
+ };
609
+ }, { key: false });
610
+ this.isIndexInRange = (index) => index >= 0 && index < this.options.count;
611
+ this.getMeasurements = memo(() => [this.getMeasurementOptions(), this.itemSizeCacheVersion], ({ count, paddingStart, scrollMargin, getItemKey, enabled, lanes, laneAssignmentMode, gap }, _itemSizeCacheVersion) => {
612
+ const itemSizeCache = this.itemSizeCache;
613
+ if (!enabled) {
614
+ this.measurementsCache = [];
615
+ this.itemSizeCache.clear();
616
+ this.laneAssignments.clear();
617
+ return [];
618
+ }
619
+ if (this.laneAssignments.size > count) {
620
+ for (const index of this.laneAssignments.keys()) if (index >= count) this.laneAssignments.delete(index);
621
+ }
622
+ if (this.lanesChangedFlag) {
623
+ this.lanesChangedFlag = false;
624
+ this.lanesSettling = true;
625
+ this.measurementsCache = [];
626
+ this.itemSizeCache.clear();
627
+ this.laneAssignments.clear();
628
+ this.pendingMin = null;
629
+ }
630
+ if (this.measurementsCache.length === 0 && !this.lanesSettling) {
631
+ this.measurementsCache = this.options.initialMeasurementsCache;
632
+ this.measurementsCache.forEach((item) => {
633
+ this.itemSizeCache.set(item.key, item.size);
634
+ });
635
+ }
636
+ const min = this.lanesSettling ? 0 : this.pendingMin ?? 0;
637
+ this.pendingMin = null;
638
+ if (this.lanesSettling && this.measurementsCache.length === count) this.lanesSettling = false;
639
+ if (lanes === 1) {
640
+ const need = count * 2;
641
+ let flat = this._flatMeasurements;
642
+ if (!flat || flat.length < need) {
643
+ const next = new Float64Array(need);
644
+ if (flat && min > 0) next.set(flat.subarray(0, min * 2));
645
+ flat = next;
646
+ this._flatMeasurements = flat;
647
+ }
648
+ let runningStart;
649
+ if (min === 0) runningStart = paddingStart + scrollMargin;
650
+ else {
651
+ const prevIdx = min - 1;
652
+ runningStart = flat[prevIdx * 2] + flat[prevIdx * 2 + 1] + gap;
653
+ }
654
+ for (let i = min; i < count; i++) {
655
+ const key = getItemKey(i);
656
+ const measuredSize = itemSizeCache.get(key);
657
+ const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i);
658
+ flat[i * 2] = runningStart;
659
+ flat[i * 2 + 1] = size;
660
+ runningStart += size + gap;
661
+ }
662
+ const view = createLazyMeasurementsView(count, flat, getItemKey);
663
+ this.measurementsCache = view;
664
+ return view;
665
+ }
666
+ const measurements = this.measurementsCache.slice(0, min);
667
+ const laneLastIndex = new Array(lanes).fill(void 0);
668
+ const laneEnds = new Float64Array(lanes);
669
+ let filledLanes = 0;
670
+ for (let m = 0; m < min; m++) {
671
+ const item = measurements[m];
672
+ if (item) {
673
+ if (laneLastIndex[item.lane] === void 0) filledLanes++;
674
+ laneLastIndex[item.lane] = m;
675
+ laneEnds[item.lane] = item.end;
676
+ }
677
+ }
678
+ for (let i = min; i < count; i++) {
679
+ const key = getItemKey(i);
680
+ const cachedLane = this.laneAssignments.get(i);
681
+ let lane;
682
+ let start;
683
+ const shouldCacheLane = laneAssignmentMode === "estimate" || itemSizeCache.has(key);
684
+ if (cachedLane !== void 0 && this.options.lanes > 1) {
685
+ lane = cachedLane;
686
+ const prevIndex = laneLastIndex[lane];
687
+ const prevInLane = prevIndex !== void 0 ? measurements[prevIndex] : void 0;
688
+ start = prevInLane ? prevInLane.end + gap : paddingStart + scrollMargin;
689
+ } else if (filledLanes === lanes) {
690
+ let bestLane = 0;
691
+ let bestEnd = laneEnds[0];
692
+ let bestIdx = laneLastIndex[0];
693
+ for (let l = 1; l < lanes; l++) {
694
+ const e = laneEnds[l];
695
+ if (e < bestEnd || e === bestEnd && laneLastIndex[l] < bestIdx) {
696
+ bestLane = l;
697
+ bestEnd = e;
698
+ bestIdx = laneLastIndex[l];
699
+ }
700
+ }
701
+ lane = bestLane;
702
+ start = bestEnd + gap;
703
+ if (shouldCacheLane) this.laneAssignments.set(i, lane);
704
+ } else {
705
+ lane = i % this.options.lanes;
706
+ start = paddingStart + scrollMargin;
707
+ if (shouldCacheLane) this.laneAssignments.set(i, lane);
708
+ }
709
+ const measuredSize = itemSizeCache.get(key);
710
+ const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i);
711
+ const end = start + size;
712
+ measurements[i] = {
713
+ index: i,
714
+ start,
715
+ size,
716
+ end,
717
+ key,
718
+ lane
719
+ };
720
+ if (laneLastIndex[lane] === void 0) filledLanes++;
721
+ laneLastIndex[lane] = i;
722
+ laneEnds[lane] = end;
723
+ }
724
+ this.measurementsCache = measurements;
725
+ return measurements;
726
+ }, {
727
+ key: process.env.NODE_ENV !== "production" && "getMeasurements",
728
+ debug: () => this.options.debug
729
+ });
730
+ this.calculateRange = memo(() => [
731
+ this.getMeasurements(),
732
+ this.getSize(),
733
+ this.getScrollOffset(),
734
+ this.options.lanes
735
+ ], (measurements, outerSize, scrollOffset, lanes) => {
736
+ if (measurements.length === 0 || outerSize === 0) {
737
+ this.range = null;
738
+ return null;
739
+ }
740
+ this.range = calculateRangeImpl(measurements, outerSize, scrollOffset, lanes, lanes === 1 && this._flatMeasurements != null ? this._flatMeasurements : null);
741
+ return this.range;
742
+ }, {
743
+ key: process.env.NODE_ENV !== "production" && "calculateRange",
744
+ debug: () => this.options.debug
745
+ });
746
+ this.getVirtualIndexes = memo(() => {
747
+ let startIndex = null;
748
+ let endIndex = null;
749
+ const range = this.calculateRange();
750
+ if (range) {
751
+ startIndex = range.startIndex;
752
+ endIndex = range.endIndex;
753
+ }
754
+ this.maybeNotify.updateDeps([
755
+ this.isScrolling,
756
+ startIndex,
757
+ endIndex
758
+ ]);
759
+ return [
760
+ this.options.rangeExtractor,
761
+ this.options.overscan,
762
+ this.options.count,
763
+ startIndex,
764
+ endIndex
765
+ ];
766
+ }, (rangeExtractor, overscan, count, startIndex, endIndex) => {
767
+ return startIndex === null || endIndex === null ? [] : rangeExtractor({
768
+ startIndex,
769
+ endIndex,
770
+ overscan,
771
+ count
772
+ });
773
+ }, {
774
+ key: process.env.NODE_ENV !== "production" && "getVirtualIndexes",
775
+ debug: () => this.options.debug
776
+ });
777
+ this.indexFromElement = (node) => {
778
+ const attributeName = this.options.indexAttribute;
779
+ const indexStr = node.getAttribute(attributeName);
780
+ if (!indexStr) {
781
+ console.warn(`Missing attribute name '${attributeName}={index}' on measured element.`);
782
+ return -1;
783
+ }
784
+ return parseInt(indexStr, 10);
785
+ };
786
+ this.shouldMeasureDuringScroll = (index) => {
787
+ var _a;
788
+ if (!this.scrollState || this.scrollState.behavior !== "smooth") return true;
789
+ const scrollIndex = this.scrollState.index ?? ((_a = this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)) == null ? void 0 : _a.index);
790
+ if (scrollIndex !== void 0 && this.range) {
791
+ const bufferSize = Math.max(this.options.overscan, Math.ceil((this.range.endIndex - this.range.startIndex) / 2));
792
+ const minIndex = Math.max(0, scrollIndex - bufferSize);
793
+ const maxIndex = Math.min(this.options.count - 1, scrollIndex + bufferSize);
794
+ return index >= minIndex && index <= maxIndex;
795
+ }
796
+ return true;
797
+ };
798
+ this.measureElement = (node) => {
799
+ if (!node) {
800
+ this.elementsCache.forEach((cached, key2) => {
801
+ if (!cached.isConnected) {
802
+ this.observer.unobserve(cached);
803
+ this.elementsCache.delete(key2);
804
+ }
805
+ });
806
+ return;
807
+ }
808
+ const index = this.indexFromElement(node);
809
+ if (!this.isIndexInRange(index)) return;
810
+ const key = this.options.getItemKey(index);
811
+ const prevNode = this.elementsCache.get(key);
812
+ if (prevNode !== node) {
813
+ if (prevNode) this.observer.unobserve(prevNode);
814
+ this.observer.observe(node);
815
+ this.elementsCache.set(key, node);
816
+ }
817
+ if ((!this.isScrolling || this.scrollState) && this.shouldMeasureDuringScroll(index)) this.resizeItem(index, this.options.measureElement(node, void 0, this));
818
+ };
819
+ this.resizeItem = (index, size) => {
820
+ var _a, _b;
821
+ if (!this.isIndexInRange(index)) return;
822
+ let cachedSize;
823
+ let itemStart;
824
+ let key;
825
+ const flat = this._flatMeasurements;
826
+ if (this.options.lanes === 1 && flat !== null) {
827
+ key = this.options.getItemKey(index);
828
+ itemStart = flat[index * 2];
829
+ cachedSize = flat[index * 2 + 1];
830
+ } else {
831
+ const item = this.measurementsCache[index];
832
+ if (!item) return;
833
+ key = item.key;
834
+ itemStart = item.start;
835
+ cachedSize = item.size;
836
+ }
837
+ const itemSize = this.itemSizeCache.get(key) ?? cachedSize;
838
+ const delta = size - itemSize;
839
+ if (delta !== 0) {
840
+ const wasAtEnd = this.options.anchorTo === "end" && ((_a = this.scrollState) == null ? void 0 : _a.behavior) !== "smooth" && this.getVirtualDistanceFromEnd() <= this.options.scrollEndThreshold;
841
+ const prevTotalSize = wasAtEnd ? this.getTotalSize() : 0;
842
+ const scrollOffsetWithAdj = this.getScrollOffset() + this.scrollAdjustments;
843
+ const defaultShouldAdjust = !this.itemSizeCache.has(key) ? itemStart < scrollOffsetWithAdj : itemStart + itemSize <= scrollOffsetWithAdj && this.scrollDirection !== "backward";
844
+ const shouldAdjustScroll = ((_b = this.scrollState) == null ? void 0 : _b.behavior) !== "smooth" && (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(this.measurementsCache[index] ?? {
845
+ index,
846
+ key,
847
+ start: itemStart,
848
+ size: cachedSize,
849
+ end: itemStart + cachedSize,
850
+ lane: 0
851
+ }, delta, this) : defaultShouldAdjust);
852
+ if (this.pendingMin === null || index < this.pendingMin) this.pendingMin = index;
853
+ this.itemSizeCache.set(key, size);
854
+ this.itemSizeCacheVersion++;
855
+ let adjustedSync = false;
856
+ if (wasAtEnd) adjustedSync = this.applyScrollAdjustment(this.getTotalSize() - prevTotalSize);
857
+ else if (shouldAdjustScroll) adjustedSync = this.applyScrollAdjustment(delta);
858
+ this.notify(adjustedSync);
859
+ }
860
+ };
861
+ this.getVirtualItems = memo(() => [this.getVirtualIndexes(), this.getMeasurements()], (indexes, measurements) => {
862
+ const virtualItems = [];
863
+ for (let k = 0, len = indexes.length; k < len; k++) {
864
+ const measurement = measurements[indexes[k]];
865
+ virtualItems.push(measurement);
866
+ }
867
+ return virtualItems;
868
+ }, {
869
+ key: process.env.NODE_ENV !== "production" && "getVirtualItems",
870
+ debug: () => this.options.debug
871
+ });
872
+ this.getVirtualItemForOffset = (offset) => {
873
+ const measurements = this.getMeasurements();
874
+ if (measurements.length === 0) return;
875
+ const flat = this._flatMeasurements;
876
+ const useFlat = this.options.lanes === 1 && flat != null;
877
+ return notUndefined(measurements[findNearestBinarySearch(0, measurements.length - 1, useFlat ? (i) => flat[i * 2] : (i) => notUndefined(measurements[i]).start, offset)]);
878
+ };
879
+ this.getMaxScrollOffset = () => {
880
+ if (!this.scrollElement) return 0;
881
+ if ("scrollHeight" in this.scrollElement) return this.options.horizontal ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth : this.scrollElement.scrollHeight - this.scrollElement.clientHeight;
882
+ else {
883
+ const doc = this.scrollElement.document.documentElement;
884
+ return this.options.horizontal ? doc.scrollWidth - this.scrollElement.innerWidth : doc.scrollHeight - this.scrollElement.innerHeight;
885
+ }
886
+ };
887
+ this.getVirtualDistanceFromEnd = () => {
888
+ return Math.max(this.getTotalSize() - this.getSize() - this.getScrollOffset(), 0);
889
+ };
890
+ this.getDistanceFromEnd = () => {
891
+ return Math.max(this.getMaxScrollOffset() - this.getScrollOffset(), 0);
892
+ };
893
+ this.isAtEnd = (threshold = this.options.scrollEndThreshold) => {
894
+ return this.getDistanceFromEnd() <= threshold;
895
+ };
896
+ this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
897
+ if (!this.scrollElement) return 0;
898
+ const size = this.getSize();
899
+ const scrollOffset = this.getScrollOffset();
900
+ if (align === "auto") align = toOffset >= scrollOffset + size ? "end" : "start";
901
+ if (align === "center") toOffset += (itemSize - size) / 2;
902
+ else if (align === "end") toOffset -= size;
903
+ const maxOffset = this.getMaxScrollOffset();
904
+ return Math.max(Math.min(maxOffset, toOffset), 0);
905
+ };
906
+ this.getOffsetForIndex = (index, align = "auto") => {
907
+ index = Math.max(0, Math.min(index, this.options.count - 1));
908
+ const size = this.getSize();
909
+ const scrollOffset = this.getScrollOffset();
910
+ const item = this.measurementsCache[index];
911
+ if (!item) return;
912
+ if (align === "auto") {
913
+ if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) align = "end";
914
+ else if (item.start <= scrollOffset + this.options.scrollPaddingStart) align = "start";
915
+ else return [scrollOffset, align];
916
+ }
917
+ if (align === "end" && index === this.options.count - 1) return [this.getMaxScrollOffset(), align];
918
+ const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;
919
+ return [this.getOffsetForAlignment(toOffset, align, item.size), align];
920
+ };
921
+ this.scrollToOffset = (toOffset, { align = "start", behavior = "auto" } = {}) => {
922
+ this._iosDeferredAdjustment = 0;
923
+ const offset = this.getOffsetForAlignment(toOffset, align);
924
+ const now = this.now();
925
+ this.scrollState = {
926
+ index: null,
927
+ align,
928
+ behavior,
929
+ startedAt: now,
930
+ lastTargetOffset: offset,
931
+ stableFrames: 0
932
+ };
933
+ this._scrollToOffset(offset, {
934
+ adjustments: void 0,
935
+ behavior
936
+ });
937
+ this.scheduleScrollReconcile();
938
+ };
939
+ this.scrollToIndex = (index, { align: initialAlign = "auto", behavior = "auto" } = {}) => {
940
+ this._iosDeferredAdjustment = 0;
941
+ index = Math.max(0, Math.min(index, this.options.count - 1));
942
+ const offsetInfo = this.getOffsetForIndex(index, initialAlign);
943
+ if (!offsetInfo) return;
944
+ const [offset, align] = offsetInfo;
945
+ const now = this.now();
946
+ this.scrollState = {
947
+ index,
948
+ align,
949
+ behavior,
950
+ startedAt: now,
951
+ lastTargetOffset: offset,
952
+ stableFrames: 0
953
+ };
954
+ this._scrollToOffset(offset, {
955
+ adjustments: void 0,
956
+ behavior
957
+ });
958
+ this.scheduleScrollReconcile();
959
+ };
960
+ this.scrollBy = (delta, { behavior = "auto" } = {}) => {
961
+ const offset = this.getScrollOffset() + delta;
962
+ const now = this.now();
963
+ this.scrollState = {
964
+ index: null,
965
+ align: "start",
966
+ behavior,
967
+ startedAt: now,
968
+ lastTargetOffset: offset,
969
+ stableFrames: 0
970
+ };
971
+ this._scrollToOffset(offset, {
972
+ adjustments: void 0,
973
+ behavior
974
+ });
975
+ this.scheduleScrollReconcile();
976
+ };
977
+ this.scrollToEnd = ({ behavior = "auto" } = {}) => {
978
+ if (this.options.count > 0) {
979
+ this.scrollToIndex(this.options.count - 1, {
980
+ align: "end",
981
+ behavior
982
+ });
983
+ return;
984
+ }
985
+ this.scrollToOffset(Math.max(this.getTotalSize() - this.getSize(), 0), { behavior });
986
+ };
987
+ this.getTotalSize = () => {
988
+ var _a;
989
+ const measurements = this.getMeasurements();
990
+ let end;
991
+ if (measurements.length === 0) end = this.options.paddingStart;
992
+ else if (this.options.lanes === 1) {
993
+ const lastIdx = measurements.length - 1;
994
+ const flat = this._flatMeasurements;
995
+ if (flat != null) end = flat[lastIdx * 2] + flat[lastIdx * 2 + 1];
996
+ else end = ((_a = measurements[lastIdx]) == null ? void 0 : _a.end) ?? 0;
997
+ } else {
998
+ const endByLane = Array(this.options.lanes).fill(null);
999
+ let endIndex = measurements.length - 1;
1000
+ while (endIndex >= 0 && endByLane.some((val) => val === null)) {
1001
+ const item = measurements[endIndex];
1002
+ if (endByLane[item.lane] === null) endByLane[item.lane] = item.end;
1003
+ endIndex--;
1004
+ }
1005
+ end = Math.max(...endByLane.filter((val) => val !== null));
1006
+ }
1007
+ return Math.max(end - this.options.scrollMargin + this.options.paddingEnd, 0);
1008
+ };
1009
+ this.takeSnapshot = () => {
1010
+ const snapshot = [];
1011
+ if (this.itemSizeCache.size === 0) return snapshot;
1012
+ const m = this.getMeasurements();
1013
+ for (const item of m) if (item && this.itemSizeCache.has(item.key)) snapshot.push({
1014
+ index: item.index,
1015
+ key: item.key,
1016
+ start: item.start,
1017
+ size: item.size,
1018
+ end: item.end,
1019
+ lane: item.lane
1020
+ });
1021
+ return snapshot;
1022
+ };
1023
+ this._scrollToOffset = (offset, { adjustments, behavior }) => {
1024
+ this._intendedScrollOffset = offset + (adjustments ?? 0);
1025
+ this.options.scrollToFn(offset, {
1026
+ behavior,
1027
+ adjustments
1028
+ }, this);
1029
+ };
1030
+ this.measure = () => {
1031
+ this.pendingMin = null;
1032
+ this.itemSizeCache.clear();
1033
+ this.laneAssignments.clear();
1034
+ this.itemSizeCacheVersion++;
1035
+ this.notify(false);
1036
+ };
1037
+ this.setOptions(opts);
1038
+ }
1039
+ applyScrollAdjustment(delta, behavior) {
1040
+ if (delta === 0) return false;
1041
+ if (process.env.NODE_ENV !== "production" && this.options.debug) console.info("correction", delta);
1042
+ if (isIOSWebKit() && (this.isScrolling || this._iosTouching || this._iosJustTouchEnded)) {
1043
+ this._iosDeferredAdjustment += delta;
1044
+ return false;
1045
+ } else {
1046
+ this._scrollToOffset(this.getScrollOffset(), {
1047
+ adjustments: this.scrollAdjustments += delta,
1048
+ behavior
1049
+ });
1050
+ if (this.scrollOffset !== null) {
1051
+ this.scrollOffset += this.scrollAdjustments;
1052
+ if (this.scrollOffset < 0) this.scrollOffset = 0;
1053
+ this.scrollAdjustments = 0;
1054
+ }
1055
+ return true;
1056
+ }
1057
+ }
1058
+ scheduleScrollReconcile() {
1059
+ if (!this.targetWindow) {
1060
+ this.scrollState = null;
1061
+ return;
1062
+ }
1063
+ if (this.rafId != null) return;
1064
+ this.rafId = this.targetWindow.requestAnimationFrame(() => {
1065
+ this.rafId = null;
1066
+ this.reconcileScroll();
1067
+ });
1068
+ }
1069
+ reconcileScroll() {
1070
+ if (!this.scrollState) return;
1071
+ if (!this.scrollElement) return;
1072
+ if (this.now() - this.scrollState.startedAt > 5e3) {
1073
+ this.scrollState = null;
1074
+ return;
1075
+ }
1076
+ const offsetInfo = this.scrollState.index != null ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align) : void 0;
1077
+ const targetOffset = offsetInfo ? offsetInfo[0] : this.scrollState.lastTargetOffset;
1078
+ const STABLE_FRAMES = 1;
1079
+ const targetChanged = targetOffset !== this.scrollState.lastTargetOffset;
1080
+ if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {
1081
+ this.scrollState.stableFrames++;
1082
+ if (this.scrollState.stableFrames >= STABLE_FRAMES) {
1083
+ if (this.getScrollOffset() !== targetOffset) this._scrollToOffset(targetOffset, {
1084
+ adjustments: void 0,
1085
+ behavior: "auto"
1086
+ });
1087
+ this.scrollState = null;
1088
+ return;
1089
+ }
1090
+ } else {
1091
+ this.scrollState.stableFrames = 0;
1092
+ if (targetChanged) {
1093
+ const viewport = this.getSize() || 600;
1094
+ const distance = Math.abs(targetOffset - this.getScrollOffset());
1095
+ const keepSmooth = this.scrollState.behavior === "smooth" && distance > viewport;
1096
+ this.scrollState.lastTargetOffset = targetOffset;
1097
+ if (!keepSmooth) this.scrollState.behavior = "auto";
1098
+ this._scrollToOffset(targetOffset, {
1099
+ adjustments: void 0,
1100
+ behavior: keepSmooth ? "smooth" : "auto"
1101
+ });
1102
+ }
1103
+ }
1104
+ this.scheduleScrollReconcile();
1105
+ }
142
1106
  };
143
- const filterIcons = (names, query, suffix) => {
144
- return names.filter((key) => {
145
- let match = true;
146
- if (query && key.indexOf(query) === -1) {
147
- match = false;
148
- }
149
- if (suffix && key.indexOf(`-${suffix}`) === -1) {
150
- match = false;
151
- }
152
- return match;
153
- });
1107
+ var findNearestBinarySearch = (low, high, getCurrentValue, value) => {
1108
+ while (low <= high) {
1109
+ const middle = (low + high) / 2 | 0;
1110
+ const currentValue = getCurrentValue(middle);
1111
+ if (currentValue < value) low = middle + 1;
1112
+ else if (currentValue > value) high = middle - 1;
1113
+ else return middle;
1114
+ }
1115
+ if (low > 0) return low - 1;
1116
+ else return 0;
154
1117
  };
155
- const _sfc_main$1 = /* @__PURE__ */ defineComponent({
156
- __name: "IconifyCollection",
157
- props: {
158
- prefix: {},
159
- search: {},
160
- perpage: { default: 200 },
161
- iconSize: { default: 20 }
162
- },
163
- emits: ["select"],
164
- setup(__props, { emit: __emit }) {
165
- const props = __props;
166
- const emits = __emit;
167
- const dialogContext = injectDialogRootContext(null);
168
- const shouldDisplay = ref("all");
169
- const groupCollections = ref([]);
170
- const collectionFilter = ref("");
171
- const page = ref(1);
172
- const searchQuery = ref("");
173
- const searchResultIcons = ref([]);
174
- const collectionData = ref();
175
- const collectionQuery = ref("");
176
- const collectionSuffix = ref("");
177
- const reset = () => {
178
- page.value = 1;
179
- searchQuery.value = "";
180
- searchResultIcons.value = [];
181
- collectionData.value = void 0;
182
- collectionQuery.value = "";
183
- collectionSuffix.value = "";
184
- shouldDisplay.value = "all";
185
- };
186
- const onSelectIcon = (icon) => {
187
- emits("select", icon);
188
- if (dialogContext) {
189
- dialogContext.onOpenChange(false);
190
- }
191
- };
192
- const onSearch = async () => {
193
- if (searchQuery.value) {
194
- shouldDisplay.value = "search";
195
- searchResultIcons.value = await searchIcons(searchQuery.value);
196
- } else {
197
- shouldDisplay.value = "all";
198
- }
199
- };
200
- const onSelectPrefix = async (prefix) => {
201
- collectionData.value = void 0;
202
- collectionQuery.value = "";
203
- collectionSuffix.value = "";
204
- shouldDisplay.value = "collection";
205
- collectionData.value = await fetchCollectionIcons(prefix);
206
- };
207
- const collectionCount = computed(() => {
208
- let count = 0;
209
- groupCollections.value.forEach((item) => {
210
- count += item.items.length;
211
- });
212
- return count;
213
- });
214
- const visibleCollections = computed(() => {
215
- if (!collectionFilter.value) {
216
- return groupCollections.value;
217
- }
218
- return groupCollections.value.map((collection) => {
219
- const items = collection.items.filter((item) => {
220
- const key = [item.category, item.name, item.prefix].join(" ");
221
- return key.toLowerCase().indexOf(collectionFilter.value) !== -1;
222
- });
223
- return { ...collection, items };
224
- }).filter((collection) => collection.items.length !== 0);
225
- });
226
- const collectionIcons = computed(() => {
227
- let rv = [];
228
- if (!collectionData.value) {
229
- return rv;
230
- }
231
- if (collectionData.value.uncategorized) {
232
- rv = filterIcons(collectionData.value.uncategorized, collectionQuery.value, collectionSuffix.value);
233
- } else if (collectionData.value.categories) {
234
- Object.keys(collectionData.value.categories).forEach((category) => {
235
- const icons = collectionData.value.categories[category];
236
- filterIcons(icons, collectionQuery.value, collectionSuffix.value).forEach((k) => {
237
- rv.push(k);
238
- });
239
- });
240
- }
241
- if (collectionQuery.value && !rv.length && collectionData.value.hidden) {
242
- rv = filterIcons(collectionData.value.hidden, collectionQuery.value, collectionSuffix.value);
243
- }
244
- return rv.map((name) => `${collectionData.value?.prefix}:${name}`);
245
- });
246
- const allIcons = computed(() => {
247
- if (shouldDisplay.value === "search") {
248
- return searchResultIcons.value;
249
- } else if (shouldDisplay.value === "collection") {
250
- return collectionIcons.value;
251
- } else {
252
- return [];
253
- }
254
- });
255
- const visibleIcons = computed(() => {
256
- const start = (page.value - 1) * props.perpage;
257
- const end = page.value * props.perpage;
258
- return allIcons.value.slice(start, end);
259
- });
260
- const iconSize = computed(() => {
261
- const size = props.iconSize.toString();
262
- if (/^\d+/.test(size)) {
263
- return size + "px";
264
- } else {
265
- return size;
266
- }
267
- });
268
- onMounted(async () => {
269
- if (props.prefix) {
270
- onSelectPrefix(props.prefix);
271
- } else if (props.search) {
272
- searchQuery.value = props.search;
273
- onSearch();
274
- }
275
- groupCollections.value = await fetchCollections();
276
- });
277
- return (_ctx, _cache) => {
278
- return openBlock(), createElementBlock("div", _hoisted_1, [
279
- withDirectives(createElementVNode("div", _hoisted_2, [
280
- createElementVNode("section", _hoisted_3, [
281
- createElementVNode("h1", null, toDisplayString(collectionCount.value) + " icon sets", 1),
282
- createElementVNode("div", _hoisted_4, [
283
- createVNode(unref(TextField), {
284
- modelValue: collectionFilter.value,
285
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => collectionFilter.value = $event),
286
- placeholder: "Filter icon sets..."
287
- }, null, 8, ["modelValue"]),
288
- createVNode(unref(TextField), {
289
- modelValue: searchQuery.value,
290
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => searchQuery.value = $event),
291
- placeholder: "Search icons...",
292
- onKeydown: withKeys(onSearch, ["enter"])
293
- }, null, 8, ["modelValue"])
294
- ])
295
- ]),
296
- (openBlock(true), createElementBlock(Fragment, null, renderList(visibleCollections.value, (collection) => {
297
- return openBlock(), createElementBlock("section", {
298
- key: collection.category,
299
- class: "ui-IconifyCollectionSample"
300
- }, [
301
- createElementVNode("h1", _hoisted_5, [
302
- createElementVNode("span", _hoisted_6, toDisplayString(collection.category), 1),
303
- createElementVNode("span", _hoisted_7, "(" + toDisplayString(collection.items.length) + " icon sets)", 1)
304
- ]),
305
- createElementVNode("div", _hoisted_8, [
306
- (openBlock(true), createElementBlock(Fragment, null, renderList(collection.items, (item) => {
307
- return openBlock(), createBlock(_sfc_main$2, mergeProps({
308
- key: item.prefix
309
- }, { ref_for: true }, item, {
310
- onClick: withModifiers(($event) => onSelectPrefix(item.prefix), ["prevent"])
311
- }), null, 16, ["onClick"]);
312
- }), 128))
313
- ])
314
- ]);
315
- }), 128))
316
- ], 512), [
317
- [vShow, shouldDisplay.value === "all"]
318
- ]),
319
- shouldDisplay.value !== "all" ? (openBlock(), createElementBlock("div", _hoisted_9, [
320
- createElementVNode("div", _hoisted_10, [
321
- createVNode(unref(Button), {
322
- type: "button",
323
- variant: "surface",
324
- color: "gray",
325
- onClick: withModifiers(reset, ["prevent"])
326
- }, {
327
- default: withCtx(() => [..._cache[5] || (_cache[5] = [
328
- createTextVNode(" Back ", -1)
329
- ])]),
330
- _: 1
331
- }),
332
- shouldDisplay.value === "search" ? (openBlock(), createBlock(unref(TextField), {
333
- key: 0,
334
- modelValue: searchQuery.value,
335
- "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => searchQuery.value = $event),
336
- placeholder: "Search icons...",
337
- onKeydown: withKeys(onSearch, ["enter"])
338
- }, null, 8, ["modelValue"])) : createCommentVNode("", true),
339
- shouldDisplay.value === "collection" ? (openBlock(), createBlock(unref(TextField), {
340
- key: 1,
341
- modelValue: collectionQuery.value,
342
- "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => collectionQuery.value = $event),
343
- placeholder: "Search icons..."
344
- }, null, 8, ["modelValue"])) : createCommentVNode("", true)
345
- ]),
346
- shouldDisplay.value === "collection" && collectionData.value?.suffixes ? (openBlock(), createElementBlock("div", _hoisted_11, [
347
- (openBlock(true), createElementBlock(Fragment, null, renderList(collectionData.value.suffixes, (k, v) => {
348
- return openBlock(), createBlock(unref(Button), {
349
- key: v,
350
- variant: collectionSuffix.value === v ? "solid" : "outline",
351
- color: "gray",
352
- "high-contrast": "",
353
- radius: "full",
354
- onClick: withModifiers(($event) => collectionSuffix.value = v, ["prevent"])
355
- }, {
356
- default: withCtx(() => [
357
- createTextVNode(toDisplayString(k), 1)
358
- ]),
359
- _: 2
360
- }, 1032, ["variant", "onClick"]);
361
- }), 128))
362
- ])) : createCommentVNode("", true),
363
- createElementVNode("div", {
364
- class: "ui-IconifyCollectionIconGrid",
365
- style: normalizeStyle({ fontSize: iconSize.value })
366
- }, [
367
- (openBlock(true), createElementBlock(Fragment, null, renderList(visibleIcons.value, (icon) => {
368
- return openBlock(), createBlock(unref(Tooltip), {
369
- key: icon,
370
- as: "div",
371
- content: icon
372
- }, {
373
- default: withCtx(() => [
374
- createElementVNode("button", {
375
- type: "button",
376
- onClick: withModifiers(($event) => onSelectIcon(icon), ["prevent"])
377
- }, [
378
- createVNode(unref(Icon), { icon }, null, 8, ["icon"])
379
- ], 8, _hoisted_12)
380
- ]),
381
- _: 2
382
- }, 1032, ["content"]);
383
- }), 128))
384
- ], 4),
385
- createVNode(unref(Pagination), {
386
- page: page.value,
387
- "onUpdate:page": _cache[4] || (_cache[4] = ($event) => page.value = $event),
388
- total: allIcons.value.length,
389
- "items-per-page": __props.perpage
390
- }, null, 8, ["page", "total", "items-per-page"])
391
- ])) : createCommentVNode("", true)
392
- ]);
393
- };
394
- }
1118
+ function findNearestBinarySearchFlat(flat, high, value) {
1119
+ let low = 0;
1120
+ while (low <= high) {
1121
+ const middle = (low + high) / 2 | 0;
1122
+ const currentValue = flat[middle * 2];
1123
+ if (currentValue < value) low = middle + 1;
1124
+ else if (currentValue > value) high = middle - 1;
1125
+ else return middle;
1126
+ }
1127
+ return low > 0 ? low - 1 : 0;
1128
+ }
1129
+ function calculateRangeImpl(measurements, outerSize, scrollOffset, lanes, flat) {
1130
+ const lastIndex = measurements.length - 1;
1131
+ if (measurements.length <= lanes) return {
1132
+ startIndex: 0,
1133
+ endIndex: lastIndex
1134
+ };
1135
+ if (lanes === 1 && flat !== null) {
1136
+ const startIndex2 = findNearestBinarySearchFlat(flat, lastIndex, scrollOffset);
1137
+ let endIndex2 = startIndex2;
1138
+ const limit = scrollOffset + outerSize;
1139
+ while (endIndex2 < lastIndex && flat[endIndex2 * 2] + flat[endIndex2 * 2 + 1] < limit) endIndex2++;
1140
+ return {
1141
+ startIndex: startIndex2,
1142
+ endIndex: endIndex2
1143
+ };
1144
+ }
1145
+ const getStart = (index) => measurements[index].start;
1146
+ let startIndex = findNearestBinarySearch(0, lastIndex, getStart, scrollOffset);
1147
+ let endIndex = startIndex;
1148
+ if (lanes === 1) while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) endIndex++;
1149
+ else if (lanes > 1) {
1150
+ const endPerLane = Array(lanes).fill(0);
1151
+ while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
1152
+ const item = measurements[endIndex];
1153
+ endPerLane[item.lane] = item.end;
1154
+ endIndex++;
1155
+ }
1156
+ const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
1157
+ while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
1158
+ const item = measurements[startIndex];
1159
+ startPerLane[item.lane] = item.start;
1160
+ startIndex--;
1161
+ }
1162
+ startIndex = Math.max(0, startIndex - startIndex % lanes);
1163
+ endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
1164
+ }
1165
+ return {
1166
+ startIndex,
1167
+ endIndex
1168
+ };
1169
+ }
1170
+ //#endregion
1171
+ //#region ../../node_modules/.pnpm/@tanstack+vue-virtual@3.13.36_vue@3.5.42_typescript@5.9.3_/node_modules/@tanstack/vue-virtual/dist/esm/index.js
1172
+ function useVirtualizerBase(options) {
1173
+ const virtualizer = new Virtualizer(unref(options));
1174
+ const state = shallowRef(virtualizer);
1175
+ const cleanup = virtualizer._didMount();
1176
+ watch(() => unref(options).getScrollElement(), (el) => {
1177
+ if (el) virtualizer._willUpdate();
1178
+ }, { immediate: true });
1179
+ watch(() => unref(options), (options2) => {
1180
+ virtualizer.setOptions({
1181
+ ...options2,
1182
+ onChange: (instance, sync) => {
1183
+ var _a;
1184
+ triggerRef(state);
1185
+ (_a = options2.onChange) == null || _a.call(options2, instance, sync);
1186
+ }
1187
+ });
1188
+ virtualizer._willUpdate();
1189
+ triggerRef(state);
1190
+ }, { immediate: true });
1191
+ onScopeDispose(cleanup);
1192
+ return state;
1193
+ }
1194
+ function useVirtualizer(options) {
1195
+ return useVirtualizerBase(computed(() => ({
1196
+ observeElementRect,
1197
+ observeElementOffset,
1198
+ scrollToFn: elementScroll,
1199
+ ...unref(options)
1200
+ })));
1201
+ }
1202
+ //#endregion
1203
+ //#region src/addons/iconset/api.ts
1204
+ var apiRoot = "https://api.iconify.design";
1205
+ var collectionsCache = /* @__PURE__ */ new Map();
1206
+ var collectionDataCache = /* @__PURE__ */ new Map();
1207
+ async function getJson(url, signal) {
1208
+ const response = await fetch(url, { signal });
1209
+ if (!response.ok) throw new Error(`Iconify request failed (${response.status})`);
1210
+ return response.json();
1211
+ }
1212
+ /** Fetches the Iconify catalog, grouped by its category. */
1213
+ function fetchCollections() {
1214
+ const cached = collectionsCache.get("all");
1215
+ if (cached) return cached;
1216
+ const request = getJson(`${apiRoot}/collections`).then((data) => {
1217
+ const groups = /* @__PURE__ */ new Map();
1218
+ for (const [prefix, item] of Object.entries(data)) {
1219
+ if (item.hidden) continue;
1220
+ const category = item.category || "Other";
1221
+ const group = groups.get(category) || [];
1222
+ group.push({
1223
+ ...item,
1224
+ prefix,
1225
+ category
1226
+ });
1227
+ groups.set(category, group);
1228
+ }
1229
+ const orderedGroups = [...groups.entries()].map(([category, items]) => ({
1230
+ category,
1231
+ items
1232
+ }));
1233
+ return [...orderedGroups.filter((group) => !/archiv|unmaintained/i.test(group.category)), ...orderedGroups.filter((group) => /archiv|unmaintained/i.test(group.category))];
1234
+ });
1235
+ collectionsCache.set("all", request);
1236
+ request.catch(() => collectionsCache.delete("all"));
1237
+ return request;
1238
+ }
1239
+ /** Fetches one icon set's names and metadata. Requests are cached by prefix. */
1240
+ function fetchCollection(prefix) {
1241
+ const cached = collectionDataCache.get(prefix);
1242
+ if (cached) return cached;
1243
+ const request = getJson(`${apiRoot}/collection?prefix=${encodeURIComponent(prefix)}&chars=true&aliases=true`);
1244
+ collectionDataCache.set(prefix, request);
1245
+ request.catch(() => collectionDataCache.delete(prefix));
1246
+ return request;
1247
+ }
1248
+ /** Searches the global Iconify index. The signal lets callers cancel stale requests. */
1249
+ function searchIcons(query, signal) {
1250
+ return getJson(`${apiRoot}/search?query=${encodeURIComponent(query)}&limit=999`, signal).then((data) => ({ icons: data.icons || [] }));
1251
+ }
1252
+ /** Returns icon names from a collection in stable API order. */
1253
+ function getCollectionIconNames(data, query = "") {
1254
+ const names = [];
1255
+ if (data.uncategorized) names.push(...data.uncategorized);
1256
+ if (data.categories) for (const category of Object.keys(data.categories)) names.push(...data.categories[category]);
1257
+ const normalizedQuery = query.toLowerCase();
1258
+ const filtered = names.filter((name) => !normalizedQuery || name.toLowerCase().includes(normalizedQuery));
1259
+ if (filtered.length === 0 && normalizedQuery && data.hidden) filtered.push(...data.hidden.filter((name) => name.toLowerCase().includes(normalizedQuery)));
1260
+ return [...new Set(filtered)];
1261
+ }
1262
+ //#endregion
1263
+ //#region src/addons/iconset/IconGrid.vue?vue&type=script&setup=true&lang.ts
1264
+ var _hoisted_1$1 = ["aria-pressed"];
1265
+ var _hoisted_2 = ["aria-pressed", "onClick"];
1266
+ var _hoisted_3 = [
1267
+ "aria-label",
1268
+ "aria-pressed",
1269
+ "title",
1270
+ "onClick"
1271
+ ];
1272
+ //#endregion
1273
+ //#region src/addons/iconset/IconGrid.vue
1274
+ var IconGrid_default = /* @__PURE__ */ defineComponent({
1275
+ __name: "IconGrid",
1276
+ props: {
1277
+ collections: { default: () => [] },
1278
+ modelValue: {},
1279
+ query: { default: "" },
1280
+ activeCollection: { default: "" },
1281
+ iconSize: { default: 20 },
1282
+ cellSize: { default: 40 },
1283
+ height: { default: 420 },
1284
+ ui: {},
1285
+ overscan: { default: 4 }
1286
+ },
1287
+ emits: [
1288
+ "update:modelValue",
1289
+ "update:query",
1290
+ "update:activeCollection",
1291
+ "select"
1292
+ ],
1293
+ setup(__props, { emit: __emit }) {
1294
+ const props = __props;
1295
+ const emits = __emit;
1296
+ const viewport = ref();
1297
+ const viewportWidth = ref(0);
1298
+ const icons = ref([]);
1299
+ const labels = ref({});
1300
+ const selectedIcon = ref(props.modelValue || "");
1301
+ const query = ref(props.query);
1302
+ const activeCollection = ref(props.activeCollection);
1303
+ const loading = ref(false);
1304
+ const error = ref();
1305
+ const requestId = ref(0);
1306
+ let searchController;
1307
+ const toCssSize = (size) => {
1308
+ const value = String(size);
1309
+ return /^\d+(\.\d+)?$/.test(value) ? `${value}px` : value;
1310
+ };
1311
+ const iconSize = computed(() => toCssSize(props.iconSize));
1312
+ const viewportHeight = computed(() => toCssSize(props.height));
1313
+ const columns = computed(() => Math.max(1, Math.floor(viewportWidth.value / props.cellSize) || 1));
1314
+ const rowCount = computed(() => Math.ceil(icons.value.length / columns.value));
1315
+ const activePrefix = computed(() => {
1316
+ if (props.collections.length <= 1) return props.collections[0] || "";
1317
+ return props.collections.includes(activeCollection.value) ? activeCollection.value : "";
1318
+ });
1319
+ const hasCollectionTabs = computed(() => props.collections.length > 1);
1320
+ const virtualizer = useVirtualizer({
1321
+ get count() {
1322
+ return rowCount.value;
1323
+ },
1324
+ getScrollElement() {
1325
+ return viewport.value || null;
1326
+ },
1327
+ estimateSize() {
1328
+ return props.cellSize;
1329
+ },
1330
+ getItemKey(index) {
1331
+ return `${activePrefix.value}:${query.value}:${index}`;
1332
+ },
1333
+ get overscan() {
1334
+ return props.overscan;
1335
+ }
1336
+ });
1337
+ const virtualRows = computed(() => virtualizer.value.getVirtualItems());
1338
+ const selectCollection = (prefix) => {
1339
+ activeCollection.value = prefix;
1340
+ emits("update:activeCollection", prefix);
1341
+ };
1342
+ const selectIcon = (icon) => {
1343
+ selectedIcon.value = icon;
1344
+ emits("update:modelValue", icon);
1345
+ emits("select", icon);
1346
+ };
1347
+ const updateQuery = (value) => {
1348
+ query.value = value;
1349
+ emits("update:query", value);
1350
+ };
1351
+ const resetScroll = async () => {
1352
+ await nextTick();
1353
+ virtualizer.value.scrollToOffset(0);
1354
+ virtualizer.value.measure();
1355
+ };
1356
+ const loadIcons = async () => {
1357
+ const id = ++requestId.value;
1358
+ searchController?.abort();
1359
+ searchController = void 0;
1360
+ error.value = void 0;
1361
+ icons.value = [];
1362
+ const normalizedQuery = query.value.trim();
1363
+ if (props.collections.length === 0 && !normalizedQuery) {
1364
+ loading.value = false;
1365
+ await resetScroll();
1366
+ return;
1367
+ }
1368
+ loading.value = true;
1369
+ try {
1370
+ if (props.collections.length === 0) {
1371
+ searchController = new AbortController();
1372
+ const result = await searchIcons(normalizedQuery, searchController.signal);
1373
+ if (id !== requestId.value) return;
1374
+ icons.value = result.icons;
1375
+ } else {
1376
+ const prefixes = activePrefix.value ? [activePrefix.value] : props.collections;
1377
+ const data = await Promise.all(prefixes.map((prefix) => fetchCollection(prefix)));
1378
+ if (id !== requestId.value) return;
1379
+ const nextIcons = [];
1380
+ data.forEach((collection, index) => {
1381
+ const prefix = prefixes[index];
1382
+ getCollectionIconNames(collection, normalizedQuery).forEach((name) => nextIcons.push(`${prefix}:${name}`));
1383
+ });
1384
+ icons.value = [...new Set(nextIcons)];
1385
+ }
1386
+ } catch (cause) {
1387
+ if (id !== requestId.value || cause instanceof DOMException && cause.name === "AbortError") return;
1388
+ error.value = cause instanceof Error ? cause : /* @__PURE__ */ new Error("Unable to load icons");
1389
+ } finally {
1390
+ if (id === requestId.value) {
1391
+ loading.value = false;
1392
+ resetScroll();
1393
+ }
1394
+ }
1395
+ };
1396
+ const loadLabels = async () => {
1397
+ if (props.collections.length === 0) {
1398
+ labels.value = {};
1399
+ return;
1400
+ }
1401
+ try {
1402
+ const groups = await fetchCollections();
1403
+ const next = {};
1404
+ groups.forEach((group) => group.items.forEach((item) => {
1405
+ next[item.prefix] = item.name;
1406
+ }));
1407
+ labels.value = next;
1408
+ } catch {
1409
+ labels.value = {};
1410
+ }
1411
+ };
1412
+ const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver((entries) => {
1413
+ viewportWidth.value = entries[0]?.contentRect.width || 0;
1414
+ }) : void 0;
1415
+ watch(viewport, (element, previous) => {
1416
+ if (previous) resizeObserver?.unobserve(previous);
1417
+ if (element) {
1418
+ resizeObserver?.observe(element);
1419
+ const style = getComputedStyle(element);
1420
+ viewportWidth.value = element.clientWidth - Number.parseFloat(style.paddingLeft) - Number.parseFloat(style.paddingRight);
1421
+ }
1422
+ });
1423
+ watch(() => props.modelValue, (value) => {
1424
+ selectedIcon.value = value || "";
1425
+ });
1426
+ watch(() => props.query, (value) => {
1427
+ query.value = value;
1428
+ });
1429
+ watch(() => props.activeCollection, (value) => {
1430
+ activeCollection.value = value;
1431
+ });
1432
+ watch(() => [
1433
+ props.collections,
1434
+ query.value,
1435
+ activeCollection.value
1436
+ ], loadIcons, {
1437
+ deep: true,
1438
+ immediate: true
1439
+ });
1440
+ watch(() => props.collections, loadLabels, {
1441
+ deep: true,
1442
+ immediate: true
1443
+ });
1444
+ watch(() => props.cellSize, () => virtualizer.value.measure());
1445
+ onBeforeUnmount(() => {
1446
+ searchController?.abort();
1447
+ resizeObserver?.disconnect();
1448
+ });
1449
+ return (_ctx, _cache) => {
1450
+ return openBlock(), createElementBlock("div", { class: normalizeClass(["ui-IconGrid", props.ui?.base]) }, [
1451
+ createElementVNode("div", { class: normalizeClass(["ui-IconGridHeader", props.ui?.header]) }, [renderSlot(_ctx.$slots, "header-leading"), renderSlot(_ctx.$slots, "header-search", {}, () => [createVNode(unref(TextField), {
1452
+ "model-value": query.value,
1453
+ type: "search",
1454
+ placeholder: "Search icons...",
1455
+ "aria-label": "Search icons",
1456
+ class: normalizeClass(["ui-IconGridSearch", props.ui?.search]),
1457
+ "onUpdate:modelValue": updateQuery
1458
+ }, null, 8, ["model-value", "class"])])], 2),
1459
+ hasCollectionTabs.value ? (openBlock(), createElementBlock("div", {
1460
+ key: 0,
1461
+ class: normalizeClass(["ui-IconGridTabs", props.ui?.tabs]),
1462
+ role: "group",
1463
+ "aria-label": "Icon collections"
1464
+ }, [createElementVNode("button", {
1465
+ type: "button",
1466
+ class: normalizeClass([props.ui?.tab, { "is-active": !activePrefix.value }]),
1467
+ "aria-pressed": !activePrefix.value,
1468
+ onClick: _cache[0] || (_cache[0] = ($event) => selectCollection(""))
1469
+ }, " All ", 10, _hoisted_1$1), (openBlock(true), createElementBlock(Fragment, null, renderList(props.collections, (prefix) => {
1470
+ return openBlock(), createElementBlock("button", {
1471
+ key: prefix,
1472
+ type: "button",
1473
+ class: normalizeClass([props.ui?.tab, { "is-active": activePrefix.value === prefix }]),
1474
+ "aria-pressed": activePrefix.value === prefix,
1475
+ onClick: ($event) => selectCollection(prefix)
1476
+ }, toDisplayString(labels.value[prefix] || prefix), 11, _hoisted_2);
1477
+ }), 128))], 2)) : createCommentVNode("", true),
1478
+ createElementVNode("div", {
1479
+ ref_key: "viewport",
1480
+ ref: viewport,
1481
+ class: normalizeClass(["ui-IconGridViewport", props.ui?.viewport]),
1482
+ style: normalizeStyle({ height: viewportHeight.value }),
1483
+ tabindex: "0"
1484
+ }, [loading.value ? (openBlock(), createElementBlock("p", {
1485
+ key: 0,
1486
+ class: normalizeClass(["ui-IconGridMessage", props.ui?.message]),
1487
+ role: "status"
1488
+ }, " Loading icons... ", 2)) : error.value ? (openBlock(), createElementBlock("p", {
1489
+ key: 1,
1490
+ class: normalizeClass(["ui-IconGridMessage", props.ui?.message]),
1491
+ role: "alert"
1492
+ }, toDisplayString(error.value.message), 3)) : icons.value.length === 0 ? (openBlock(), createElementBlock("p", {
1493
+ key: 2,
1494
+ class: normalizeClass(["ui-IconGridMessage", props.ui?.message])
1495
+ }, " No icons found. ", 2)) : (openBlock(), createElementBlock("div", {
1496
+ key: 3,
1497
+ class: normalizeClass(["ui-IconGridContent", props.ui?.content]),
1498
+ style: normalizeStyle({ height: `${unref(virtualizer).getTotalSize()}px` })
1499
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(virtualRows.value, (row) => {
1500
+ return openBlock(), createElementBlock("div", {
1501
+ key: String(row.key),
1502
+ class: "ui-IconGridRow",
1503
+ style: normalizeStyle({
1504
+ transform: `translateY(${row.start}px)`,
1505
+ height: `${props.cellSize}px`
1506
+ })
1507
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(icons.value.slice(row.index * columns.value, (row.index + 1) * columns.value), (icon) => {
1508
+ return openBlock(), createElementBlock("button", {
1509
+ key: icon,
1510
+ type: "button",
1511
+ class: normalizeClass(["ui-IconGridCell", props.ui?.cell]),
1512
+ "aria-label": icon,
1513
+ "aria-pressed": selectedIcon.value === icon,
1514
+ title: icon,
1515
+ style: normalizeStyle({ flexBasis: `${100 / columns.value}%` }),
1516
+ onClick: ($event) => selectIcon(icon)
1517
+ }, [createVNode(unref(Icon), {
1518
+ icon,
1519
+ style: normalizeStyle({ fontSize: iconSize.value }),
1520
+ "aria-hidden": "true"
1521
+ }, null, 8, ["icon", "style"])], 14, _hoisted_3);
1522
+ }), 128))], 4);
1523
+ }), 128))], 6))], 6)
1524
+ ], 2);
1525
+ };
1526
+ }
395
1527
  });
396
- const turnstileSrc = "https://challenges.cloudflare.com/turnstile/v0/api.js";
397
- const turnstileLoadFunction = "cfTurnstileOnLoad";
398
- let turnstileState = typeof window !== "undefined" ? window.turnstile !== void 0 ? "ready" : "unloaded" : "unloaded";
399
- let turnstileLoad;
400
- let widgetId;
401
- let resetTimeout;
402
- const _sfc_main = /* @__PURE__ */ defineComponent({
403
- __name: "Turnstile",
404
- props: {
405
- sitekey: {},
406
- modelValue: {},
407
- resetInterval: { default: 295 * 1e3 },
408
- size: { default: "normal" },
409
- theme: { default: "auto" },
410
- action: { default: "" },
411
- appearance: { default: "always" },
412
- renderOnMount: { type: Boolean, default: true }
413
- },
414
- emits: ["update:modelValue"],
415
- setup(__props, { emit: __emit }) {
416
- const props = __props;
417
- const emit = __emit;
418
- const element = useTemplateRef("element");
419
- const resetTurnstile = () => {
420
- if (window.turnstile) {
421
- emit("update:modelValue", "");
422
- window.turnstile.reset();
423
- }
424
- };
425
- const removeTurnstile = () => {
426
- if (widgetId) {
427
- window.turnstile.remove(widgetId);
428
- widgetId = void 0;
429
- }
430
- };
431
- const callbackTurnstile = (token) => {
432
- emit("update:modelValue", token);
433
- resetTimeout = setTimeout(() => {
434
- resetTurnstile();
435
- }, props.resetInterval);
436
- };
437
- const renderTurnstile = () => {
438
- widgetId = window.turnstile.render(element.value, {
439
- sitekey: props.sitekey,
440
- theme: props.theme,
441
- size: props.size,
442
- callback: callbackTurnstile,
443
- action: props.action,
444
- appearance: props.appearance
445
- });
446
- };
447
- onMounted(async () => {
448
- const turnstileLoadPromise = new Promise((resolve, reject) => {
449
- turnstileLoad = { resolve, reject };
450
- if (turnstileState === "ready") resolve(void 0);
451
- });
452
- window[turnstileLoadFunction] = () => {
453
- turnstileLoad.resolve();
454
- turnstileState = "ready";
455
- };
456
- const ensureTurnstile = () => {
457
- if (turnstileState === "unloaded") {
458
- turnstileState = "loading";
459
- const url = `${turnstileSrc}?onload=${turnstileLoadFunction}&render=explicit`;
460
- const script = document.createElement("script");
461
- script.src = url;
462
- script.async = true;
463
- script.addEventListener("error", () => {
464
- turnstileLoad.reject("Failed to load Turnstile.");
465
- });
466
- document.head.appendChild(script);
467
- }
468
- return turnstileLoadPromise;
469
- };
470
- await ensureTurnstile();
471
- if (props.renderOnMount) {
472
- renderTurnstile();
473
- }
474
- });
475
- onBeforeUnmount(() => {
476
- removeTurnstile();
477
- clearTimeout(resetTimeout);
478
- });
479
- return (_ctx, _cache) => {
480
- return openBlock(), createElementBlock("div", {
481
- ref_key: "element",
482
- ref: element,
483
- class: normalizeClass(["ui-Turnstile", `r-size-${__props.size}`])
484
- }, null, 2);
485
- };
486
- }
1528
+ //#endregion
1529
+ //#region src/addons/iconset/IconCollection.vue?vue&type=script&setup=true&lang.ts
1530
+ var _hoisted_1 = ["onClick"];
1531
+ //#endregion
1532
+ //#region src/addons/iconset/IconCollection.vue
1533
+ var IconCollection_default = /* @__PURE__ */ defineComponent({
1534
+ __name: "IconCollection",
1535
+ props: {
1536
+ modelValue: {},
1537
+ collection: { default: "" },
1538
+ query: { default: "" },
1539
+ filter: { default: "" },
1540
+ iconSize: { default: 20 },
1541
+ cellSize: { default: 40 },
1542
+ height: { default: 420 },
1543
+ overscan: { default: 4 },
1544
+ ui: {}
1545
+ },
1546
+ emits: [
1547
+ "update:modelValue",
1548
+ "update:collection",
1549
+ "update:query",
1550
+ "update:filter",
1551
+ "select"
1552
+ ],
1553
+ setup(__props, { emit: __emit }) {
1554
+ const props = __props;
1555
+ const emits = __emit;
1556
+ const groups = ref([]);
1557
+ const selectedIcon = ref(props.modelValue || "");
1558
+ const collection = ref(props.collection);
1559
+ const query = ref(props.query);
1560
+ const filter = ref(props.filter);
1561
+ const loading = ref(true);
1562
+ const error = ref();
1563
+ const toCssSize = (size) => {
1564
+ const value = String(size);
1565
+ return /^\d+(\.\d+)?$/.test(value) ? `${value}px` : value;
1566
+ };
1567
+ const viewportHeight = computed(() => toCssSize(props.height));
1568
+ const visibleGroups = computed(() => {
1569
+ const normalizedFilter = filter.value.trim().toLowerCase();
1570
+ if (!normalizedFilter) return groups.value;
1571
+ return groups.value.map((group) => ({
1572
+ ...group,
1573
+ items: group.items.filter((item) => [
1574
+ group.category,
1575
+ item.name,
1576
+ item.prefix
1577
+ ].join(" ").toLowerCase().includes(normalizedFilter))
1578
+ })).filter((group) => group.items.length > 0);
1579
+ });
1580
+ const collectionCount = computed(() => groups.value.reduce((count, group) => count + group.items.length, 0));
1581
+ const updateFilter = (value) => {
1582
+ filter.value = value;
1583
+ emits("update:filter", value);
1584
+ };
1585
+ const selectCollection = (item) => {
1586
+ collection.value = item.prefix;
1587
+ query.value = "";
1588
+ emits("update:collection", item.prefix);
1589
+ emits("update:query", "");
1590
+ };
1591
+ const showCollections = () => {
1592
+ collection.value = "";
1593
+ query.value = "";
1594
+ emits("update:collection", "");
1595
+ emits("update:query", "");
1596
+ };
1597
+ const updateQuery = (value) => {
1598
+ query.value = value;
1599
+ emits("update:query", value);
1600
+ };
1601
+ const selectIcon = (icon) => {
1602
+ selectedIcon.value = icon;
1603
+ emits("update:modelValue", icon);
1604
+ emits("select", icon);
1605
+ };
1606
+ watch(() => props.modelValue, (value) => {
1607
+ selectedIcon.value = value || "";
1608
+ });
1609
+ watch(() => props.collection, (value) => {
1610
+ collection.value = value;
1611
+ });
1612
+ watch(() => props.query, (value) => {
1613
+ query.value = value;
1614
+ });
1615
+ watch(() => props.filter, (value) => {
1616
+ filter.value = value;
1617
+ });
1618
+ onMounted(async () => {
1619
+ try {
1620
+ groups.value = await fetchCollections();
1621
+ } catch (cause) {
1622
+ error.value = cause instanceof Error ? cause : /* @__PURE__ */ new Error("Unable to load icon collections");
1623
+ } finally {
1624
+ loading.value = false;
1625
+ }
1626
+ });
1627
+ return (_ctx, _cache) => {
1628
+ return openBlock(), createElementBlock("div", { class: normalizeClass(["ui-IconCollection", props.ui?.base]) }, [collection.value ? (openBlock(), createBlock(IconGrid_default, {
1629
+ key: 0,
1630
+ "model-value": selectedIcon.value,
1631
+ query: query.value,
1632
+ collections: [collection.value],
1633
+ "icon-size": props.iconSize,
1634
+ "cell-size": props.cellSize,
1635
+ height: props.height,
1636
+ overscan: props.overscan,
1637
+ ui: props.ui?.grid,
1638
+ "onUpdate:query": updateQuery,
1639
+ onSelect: selectIcon
1640
+ }, {
1641
+ "header-leading": withCtx(() => [createVNode(unref(Button), {
1642
+ type: "button",
1643
+ variant: "ghost",
1644
+ color: "gray",
1645
+ class: normalizeClass(["ui-IconCollectionBack", props.ui?.back]),
1646
+ "aria-label": "Back to icon sets",
1647
+ onClick: showCollections
1648
+ }, {
1649
+ default: withCtx(() => [createVNode(unref(Icon), {
1650
+ icon: "lucide:chevron-left",
1651
+ "aria-hidden": "true"
1652
+ }), _cache[0] || (_cache[0] = createTextVNode(" Back ", -1))]),
1653
+ _: 1
1654
+ }, 8, ["class"])]),
1655
+ _: 1
1656
+ }, 8, [
1657
+ "model-value",
1658
+ "query",
1659
+ "collections",
1660
+ "icon-size",
1661
+ "cell-size",
1662
+ "height",
1663
+ "overscan",
1664
+ "ui"
1665
+ ])) : (openBlock(), createElementBlock("div", {
1666
+ key: 1,
1667
+ class: normalizeClass(["ui-IconCollectionBrowser", props.ui?.browser]),
1668
+ style: normalizeStyle({ height: viewportHeight.value }),
1669
+ tabindex: "0"
1670
+ }, [createElementVNode("div", { class: normalizeClass(["ui-IconCollectionToolbar", props.ui?.toolbar]) }, [createElementVNode("h2", { class: normalizeClass(["ui-IconCollectionTitle", props.ui?.title]) }, toDisplayString(collectionCount.value) + " icon sets", 3), createVNode(unref(TextField), {
1671
+ "model-value": filter.value,
1672
+ type: "search",
1673
+ placeholder: "Filter icon sets...",
1674
+ "aria-label": "Filter icon sets",
1675
+ class: normalizeClass(["ui-IconCollectionFilter", props.ui?.filter]),
1676
+ "onUpdate:modelValue": updateFilter
1677
+ }, null, 8, ["model-value", "class"])], 2), loading.value ? (openBlock(), createElementBlock("p", {
1678
+ key: 0,
1679
+ class: normalizeClass(["ui-IconCollectionMessage", props.ui?.message]),
1680
+ role: "status"
1681
+ }, " Loading icon sets... ", 2)) : error.value ? (openBlock(), createElementBlock("p", {
1682
+ key: 1,
1683
+ class: normalizeClass(["ui-IconCollectionMessage", props.ui?.message]),
1684
+ role: "alert"
1685
+ }, toDisplayString(error.value.message), 3)) : visibleGroups.value.length === 0 ? (openBlock(), createElementBlock("p", {
1686
+ key: 2,
1687
+ class: normalizeClass(["ui-IconCollectionMessage", props.ui?.message])
1688
+ }, " No icon sets found. ", 2)) : (openBlock(), createElementBlock("div", {
1689
+ key: 3,
1690
+ class: normalizeClass(["ui-IconCollectionGroups", props.ui?.groups])
1691
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(visibleGroups.value, (group) => {
1692
+ return openBlock(), createElementBlock("section", {
1693
+ key: group.category,
1694
+ class: normalizeClass(["ui-IconCollectionGroup", props.ui?.group])
1695
+ }, [createElementVNode("h3", { class: normalizeClass(["ui-IconCollectionGroupTitle", props.ui?.groupTitle]) }, [createElementVNode("span", null, toDisplayString(group.category), 1), createElementVNode("span", null, "(" + toDisplayString(group.items.length) + " icon sets)", 1)], 2), createElementVNode("div", { class: normalizeClass(["ui-IconCollectionCards", props.ui?.cards]) }, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.items, (item) => {
1696
+ return openBlock(), createElementBlock("button", {
1697
+ key: item.prefix,
1698
+ type: "button",
1699
+ class: normalizeClass(["ui-IconCollectionCard", props.ui?.card]),
1700
+ onClick: ($event) => selectCollection(item)
1701
+ }, [createElementVNode("span", { class: normalizeClass(["ui-IconCollectionInfo", props.ui?.info]) }, [
1702
+ createElementVNode("strong", null, toDisplayString(item.name), 1),
1703
+ createElementVNode("span", null, toDisplayString(item.license?.title || "Unknown license"), 1),
1704
+ createElementVNode("span", null, toDisplayString(item.total) + " icons", 1)
1705
+ ], 2), createElementVNode("span", {
1706
+ class: normalizeClass(["ui-IconCollectionSamples", props.ui?.samples]),
1707
+ "aria-hidden": "true"
1708
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(item.samples?.slice(0, 6), (sample) => {
1709
+ return openBlock(), createBlock(unref(Icon), {
1710
+ key: sample,
1711
+ icon: `${item.prefix}:${sample}`
1712
+ }, null, 8, ["icon"]);
1713
+ }), 128))], 2)], 10, _hoisted_1);
1714
+ }), 128))], 2)], 2);
1715
+ }), 128))], 2))], 6))], 2);
1716
+ };
1717
+ }
487
1718
  });
488
- export {
489
- _sfc_main$1 as IconifyCollection,
490
- _sfc_main$3 as SocialButton,
491
- _sfc_main as Turnstile
1719
+ //#endregion
1720
+ //#region src/addons/turnstile/Turnstile.vue?vue&type=script&setup=true&lang.ts
1721
+ var turnstileSrc = "https://challenges.cloudflare.com/turnstile/v0/api.js";
1722
+ var turnstileLoadFunction = "cfTurnstileOnLoad";
1723
+ var turnstileLoadPromise;
1724
+ var loadTurnstile = () => {
1725
+ if (typeof window === "undefined") return Promise.reject(/* @__PURE__ */ new Error("Turnstile is only available in a browser."));
1726
+ if (window.turnstile) return Promise.resolve();
1727
+ if (turnstileLoadPromise) return turnstileLoadPromise;
1728
+ turnstileLoadPromise = new Promise((resolve, reject) => {
1729
+ const onLoad = () => {
1730
+ if (window.turnstile) resolve();
1731
+ else reject(/* @__PURE__ */ new Error("Turnstile loaded without exposing its API."));
1732
+ };
1733
+ window[turnstileLoadFunction] = onLoad;
1734
+ const script = document.createElement("script");
1735
+ script.src = `${turnstileSrc}?onload=${turnstileLoadFunction}&render=explicit`;
1736
+ script.async = true;
1737
+ script.addEventListener("error", () => {
1738
+ reject(/* @__PURE__ */ new Error("Failed to load Turnstile."));
1739
+ }, { once: true });
1740
+ document.head.appendChild(script);
1741
+ }).catch((error) => {
1742
+ turnstileLoadPromise = void 0;
1743
+ if (window.cfTurnstileOnLoad) delete window.cfTurnstileOnLoad;
1744
+ throw error;
1745
+ });
1746
+ return turnstileLoadPromise;
492
1747
  };
1748
+ //#endregion
1749
+ //#region src/addons/turnstile/Turnstile.vue
1750
+ var Turnstile_default = /* @__PURE__ */ defineComponent({
1751
+ __name: "Turnstile",
1752
+ props: {
1753
+ sitekey: {},
1754
+ modelValue: {},
1755
+ resetInterval: { default: 295e3 },
1756
+ size: { default: "normal" },
1757
+ theme: { default: "auto" },
1758
+ action: { default: "" },
1759
+ appearance: { default: "always" },
1760
+ renderOnMount: {
1761
+ type: Boolean,
1762
+ default: true
1763
+ }
1764
+ },
1765
+ emits: ["update:modelValue"],
1766
+ setup(__props, { expose: __expose, emit: __emit }) {
1767
+ const props = __props;
1768
+ const emit = __emit;
1769
+ const element = useTemplateRef("element");
1770
+ const mounted = ref(false);
1771
+ let widgetId;
1772
+ let resetTimeout;
1773
+ const clearResetTimeout = () => {
1774
+ if (resetTimeout !== void 0) {
1775
+ clearTimeout(resetTimeout);
1776
+ resetTimeout = void 0;
1777
+ }
1778
+ };
1779
+ const resetTurnstile = () => {
1780
+ if (widgetId !== void 0 && window.turnstile) {
1781
+ clearResetTimeout();
1782
+ emit("update:modelValue", "");
1783
+ window.turnstile.reset(widgetId);
1784
+ }
1785
+ };
1786
+ const removeTurnstile = () => {
1787
+ clearResetTimeout();
1788
+ if (widgetId !== void 0) {
1789
+ if (window.turnstile) window.turnstile.remove(widgetId);
1790
+ widgetId = void 0;
1791
+ }
1792
+ };
1793
+ const callbackTurnstile = (token) => {
1794
+ emit("update:modelValue", token);
1795
+ clearResetTimeout();
1796
+ resetTimeout = setTimeout(() => {
1797
+ resetTurnstile();
1798
+ }, props.resetInterval);
1799
+ };
1800
+ const renderTurnstile = async () => {
1801
+ if (!mounted.value || widgetId !== void 0 || !element.value) return;
1802
+ if (!window.turnstile) try {
1803
+ await loadTurnstile();
1804
+ } catch {
1805
+ return;
1806
+ }
1807
+ if (!mounted.value || widgetId !== void 0 || !element.value || !window.turnstile) return;
1808
+ widgetId = window.turnstile.render(element.value, {
1809
+ sitekey: props.sitekey,
1810
+ theme: props.theme,
1811
+ size: props.size,
1812
+ callback: callbackTurnstile,
1813
+ action: props.action,
1814
+ appearance: props.appearance
1815
+ });
1816
+ };
1817
+ __expose({
1818
+ render: renderTurnstile,
1819
+ reset: resetTurnstile,
1820
+ remove: removeTurnstile
1821
+ });
1822
+ onMounted(() => {
1823
+ mounted.value = true;
1824
+ if (props.renderOnMount) renderTurnstile();
1825
+ });
1826
+ onBeforeUnmount(() => {
1827
+ mounted.value = false;
1828
+ removeTurnstile();
1829
+ });
1830
+ return (_ctx, _cache) => {
1831
+ return openBlock(), createElementBlock("div", {
1832
+ ref_key: "element",
1833
+ ref: element,
1834
+ class: normalizeClass(["ui-Turnstile", `r-size-${__props.size}`])
1835
+ }, null, 2);
1836
+ };
1837
+ }
1838
+ });
1839
+ //#endregion
1840
+ export { IconCollection_default as IconCollection, IconGrid_default as IconGrid, SocialButton_default as SocialButton, Turnstile_default as Turnstile };