@powerportalspro/react-fluent 5.0.0 → 5.1.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/dist/index.cjs CHANGED
@@ -2483,6 +2483,7 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
2483
2483
  const selectionRef = react.useRef(selection);
2484
2484
  selectionRef.current = selection;
2485
2485
  const prevTransformRef = react.useRef({ angle, zoom, pan, flipH, flipV });
2486
+ const resizingRef = react.useRef(false);
2486
2487
  const dragRef = react.useRef(null);
2487
2488
  const [isDragging, setIsDragging] = react.useState(false);
2488
2489
  const zoomRef = react.useRef(zoom);
@@ -2512,6 +2513,7 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
2512
2513
  const cur = { angle, zoom, pan, flipH, flipV };
2513
2514
  const transformChanged = prev.angle !== cur.angle || prev.zoom !== cur.zoom || prev.pan.x !== cur.pan.x || prev.pan.y !== cur.pan.y || prev.flipH !== cur.flipH || prev.flipV !== cur.flipV;
2514
2515
  if (transformChanged) {
2516
+ resizingRef.current = false;
2515
2517
  const sel = selectionRef.current;
2516
2518
  const imgEl = imgRef.current;
2517
2519
  if (sel && imgEl) {
@@ -2542,6 +2544,51 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
2542
2544
  }
2543
2545
  prevTransformRef.current = cur;
2544
2546
  }, [angle, zoom, pan, flipH, flipV]);
2547
+ react.useEffect(() => {
2548
+ if (!toolbar) return;
2549
+ const container = imageContainerRef.current;
2550
+ if (!container) return;
2551
+ let prevMetrics = imgRef.current ? readImageLayoutMetrics(imgRef.current) : null;
2552
+ const observer = new ResizeObserver(() => {
2553
+ const imgEl = imgRef.current;
2554
+ if (!imgEl) return;
2555
+ const newMetrics = readImageLayoutMetrics(imgEl);
2556
+ if (!newMetrics) return;
2557
+ const sel = selectionRef.current;
2558
+ const layoutChanged = !prevMetrics || prevMetrics.layoutW !== newMetrics.layoutW || prevMetrics.layoutH !== newMetrics.layoutH || prevMetrics.offsetLeft !== newMetrics.offsetLeft || prevMetrics.offsetTop !== newMetrics.offsetTop;
2559
+ if (sel && prevMetrics && layoutChanged) {
2560
+ const natural = containerRectToImageNatural(
2561
+ sel,
2562
+ imgEl,
2563
+ angleRef.current,
2564
+ zoomRef.current,
2565
+ panRef.current,
2566
+ flipHRef.current,
2567
+ flipVRef.current,
2568
+ prevMetrics
2569
+ );
2570
+ if (natural) {
2571
+ const reprojected = imageNaturalRectToContainer(
2572
+ natural,
2573
+ imgEl,
2574
+ angleRef.current,
2575
+ zoomRef.current,
2576
+ panRef.current,
2577
+ flipHRef.current,
2578
+ flipVRef.current,
2579
+ newMetrics
2580
+ );
2581
+ if (reprojected) {
2582
+ resizingRef.current = true;
2583
+ setSelection(reprojected);
2584
+ }
2585
+ }
2586
+ }
2587
+ prevMetrics = newMetrics;
2588
+ });
2589
+ observer.observe(container);
2590
+ return () => observer.disconnect();
2591
+ }, [toolbar]);
2545
2592
  const onDirtyChangedRef = react.useRef(onDirtyChanged);
2546
2593
  onDirtyChangedRef.current = onDirtyChanged;
