@bizapps/ui 1.7.0 → 1.10.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/main.cjs CHANGED
@@ -28,6 +28,7 @@ var reactHookForm = require('react-hook-form');
28
28
  var zod = require('@hookform/resolvers/zod');
29
29
  var confetti = require('canvas-confetti');
30
30
  var reactTable = require('@tanstack/react-table');
31
+ var SignaturePadLib = require('signature_pad');
31
32
 
32
33
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
33
34
 
@@ -53,6 +54,7 @@ var useEmblaCarousel__default = /*#__PURE__*/_interopDefault(useEmblaCarousel);
53
54
  var countryFlags__namespace = /*#__PURE__*/_interopNamespace(countryFlags);
54
55
  var Color__default = /*#__PURE__*/_interopDefault(Color);
55
56
  var confetti__default = /*#__PURE__*/_interopDefault(confetti);
57
+ var SignaturePadLib__default = /*#__PURE__*/_interopDefault(SignaturePadLib);
56
58
 
57
59
  // src/components/ui/Alert/alert.tsx
58
60
  function cn(...inputs) {
@@ -953,10 +955,11 @@ function Input({ className, type, ...props }) {
953
955
  type,
954
956
  "data-slot": "input",
955
957
  className: cn(
956
- "border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none",
957
- "placeholder:text-muted-foreground",
958
+ "border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[border-color,box-shadow] outline-hidden md:text-sm",
959
+ "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground",
960
+ "file:text-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium",
958
961
  "focus-visible:border-ring focus-visible:ring-ring/30 focus-visible:ring-3",
959
- "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
962
+ "disabled:cursor-not-allowed disabled:opacity-50",
960
963
  "aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:ring-3",
961
964
  "dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
962
965
  className
@@ -6188,10 +6191,10 @@ function Textarea({ className, ...props }) {
6188
6191
  {
6189
6192
  "data-slot": "textarea",
6190
6193
  className: cn(
6191
- "border-input flex min-h-[80px] w-full resize-y rounded-md border bg-transparent px-3 py-2 text-sm shadow-xs transition-[color,box-shadow] outline-none",
6194
+ "border-input flex min-h-[80px] w-full resize-y rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[border-color,box-shadow] outline-hidden md:text-sm",
6192
6195
  "placeholder:text-muted-foreground",
6193
6196
  "focus-visible:border-ring focus-visible:ring-ring/30 focus-visible:ring-3",
6194
- "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
6197
+ "disabled:cursor-not-allowed disabled:opacity-50",
6195
6198
  "aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:ring-3",
6196
6199
  "dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
6197
6200
  className
@@ -7105,6 +7108,7 @@ function useAppForm(schema, options) {
7105
7108
  // src/lib/cdn.ts
7106
7109
  var CDN_BASE = "https://dibt9vplwriap.cloudfront.net";
7107
7110
  var logos = {
7111
+ // Total Civil
7108
7112
  color: `${CDN_BASE}/logos/Logo_Total_Color.webp`,
7109
7113
  colorAna: `${CDN_BASE}/logos/Logo_Total_Color-ANA.webp`,
7110
7114
  colorAnaa: `${CDN_BASE}/logos/Logo_Total_Color-ANAA.webp`,
@@ -7112,7 +7116,11 @@ var logos = {
7112
7116
  positive: `${CDN_BASE}/logos/Logo_Total_Positive.webp`,
7113
7117
  grayScale: `${CDN_BASE}/logos/Logo_Total_gray_scale.webp`,
7114
7118
  monochBlack: `${CDN_BASE}/logos/Logo_Total_monochB.webp`,
7115
- monochOrange: `${CDN_BASE}/logos/Logo_Total_monochO.webp`
7119
+ monochOrange: `${CDN_BASE}/logos/Logo_Total_monochO.webp`,
7120
+ isotype: `${CDN_BASE}/logos/Isotipo_Total_Color.webp`,
7121
+ // Total Millwork
7122
+ millworkColor: `${CDN_BASE}/logos/Logo_Millwork_Color.webp`,
7123
+ millworkNegative: `${CDN_BASE}/logos/Logo_Millwork_Negative.webp`
7116
7124
  };
7117
7125
  var CONFETTI_COLORS = [
7118
7126
  "#22205f",
@@ -9416,6 +9424,198 @@ function DrawerDescription({
9416
9424
  }
9417
9425
  );
9418
9426
  }
9427
+ function SignaturePad({
9428
+ "aria-label": ariaLabel,
9429
+ "aria-describedby": ariaDescribedBy,
9430
+ onEmptyChange,
9431
+ disabled = false,
9432
+ height = 260,
9433
+ penColor = "black",
9434
+ // Smoother than the library defaults (0.5–2.5 px, 5 px, 16 ms), which drop points and turn
9435
+ // fast or small curves into visible straight segments.
9436
+ minWidth = 1,
9437
+ maxWidth = 3,
9438
+ minDistance = 1,
9439
+ throttle = 0,
9440
+ velocityFilterWeight,
9441
+ clearLabel,
9442
+ className,
9443
+ ref
9444
+ }) {
9445
+ const canvasRef = react.useRef(null);
9446
+ const padRef = react.useRef(null);
9447
+ const emptyRef = react.useRef(true);
9448
+ const [empty, setEmptyState] = react.useState(true);
9449
+ const onEmptyChangeRef = react.useRef(onEmptyChange);
9450
+ const drawnRef = react.useRef({
9451
+ data: [],
9452
+ width: 0,
9453
+ height: 0,
9454
+ scale: 1
9455
+ });
9456
+ const optionsRef = react.useRef({
9457
+ penColor,
9458
+ minWidth,
9459
+ maxWidth,
9460
+ minDistance,
9461
+ throttle,
9462
+ velocityFilterWeight
9463
+ });
9464
+ react.useEffect(() => {
9465
+ onEmptyChangeRef.current = onEmptyChange;
9466
+ }, [onEmptyChange]);
9467
+ const setEmpty = (next) => {
9468
+ if (emptyRef.current === next) return;
9469
+ emptyRef.current = next;
9470
+ setEmptyState(next);
9471
+ onEmptyChangeRef.current?.(next);
9472
+ };
9473
+ const clear = () => {
9474
+ padRef.current?.clear();
9475
+ drawnRef.current = { data: [], width: 0, height: 0, scale: 1 };
9476
+ setEmpty(true);
9477
+ };
9478
+ react.useEffect(() => {
9479
+ const canvas = canvasRef.current;
9480
+ if (!canvas) return;
9481
+ const pad = new SignaturePadLib__default.default(canvas, optionsRef.current);
9482
+ padRef.current = pad;
9483
+ let width = 0;
9484
+ let fittedHeight = 0;
9485
+ const redraw = () => {
9486
+ const drawn = drawnRef.current;
9487
+ drawn.scale = Math.min(width / drawn.width, fittedHeight / drawn.height, 1);
9488
+ pad.clear();
9489
+ pad.fromData(
9490
+ drawn.data.map((group) => ({
9491
+ ...group,
9492
+ points: group.points.map((point) => ({
9493
+ ...point,
9494
+ x: point.x * drawn.scale,
9495
+ y: point.y * drawn.scale
9496
+ }))
9497
+ }))
9498
+ );
9499
+ };
9500
+ const handleEnd = () => {
9501
+ const drawn = drawnRef.current;
9502
+ if (drawn.data.length === 0) {
9503
+ drawn.width = width;
9504
+ drawn.height = fittedHeight;
9505
+ drawn.scale = 1;
9506
+ }
9507
+ const newest = pad.toData().at(-1);
9508
+ if (newest) {
9509
+ const points = newest.points.map((point) => ({
9510
+ ...point,
9511
+ x: point.x / drawn.scale,
9512
+ y: point.y / drawn.scale
9513
+ }));
9514
+ drawn.data = [...drawn.data, { ...newest, points }];
9515
+ const margin = newest.maxWidth ?? 0;
9516
+ const reach = (axis) => Math.max(...points.map((point) => point[axis])) + margin;
9517
+ drawn.width = Math.max(drawn.width, reach("x"));
9518
+ drawn.height = Math.max(drawn.height, reach("y"));
9519
+ const fitting = Math.min(width / drawn.width, fittedHeight / drawn.height, 1);
9520
+ if (fitting !== drawn.scale) redraw();
9521
+ }
9522
+ setEmpty(pad.isEmpty());
9523
+ };
9524
+ pad.addEventListener("endStroke", handleEnd);
9525
+ const fit = () => {
9526
+ const nextWidth = canvas.offsetWidth;
9527
+ const nextHeight = canvas.offsetHeight;
9528
+ if (!nextWidth || !nextHeight) return;
9529
+ if (nextWidth === width && nextHeight === fittedHeight) return;
9530
+ width = nextWidth;
9531
+ fittedHeight = nextHeight;
9532
+ const ratio = window.devicePixelRatio || 1;
9533
+ canvas.width = nextWidth * ratio;
9534
+ canvas.height = nextHeight * ratio;
9535
+ canvas.getContext("2d")?.scale(ratio, ratio);
9536
+ pad.clear();
9537
+ if (drawnRef.current.data.length > 0) redraw();
9538
+ };
9539
+ fit();
9540
+ const observer = new ResizeObserver(fit);
9541
+ observer.observe(canvas);
9542
+ return () => {
9543
+ observer.disconnect();
9544
+ pad.removeEventListener("endStroke", handleEnd);
9545
+ pad.off();
9546
+ padRef.current = null;
9547
+ };
9548
+ }, []);
9549
+ react.useEffect(() => {
9550
+ if (disabled) padRef.current?.off();
9551
+ else padRef.current?.on();
9552
+ }, [disabled]);
9553
+ react.useImperativeHandle(
9554
+ ref,
9555
+ () => ({
9556
+ clear,
9557
+ isEmpty: () => padRef.current?.isEmpty() ?? true,
9558
+ toBlob: () => new Promise((resolve, reject) => {
9559
+ const canvas = canvasRef.current;
9560
+ if (!canvas) return reject(new Error("The signature pad is not mounted"));
9561
+ canvas.toBlob((blob) => {
9562
+ if (blob) resolve(blob);
9563
+ else reject(new Error("The signature could not be encoded as PNG"));
9564
+ }, "image/png");
9565
+ })
9566
+ }),
9567
+ // `clear` only touches refs and state setters, so the handle is created once.
9568
+ // eslint-disable-next-line react-hooks/exhaustive-deps
9569
+ []
9570
+ );
9571
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9572
+ "div",
9573
+ {
9574
+ "data-slot": "signature-pad",
9575
+ "data-disabled": disabled ? "" : void 0,
9576
+ className: cn(
9577
+ // Fixed light "paper": the pen is black and the PNG is read on white by others. The
9578
+ // primitive keeps the pad light for consumers that define a dark theme, where a themed
9579
+ // surface (`background`, `border`) would turn dark and hide the black ink.
9580
+ "bg-main-alternative-secondary border-dark-100 relative overflow-hidden rounded-xl border",
9581
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
9582
+ className
9583
+ ),
9584
+ children: [
9585
+ /* @__PURE__ */ jsxRuntime.jsx(
9586
+ "canvas",
9587
+ {
9588
+ ref: canvasRef,
9589
+ "data-slot": "signature-pad-canvas",
9590
+ role: "img",
9591
+ "aria-label": ariaLabel,
9592
+ "aria-describedby": ariaDescribedBy,
9593
+ "aria-disabled": disabled || void 0,
9594
+ style: { height },
9595
+ className: "block w-full touch-none"
9596
+ }
9597
+ ),
9598
+ /* @__PURE__ */ jsxRuntime.jsx(
9599
+ Button,
9600
+ {
9601
+ type: "button",
9602
+ variant: "ghost",
9603
+ size: "icon-sm",
9604
+ "data-slot": "signature-pad-clear",
9605
+ "aria-label": clearLabel,
9606
+ disabled,
9607
+ "aria-disabled": empty && !disabled ? true : void 0,
9608
+ onClick: () => {
9609
+ if (!emptyRef.current) clear();
9610
+ },
9611
+ className: "bg-main-white text-dark-600 border-dark-100 hover:bg-dark-100 hover:text-main-black aria-disabled:hover:bg-main-white absolute right-2 bottom-2 border border-solid aria-disabled:cursor-not-allowed aria-disabled:opacity-50",
9612
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BrushCleaning, { "aria-hidden": true, className: "size-4" })
9613
+ }
9614
+ )
9615
+ ]
9616
+ }
9617
+ );
9618
+ }
9419
9619
  function TCCEProvider({
9420
9620
  children,
9421
9621
  permissions,
@@ -9656,6 +9856,7 @@ exports.SidebarProvider = SidebarProvider;
9656
9856
  exports.SidebarRail = SidebarRail;
9657
9857
  exports.SidebarSeparator = SidebarSeparator;
9658
9858
  exports.SidebarTrigger = SidebarTrigger;
9859
+ exports.SignaturePad = SignaturePad;
9659
9860
  exports.Skeleton = Skeleton;
9660
9861
  exports.Slider = Slider;
9661
9862
  exports.Spinner = Spinner;