@canonical/react-components 3.9.1 → 3.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.
Files changed (41) hide show
  1. package/dist/components/PrefixedInput/PrefixedInput.d.ts +13 -0
  2. package/dist/components/PrefixedInput/PrefixedInput.js +64 -0
  3. package/dist/components/PrefixedInput/PrefixedInput.scss +22 -0
  4. package/dist/components/PrefixedInput/PrefixedInput.stories.d.ts +11 -0
  5. package/dist/components/PrefixedInput/PrefixedInput.stories.js +58 -0
  6. package/dist/components/PrefixedInput/PrefixedInput.test.d.ts +1 -0
  7. package/dist/components/PrefixedInput/index.d.ts +1 -0
  8. package/dist/components/PrefixedInput/index.js +13 -0
  9. package/dist/components/PrefixedIpInput/PrefixedIpInput.d.ts +27 -0
  10. package/dist/components/PrefixedIpInput/PrefixedIpInput.js +65 -0
  11. package/dist/components/PrefixedIpInput/PrefixedIpInput.stories.d.ts +13 -0
  12. package/dist/components/PrefixedIpInput/PrefixedIpInput.stories.js +137 -0
  13. package/dist/components/PrefixedIpInput/PrefixedIpInput.test.d.ts +1 -0
  14. package/dist/components/PrefixedIpInput/index.d.ts +2 -0
  15. package/dist/components/PrefixedIpInput/index.js +56 -0
  16. package/dist/components/PrefixedIpInput/utils.d.ts +39 -0
  17. package/dist/components/PrefixedIpInput/utils.js +125 -0
  18. package/dist/components/PrefixedIpInput/utils.test.d.ts +1 -0
  19. package/dist/esm/components/PrefixedInput/PrefixedInput.d.ts +13 -0
  20. package/dist/esm/components/PrefixedInput/PrefixedInput.js +57 -0
  21. package/dist/esm/components/PrefixedInput/PrefixedInput.scss +22 -0
  22. package/dist/esm/components/PrefixedInput/PrefixedInput.stories.d.ts +11 -0
  23. package/dist/esm/components/PrefixedInput/PrefixedInput.stories.js +51 -0
  24. package/dist/esm/components/PrefixedInput/PrefixedInput.test.d.ts +1 -0
  25. package/dist/esm/components/PrefixedInput/index.d.ts +1 -0
  26. package/dist/esm/components/PrefixedInput/index.js +1 -0
  27. package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.d.ts +27 -0
  28. package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.js +58 -0
  29. package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.stories.d.ts +13 -0
  30. package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.stories.js +128 -0
  31. package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.test.d.ts +1 -0
  32. package/dist/esm/components/PrefixedIpInput/index.d.ts +2 -0
  33. package/dist/esm/components/PrefixedIpInput/index.js +2 -0
  34. package/dist/esm/components/PrefixedIpInput/utils.d.ts +39 -0
  35. package/dist/esm/components/PrefixedIpInput/utils.js +112 -0
  36. package/dist/esm/components/PrefixedIpInput/utils.test.d.ts +1 -0
  37. package/dist/esm/index.d.ts +4 -0
  38. package/dist/esm/index.js +2 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +65 -0
  41. package/package.json +1 -1
