@openzeppelin/ui-components 1.2.0 → 1.3.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
@@ -618,6 +618,134 @@ const DropdownMenuShortcut = ({ className, ...props }) => {
618
618
  };
619
619
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
620
620
 
621
+ //#endregion
622
+ //#region src/components/ui/ecosystem-dropdown.tsx
623
+ /** Simple dropdown selector for choosing a blockchain ecosystem. */
624
+ function EcosystemDropdown({ options, value, onValueChange, getEcosystemIcon, disabled = false, className, placeholder = "Select blockchain...", "aria-labelledby": ariaLabelledby }) {
625
+ const [open, setOpen] = react.useState(false);
626
+ const selectedOption = options.find((o) => o.value === value);
627
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DropdownMenu, {
628
+ open,
629
+ onOpenChange: setOpen,
630
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropdownMenuTrigger, {
631
+ asChild: true,
632
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
633
+ variant: "outline",
634
+ role: "combobox",
635
+ "aria-expanded": open,
636
+ "aria-labelledby": ariaLabelledby,
637
+ disabled,
638
+ className: (0, _openzeppelin_ui_utils.cn)("w-full justify-between", className),
639
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
640
+ className: "flex items-center gap-2 truncate",
641
+ children: selectedOption ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [getEcosystemIcon?.(selectedOption.value), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
642
+ className: "truncate",
643
+ children: selectedOption.label
644
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
645
+ className: "text-muted-foreground",
646
+ children: placeholder
647
+ })
648
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
649
+ })
650
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropdownMenuContent, {
651
+ className: "w-[--radix-dropdown-menu-trigger-width] min-w-[200px]",
652
+ align: "start",
653
+ children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DropdownMenuItem, {
654
+ disabled: !option.enabled,
655
+ onSelect: () => {
656
+ onValueChange(option.value);
657
+ setOpen(false);
658
+ },
659
+ className: "gap-2",
660
+ children: [
661
+ getEcosystemIcon?.(option.value),
662
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
663
+ className: "flex-1 truncate",
664
+ children: option.label
665
+ }),
666
+ !option.enabled && option.disabledLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
667
+ className: "shrink-0 text-xs text-muted-foreground",
668
+ children: option.disabledLabel
669
+ }),
670
+ value === option.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "h-4 w-4 shrink-0 opacity-100" })
671
+ ]
672
+ }, option.value))
673
+ })]
674
+ });
675
+ }
676
+
677
+ //#endregion
678
+ //#region src/components/icons/MidnightIcon.tsx
679
+ /**
680
+ * MidnightIcon - SVG icon for the Midnight blockchain
681
+ * Inline SVG to ensure it renders correctly when this package is consumed as a library
682
+ */
683
+ function MidnightIcon({ size = 16, className = "", variant: _variant }) {
684
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
685
+ xmlns: "http://www.w3.org/2000/svg",
686
+ viewBox: "0 0 789.37 789.37",
687
+ width: size,
688
+ height: size,
689
+ className,
690
+ "aria-hidden": "true",
691
+ children: [
692
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
693
+ d: "m394.69,0C176.71,0,0,176.71,0,394.69s176.71,394.69,394.69,394.69,394.69-176.71,394.69-394.69S612.67,0,394.69,0Zm0,716.6c-177.5,0-321.91-144.41-321.91-321.91S217.18,72.78,394.69,72.78s321.91,144.41,321.91,321.91-144.41,321.91-321.91,321.91Z",
694
+ fill: "currentColor"
695
+ }),
696
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
697
+ x: "357.64",
698
+ y: "357.64",
699
+ width: "74.09",
700
+ height: "74.09",
701
+ fill: "currentColor"
702
+ }),
703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
704
+ x: "357.64",
705
+ y: "240.66",
706
+ width: "74.09",
707
+ height: "74.09",
708
+ fill: "currentColor"
709
+ }),
710
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
711
+ x: "357.64",
712
+ y: "123.69",
713
+ width: "74.09",
714
+ height: "74.09",
715
+ fill: "currentColor"
716
+ })
717
+ ]
718
+ });
719
+ }
720
+
721
+ //#endregion
722
+ //#region src/components/ui/ecosystem-icon.tsx
723
+ /** Displays the appropriate icon for a blockchain ecosystem. */
724
+ function EcosystemIcon({ ecosystem, fallbackLabel, className, size = 16, variant = "branded" }) {
725
+ if (ecosystem.id === "midnight") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MidnightIcon, {
726
+ size,
727
+ variant,
728
+ className: (0, _openzeppelin_ui_utils.cn)("shrink-0", className)
729
+ });
730
+ if (ecosystem.iconComponent) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ecosystem.iconComponent, {
731
+ size,
732
+ variant,
733
+ className: (0, _openzeppelin_ui_utils.cn)("shrink-0", className)
734
+ });
735
+ const initial = (fallbackLabel ?? ecosystem.id).charAt(0).toUpperCase();
736
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
737
+ className: (0, _openzeppelin_ui_utils.cn)("bg-muted text-muted-foreground shrink-0 rounded-full flex items-center justify-center font-medium", className),
738
+ style: {
739
+ width: size,
740
+ height: size,
741
+ fontSize: size * .5
742
+ },
743
+ role: "img",
744
+ "aria-label": fallbackLabel ?? ecosystem.id,
745
+ children: initial
746
+ });
747
+ }
748
+
621
749
  //#endregion