2547
2594
  react.useEffect(() => {
@@ -3295,7 +3342,7 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
3295
3342
  // pointermove (which is what changes the selection during
3296
3343
  // a drag) calls setSelection — that triggers a re-render
3297
3344
  // which reads the current dragRef value.
3298
- transition: dragRef.current ? "none" : "left 120ms ease-out, top 120ms ease-out, width 120ms ease-out, height 120ms ease-out"
3345
+ transition: dragRef.current || resizingRef.current ? "none" : "left 120ms ease-out, top 120ms ease-out, width 120ms ease-out, height 120ms ease-out"
3299
3346
  },
3300
3347
  children: [
3301
3348
  showThirds && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.thirdsGuide, "aria-hidden": "true", children: [
@@ -3456,6 +3503,21 @@ function useImageSrc(source) {
3456
3503
  return source.value ? `data:${resolveMimeType(source)};base64,${source.value}` : null;
3457
3504
  return bytesUrlRef.current;
3458
3505
  }
3506
+ function readImageLayoutMetrics(imageEl) {
3507
+ const layoutW = imageEl.offsetWidth;
3508
+ const layoutH = imageEl.offsetHeight;
3509
+ const naturalW = imageEl.naturalWidth;
3510
+ const naturalH = imageEl.naturalHeight;
3511
+ if (layoutW === 0 || layoutH === 0 || naturalW === 0 || naturalH === 0) return null;
3512
+ return {
3513
+ layoutW,
3514
+ layoutH,
3515
+ offsetLeft: imageEl.offsetLeft,
3516
+ offsetTop: imageEl.offsetTop,
3517
+ naturalW,
3518
+ naturalH
3519
+ };
3520
+ }
3459
3521
  function getDisplayedImageBounds(imageEl, angle, zoom, pan, flipH, flipV) {
3460
3522
  const layoutW = imageEl.offsetWidth;
3461
3523
  const layoutH = imageEl.offsetHeight;
@@ -3498,15 +3560,13 @@ function getDisplayedImageBounds(imageEl, angle, zoom, pan, flipH, flipV) {
3498
3560
  }
3499
3561
  return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
3500
3562
  }
3501
- function containerRectToImageNatural(rect, imageEl, angle, zoom, pan, flipH, flipV) {
3502
- const layoutW = imageEl.offsetWidth;
3503
- const layoutH = imageEl.offsetHeight;
3504
- const naturalW = imageEl.naturalWidth;
3505
- const naturalH = imageEl.naturalHeight;
3506
- if (layoutW === 0 || layoutH === 0 || naturalW === 0 || naturalH === 0) return null;
3563
+ function containerRectToImageNatural(rect, imageEl, angle, zoom, pan, flipH, flipV, metricsOverride) {
3564
+ const m = metricsOverride ?? readImageLayoutMetrics(imageEl);
3565
+ if (!m) return null;
3566
+ const { layoutW, layoutH, naturalW, naturalH } = m;
3507
3567
  const containScale = Math.min(layoutW / naturalW, layoutH / naturalH);
3508
- const imgCenterX = imageEl.offsetLeft + layoutW / 2;
3509
- const imgCenterY = imageEl.offsetTop + layoutH / 2;
3568
+ const imgCenterX = m.offsetLeft + layoutW / 2;
3569
+ const imgCenterY = m.offsetTop + layoutH / 2;
3510
3570
  const sx = zoom * (flipH ? -1 : 1);
3511
3571
  const sy = zoom * (flipV ? -1 : 1);
3512
3572
  if (sx === 0 || sy === 0) return null;
@@ -3539,15 +3599,13 @@ function containerRectToImageNatural(rect, imageEl, angle, zoom, pan, flipH, fli
3539
3599
  }
3540
3600
  return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
3541
3601
  }
3542
- function imageNaturalRectToContainer(rect, imageEl, angle, zoom, pan, flipH, flipV) {
3543
- const layoutW = imageEl.offsetWidth;
3544
- const layoutH = imageEl.offsetHeight;
3545
- const naturalW = imageEl.naturalWidth;
3546
- const naturalH = imageEl.naturalHeight;
3547
- if (layoutW === 0 || layoutH === 0 || naturalW === 0 || naturalH === 0) return null;
3602
+ function imageNaturalRectToContainer(rect, imageEl, angle, zoom, pan, flipH, flipV, metricsOverride) {
3603
+ const m = metricsOverride ?? readImageLayoutMetrics(imageEl);
3604
+ if (!m) return null;
3605
+ const { layoutW, layoutH, naturalW, naturalH } = m;
3548
3606
  const containScale = Math.min(layoutW / naturalW, layoutH / naturalH);
3549
- const imgCenterX = imageEl.offsetLeft + layoutW / 2;
3550
- const imgCenterY = imageEl.offsetTop + layoutH / 2;
3607
+ const imgCenterX = m.offsetLeft + layoutW / 2;
3608
+ const imgCenterY = m.offsetTop + layoutH / 2;
3551
3609
  const sx = zoom * (flipH ? -1 : 1);
3552
3610
  const sy = zoom * (flipV ? -1 : 1);
3553
3611
  const rad = angle * Math.PI / 180;
@@ -4425,6 +4483,69 @@ function ZipViewer({
4425
4483
  }
4426
4484
  );
4427
4485
  }
4486
+ function ZipEntryIcon({ fileName, className }) {
4487
+ switch (getFileExtension(fileName)) {
4488
+ case "pdf":
4489
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentPdf20Regular, { className });
4490
+ case "xls":
4491
+ case "xlsx":
4492
+ case "csv":
4493
+ case "ods":
4494
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentTable20Regular, { className });
4495
+ case "ppt":
4496
+ case "pptx":
4497
+ case "odp":
4498
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.SlideText20Regular, { className });
4499
+ case "png":
4500
+ case "jpg":
4501
+ case "jpeg":
4502
+ case "gif":
4503
+ case "bmp":
4504
+ case "webp":
4505
+ case "svg":
4506
+ case "ico":
4507
+ case "tif":
4508
+ case "tiff":
4509
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Image20Regular, { className });
4510
+ case "mp4":
4511
+ case "mov":
4512
+ case "avi":
4513
+ case "mkv":
4514
+ case "webm":
4515
+ case "m4v":
4516
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Video20Regular, { className });
4517
+ case "mp3":
4518
+ case "wav":
4519
+ case "ogg":
4520
+ case "flac":
4521
+ case "m4a":
4522
+ case "aac":
4523
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.MusicNote220Regular, { className });
4524
+ case "zip":
4525
+ case "7z":
4526
+ case "rar":
4527
+ case "tar":
4528
+ case "gz":
4529
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.FolderZip20Regular, { className });
4530
+ case "txt":
4531
+ case "md":
4532
+ case "markdown":
4533
+ case "log":
4534
+ case "json":
4535
+ case "xml":
4536
+ case "yaml":
4537
+ case "yml":
4538
+ case "html":
4539
+ case "htm":
4540
+ case "js":
4541
+ case "ts":
4542
+ case "cs":
4543
+ case "css":
4544
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentText20Regular, { className });
4545
+ default:
4546
+ return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Document20Regular, { className });
4547
+ }
4548
+ }
4428
4549
  function ZipTreeNode({ node, depth, expanded, selected, onToggle, onSelect }) {
4429
4550
  const styles = useFileViewerStyles();
4430
4551
  const isExpanded = expanded.has(node.fullPath);
@@ -4483,7 +4604,7 @@ function ZipTreeNode({ node, depth, expanded, selected, onToggle, onSelect }) {
4483
4604
  style: indent,
4484
4605
  children: [
4485
4606
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.zipChevronSpacer }),
4486
- /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Document20Regular, { className: styles.zipIcon }),
4607
+ /* @__PURE__ */ jsxRuntime.jsx(ZipEntryIcon, { fileName: node.name, className: styles.zipIcon }),
4487
4608
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.zipName, children: node.name })
4488
4609
  ]