@@ -0,0 +1,13 @@
1
+ import { type ReactElement } from "react";
2
+ import { type InputProps } from "../Input";
3
+ import "./PrefixedInput.scss";
4
+ import { PropsWithSpread } from "../../types";
5
+ export type PrefixedInputProps = PropsWithSpread<{
6
+ /**
7
+ * The immutable text that appears at the beginning of the input field.
8
+ * This text is not editable by the user and visually appears inside the input.
9
+ */
10
+ immutableText: string;
11
+ }, Omit<InputProps, "type">>;
12
+ declare const PrefixedInput: ({ immutableText, ...props }: PrefixedInputProps) => ReactElement;
13
+ export default PrefixedInput;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _Input = _interopRequireDefault(require("../Input"));
9
+ var _classnames = _interopRequireDefault(require("classnames"));
10
+ require("./PrefixedInput.scss");
11
+ var _useListener = require("../../hooks/useListener");
12
+ const _excluded = ["immutableText"];
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
15
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
16
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
17
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
18
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
19
+ // export type PrefixedInputProps = Omit<InputProps, "type"> & {
20
+ // /**
21
+ // * The immutable text that appears at the beginning of the input field.
22
+ // * This text is not editable by the user and visually appears inside the input.
23
+ // */
24
+ // immutableText: string;
25
+ // };
26
+
27
+ const PrefixedInput = _ref => {
28
+ let {
29
+ immutableText
30
+ } = _ref,
31
+ props = _objectWithoutProperties(_ref, _excluded);
32
+ const prefixTextRef = (0, _react.useRef)(null);
33
+ const inputWrapperRef = (0, _react.useRef)(null);
34
+ const updatePadding = (0, _react.useCallback)(() => {
35
+ var _inputWrapperRef$curr;
36
+ const prefixElement = prefixTextRef.current;
37
+ const inputElement = (_inputWrapperRef$curr = inputWrapperRef.current) === null || _inputWrapperRef$curr === void 0 ? void 0 : _inputWrapperRef$curr.querySelector("input");
38
+ if (prefixElement && inputElement) {
39
+ // Adjust the left padding of the input to be the same width as the immutable text.
40
+ // This displays the user input and the unchangeable text together as one combined string.
41
+ const prefixWidth = prefixElement.getBoundingClientRect().width;
42
+ inputElement.style.paddingLeft = "".concat(prefixWidth, "px");
43
+ }
44
+ }, []);
45
+ (0, _useListener.useListener)(window, updatePadding, "resize", true);
46
+ (0, _react.useLayoutEffect)(() => {
47
+ updatePadding();
48
+ }, [immutableText, props.label, updatePadding]);
49
+ return /*#__PURE__*/_react.default.createElement("div", {
50
+ className: (0, _classnames.default)("prefixed-input", {
51
+ "prefixed-input--with-label": !!props.label
52
+ })
53
+ }, /*#__PURE__*/_react.default.createElement("div", {
54
+ className: "prefixed-input__text",
55
+ ref: prefixTextRef
56
+ }, immutableText), /*#__PURE__*/_react.default.createElement("div", {
57
+ ref: inputWrapperRef
58
+ }, /*#__PURE__*/_react.default.createElement(_Input.default, _extends({}, props, {
59
+ className: (0, _classnames.default)("prefixed-input__input", props.className),
60
+ type: "text",
61
+ wrapperClassName: (0, _classnames.default)("prefixed-input__wrapper", props.wrapperClassName)
62
+ }))));
63
+ };
64
+ var _default = exports.default = PrefixedInput;
@@ -0,0 +1,22 @@
1
+ @import "vanilla-framework";
2
+
3
+ .prefixed-input {
4
+ position: relative;
5
+
6
+ .prefixed-input__input {
7
+ padding-top: 0.25rem;
8
+ }
9
+
10
+ .prefixed-input__text {
11
+ padding-left: $spv--large;
12
+ padding-top: 0.3rem;
13
+ pointer-events: none;
14
+ position: absolute;
15
+ }
16
+
17
+ &--with-label {
18
+ .prefixed-input__text {
19
+ top: 2.5rem;
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,11 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import PrefixedInput from "./PrefixedInput";
3
+ declare const meta: Meta<typeof PrefixedInput>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof PrefixedInput>;
6
+ export declare const Default: Story;
7
+ export declare const WithLabel: Story;
8
+ export declare const Disabled: Story;
9
+ export declare const WithError: Story;
10
+ export declare const WithHelpText: Story;
11
+ export declare const Required: Story;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.WithLabel = exports.WithHelpText = exports.WithError = exports.Required = exports.Disabled = exports.Default = void 0;
7
+ var _PrefixedInput = _interopRequireDefault(require("./PrefixedInput"));
8
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ const meta = {
10
+ component: _PrefixedInput.default,
11
+ tags: ["autodocs"]
12
+ };
13
+ var _default = exports.default = meta;
14
+ const Default = exports.Default = {
15
+ args: {
16
+ immutableText: "https://",
17
+ placeholder: "example.com"
18
+ }
19
+ };
20
+ const WithLabel = exports.WithLabel = {
21
+ args: {
22
+ immutableText: "https://",
23
+ label: "Website URL",
24
+ placeholder: "example.com"
25
+ }
26
+ };
27
+ const Disabled = exports.Disabled = {
28
+ args: {
29
+ immutableText: "@",
30
+ label: "Username",
31
+ placeholder: "username",
32
+ disabled: true
33
+ }
34
+ };
35
+ const WithError = exports.WithError = {
36
+ args: {
37
+ immutableText: "https://",
38
+ label: "Website URL",
39
+ placeholder: "example.com",
40
+ error: "Invalid URL format"
41
+ }
42
+ };
43
+ const WithHelpText = exports.WithHelpText = {
44
+ args: {
45
+ immutableText: "User ID:",
46
+ label: "User Identifier",
47
+ placeholder: " Enter user ID",
48
+ help: "This will be used to identify your account"
49
+ }
50
+ };
51
+ const Required = exports.Required = {
52
+ args: {
53
+ immutableText: "https://",
54
+ label: "Website URL",
55
+ placeholder: "example.com",
56
+ required: true
57
+ }
58
+ };
@@ -0,0 +1 @@
1
+ export { default, type PrefixedInputProps } from "./PrefixedInput";
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "default", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _PrefixedInput.default;
10
+ }
11
+ });
12
+ var _PrefixedInput = _interopRequireDefault(require("./PrefixedInput"));
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,27 @@
1
+ import { type ReactElement } from "react";
2
+ import { type PrefixedInputProps } from "../PrefixedInput";
3
+ import { PropsWithSpread } from "../../types";
4
+ export type PrefixedIpInputProps = PropsWithSpread<{
5
+ /**
6
+ * The CIDR for the subnet (e.g., "192.168.1.0/24" or "2001:db8::/32").
7
+ * Used to calculate the immutable prefix and available IP range.
8
+ */
9
+ cidr: string;
10
+ /**
11
+ * The full IP address value (if available).
12
+ * For IPv4: e.g., "192.168.1.100"
13
+ * For IPv6: e.g., "2001:db8::1"
14
+ */
15
+ ip: string;
16
+ /**
17
+ * The name attribute for the input field.
18
+ */
19
+ name: string;
20
+ /**
21
+ * Callback function that is called when the IP address changes.
22
+ * Receives the full IP address as a string parameter.
23
+ */
24
+ onIpChange: (ip: string) => void;
25
+ }, Omit<PrefixedInputProps, "immutableText" | "maxLength" | "placeholder" | "name">>;
26
+ declare const PrefixedIpInput: ({ cidr, help, onIpChange, ip, name, ...props }: PrefixedIpInputProps) => ReactElement;
27
+ export default PrefixedIpInput;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _PrefixedInput = _interopRequireDefault(require("../PrefixedInput"));
9
+ var _utils = require("./utils");
10
+ const _excluded = ["cidr", "help", "onIpChange", "ip", "name"];
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
13
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
14
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
15
+ const PrefixedIpInput = _ref => {
16
+ let {
17
+ cidr,
18
+ help,
19
+ onIpChange,
20
+ ip,
21
+ name
22
+ } = _ref,
23
+ props = _objectWithoutProperties(_ref, _excluded);
24
+ const [networkAddress] = cidr.split("/");
25
+ const isIPV4 = (0, _utils.isIPv4)(networkAddress);
26
+ const [immutable, editable] = (0, _utils.getImmutableAndEditable)(cidr);
27
+ const inputValue = isIPV4 ? ip.split(".").slice(immutable.split(".").length).join(".") : ip.replace(immutable, "");
28
+ const getIPv4MaxLength = () => {
29
+ const immutableOctetsLength = immutable.split(".").length;
30
+ const lengths = [15, 11, 7, 3]; // Corresponding to 0-3 immutable octets
31
+ return lengths[immutableOctetsLength];
32
+ };
33
+ const maxLength = isIPV4 ? getIPv4MaxLength() : editable.length;
34
+ const placeholder = props.disabled ? "" : editable;
35
+ const setIp = editableValue => {
36
+ const fullIp = editableValue ? isIPV4 ? "".concat(immutable, ".").concat(editableValue) : "".concat(immutable).concat(editableValue) : "";
37
+ onIpChange(fullIp);
38
+ };
39
+ const handlePaste = e => {
40
+ e.preventDefault();
41
+ const pastedText = e.clipboardData.getData("text");
42
+ if (isIPV4) {
43
+ const octets = pastedText.split(".");
44
+ const trimmed = octets.slice(0 - editable.split(".").length);
45
+ const ip = trimmed.join(".");
46
+ setIp(ip);
47
+ } else {
48
+ const ip = pastedText.replace(immutable, "");
49
+ setIp(ip);
50
+ }
51
+ };
52
+ return /*#__PURE__*/_react.default.createElement(_PrefixedInput.default, _extends({
53
+ help: help ? help : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, " ", isIPV4 ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, " ", "The available range in this subnet is", " ", /*#__PURE__*/_react.default.createElement("code", null, immutable, ".", editable, " ")) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, " ", "The available IPV6 address range is", " ", /*#__PURE__*/_react.default.createElement("code", null, immutable, editable, " ")), "."),
54
+ immutableText: isIPV4 ? "".concat(immutable, ".") : immutable,
55
+ maxLength: maxLength,
56
+ name: name,
57
+ onPaste: handlePaste,
58
+ value: inputValue,
59
+ onChange: e => {
60
+ setIp(e.target.value);
61
+ },
62
+ placeholder: placeholder
63
+ }, props));
64
+ };
65
+ var _default = exports.default = PrefixedIpInput;
@@ -0,0 +1,13 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import PrefixedIpInput from "./PrefixedIpInput";
3
+ declare const meta: Meta<typeof PrefixedIpInput>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof PrefixedIpInput>;
6
+ export declare const IPv4Default: Story;
7
+ export declare const IPv4WithValue: Story;
8
+ export declare const IPv4WithError: Story;
9
+ export declare const IPv4Disabled: Story;
10
+ export declare const IPv6Default: Story;
11
+ export declare const IPv6WithValue: Story;
12
+ export declare const WithCustomHelp: Story;
13
+ export declare const Required: Story;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.WithCustomHelp = exports.Required = exports.IPv6WithValue = exports.IPv6Default = exports.IPv4WithValue = exports.IPv4WithError = exports.IPv4Disabled = exports.IPv4Default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _PrefixedIpInput = _interopRequireDefault(require("./PrefixedIpInput"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
11
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
12
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
13
+ const PrefixedIpInputWrapper = args => {
14
+ const [ip, setIp] = (0, _react.useState)(args.ip);
15
+ return /*#__PURE__*/_react.default.createElement(_PrefixedIpInput.default, _extends({}, args, {
16
+ ip: ip,
17
+ onIpChange: newIp => {
18
+ var _args$onIpChange;
19
+ setIp(newIp);
20
+ (_args$onIpChange = args.onIpChange) === null || _args$onIpChange === void 0 || _args$onIpChange.call(args, newIp);
21
+ }
22
+ }));
23
+ };
24
+ const meta = {
25
+ component: _PrefixedIpInput.default,
26
+ tags: ["autodocs"],
27
+ argTypes: {
28
+ ip: {
29
+ control: "text"
30
+ },
31
+ cidr: {
32
+ control: "text"
33
+ },
34
+ label: {
35
+ control: "text"
36
+ },
37
+ name: {
38
+ control: "text"
39
+ },
40
+ error: {
41
+ control: "text"
42
+ },
43
+ help: {
44
+ control: "text"
45
+ },
46
+ disabled: {
47
+ control: "boolean"
48
+ },
49
+ required: {
50
+ control: "boolean"
51
+ }
52
+ },
53
+ render: args => /*#__PURE__*/_react.default.createElement(PrefixedIpInputWrapper, args)
54
+ };
55
+ var _default = exports.default = meta;
56
+ const IPv4Default = exports.IPv4Default = {
57
+ name: "IPv4 default",
58
+ args: {
59
+ cidr: "192.168.1.0/24",
60
+ ip: "",
61
+ name: "ip-address",
62
+ label: "IP Address",
63
+ onIpChange: ip => console.log("IP changed:", ip)
64
+ }
65
+ };
66
+ const IPv4WithValue = exports.IPv4WithValue = {
67
+ name: "IPv4 with value",
68
+ args: {
69
+ cidr: "192.168.1.0/24",
70
+ ip: "192.168.1.100",
71
+ name: "ip-address",
72
+ label: "IP Address",
73
+ onIpChange: ip => console.log("IP changed:", ip)
74
+ }
75
+ };
76
+ const IPv4WithError = exports.IPv4WithError = {
77
+ name: "IPv4 with error",
78
+ args: {
79
+ cidr: "192.168.1.0/24",
80
+ ip: "192.168.1.256",
81
+ name: "ip-address",
82
+ label: "IP Address",
83
+ error: "Invalid IP address",
84
+ onIpChange: ip => console.log("IP changed:", ip)
85
+ }
86
+ };
87
+ const IPv4Disabled = exports.IPv4Disabled = {
88
+ name: "IPv4 disabled",
89
+ args: {
90
+ cidr: "192.168.1.0/24",
91
+ ip: "192.168.1.50",
92
+ name: "ip-address",
93
+ label: "IP Address",
94
+ disabled: true,
95
+ onIpChange: ip => console.log("IP changed:", ip)
96
+ }
97
+ };
98
+ const IPv6Default = exports.IPv6Default = {
99
+ name: "IPv6 default",
100
+ args: {
101
+ cidr: "2001:db8::/32",
102
+ ip: "",
103
+ name: "ipv6-address",
104
+ label: "IPv6 Address",
105
+ onIpChange: ip => console.log("IP changed:", ip)
106
+ }
107
+ };
108
+ const IPv6WithValue = exports.IPv6WithValue = {
109
+ name: "IPv6 with value",
110
+ args: {
111
+ cidr: "2001:db8::/32",
112
+ ip: "2001:db8::1",
113
+ name: "ipv6-address",
114
+ label: "IPv6 Address",
115
+ onIpChange: ip => console.log("IP changed:", ip)
116
+ }
117
+ };
118
+ const WithCustomHelp = exports.WithCustomHelp = {
119
+ args: {
120
+ cidr: "10.0.0.0/16",
121
+ ip: "",
122
+ name: "ip-address",
123
+ label: "IP Address",
124
+ help: "Enter a custom IP address for this device",
125
+ onIpChange: ip => console.log("IP changed:", ip)
126
+ }
127
+ };
128
+ const Required = exports.Required = {
129
+ args: {
130
+ cidr: "192.168.0.0/24",
131
+ ip: "",
132
+ name: "ip-address",
133
+ label: "IP Address",
134
+ required: true,
135
+ onIpChange: ip => console.log("IP changed:", ip)
136
+ }
137
+ };
@@ -0,0 +1,2 @@
1
+ export { default, type PrefixedIpInputProps } from "./PrefixedIpInput";
2
+ export { isIPv4, getIpRangeFromCidr, getFirstValidIp, convertIpToUint32, isIpInSubnet, getImmutableAndEditableOctets, getImmutableAndEditable, } from "./utils";
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "convertIpToUint32", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _utils.convertIpToUint32;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "default", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _PrefixedIpInput.default;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "getFirstValidIp", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _utils.getFirstValidIp;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "getImmutableAndEditable", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _utils.getImmutableAndEditable;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "getImmutableAndEditableOctets", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _utils.getImmutableAndEditableOctets;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "getIpRangeFromCidr", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _utils.getIpRangeFromCidr;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "isIPv4", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _utils.isIPv4;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "isIpInSubnet", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _utils.isIpInSubnet;
52
+ }
53
+ });
54
+ var _PrefixedIpInput = _interopRequireDefault(require("./PrefixedIpInput"));
55
+ var _utils = require("./utils");
56
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Checks if a given IP address is a valid IPv4 address.
3
+ * @param ip The IP address to check
4
+ * @returns True if the IP is a valid IPv4 address, false otherwise
5
+ */
6
+ export declare const isIPv4: (ip: string) => boolean;
7
+ /**
8
+ * Takes a subnet CIDR notation (IPv4) and returns the first and last IP of the subnet.
9
+ * The network and host addresses are excluded.
10
+ *
11
+ * @param cidr The CIDR notation of the subnet
12
+ * @returns The first and last valid IP addresses as two strings in a list.
13
+ */
14
+ export declare const getIpRangeFromCidr: (cidr: string) => string[];
15
+ export declare const getFirstValidIp: (ip: string) => string;
16
+ export declare const convertIpToUint32: (ip: string) => number;
17
+ /**
18
+ * Checks if an IPv4 address is valid for the given subnet.
19
+ *
20
+ * @param ip The IPv4 address to check, as a string
21
+ * @param cidr The subnet's CIDR notation e.g. 192.168.0.0/24
22
+ * @returns True if the IP is in the subnet, false otherwise
23
+ */
24
+ export declare const isIpInSubnet: (ip: string, cidr: string) => boolean;
25
+ /**
26
+ * Separates the immutable and editable octets of an IPv4 subnet range.
27
+ *
28
+ * @param startIp The start IP of the subnet
29
+ * @param endIp The end IP of the subnet
30
+ * @returns The immutable and editable octects as two strings in a list
31
+ */
32
+ export declare const getImmutableAndEditableOctets: (startIp: string, endIp: string) => string[];
33
+ /**
34
+ * Get the immutable and editable parts of an IPv4 or IPv6 subnet.
35
+ *
36
+ * @param cidr The CIDR notation of the subnet
37
+ * @returns The immutable and editable as two strings in a list
38
+ */
39
+ export declare const getImmutableAndEditable: (cidr: string) => string[];
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isIpInSubnet = exports.isIPv4 = exports.getIpRangeFromCidr = exports.getImmutableAndEditableOctets = exports.getImmutableAndEditable = exports.getFirstValidIp = exports.convertIpToUint32 = void 0;
7
+ /**
8
+ * Checks if a given IP address is a valid IPv4 address.
9
+ * @param ip The IP address to check
10
+ * @returns True if the IP is a valid IPv4 address, false otherwise
11
+ */
12
+ const isIPv4 = ip => {
13
+ const ipv4Regex = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
14
+ return ipv4Regex.test(ip);
15
+ };
16
+
17
+ /**
18
+ * Takes a subnet CIDR notation (IPv4) and returns the first and last IP of the subnet.
19
+ * The network and host addresses are excluded.
20
+ *
21
+ * @param cidr The CIDR notation of the subnet
22
+ * @returns The first and last valid IP addresses as two strings in a list.
23
+ */
24
+ exports.isIPv4 = isIPv4;
25
+ const getIpRangeFromCidr = cidr => {
26
+ // https://gist.github.com/binarymax/6114792
27
+
28
+ // Get start IP and number of valid addresses
29
+ const [startIp, mask] = cidr.split("/");
30
+ const numberOfAddresses = (1 << 32 - parseInt(mask)) - 1;
31
+
32
+ // IPv4 can be represented by an unsigned 32-bit integer, so we can use a Uint32Array to store the IP
33
+ const buffer = new ArrayBuffer(4); //4 octets
34
+ const int32 = new Uint32Array(buffer);
35
+
36
+ // Convert starting IP to Uint32 and add the number of addresses to get the end IP.
37
+ // Subtract 1 from the number of addresses to exclude the broadcast address.
38
+ int32[0] = convertIpToUint32(startIp) + numberOfAddresses - 1;
39
+
40
+ // Convert the buffer to a Uint8Array to get the octets, then convert it to an array
41
+ const arrayApplyBuffer = Array.from(new Uint8Array(buffer));
42
+
43
+ // Reverse the octets and join them with "." to get the end IP
44
+ const endIp = arrayApplyBuffer.reverse().join(".");
45
+ const firstValidIp = getFirstValidIp(startIp);
46
+ return [firstValidIp, endIp];
47
+ };
48
+ exports.getIpRangeFromCidr = getIpRangeFromCidr;
49
+ const getFirstValidIp = ip => {
50
+ const buffer = new ArrayBuffer(4); //4 octets
51
+ const int32 = new Uint32Array(buffer);
52
+
53
+ // add 1 because the first IP is the network address
54
+ int32[0] = convertIpToUint32(ip) + 1;
55
+ const arrayApplyBuffer = Array.from(new Uint8Array(buffer));
56
+ return arrayApplyBuffer.reverse().join(".");
57
+ };
58
+ exports.getFirstValidIp = getFirstValidIp;
59
+ const convertIpToUint32 = ip => {
60
+ const octets = ip.split(".").map(a => parseInt(a));
61
+ const buffer = new ArrayBuffer(4);
62
+ const int32 = new Uint32Array(buffer);
63
+ int32[0] = (octets[0] << 24) + (octets[1] << 16) + (octets[2] << 8) + octets[3];
64
+ return int32[0];
65
+ };
66
+
67
+ /**
68
+ * Checks if an IPv4 address is valid for the given subnet.
69
+ *
70
+ * @param ip The IPv4 address to check, as a string
71
+ * @param cidr The subnet's CIDR notation e.g. 192.168.0.0/24
72
+ * @returns True if the IP is in the subnet, false otherwise
73
+ */
74
+ exports.convertIpToUint32 = convertIpToUint32;
75
+ const isIpInSubnet = (ip, cidr) => {
76
+ const [startIP, endIP] = getIpRangeFromCidr(cidr);
77
+ const ipUint32 = convertIpToUint32(ip);
78
+ const startIPUint32 = convertIpToUint32(startIP);
79
+ const endIPUint32 = convertIpToUint32(endIP);
80
+ return ipUint32 >= startIPUint32 && ipUint32 <= endIPUint32;
81
+ };
82
+
83
+ /**
84
+ * Separates the immutable and editable octets of an IPv4 subnet range.
85
+ *
86
+ * @param startIp The start IP of the subnet
87
+ * @param endIp The end IP of the subnet
88
+ * @returns The immutable and editable octects as two strings in a list
89
+ */
90
+ exports.isIpInSubnet = isIpInSubnet;
91
+ const getImmutableAndEditableOctets = (startIp, endIp) => {
92
+ const startIpOctetList = startIp.split(".");
93
+ const endIpOctetList = endIp.split(".");
94
+ const immutable = [];
95
+ const editable = [];
96
+ startIpOctetList.forEach((octet, index) => {
97
+ if (octet === endIpOctetList[index]) {
98
+ immutable.push(octet);
99
+ } else {
100
+ editable.push("[".concat(octet, "-").concat(endIpOctetList[index], "]"));
101
+ }
102
+ });
103
+ return [immutable.join("."), editable.join(".")];
104
+ };
105
+
106
+ /**
107
+ * Get the immutable and editable parts of an IPv4 or IPv6 subnet.
108
+ *
109
+ * @param cidr The CIDR notation of the subnet
110
+ * @returns The immutable and editable as two strings in a list
111
+ */
112
+ exports.getImmutableAndEditableOctets = getImmutableAndEditableOctets;
113
+ const getImmutableAndEditable = cidr => {
114
+ const isIPV4 = isIPv4(cidr.split("/")[0]);
115
+ if (isIPV4) {
116
+ const [startIp, endIp] = getIpRangeFromCidr(cidr);
117
+ return getImmutableAndEditableOctets(startIp, endIp);
118
+ }
119
+ const [networkAddress] = cidr.split("/");
120
+ const immutableIPV6 = networkAddress.substring(0, networkAddress.lastIndexOf(":"));
121
+ const ipv6PlaceholderColons = 7 - (immutableIPV6.match(/:/g) || []).length; // 7 is the maximum number of colons in an IPv6 address
122
+ const editableIPV6 = "".concat("0000:".repeat(ipv6PlaceholderColons), "0000");
123
+ return [immutableIPV6, editableIPV6];
124
+ };
125
+ exports.getImmutableAndEditable = getImmutableAndEditable;