622
750
  //#region src/components/ui/empty-state.tsx
623
751
  /**
@@ -943,50 +1071,6 @@ const LoadingButton = react.forwardRef(({ className, loading = false, children,
943
1071
  });
944
1072
  LoadingButton.displayName = "LoadingButton";
945
1073
 
946
- //#endregion
947
- //#region src/components/icons/MidnightIcon.tsx
948
- /**
949
- * MidnightIcon - SVG icon for the Midnight blockchain
950
- * Inline SVG to ensure it renders correctly when this package is consumed as a library
951
- */
952
- function MidnightIcon({ size = 16, className = "", variant: _variant }) {
953
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
954
- xmlns: "http://www.w3.org/2000/svg",
955
- viewBox: "0 0 789.37 789.37",
956
- width: size,
957
- height: size,
958
- className,
959
- "aria-hidden": "true",
960
- children: [
961
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
962
- d: "m394.69,0C176.71,0,0,176.71,0,394.69s176.71,394.69,394.69,394.69,394.69-176.71,394.69-394.69S612.67,0,394.69,0Zm0,716.6c-177.5,0-321.91-144.41-321.91-321.91S217.18,72.78,394.69,72.78s321.91,144.41,321.91,321.91-144.41,321.91-321.91,321.91Z",
963
- fill: "currentColor"
964
- }),
965
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
966
- x: "357.64",
967
- y: "357.64",
968
- width: "74.09",
969
- height: "74.09",
970
- fill: "currentColor"
971
- }),
972
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
973
- x: "357.64",
974
- y: "240.66",
975
- width: "74.09",
976
- height: "74.09",
977
- fill: "currentColor"
978
- }),
979
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
980
- x: "357.64",
981
- y: "123.69",
982
- width: "74.09",
983
- height: "74.09",
984
- fill: "currentColor"
985
- })
986
- ]
987
- });
988
- }
989
-
990
1074
  //#endregion
991
1075
  //#region src/components/ui/network-icon.tsx
992
1076
  /** Displays the appropriate icon for a blockchain network. */
@@ -2713,7 +2797,7 @@ BooleanField.displayName = "BooleanField";
2713
2797
  * 4. BaseField provides consistent layout and hook form integration
2714
2798
  * 5. This component handles bytes-specific validation and formatting
2715
2799
  */
2716
- function BytesField({ id, label, helperText, control, name, width = "full", validation, placeholder = "Enter hex or base64 encoded bytes", rows = 3, maxBytes, acceptedFormats = "both", autoPrefix = false, allowHexPrefix = true, readOnly }) {
2800
+ function BytesField({ id, label, helperText, control, name, width = "full", validation, placeholder = "Enter hex or base64 encoded bytes", rows = 3, maxBytes, exactBytes, acceptedFormats = "both", autoPrefix = false, allowHexPrefix = true, readOnly }) {
2717
2801
  const isRequired = !!validation?.required;
2718
2802
  const errorId = `${id}-error`;
2719
2803
  const descriptionId = `${id}-description`;
@@ -2724,6 +2808,7 @@ function BytesField({ id, label, helperText, control, name, width = "full", vali
2724
2808
  return (0, _openzeppelin_ui_utils.validateBytesSimple)(value, {
2725
2809
  acceptedFormats,
2726
2810
  maxBytes,
2811
+ exactBytes,
2727
2812
  allowHexPrefix
2728
2813
  });
2729
2814
  };
@@ -2799,7 +2884,8 @@ function BytesField({ id, label, helperText, control, name, width = "full", vali
2799
2884
  acceptedFormats === "hex" && "Hex format (e.g., 48656c6c6f or 0x48656c6c6f)",
2800
2885
  acceptedFormats === "base64" && "Base64 format (e.g., SGVsbG8=)",
2801
2886
  acceptedFormats === "both" && "Hex (e.g., 48656c6c6f) or Base64 (e.g., SGVsbG8=) format",
2802
- maxBytes && ` • Max ${maxBytes} bytes`
2887
+ exactBytes && ` • Exactly ${exactBytes} bytes (${exactBytes * 2} hex chars)`,
2888
+ !exactBytes && maxBytes && ` • Max ${maxBytes} bytes`
2803
2889
  ]
2804
2890
  })]
2805
2891
  }),
@@ -5224,6 +5310,8 @@ exports.DropdownMenuSub = DropdownMenuSub;
5224
5310
  exports.DropdownMenuSubContent = DropdownMenuSubContent;
5225
5311
  exports.DropdownMenuSubTrigger = DropdownMenuSubTrigger;
5226
5312
  exports.DropdownMenuTrigger = DropdownMenuTrigger;
5313
+ exports.EcosystemDropdown = EcosystemDropdown;
5314
+ exports.EcosystemIcon = EcosystemIcon;
5227
5315
  exports.EmptyState = EmptyState;
5228
5316
  exports.EnumField = EnumField;
5229
5317
  exports.ErrorMessage = require_ErrorMessage.ErrorMessage;