4489
4610
  }
@@ -5128,11 +5249,13 @@ var useFileViewerStyles = reactComponents.makeStyles({
5128
5249
  outlineOffset: "-1px"
5129
5250
  }
5130
5251
  },
5252
+ // Selection style ported from the Blazor zip viewer: a subtle accent tint over
5253
+ // the row (text stays its normal color), intensifying slightly on hover so the
5254
+ // neutral row-hover doesn't wash out the selection.
5131
5255
  zipRowSelected: {
5132
- backgroundColor: reactComponents.tokens.colorBrandBackground2,
5133
- color: reactComponents.tokens.colorBrandForeground2,
5256
+ backgroundColor: `color-mix(in srgb, ${reactComponents.tokens.colorBrandBackground} 12%, transparent)`,
5134
5257
  ":hover": {
5135
- backgroundColor: reactComponents.tokens.colorBrandBackground2Hover
5258
+ backgroundColor: `color-mix(in srgb, ${reactComponents.tokens.colorBrandBackground} 18%, transparent)`
5136
5259
  }
5137
5260
  },
5138
5261
  zipChevron: {
@@ -11671,15 +11794,11 @@ function ManyToManyLookupEdit({
11671
11794
  return relatedPrimaryName;
11672
11795
  }, [resolvedColumns, relatedPrimaryName]);
11673
11796
  const lastSeededRecordIdRef = react.useRef(void 0);
11674
- const lastSeededViewIdRef = react.useRef(void 0);
11675
11797
  react.useEffect(() => {
11676
11798
  if (initialLoad.status !== react$1.QueryStatus.Success || !initialLoad.data) return;
11677
11799
  if (!primaryNameColumn || !parentRecord) return;
11678
- if (lastSeededRecordIdRef.current === parentRefId && lastSeededViewIdRef.current === selectedViewId) {
11679
- return;
11680
- }
11800
+ if (lastSeededRecordIdRef.current === parentRefId) return;
11681
11801
  lastSeededRecordIdRef.current = parentRefId;
11682
- lastSeededViewIdRef.current = selectedViewId;
11683
11802
  const seeded = initialLoad.data.tableRecords.map((r) => ({
11684
11803
  id: r.id,
11685
11804
  displayName: resolveDisplayName(r, primaryNameColumn) ?? "",
@@ -11688,7 +11807,7 @@ function ManyToManyLookupEdit({
11688
11807
  setInitialSelection(seeded);
11689
11808
  setPendingAdds([]);
11690
11809
  setPendingRemoveIds([]);
11691
- }, [initialLoad.status, initialLoad.data, parentRecord, primaryNameColumn, selectedViewId]);
11810
+ }, [initialLoad.status, initialLoad.data, parentRecord, primaryNameColumn, parentRefId]);
11692
11811
  const [query, setQuery] = react.useState("");
11693
11812
  const [debouncedQuery, setDebouncedQuery] = react.useState("");
11694
11813
  const [searchResults, setSearchResults] = react.useState([]);
@@ -11800,7 +11919,6 @@ function ManyToManyLookupEdit({
11800
11919
  setPendingAdds([]);
11801
11920
  setPendingRemoveIds([]);
11802
11921
  lastSeededRecordIdRef.current = void 0;
11803
- lastSeededViewIdRef.current = void 0;
11804
11922
  },
11805
11923
  // Cancel/Discard: just drop the pending adds/removes; the
11806
11924
  // seed-guard refs stay so the initial selection (already loaded