@clyrex-digital/clyrex-controls-dev 0.8.1-dev.20260924080906 → 0.8.1-dev.20260924115534

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.
@@ -0,0 +1,481 @@
1
+ "use client";
2
+ import {
3
+ InputControlType_default
4
+ } from "./chunk-HRDHAIZF.mjs";
5
+ import {
6
+ Button_default
7
+ } from "./chunk-4WMSS6CE.mjs";
8
+ import "./chunk-56HSDML5.mjs";
9
+
10
+ // src/components/pageRenderingEngine/nodes/DataBindingControls.tsx
11
+ import { useCallback, useEffect, useMemo, useState } from "react";
12
+ import { useRouter, useSearchParams } from "next/navigation";
13
+
14
+ // src/components/controls/edit/InputControl.tsx
15
+ import dynamic from "next/dynamic";
16
+ var InputControl = dynamic(() => import("./InputControlClient-NHXG4QBU.mjs"), {
17
+ ssr: false
18
+ });
19
+ var InputControl_default = InputControl;
20
+
21
+ // src/components/pageRenderingEngine/nodes/DataBindingControls.tsx
22
+ import { jsx, jsxs } from "react/jsx-runtime";
23
+ var humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
24
+ var escapeODataString = (value) => value.replace(/'/g, "''");
25
+ var parseFacetSelections = (filter) => {
26
+ const selections = /* @__PURE__ */ new Map();
27
+ if (!filter || !filter.trim()) return selections;
28
+ const expression = /(?:^|[\s()]+(?:and[\s()]+)?)([\w./-]+)\s+eq\s+'((?:''|[^'])*)'/gi;
29
+ for (const match of filter.matchAll(expression)) {
30
+ if (match[1] && match[2] !== void 0) {
31
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
32
+ }
33
+ }
34
+ return selections;
35
+ };
36
+ var buildFacetFilter = (selections) => Array.from(selections.entries()).map(([field, value]) => `${field} eq '${escapeODataString(value)}'`).join(" and ");
37
+ var parseODataSearch = (value) => {
38
+ if (!value) return "";
39
+ const trimmedValue = value.trim();
40
+ if (trimmedValue.startsWith("'") && trimmedValue.endsWith("'")) {
41
+ return trimmedValue.slice(1, -1).replace(/''/g, "'");
42
+ }
43
+ return trimmedValue;
44
+ };
45
+ var SearchIcon = ({ className = "" }) => /* @__PURE__ */ jsxs(
46
+ "svg",
47
+ {
48
+ "aria-hidden": "true",
49
+ className,
50
+ fill: "none",
51
+ viewBox: "0 0 24 24",
52
+ stroke: "currentColor",
53
+ strokeWidth: "2",
54
+ children: [
55
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
56
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "m20 20-4-4" })
57
+ ]
58
+ }
59
+ );
60
+ var ResetIcon = ({ className = "" }) => /* @__PURE__ */ jsxs(
61
+ "svg",
62
+ {
63
+ "aria-hidden": "true",
64
+ className,
65
+ fill: "none",
66
+ viewBox: "0 0 24 24",
67
+ stroke: "currentColor",
68
+ strokeWidth: "2",
69
+ children: [
70
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 4v6h6" }),
71
+ /* @__PURE__ */ jsx(
72
+ "path",
73
+ {
74
+ strokeLinecap: "round",
75
+ strokeLinejoin: "round",
76
+ d: "M5.5 15a8 8 0 1 0 .6-7.8L4 10"
77
+ }
78
+ )
79
+ ]
80
+ }
81
+ );
82
+ var FilterSlidersIcon = ({ className = "" }) => /* @__PURE__ */ jsxs(
83
+ "svg",
84
+ {
85
+ "aria-hidden": "true",
86
+ className,
87
+ fill: "none",
88
+ viewBox: "0 0 24 24",
89
+ stroke: "currentColor",
90
+ strokeWidth: "2",
91
+ children: [
92
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4h18M3 12h18M3 20h18" }),
93
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "4", r: "2", fill: "currentColor" }),
94
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "12", r: "2", fill: "currentColor" }),
95
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "20", r: "2", fill: "currentColor" })
96
+ ]
97
+ }
98
+ );
99
+ var ChevronDownIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
100
+ "svg",
101
+ {
102
+ "aria-hidden": "true",
103
+ className,
104
+ fill: "none",
105
+ viewBox: "0 0 24 24",
106
+ stroke: "currentColor",
107
+ strokeWidth: "2",
108
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m19 9-7 7-7-7" })
109
+ }
110
+ );
111
+ var CheckIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
112
+ "svg",
113
+ {
114
+ "aria-hidden": "true",
115
+ className,
116
+ fill: "none",
117
+ viewBox: "0 0 24 24",
118
+ stroke: "currentColor",
119
+ strokeWidth: "2.5",
120
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" })
121
+ }
122
+ );
123
+ var CloseIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
124
+ "svg",
125
+ {
126
+ "aria-hidden": "true",
127
+ className,
128
+ fill: "none",
129
+ viewBox: "0 0 24 24",
130
+ stroke: "currentColor",
131
+ strokeWidth: "2",
132
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
133
+ }
134
+ );
135
+ var normalizeSortOption = (option) => {
136
+ const direction = option.direction.trim();
137
+ return {
138
+ label: option.title || humanize(option.name),
139
+ value: [option.name, direction].filter(Boolean).join(" ")
140
+ };
141
+ };
142
+ var DataBindingControls = ({
143
+ path,
144
+ query,
145
+ facets,
146
+ sortOptions,
147
+ showFacets,
148
+ showSortOptions,
149
+ showSearchBar,
150
+ mode = "toolbar"
151
+ }) => {
152
+ const router = useRouter();
153
+ const searchParams = useSearchParams();
154
+ const [collapsedCategories, setCollapsedCategories] = useState({});
155
+ const toggleCategory = (field) => {
156
+ setCollapsedCategories((prev) => ({
157
+ ...prev,
158
+ [field]: !prev[field]
159
+ }));
160
+ };
161
+ const searchParamsFilter = searchParams?.get("$filter") ?? searchParams?.get("filter");
162
+ const searchParamsSort = searchParams?.get("$orderby") ?? searchParams?.get("orderBy");
163
+ const searchParamsSearch = searchParams?.get("$search");
164
+ const currentFilter = searchParamsFilter !== void 0 && searchParamsFilter !== null ? searchParamsFilter : query?.["$filter"] ?? query?.filter ?? "";
165
+ const currentSort = searchParamsSort !== void 0 && searchParamsSort !== null ? searchParamsSort : query?.["$orderby"] ?? query?.orderBy ?? "";
166
+ const currentSearch = parseODataSearch(
167
+ searchParamsSearch !== void 0 && searchParamsSearch !== null ? searchParamsSearch : query?.["$search"]
168
+ );
169
+ const [searchText, setSearchText] = useState(currentSearch);
170
+ useEffect(() => {
171
+ setSearchText(currentSearch);
172
+ }, [currentSearch]);
173
+ const selectedFacetValues = useMemo(
174
+ () => parseFacetSelections(currentFilter),
175
+ [currentFilter]
176
+ );
177
+ const activeFacets = useMemo(() => {
178
+ if (!facets) return [];
179
+ return Object.entries(facets).map(([field, values]) => {
180
+ if (!Array.isArray(values)) return null;
181
+ const filteredValues = values.filter(
182
+ (item) => item.count > 0 || selectedFacetValues.get(field) === item.value
183
+ );
184
+ if (filteredValues.length === 0) return null;
185
+ return [field, filteredValues];
186
+ }).filter((group) => group !== null);
187
+ }, [facets, selectedFacetValues]);
188
+ const normalizedSortOptions = (sortOptions ?? []).filter((option) => option?.name && option?.direction).map(normalizeSortOption).filter((option) => option.value);
189
+ const getQueryUrl = useCallback(
190
+ (updates) => {
191
+ const initialParams = searchParams ? searchParams.toString() : "";
192
+ const params = new URLSearchParams(initialParams || query || {});
193
+ Object.entries(updates).forEach(([key, value]) => {
194
+ if (value) {
195
+ params.set(key, value);
196
+ } else {
197
+ params.delete(key);
198
+ }
199
+ });
200
+ params.delete("$skip");
201
+ params.delete("skip");
202
+ const queryString = Array.from(params.entries()).map(
203
+ ([key, value]) => key === "$filter" || key === "filter" ? `${key}=${encodeURIComponent(value)}` : `${key}=${value}`
204
+ ).join("&");
205
+ return queryString ? `${path}?${queryString}` : path;
206
+ },
207
+ [path, query, searchParams]
208
+ );
209
+ const navigateWithoutReload = useCallback(
210
+ (url) => {
211
+ if (typeof window !== "undefined") {
212
+ const targetUrl = new URL(url, window.location.origin);
213
+ if (targetUrl.pathname === window.location.pathname && targetUrl.search === window.location.search) {
214
+ return;
215
+ }
216
+ }
217
+ router.push(url, { scroll: false });
218
+ },
219
+ [router]
220
+ );
221
+ const getFacetUrl = (field, value) => {
222
+ const updatedSelections = new Map(selectedFacetValues);
223
+ if (value) {
224
+ if (updatedSelections.get(field) === value) {
225
+ updatedSelections.delete(field);
226
+ } else {
227
+ updatedSelections.set(field, value);
228
+ }
229
+ } else {
230
+ updatedSelections.delete(field);
231
+ }
232
+ const updatedFilter = buildFacetFilter(updatedSelections);
233
+ return getQueryUrl({
234
+ $filter: updatedFilter || void 0,
235
+ filter: void 0
236
+ });
237
+ };
238
+ const clearFacetField = (field) => {
239
+ const updatedSelections = new Map(selectedFacetValues);
240
+ updatedSelections.delete(field);
241
+ const updatedFilter = buildFacetFilter(updatedSelections);
242
+ navigateWithoutReload(
243
+ getQueryUrl({
244
+ $filter: updatedFilter || void 0,
245
+ filter: void 0
246
+ })
247
+ );
248
+ };
249
+ const handleSearch = useCallback(async () => {
250
+ const trimmedSearchText = searchText.trim();
251
+ if (trimmedSearchText === currentSearch.trim()) {
252
+ return { isSuccessful: true };
253
+ }
254
+ navigateWithoutReload(
255
+ getQueryUrl({
256
+ "$search": trimmedSearchText || void 0
257
+ })
258
+ );
259
+ return { isSuccessful: true };
260
+ }, [currentSearch, getQueryUrl, navigateWithoutReload, searchText]);
261
+ const handleClearAll = useCallback(async () => {
262
+ navigateWithoutReload(
263
+ getQueryUrl({
264
+ $filter: void 0,
265
+ filter: void 0,
266
+ $orderby: void 0,
267
+ orderBy: void 0
268
+ })
269
+ );
270
+ return { isSuccessful: true };
271
+ }, [getQueryUrl, navigateWithoutReload]);
272
+ const hasFacetControls = showFacets && activeFacets.length > 0;
273
+ const hasSortControls = showSortOptions && normalizedSortOptions.length > 0;
274
+ const hasActiveFiltersOrSort = Boolean(
275
+ currentFilter.trim() || currentSort.trim()
276
+ );
277
+ const selectedFacetCount = selectedFacetValues.size;
278
+ const shouldShowToolbarClearAll = hasActiveFiltersOrSort && !hasFacetControls;
279
+ const shouldShowToolbar = mode === "toolbar" && (showSearchBar || hasSortControls || shouldShowToolbarClearAll);
280
+ const shouldShowFacets = mode === "facets" && hasFacetControls;
281
+ if (!shouldShowToolbar && !shouldShowFacets) {
282
+ return null;
283
+ }
284
+ const renderFacetItems = (field, values) => /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 pt-1 pb-1", children: values.map((facet) => {
285
+ const isSelected = selectedFacetValues.get(field) === facet.value;
286
+ return /* @__PURE__ */ jsxs(
287
+ "button",
288
+ {
289
+ type: "button",
290
+ onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
291
+ "aria-pressed": isSelected,
292
+ className: `group flex w-full cursor-pointer items-center justify-between gap-2.5 rounded-md px-2 py-1.5 text-left text-sm transition-all duration-150 ease-out focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary-base ${isSelected ? "bg-neutral-soft font-medium border " : "hover:bg-neutral-weak border border-transparent"}`,
293
+ children: [
294
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
295
+ /* @__PURE__ */ jsx(
296
+ "span",
297
+ {
298
+ className: `flex h-4 w-4 shrink-0 items-center justify-center rounded-[3px] border transition-colors duration-150 ${isSelected ? "bg-primary-base border-primary-base" : " group-hover:border-neutral-strong bg-default"}`,
299
+ children: isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-3 w-3" })
300
+ }
301
+ ),
302
+ /* @__PURE__ */ jsx("span", { className: "leading-snug break-words", children: facet.value })
303
+ ] }),
304
+ /* @__PURE__ */ jsx(
305
+ "span",
306
+ {
307
+ className: `shrink-0 rounded px-1.5 py-0.5 text-xs transition-colors ml-2 ${isSelected ? "bg-neutral-weak font-semibold" : "bg-neutral-weak font-normal"}`,
308
+ children: facet.count
309
+ }
310
+ )
311
+ ]
312
+ },
313
+ `${field}-${facet.value}`
314
+ );
315
+ }) });
316
+ return /* @__PURE__ */ jsxs(
317
+ "div",
318
+ {
319
+ className: mode === "toolbar" ? "my-6" : "flex flex-col rounded-md border bg-default p-3.5 shadow-sm",
320
+ children: [
321
+ shouldShowToolbar && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
322
+ showSearchBar && // <form
323
+ // role="search"
324
+ // className="flex w-full flex-col gap-3 rounded-md border border-info bg-info-soft p-3 sm:flex-row sm:items-center md:min-w-0 md:flex-1"
325
+ // onSubmit={(event) => {
326
+ // event.preventDefault();
327
+ // void handleSearch();
328
+ // }}
329
+ // >
330
+ /* @__PURE__ */ jsxs(
331
+ "form",
332
+ {
333
+ role: "search",
334
+ className: "flex w-full flex-col gap-3 rounded-md sm:flex-row sm:items-center md:min-w-0 md:flex-1",
335
+ onSubmit: (event) => {
336
+ event.preventDefault();
337
+ void handleSearch();
338
+ },
339
+ children: [
340
+ /* @__PURE__ */ jsxs("div", { className: "relative bg-default rounded-md min-w-0 flex-1", children: [
341
+ /* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute left-4 top-1/2 z-10 h-5 w-5 -translate-y-1/2" }),
342
+ /* @__PURE__ */ jsx(
343
+ InputControl_default,
344
+ {
345
+ name: "searchText",
346
+ controlType: InputControlType_default.lineTextInput,
347
+ value: searchText,
348
+ callback: (updatedValues) => setSearchText(updatedValues.value),
349
+ attributes: {
350
+ placeholder: "Search discussions, topics, or keywords..."
351
+ },
352
+ inputClasses: "!mt-0 !rounded-md !py-3 !pl-11 !pr-4 !shadow-sm"
353
+ }
354
+ )
355
+ ] }),
356
+ /* @__PURE__ */ jsxs(
357
+ Button_default,
358
+ {
359
+ ButtonType: "Primary" /* Solid */,
360
+ onClick: handleSearch,
361
+ className: "!rounded-md !px-6 !py-3 sm:self-stretch",
362
+ children: [
363
+ /* @__PURE__ */ jsx(SearchIcon, { className: "h-5 w-5" }),
364
+ /* @__PURE__ */ jsx("span", { children: "Search" })
365
+ ]
366
+ }
367
+ )
368
+ ]
369
+ }
370
+ ),
371
+ hasSortControls && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-3 rounded-md border border-info bg-info-soft p-3 text-sm md:ml-auto md:w-auto md:min-w-72 md:self-stretch", children: [
372
+ /* @__PURE__ */ jsx(
373
+ "label",
374
+ {
375
+ htmlFor: "sortOptions",
376
+ className: "shrink-0 whitespace-nowrap font-medium",
377
+ children: "Sort by"
378
+ }
379
+ ),
380
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 rounded-md bg-default md:min-w-48", children: /* @__PURE__ */ jsx(
381
+ InputControl_default,
382
+ {
383
+ name: "sortOptions",
384
+ controlType: InputControlType_default.select,
385
+ value: currentSort,
386
+ dataset: normalizedSortOptions,
387
+ dataKeyFieldName: "value",
388
+ dataTextFieldName: "label",
389
+ callback: (updatedValues) => {
390
+ const updatedSort = updatedValues.value || "";
391
+ navigateWithoutReload(
392
+ getQueryUrl({
393
+ $orderby: updatedSort || void 0,
394
+ orderBy: void 0
395
+ })
396
+ );
397
+ },
398
+ attributes: { placeholder: "Default" },
399
+ inputClasses: "!mt-0 !rounded-md !border-info !bg-default !px-4 !py-3 !shadow-sm focus:!border-primary focus:!ring-primary-base"
400
+ }
401
+ ) })
402
+ ] })
403
+ ] }),
404
+ shouldShowFacets && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
405
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b pb-3", children: [
406
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
407
+ /* @__PURE__ */ jsx(FilterSlidersIcon, { className: "h-4 w-4" }),
408
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold tracking-tight", children: "Filters" }),
409
+ selectedFacetCount > 0 && /* @__PURE__ */ jsx("span", { className: "flex h-5 items-center justify-center rounded-full bg-primary-base px-2 text-xs font-semibold", children: selectedFacetCount })
410
+ ] }),
411
+ hasActiveFiltersOrSort && /* @__PURE__ */ jsxs(
412
+ "button",
413
+ {
414
+ type: "button",
415
+ onClick: () => void handleClearAll(),
416
+ className: "group inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium transition-colors duration-150 hover:bg-neutral-soft focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary-base",
417
+ "aria-label": "Clear all filters and sorting",
418
+ children: [
419
+ /* @__PURE__ */ jsx(ResetIcon, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:-rotate-45" }),
420
+ /* @__PURE__ */ jsx("span", { children: "Clear all" })
421
+ ]
422
+ }
423
+ )
424
+ ] }),
425
+ selectedFacetCount > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 pb-2.5 border-b ", children: Array.from(selectedFacetValues.entries()).map(([field, value]) => /* @__PURE__ */ jsxs(
426
+ "button",
427
+ {
428
+ type: "button",
429
+ onClick: () => clearFacetField(field),
430
+ className: "group inline-flex max-w-full cursor-pointer items-center gap-1.5 rounded-md border bg-neutral-weak px-2.5 py-1 text-xs transition-colors hover:bg-neutral-soft",
431
+ title: `Remove filter: ${value}`,
432
+ children: [
433
+ /* @__PURE__ */ jsx("span", { className: "font-medium truncate max-w-[150px]", children: value }),
434
+ /* @__PURE__ */ jsx(CloseIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-60 group-hover:opacity-100" })
435
+ ]
436
+ },
437
+ `chip-${field}`
438
+ )) }),
439
+ activeFacets.length === 1 && /* @__PURE__ */ jsx("nav", { "aria-label": `${humanize(activeFacets[0][0])} filters`, children: /* @__PURE__ */ jsxs("div", { className: "py-1", children: [
440
+ /* @__PURE__ */ jsx("div", { className: "px-1 pb-2 font-medium text-sm", children: humanize(activeFacets[0][0]) }),
441
+ renderFacetItems(activeFacets[0][0], activeFacets[0][1])
442
+ ] }) }),
443
+ activeFacets.length > 1 && /* @__PURE__ */ jsx("div", { className: "flex flex-col divide-y divide-neutral-soft", children: activeFacets.map(([field, values]) => {
444
+ const isOpen = !collapsedCategories[field];
445
+ return /* @__PURE__ */ jsxs(
446
+ "div",
447
+ {
448
+ className: "py-2 first:pt-0 last:pb-0",
449
+ children: [
450
+ /* @__PURE__ */ jsxs(
451
+ "button",
452
+ {
453
+ type: "button",
454
+ onClick: () => toggleCategory(field),
455
+ className: "flex w-full cursor-pointer items-center justify-between rounded-md px-1.5 py-1.5 text-sm font-semibold transition-colors duration-150 hover:bg-neutral-weak focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary-base",
456
+ children: [
457
+ /* @__PURE__ */ jsx("span", { children: humanize(field) }),
458
+ /* @__PURE__ */ jsx(
459
+ ChevronDownIcon,
460
+ {
461
+ className: `h-4 w-4 transition-transform duration-200 ease-out ${isOpen ? "rotate-180" : ""}`
462
+ }
463
+ )
464
+ ]
465
+ }
466
+ ),
467
+ isOpen && /* @__PURE__ */ jsx("div", { className: "pt-1", children: renderFacetItems(field, values) })
468
+ ]
469
+ },
470
+ field
471
+ );
472
+ }) })
473
+ ] })
474
+ ]
475
+ }
476
+ );
477
+ };
478
+ var DataBindingControls_default = DataBindingControls;
479
+ export {
480
+ DataBindingControls_default as default
481
+ };
@@ -34,6 +34,7 @@ var Slider = ({
34
34
  const [isPlaying, setIsPlaying] = useState(autoplay);
35
35
  const trackRef = useRef(null);
36
36
  console.log("trackRef:", trackRef);
37
+ const [videoProgress, setVideoProgress] = useState(null);
37
38
  useEffect(() => {
38
39
  if (typeof initialSlidesToShow === "number") {
39
40
  setSlidesToShowState(initialSlidesToShow);
@@ -58,28 +59,36 @@ var Slider = ({
58
59
  const videoElement = activeSlideElement?.querySelector("video");
59
60
  if (videoElement) {
60
61
  videoElement.loop = false;
62
+ setVideoProgress(0);
61
63
  if (videoElement.ended) {
62
64
  videoElement.currentTime = 0;
63
65
  }
64
66
  videoElement.play().catch(() => {
65
67
  });
66
68
  const handleTimeUpdate = () => {
67
- if (videoElement.duration && !isNaN(videoElement.duration)) {
69
+ if (videoElement.duration && !isNaN(videoElement.duration) && videoElement.duration > 0) {
68
70
  const pct = videoElement.currentTime / videoElement.duration * 100;
71
+ setVideoProgress(pct);
69
72
  }
70
73
  };
71
74
  const handleVideoEnded = () => {
75
+ setVideoProgress(100);
72
76
  nextSlide();
73
77
  };
74
78
  const handleVideoError = () => {
75
79
  nextSlide();
76
80
  };
81
+ videoElement.addEventListener("timeupdate", handleTimeUpdate);
82
+ videoElement.addEventListener("loadedmetadata", handleTimeUpdate);
77
83
  videoElement.addEventListener("ended", handleVideoEnded, { once: true });
78
84
  videoElement.addEventListener("error", handleVideoError, { once: true });
79
85
  return () => {
86
+ videoElement.removeEventListener("timeupdate", handleTimeUpdate);
87
+ videoElement.removeEventListener("loadedmetadata", handleTimeUpdate);
80
88
  videoElement.removeEventListener("ended", handleVideoEnded);
81
89
  videoElement.removeEventListener("error", handleVideoError);
82
90
  videoElement.pause();
91
+ setVideoProgress(null);
83
92
  };
84
93
  }
85
94
  const timer = setInterval(() => {
@@ -178,7 +187,8 @@ var Slider = ({
178
187
  activeClassName: dotActiveClassName,
179
188
  inactiveClassName: dotInactiveClassName,
180
189
  currentSlide,
181
- totalSlides
190
+ totalSlides,
191
+ customProgress: index === currentSlide ? videoProgress : null
182
192
  },
183
193
  index
184
194
  )) }),
@@ -238,7 +248,8 @@ var Slider = ({
238
248
  activeClassName: dotActiveClassName,
239
249
  inactiveClassName: dotInactiveClassName,
240
250
  currentSlide,
241
- totalSlides
251
+ totalSlides,
252
+ customProgress: index === currentSlide ? videoProgress : null
242
253
  },
243
254
  index
244
255
  )) })
@@ -274,7 +285,8 @@ var ProgressPill = ({
274
285
  activeClassName = "",
275
286
  inactiveClassName = "",
276
287
  currentSlide,
277
- totalSlides
288
+ totalSlides,
289
+ customProgress = null
278
290
  }) => {
279
291
  const [progress, setProgress] = useState(0);
280
292
  useEffect(() => {
@@ -283,7 +295,7 @@ var ProgressPill = ({
283
295
  }
284
296
  }, [active, index]);
285
297
  useEffect(() => {
286
- if (!active || !isPlaying) {
298
+ if (!active || !isPlaying || customProgress !== null) {
287
299
  if (!active) {
288
300
  setProgress(0);
289
301
  }
@@ -301,7 +313,7 @@ var ProgressPill = ({
301
313
  }
302
314
  }, 50);
303
315
  return () => clearInterval(interval);
304
- }, [active, isPlaying, duration, index]);
316
+ }, [active, isPlaying, duration, index, customProgress]);
305
317
  const isFilled = index < currentSlide;
306
318
  const isActive = index === currentSlide;
307
319
  const shouldShowProgress = isActive || style === "cumulative" && isFilled;
@@ -336,7 +348,7 @@ var ProgressPill = ({
336
348
  };
337
349
  const renderProgressBar = () => {
338
350
  if (style === "modern" && isActive || style === "cumulative" && shouldShowProgress) {
339
- const displayProgress = style === "cumulative" && isFilled ? 100 : progress;
351
+ const displayProgress = style === "cumulative" && isFilled ? 100 : customProgress !== null && customProgress !== void 0 ? customProgress : progress;
340
352
  return /* @__PURE__ */ jsx(
341
353
  "div",
342
354
  {
@@ -32,6 +32,7 @@ var Slider = ({
32
32
  const [isPlaying, setIsPlaying] = useState(autoplay);
33
33
  const trackRef = useRef(null);
34
34
  console.log("trackRef:", trackRef);
35
+ const [videoProgress, setVideoProgress] = useState(null);
35
36
  useEffect(() => {
36
37
  if (typeof initialSlidesToShow === "number") {
37
38
  setSlidesToShowState(initialSlidesToShow);
@@ -56,28 +57,36 @@ var Slider = ({
56
57
  const videoElement = activeSlideElement?.querySelector("video");
57
58
  if (videoElement) {
58
59
  videoElement.loop = false;
60
+ setVideoProgress(0);
59
61
  if (videoElement.ended) {
60
62
  videoElement.currentTime = 0;
61
63
  }
62
64
  videoElement.play().catch(() => {
63
65
  });
64
66
  const handleTimeUpdate = () => {
65
- if (videoElement.duration && !isNaN(videoElement.duration)) {
67
+ if (videoElement.duration && !isNaN(videoElement.duration) && videoElement.duration > 0) {
66
68
  const pct = videoElement.currentTime / videoElement.duration * 100;
69
+ setVideoProgress(pct);
67
70
  }
68
71
  };
69
72
  const handleVideoEnded = () => {
73
+ setVideoProgress(100);
70
74
  nextSlide();
71
75
  };
72
76
  const handleVideoError = () => {
73
77
  nextSlide();
74
78
  };
79
+ videoElement.addEventListener("timeupdate", handleTimeUpdate);
80
+ videoElement.addEventListener("loadedmetadata", handleTimeUpdate);
75
81
  videoElement.addEventListener("ended", handleVideoEnded, { once: true });
76
82
  videoElement.addEventListener("error", handleVideoError, { once: true });
77
83
  return () => {
84
+ videoElement.removeEventListener("timeupdate", handleTimeUpdate);
85
+ videoElement.removeEventListener("loadedmetadata", handleTimeUpdate);
78
86
  videoElement.removeEventListener("ended", handleVideoEnded);
79
87
  videoElement.removeEventListener("error", handleVideoError);
80
88
  videoElement.pause();
89
+ setVideoProgress(null);
81
90
  };
82
91
  }
83
92
  const timer = setInterval(() => {
@@ -176,7 +185,8 @@ var Slider = ({
176
185
  activeClassName: dotActiveClassName,
177
186
  inactiveClassName: dotInactiveClassName,
178
187
  currentSlide,
179
- totalSlides
188
+ totalSlides,
189
+ customProgress: index === currentSlide ? videoProgress : null
180
190
  },
181
191
  index
182
192
  )) }),
@@ -236,7 +246,8 @@ var Slider = ({
236
246
  activeClassName: dotActiveClassName,
237
247
  inactiveClassName: dotInactiveClassName,
238
248
  currentSlide,
239
- totalSlides
249
+ totalSlides,
250
+ customProgress: index === currentSlide ? videoProgress : null
240
251
  },
241
252
  index
242
253
  )) })
@@ -272,7 +283,8 @@ var ProgressPill = ({
272
283
  activeClassName = "",
273
284
  inactiveClassName = "",
274
285
  currentSlide,
275
- totalSlides
286
+ totalSlides,
287
+ customProgress = null
276
288
  }) => {
277
289
  const [progress, setProgress] = useState(0);
278
290
  useEffect(() => {
@@ -281,7 +293,7 @@ var ProgressPill = ({
281
293
  }
282
294
  }, [active, index]);
283
295
  useEffect(() => {
284
- if (!active || !isPlaying) {
296
+ if (!active || !isPlaying || customProgress !== null) {
285
297
  if (!active) {
286
298
  setProgress(0);
287
299
  }
@@ -299,7 +311,7 @@ var ProgressPill = ({
299
311
  }
300
312
  }, 50);
301
313
  return () => clearInterval(interval);
302
- }, [active, isPlaying, duration, index]);
314
+ }, [active, isPlaying, duration, index, customProgress]);
303
315
  const isFilled = index < currentSlide;
304
316
  const isActive = index === currentSlide;
305
317
  const shouldShowProgress = isActive || style === "cumulative" && isFilled;
@@ -334,7 +346,7 @@ var ProgressPill = ({
334
346
  };
335
347
  const renderProgressBar = () => {
336
348
  if (style === "modern" && isActive || style === "cumulative" && shouldShowProgress) {
337
- const displayProgress = style === "cumulative" && isFilled ? 100 : progress;
349
+ const displayProgress = style === "cumulative" && isFilled ? 100 : customProgress !== null && customProgress !== void 0 ? customProgress : progress;
338
350
  return /* @__PURE__ */ jsx(
339
351
  "div",
340
352
  {