@canonical/react-components 3.9.1 → 3.11.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/components/ConfirmationButton/ConfirmationButton.js +5 -5
- package/dist/components/ConfirmationModal/ConfirmationModal.d.ts +5 -1
- package/dist/components/ConfirmationModal/ConfirmationModal.js +9 -3
- package/dist/components/PrefixedInput/PrefixedInput.d.ts +13 -0
- package/dist/components/PrefixedInput/PrefixedInput.js +64 -0
- package/dist/components/PrefixedInput/PrefixedInput.scss +22 -0
- package/dist/components/PrefixedInput/PrefixedInput.stories.d.ts +11 -0
- package/dist/components/PrefixedInput/PrefixedInput.stories.js +58 -0
- package/dist/components/PrefixedInput/PrefixedInput.test.d.ts +1 -0
- package/dist/components/PrefixedInput/index.d.ts +1 -0
- package/dist/components/PrefixedInput/index.js +13 -0
- package/dist/components/PrefixedIpInput/PrefixedIpInput.d.ts +27 -0
- package/dist/components/PrefixedIpInput/PrefixedIpInput.js +65 -0
- package/dist/components/PrefixedIpInput/PrefixedIpInput.stories.d.ts +13 -0
- package/dist/components/PrefixedIpInput/PrefixedIpInput.stories.js +137 -0
- package/dist/components/PrefixedIpInput/PrefixedIpInput.test.d.ts +1 -0
- package/dist/components/PrefixedIpInput/index.d.ts +2 -0
- package/dist/components/PrefixedIpInput/index.js +56 -0
- package/dist/components/PrefixedIpInput/utils.d.ts +39 -0
- package/dist/components/PrefixedIpInput/utils.js +125 -0
- package/dist/components/PrefixedIpInput/utils.test.d.ts +1 -0
- package/dist/esm/components/ConfirmationButton/ConfirmationButton.js +5 -5
- package/dist/esm/components/ConfirmationModal/ConfirmationModal.d.ts +5 -1
- package/dist/esm/components/ConfirmationModal/ConfirmationModal.js +9 -3
- package/dist/esm/components/PrefixedInput/PrefixedInput.d.ts +13 -0
- package/dist/esm/components/PrefixedInput/PrefixedInput.js +57 -0
- package/dist/esm/components/PrefixedInput/PrefixedInput.scss +22 -0
- package/dist/esm/components/PrefixedInput/PrefixedInput.stories.d.ts +11 -0
- package/dist/esm/components/PrefixedInput/PrefixedInput.stories.js +51 -0
- package/dist/esm/components/PrefixedInput/PrefixedInput.test.d.ts +1 -0
- package/dist/esm/components/PrefixedInput/index.d.ts +1 -0
- package/dist/esm/components/PrefixedInput/index.js +1 -0
- package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.d.ts +27 -0
- package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.js +58 -0
- package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.stories.d.ts +13 -0
- package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.stories.js +128 -0
- package/dist/esm/components/PrefixedIpInput/PrefixedIpInput.test.d.ts +1 -0
- package/dist/esm/components/PrefixedIpInput/index.d.ts +2 -0
- package/dist/esm/components/PrefixedIpInput/index.js +2 -0
- package/dist/esm/components/PrefixedIpInput/utils.d.ts +39 -0
- package/dist/esm/components/PrefixedIpInput/utils.js +112 -0
- package/dist/esm/components/PrefixedIpInput/utils.test.d.ts +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +65 -0
- package/package.json +1 -1
|
@@ -37,8 +37,7 @@ const ConfirmationButton = _ref => {
|
|
|
37
37
|
const {
|
|
38
38
|
openPortal,
|
|
39
39
|
closePortal,
|
|
40
|
-
isOpen
|
|
41
|
-
Portal
|
|
40
|
+
isOpen
|
|
42
41
|
} = (0, _external.usePortal)();
|
|
43
42
|
const handleCancelModal = () => {
|
|
44
43
|
closePortal();
|
|
@@ -64,13 +63,14 @@ const ConfirmationButton = _ref => {
|
|
|
64
63
|
}
|
|
65
64
|
shiftClickEnabled ? handleShiftClick(e) : openPortal(e);
|
|
66
65
|
};
|
|
67
|
-
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isOpen && /*#__PURE__*/_react.default.createElement(
|
|
66
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isOpen && /*#__PURE__*/_react.default.createElement(_ConfirmationModal.default, _extends({}, confirmationModalProps, {
|
|
68
67
|
close: handleCancelModal,
|
|
69
68
|
confirmButtonLabel: confirmationModalProps.confirmButtonLabel,
|
|
70
|
-
onConfirm: handleConfirmModal
|
|
69
|
+
onConfirm: handleConfirmModal,
|
|
70
|
+
renderInPortal: true
|
|
71
71
|
}), confirmationModalProps.children, showShiftClickHint && /*#__PURE__*/_react.default.createElement("p", {
|
|
72
72
|
className: "p-text--small u-text--muted u-hide--small"
|
|
73
|
-
}, "Next time, you can skip this confirmation by holding", " ", /*#__PURE__*/_react.default.createElement("code", null, "SHIFT"), " and clicking the action."))
|
|
73
|
+
}, "Next time, you can skip this confirmation by holding", " ", /*#__PURE__*/_react.default.createElement("code", null, "SHIFT"), " and clicking the action.")), /*#__PURE__*/_react.default.createElement(_ActionButton.default, _extends({}, actionButtonProps, {
|
|
74
74
|
onClick: handleClick,
|
|
75
75
|
title: generateTitle(onHoverText !== null && onHoverText !== void 0 ? onHoverText : confirmationModalProps.confirmButtonLabel)
|
|
76
76
|
}), actionButtonProps.children));
|
|
@@ -45,9 +45,13 @@ export type Props = PropsWithSpread<{
|
|
|
45
45
|
* Whether the confirm button should be disabled.
|
|
46
46
|
*/
|
|
47
47
|
confirmButtonDisabled?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether to render the modal inside a Portal component.
|
|
50
|
+
*/
|
|
51
|
+
renderInPortal?: boolean;
|
|
48
52
|
}, Omit<ModalProps, "buttonRow">>;
|
|
49
53
|
/**
|
|
50
54
|
* `ConfirmationModal` is a specialised version of the [Modal](?path=/docs/modal--default-story) component to prompt a confirmation from the user before executing an action.
|
|
51
55
|
*/
|
|
52
|
-
export declare const ConfirmationModal: ({ cancelButtonLabel, cancelButtonProps, children, confirmButtonAppearance, confirmButtonLabel, confirmExtra, onConfirm, confirmButtonLoading, confirmButtonDisabled, confirmButtonProps, ...props }: Props) => React.JSX.Element;
|
|
56
|
+
export declare const ConfirmationModal: ({ cancelButtonLabel, cancelButtonProps, children, confirmButtonAppearance, confirmButtonLabel, confirmExtra, onConfirm, confirmButtonLoading, confirmButtonDisabled, confirmButtonProps, renderInPortal, ...props }: Props) => React.JSX.Element;
|
|
53
57
|
export default ConfirmationModal;
|
|
@@ -8,7 +8,8 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
8
8
|
var _Button = _interopRequireDefault(require("../Button"));
|
|
9
9
|
var _Modal = _interopRequireDefault(require("../Modal"));
|
|
10
10
|
var _ActionButton = _interopRequireDefault(require("../ActionButton"));
|
|
11
|
-
|
|
11
|
+
var _external = require("../../external");
|
|
12
|
+
const _excluded = ["cancelButtonLabel", "cancelButtonProps", "children", "confirmButtonAppearance", "confirmButtonLabel", "confirmExtra", "onConfirm", "confirmButtonLoading", "confirmButtonDisabled", "confirmButtonProps", "renderInPortal"];
|
|
12
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
14
|
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); }
|
|
14
15
|
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; }
|
|
@@ -28,9 +29,13 @@ const ConfirmationModal = _ref => {
|
|
|
28
29
|
onConfirm,
|
|
29
30
|
confirmButtonLoading,
|
|
30
31
|
confirmButtonDisabled,
|
|
31
|
-
confirmButtonProps
|
|
32
|
+
confirmButtonProps,
|
|
33
|
+
renderInPortal = false
|
|
32
34
|
} = _ref,
|
|
33
35
|
props = _objectWithoutProperties(_ref, _excluded);
|
|
36
|
+
const {
|
|
37
|
+
Portal
|
|
38
|
+
} = (0, _external.usePortal)();
|
|
34
39
|
const handleClick = action => event => {
|
|
35
40
|
if (!props.shouldPropagateClickEvent) {
|
|
36
41
|
event.stopPropagation();
|
|
@@ -39,7 +44,7 @@ const ConfirmationModal = _ref => {
|
|
|
39
44
|
action(event);
|
|
40
45
|
}
|
|
41
46
|
};
|
|
42
|
-
|
|
47
|
+
const ModalElement = /*#__PURE__*/_react.default.createElement(_Modal.default, _extends({
|
|
43
48
|
buttonRow: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, confirmExtra, /*#__PURE__*/_react.default.createElement(_Button.default, _extends({}, cancelButtonProps, {
|
|
44
49
|
type: (_cancelButtonProps$ty = cancelButtonProps === null || cancelButtonProps === void 0 ? void 0 : cancelButtonProps.type) !== null && _cancelButtonProps$ty !== void 0 ? _cancelButtonProps$ty : "button",
|
|
45
50
|
className: "u-no-margin--bottom",
|
|
@@ -52,6 +57,7 @@ const ConfirmationModal = _ref => {
|
|
|
52
57
|
disabled: confirmButtonDisabled
|
|
53
58
|
}), confirmButtonLabel))
|
|
54
59
|
}, props), children);
|
|
60
|
+
return renderInPortal ? /*#__PURE__*/_react.default.createElement(Portal, null, ModalElement) : ModalElement;
|
|
55
61
|
};
|
|
56
62
|
exports.ConfirmationModal = ConfirmationModal;
|
|
57
63
|
var _default = exports.default = ConfirmationModal;
|
|
@@ -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 {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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[];
|