@inf-monkeys-tech/monkeys-design 1.0.53 → 1.0.54

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.
@@ -9075,7 +9075,11 @@ function WorkbenchCollection({
9075
9075
  const itemsRef = useRef(null);
9076
9076
  const loadMoreRef = useRef(null);
9077
9077
  const lastSelectedIndexRef = useRef(null);
9078
- const loadMoreLockedRef = useRef(false);
9078
+ const loadMoreRequestPendingRef = useRef(false);
9079
+ const loadMoreIntersectionActiveRef = useRef(false);
9080
+ const loadMoreIntersectionConsumedRef = useRef(false);
9081
+ const loadMoreScrollValidationPendingRef = useRef(false);
9082
+ const observedLoadMoreTargetRef = useRef(null);
9079
9083
  const layoutReadyRef = useRef(false);
9080
9084
  const [containerWidth, setContainerWidth] = useState(0);
9081
9085
  const [itemsNode, setItemsNode] = useState(null);
@@ -9233,38 +9237,91 @@ function WorkbenchCollection({
9233
9237
  const canLoadMore = typeof callbacks?.onLoadMore === "function";
9234
9238
  const effectiveError = state?.error ?? virtualizationError;
9235
9239
  useEffect(() => {
9236
- if (!loadingMore || !hasMore) loadMoreLockedRef.current = false;
9237
- }, [hasMore, loadingMore, normalizedItems.length, keysSignature]);
9240
+ if (!canLoadMore || !hasMore) {
9241
+ loadMoreIntersectionActiveRef.current = false;
9242
+ loadMoreIntersectionConsumedRef.current = false;
9243
+ loadMoreScrollValidationPendingRef.current = false;
9244
+ }
9245
+ }, [canLoadMore, hasMore]);
9238
9246
  const requestLoadMore = useCallback(() => {
9239
- if (!canLoadMore || !hasMore || loadingMore || loadMoreLockedRef.current) return;
9240
- loadMoreLockedRef.current = true;
9247
+ if (!canLoadMore || !hasMore || loadingMore || loadMoreRequestPendingRef.current) return;
9248
+ loadMoreRequestPendingRef.current = true;
9249
+ const releaseRequest = () => {
9250
+ loadMoreRequestPendingRef.current = false;
9251
+ };
9241
9252
  try {
9242
9253
  const result = callbacksRef.current?.onLoadMore?.();
9243
9254
  if (result && typeof result.then === "function") {
9244
- void result.catch(() => {
9245
- loadMoreLockedRef.current = false;
9246
- });
9255
+ void result.then(releaseRequest, releaseRequest);
9256
+ } else {
9257
+ releaseRequest();
9247
9258
  }
9248
9259
  } catch (error) {
9249
- loadMoreLockedRef.current = false;
9260
+ releaseRequest();
9250
9261
  throw error;
9251
9262
  }
9252
9263
  }, [canLoadMore, hasMore, loadingMore]);
9253
9264
  useEffect(() => {
9254
9265
  const sentinel = loadMoreRef.current;
9255
- if (!sentinel || !canLoadMore || !hasMore || loadingMore) return void 0;
9266
+ if (observedLoadMoreTargetRef.current !== sentinel) {
9267
+ observedLoadMoreTargetRef.current = sentinel;
9268
+ loadMoreIntersectionActiveRef.current = false;
9269
+ loadMoreIntersectionConsumedRef.current = false;
9270
+ loadMoreScrollValidationPendingRef.current = false;
9271
+ }
9272
+ if (!sentinel || !canLoadMore || !hasMore) return void 0;
9256
9273
  if (typeof IntersectionObserver !== "function") return void 0;
9257
9274
  const owner = resolveScrollOwner();
9275
+ let observerHasDelivered = false;
9258
9276
  const observer = new IntersectionObserver((entries) => {
9259
- if (!entries.some((entry) => entry.isIntersecting)) return;
9277
+ const isIntersecting = entries.some((entry) => entry.isIntersecting);
9278
+ if (loadMoreScrollValidationPendingRef.current) {
9279
+ observerHasDelivered = true;
9280
+ loadMoreScrollValidationPendingRef.current = false;
9281
+ loadMoreIntersectionActiveRef.current = isIntersecting;
9282
+ if (!isIntersecting) {
9283
+ loadMoreIntersectionConsumedRef.current = false;
9284
+ return;
9285
+ }
9286
+ if (loadMoreIntersectionConsumedRef.current) return;
9287
+ loadMoreIntersectionConsumedRef.current = true;
9288
+ requestLoadMore();
9289
+ return;
9290
+ }
9291
+ if (!observerHasDelivered) {
9292
+ observerHasDelivered = true;
9293
+ loadMoreIntersectionActiveRef.current = isIntersecting;
9294
+ if (!isIntersecting) loadMoreIntersectionConsumedRef.current = false;
9295
+ return;
9296
+ }
9297
+ if (!isIntersecting) {
9298
+ loadMoreIntersectionActiveRef.current = false;
9299
+ loadMoreIntersectionConsumedRef.current = false;
9300
+ return;
9301
+ }
9302
+ if (loadMoreIntersectionActiveRef.current) return;
9303
+ loadMoreIntersectionActiveRef.current = true;
9304
+ loadMoreIntersectionConsumedRef.current = true;
9260
9305
  requestLoadMore();
9261
9306
  }, {
9262
9307
  root: owner === rootRef.current ? owner : owner || null,
9263
9308
  rootMargin: config.loading?.rootMargin ?? "240px",
9264
9309
  threshold: normalizeThreshold(config.loading?.threshold)
9265
9310
  });
9311
+ const scrollTarget = owner ?? (typeof window === "undefined" ? null : window);
9312
+ const validateActiveIntersection = () => {
9313
+ if (!loadMoreIntersectionActiveRef.current || loadMoreIntersectionConsumedRef.current || loadMoreScrollValidationPendingRef.current) return;
9314
+ loadMoreScrollValidationPendingRef.current = true;
9315
+ observer.unobserve(sentinel);
9316
+ observer.takeRecords();
9317
+ observer.observe(sentinel);
9318
+ };
9266
9319
  observer.observe(sentinel);
9267
- return () => observer.disconnect();
9320
+ scrollTarget?.addEventListener("scroll", validateActiveIntersection, { passive: true });
9321
+ return () => {
9322
+ observer.disconnect();
9323
+ scrollTarget?.removeEventListener("scroll", validateActiveIntersection);
9324
+ };
9268
9325
  }, [canLoadMore, config.loading?.rootMargin, config.loading?.threshold, hasMore, keysSignature, loadingMore, normalizedItems.length, requestLoadMore, resolveScrollOwner]);
9269
9326
  useEffect(() => {
9270
9327
  if (!config.loading?.autoFill || !canLoadMore || !hasMore || loadingMore) return;
@@ -9272,7 +9329,10 @@ function WorkbenchCollection({
9272
9329
  if (!sentinel) return;
9273
9330
  const owner = resolveScrollOwner() ?? (config.layout.scrollOwner === "parent" ? rootRef.current?.parentElement ?? null : null) ?? rootRef.current;
9274
9331
  if (!owner || owner.clientHeight <= 0) return;
9275
- if (owner.scrollHeight <= owner.clientHeight + 1) requestLoadMore();
9332
+ if (owner.scrollHeight <= owner.clientHeight + 1) {
9333
+ loadMoreIntersectionConsumedRef.current = true;
9334
+ requestLoadMore();
9335
+ }
9276
9336
  }, [
9277
9337
  canLoadMore,
9278
9338
  config.layout.scrollOwner,
@@ -10116,6 +10176,187 @@ function WorkbenchGalleryView({
10116
10176
  }
10117
10177
  );
10118
10178
  }
10179
+ var DEFAULT_SECTIONS = [
10180
+ {
10181
+ id: "primary",
10182
+ layout: "rail",
10183
+ filterCount: 2,
10184
+ cardCount: 4,
10185
+ aspectRatios: [16 / 11]
10186
+ },
10187
+ {
10188
+ id: "secondary",
10189
+ layout: "grid",
10190
+ filterCount: 3,
10191
+ cardCount: 5,
10192
+ aspectRatios: [4 / 5, 1, 3 / 4, 5 / 4, 1]
10193
+ }
10194
+ ];
10195
+ function normalizeCount2(value, fallback, maximum) {
10196
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
10197
+ return fallback;
10198
+ return Math.min(Math.round(value), maximum);
10199
+ }
10200
+ function normalizeAspectRatio(value) {
10201
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0)
10202
+ return 1;
10203
+ return Math.min(Math.max(value, 0.5), 2);
10204
+ }
10205
+ function WorkbenchGallerySkeletonHeading({
10206
+ animated,
10207
+ filterCount
10208
+ }) {
10209
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-10 flex-wrap items-center justify-between gap-4", children: [
10210
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10211
+ /* @__PURE__ */ jsx(
10212
+ BaseSkeleton,
10213
+ {
10214
+ variant: "line",
10215
+ animated,
10216
+ className: "h-6 w-36 rounded-md"
10217
+ }
10218
+ ),
10219
+ /* @__PURE__ */ jsx(BaseSkeleton, { variant: "line", animated, className: "h-3 w-12" })
10220
+ ] }),
10221
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-end gap-2", children: Array.from({ length: filterCount }, (_, index) => /* @__PURE__ */ jsx(
10222
+ BaseSkeleton,
10223
+ {
10224
+ variant: "block",
10225
+ animated,
10226
+ className: "h-9 w-28 rounded-lg"
10227
+ },
10228
+ index
10229
+ )) })
10230
+ ] });
10231
+ }
10232
+ function WorkbenchGallerySkeleton({
10233
+ sections = DEFAULT_SECTIONS,
10234
+ animated = true,
10235
+ className,
10236
+ ...props
10237
+ }) {
10238
+ return /* @__PURE__ */ jsx(
10239
+ "div",
10240
+ {
10241
+ ...props,
10242
+ role: "status",
10243
+ "aria-busy": "true",
10244
+ "aria-label": "Loading gallery",
10245
+ "data-monkeys-component": "workbench-gallery-skeleton",
10246
+ className: cn("grid w-full gap-4", className),
10247
+ children: sections.map((section, sectionIndex) => {
10248
+ const layout = section.layout ?? "grid";
10249
+ const filterCount = normalizeCount2(section.filterCount, 2, 8);
10250
+ const cardCount = normalizeCount2(
10251
+ section.cardCount,
10252
+ layout === "rail" ? 4 : 5,
10253
+ 24
10254
+ );
10255
+ const ratios = section.aspectRatios?.length ? section.aspectRatios : [layout === "rail" ? 16 / 11 : 1];
10256
+ return /* @__PURE__ */ jsxs(
10257
+ "section",
10258
+ {
10259
+ className: "grid gap-4",
10260
+ "data-skeleton-section": section.id,
10261
+ children: [
10262
+ /* @__PURE__ */ jsx(
10263
+ WorkbenchGallerySkeletonHeading,
10264
+ {
10265
+ animated,
10266
+ filterCount
10267
+ }
10268
+ ),
10269
+ /* @__PURE__ */ jsx(
10270
+ "div",
10271
+ {
10272
+ className: cn(
10273
+ "grid items-start gap-4",
10274
+ layout === "rail" ? "grid-cols-1 sm:grid-cols-2 xl:grid-cols-4" : "grid-cols-2 md:grid-cols-3 xl:grid-cols-5"
10275
+ ),
10276
+ "data-skeleton-layout": layout,
10277
+ children: Array.from({ length: cardCount }, (_, index) => /* @__PURE__ */ jsx(
10278
+ "div",
10279
+ {
10280
+ className: "overflow-hidden rounded-[var(--radius)] border border-border bg-card",
10281
+ children: /* @__PURE__ */ jsx(
10282
+ BaseSkeleton,
10283
+ {
10284
+ variant: "block",
10285
+ animated,
10286
+ className: "h-auto w-full rounded-none",
10287
+ style: {
10288
+ aspectRatio: String(
10289
+ normalizeAspectRatio(ratios[index % ratios.length])
10290
+ )
10291
+ }
10292
+ }
10293
+ )
10294
+ },
10295
+ index
10296
+ ))
10297
+ }
10298
+ )
10299
+ ]
10300
+ },
10301
+ section.id || sectionIndex
10302
+ );
10303
+ })
10304
+ }
10305
+ );
10306
+ }
10307
+ function WorkbenchPageSkeleton({
10308
+ animated = true,
10309
+ className,
10310
+ ...props
10311
+ }) {
10312
+ const skeleton = (classNames) => /* @__PURE__ */ jsx(BaseSkeleton, { variant: "block", animated, className: classNames });
10313
+ return /* @__PURE__ */ jsxs(
10314
+ "div",
10315
+ {
10316
+ ...props,
10317
+ role: "status",
10318
+ "aria-busy": "true",
10319
+ "aria-label": "Loading page",
10320
+ "data-monkeys-component": "workbench-page-skeleton",
10321
+ className: cn(
10322
+ "flex size-full min-h-0 flex-col gap-4 overflow-hidden",
10323
+ className
10324
+ ),
10325
+ children: [
10326
+ /* @__PURE__ */ jsxs("div", { className: "flex h-10 shrink-0 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4", children: [
10327
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10328
+ skeleton("h-5 w-20"),
10329
+ skeleton("h-5 w-16"),
10330
+ skeleton("h-5 w-24")
10331
+ ] }),
10332
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10333
+ skeleton("h-7 w-20"),
10334
+ skeleton("size-7")
10335
+ ] })
10336
+ ] }),
10337
+ /* @__PURE__ */ jsxs("div", { className: "grid shrink-0 grid-cols-1 gap-4 md:grid-cols-3", children: [
10338
+ skeleton("h-40 md:col-span-2"),
10339
+ skeleton("h-40")
10340
+ ] }),
10341
+ /* @__PURE__ */ jsxs("div", { className: "grid min-h-0 flex-1 grid-cols-1 gap-4 lg:grid-cols-[minmax(0,2fr)_minmax(14rem,1fr)]", children: [
10342
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-col gap-4 rounded-lg border border-border bg-card p-4", children: [
10343
+ skeleton("h-6 w-40"),
10344
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }, (_, index) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10345
+ skeleton("h-4 w-20"),
10346
+ skeleton("h-9 w-full")
10347
+ ] }, index)) }),
10348
+ skeleton("min-h-32 flex-1")
10349
+ ] }),
10350
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-40 flex-col gap-4 rounded-lg border border-border bg-card p-4", children: [
10351
+ skeleton("h-6 w-28"),
10352
+ skeleton("min-h-28 flex-1"),
10353
+ skeleton("h-9 w-full")
10354
+ ] })
10355
+ ] })
10356
+ ]
10357
+ }
10358
+ );
10359
+ }
10119
10360
  function toCssSize4(value) {
10120
10361
  if (value === void 0) return void 0;
10121
10362
  return typeof value === "number" ? `${value}px` : value;
@@ -11614,6 +11855,6 @@ function WorkbenchRadarMatrix({
11614
11855
  );
11615
11856
  }
11616
11857
 
11617
- export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchAssetGallery, WorkbenchCollection, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchEvidenceList, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGalleryView, WorkbenchJourneyNavigation, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchMetricGrid, WorkbenchRadarFilterChip, WorkbenchRadarInspectorSection, WorkbenchRadarMatrix, WorkbenchRadarNavigation, WorkbenchRadarWorkspace, WorkbenchRankedList, WorkbenchRelationshipGraph, WorkbenchResizableSidebar, WorkbenchScatterPlot, WorkbenchSelectionTray, WorkbenchTableView };
11858
+ export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchAssetGallery, WorkbenchCollection, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchEvidenceList, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGallerySkeleton, WorkbenchGalleryView, WorkbenchJourneyNavigation, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchMetricGrid, WorkbenchPageSkeleton, WorkbenchRadarFilterChip, WorkbenchRadarInspectorSection, WorkbenchRadarMatrix, WorkbenchRadarNavigation, WorkbenchRadarWorkspace, WorkbenchRankedList, WorkbenchRelationshipGraph, WorkbenchResizableSidebar, WorkbenchScatterPlot, WorkbenchSelectionTray, WorkbenchTableView };
11618
11859
  //# sourceMappingURL=index.mjs.map
11619
11860
  //# sourceMappingURL=index.mjs.map