🚨 Active Supply Chain Attack:node-ipc Package Compromised.Learn More
Socket
Book a DemoSign in
Socket

@canonical/react-components

Package Overview
Dependencies
Maintainers
26
Versions
200
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@canonical/react-components - npm Package Compare versions

Comparing version
4.4.1
to
4.5.0
+7
-0
dist/components/MultiSelect/MultiSelect.d.ts

@@ -27,2 +27,4 @@ import type { ReactNode } from "react";

dropdownFooter?: ReactNode;
emptyState?: ReactNode;
emptyMessage?: string;
showDropdownFooter?: boolean;

@@ -34,2 +36,5 @@ variant?: "condensed" | "search";

id?: string;
onSearchChange?: (value: string) => void;
onOpen?: () => void;
onClose?: () => void;
};

@@ -48,2 +53,4 @@ type GroupFn = (items: Parameters<typeof getGroupedItems>[0]) => ReturnType<typeof getGroupedItems>;

footer?: ReactNode;
emptyState?: ReactNode;
emptyMessage?: string;
groupFn?: GroupFn;

@@ -50,0 +57,0 @@ sortFn?: SortFn;

+44
-9

@@ -13,3 +13,3 @@ "use strict";

var _FadeInDown = require("./FadeInDown");
const _excluded = ["items", "selectedItems", "disabledItems", "header", "updateItems", "onSelectItem", "onDeselectItem", "isOpen", "footer", "sortFn", "groupFn", "hasSelectedItemsFirst"];
const _excluded = ["items", "selectedItems", "disabledItems", "header", "updateItems", "onSelectItem", "onDeselectItem", "isOpen", "footer", "emptyState", "emptyMessage", "sortFn", "groupFn", "hasSelectedItemsFirst"];
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }

@@ -61,2 +61,4 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }

footer,
emptyState,
emptyMessage,
sortFn = sortAlphabetically,

@@ -77,2 +79,3 @@ groupFn = getGroupedItems,

const hasGroup = (0, _react.useMemo)(() => items.some(item => item.group), [items]);
const hasItems = items.length > 0;
const groupedItems = (0, _react.useMemo)(() => hasGroup ? groupFn(items) : [{

@@ -106,3 +109,3 @@ group: "Ungrouped",

role: "listbox"
}, props), header ? header : null, groupedItems.map(_ref3 => {
}, props), header ? header : null, hasItems ? groupedItems.map(_ref3 => {
let {

@@ -131,3 +134,5 @@ group,

})))));
}), footer ? /*#__PURE__*/_react.default.createElement("div", {
}) : emptyState !== null && emptyState !== void 0 ? emptyState : emptyMessage ? /*#__PURE__*/_react.default.createElement("p", {
className: "multi-select__empty-state"
}, emptyMessage) : null, footer ? /*#__PURE__*/_react.default.createElement("div", {
className: "multi-select__footer"

@@ -166,2 +171,4 @@ }, footer) : null));

footer: _propTypes.default.node,
emptyState: _propTypes.default.node,
emptyMessage: _propTypes.default.string,
groupFn: _propTypes.default.func,

@@ -186,2 +193,4 @@ sortFn: _propTypes.default.any,

dropdownFooter,
emptyState,
emptyMessage,
showDropdownFooter = true,

@@ -193,2 +202,5 @@ variant = "search",

id,
onSearchChange,
onOpen,
onClose,
help,

@@ -200,5 +212,23 @@ helpClassName

const [filter, setFilter] = (0, _react.useState)("");
const handleSetDropdownOpen = newState => {
if (newState && !isDropdownOpen) {
onOpen === null || onOpen === void 0 || onOpen();
} else if (!newState && isDropdownOpen) {
onClose === null || onClose === void 0 || onClose();
}
setIsDropdownOpen(newState);
};
const [internalSelectedItems, setInternalSelectedItems] = (0, _react.useState)([]);
const selectedItems = externalSelectedItems || internalSelectedItems;
const helpId = (0, _react.useId)();
const updateFilter = value => {
setFilter(value);
onSearchChange === null || onSearchChange === void 0 || onSearchChange(value);
};
const resetSearch = () => {
if (!filter.length) {
return;
}
updateFilter("");
};
const updateItems = newItems => {

@@ -234,3 +264,3 @@ const uniqueItems = Array.from(new Set(newItems));

if (!isOpen) {
setFilter("");
resetSearch();
}

@@ -240,3 +270,3 @@ // Handle syncing the state when toggling the menu from within the

if (isOpen !== isDropdownOpen) {
setIsDropdownOpen(isOpen);
handleSetDropdownOpen(isOpen);
}

@@ -256,7 +286,8 @@ },

onChange: value => {
setFilter(value);
updateFilter(value);
// reopen if dropdown has been closed via ESC
setIsDropdownOpen(true);
handleSetDropdownOpen(true);
},
onFocus: () => setIsDropdownOpen(true),
onClear: resetSearch,
onFocus: () => handleSetDropdownOpen(true),
placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : "Search",

@@ -275,3 +306,3 @@ required: required,

onClick: () => {
setIsDropdownOpen(!isDropdownOpen);
handleSetDropdownOpen(!isDropdownOpen);
},

@@ -311,2 +342,4 @@ onMouseDown: event => {

footer: footer,
emptyState: emptyState,
emptyMessage: emptyMessage,
sortFn: isSortedAlphabetically ? sortAlphabetically : () => 0,

@@ -350,2 +383,4 @@ hasSelectedItemsFirst: hasSelectedItemsFirst

dropdownFooter: _propTypes.default.node,
emptyState: _propTypes.default.node,
emptyMessage: _propTypes.default.string,
showDropdownFooter: _propTypes.default.bool,

@@ -352,0 +387,0 @@ variant: _propTypes.default.oneOf(["condensed", "search"]),

@@ -96,2 +96,8 @@ @use "sass:map";

.multi-select__empty-state {
color: $colors--theme--text-muted;
margin: 0;
padding: $spv--small $sph--large;
}
.multi-select__dropdown-button {

@@ -98,0 +104,0 @@ border: 0;

@@ -12,1 +12,4 @@ import { Meta, StoryObj } from "@storybook/react";

export declare const HelpText: Story;
export declare const FormikCallbacksAndEmptyState: Story;
export declare const EmptyMessage: Story;
export declare const EmptyStateNode: Story;

@@ -6,4 +6,6 @@ "use strict";

});
exports.default = exports.WithoutSorting = exports.WithDisabledItems = exports.SearchExample = exports.HelpText = exports.Disabled = exports.CondensedExample = void 0;
exports.default = exports.WithoutSorting = exports.WithDisabledItems = exports.SearchExample = exports.HelpText = exports.FormikCallbacksAndEmptyState = exports.EmptyStateNode = exports.EmptyMessage = exports.Disabled = exports.CondensedExample = void 0;
var _react = _interopRequireWildcard(require("react"));
var _formik = require("formik");
var _index = require("../../index");
var _MultiSelect = require("./MultiSelect");

@@ -31,2 +33,19 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }

var _default = exports.default = meta;
const groupedItems = [{
label: "Almond",
value: "almond",
group: "Nuts"
}, {
label: "Cashew",
value: "cashew",
group: "Nuts"
}, {
label: "Mango",
value: "mango",
group: "Fruit"
}, {
label: "Peach",
value: "peach",
group: "Fruit"
}];
const CondensedExample = exports.CondensedExample = {

@@ -124,2 +143,73 @@ args: {

})
};
const FormikCallbacksAndEmptyStateTemplate = () => {
const [selectedItems, setSelectedItems] = (0, _react.useState)([]);
const [events, setEvents] = (0, _react.useState)([]);
const addEvent = eventName => {
setEvents(previousEvents => [eventName, ...previousEvents].slice(0, 6));
};
return /*#__PURE__*/_react.default.createElement("div", {
style: {
maxWidth: "28rem"
}
}, /*#__PURE__*/_react.default.createElement(_formik.Formik, {
initialValues: {
ingredients: ""
},
onSubmit: () => {}
}, /*#__PURE__*/_react.default.createElement(_index.FormikField, {
name: "ingredients",
component: _MultiSelect.MultiSelect,
label: "Ingredients",
variant: "search",
placeholder: "Search ingredients",
items: groupedItems,
selectedItems: selectedItems,
onItemsUpdate: setSelectedItems,
onSearchChange: value => {
addEvent("onSearchChange(\"".concat(value, "\")"));
},
onOpen: () => addEvent("onOpen()"),
onClose: () => addEvent("onClose()"),
emptyMessage: "No ingredients found"
})), /*#__PURE__*/_react.default.createElement("p", {
style: {
marginBottom: "0.5rem"
}
}, "Callback log:"), /*#__PURE__*/_react.default.createElement("ul", {
style: {
margin: 0,
paddingLeft: "1.25rem"
}
}, events.map((event, index) => /*#__PURE__*/_react.default.createElement("li", {
key: "".concat(event, "-").concat(index)
}, event))));
};
const FormikCallbacksAndEmptyState = exports.FormikCallbacksAndEmptyState = {
render: FormikCallbacksAndEmptyStateTemplate
};
const EmptyMessage = exports.EmptyMessage = {
args: {
variant: "search",
items: groupedItems,
emptyMessage: "No matching ingredients.",
placeholder: "Try typing kiwi"
}
};
const EmptyStateNode = exports.EmptyStateNode = {
args: {
variant: "search",
items: groupedItems,
placeholder: "Try typing kiwi",
emptyState: /*#__PURE__*/_react.default.createElement("div", {
className: "u-align--center",
style: {
padding: "0.75rem 1rem"
}
}, /*#__PURE__*/_react.default.createElement("strong", null, "No ingredient matches."), /*#__PURE__*/_react.default.createElement("p", {
style: {
margin: "0.25rem 0 0"
}
}, "Use a broader term."))
}
};

@@ -27,2 +27,4 @@ import type { ReactNode } from "react";

dropdownFooter?: ReactNode;
emptyState?: ReactNode;
emptyMessage?: string;
showDropdownFooter?: boolean;

@@ -34,2 +36,5 @@ variant?: "condensed" | "search";

id?: string;
onSearchChange?: (value: string) => void;
onOpen?: () => void;
onClose?: () => void;
};

@@ -48,2 +53,4 @@ type GroupFn = (items: Parameters<typeof getGroupedItems>[0]) => ReturnType<typeof getGroupedItems>;

footer?: ReactNode;
emptyState?: ReactNode;
emptyMessage?: string;
groupFn?: GroupFn;

@@ -50,0 +57,0 @@ sortFn?: SortFn;

import _pt from "prop-types";
var _excluded = ["items", "selectedItems", "disabledItems", "header", "updateItems", "onSelectItem", "onDeselectItem", "isOpen", "footer", "sortFn", "groupFn", "hasSelectedItemsFirst"];
var _excluded = ["items", "selectedItems", "disabledItems", "header", "updateItems", "onSelectItem", "onDeselectItem", "isOpen", "footer", "emptyState", "emptyMessage", "sortFn", "groupFn", "hasSelectedItemsFirst"];
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }

@@ -52,2 +52,4 @@ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }

footer,
emptyState,
emptyMessage,
sortFn = sortAlphabetically,

@@ -68,2 +70,3 @@ groupFn = getGroupedItems,

var hasGroup = useMemo(() => items.some(item => item.group), [items]);
var hasItems = items.length > 0;
var groupedItems = useMemo(() => hasGroup ? groupFn(items) : [{

@@ -97,3 +100,3 @@ group: "Ungrouped",

role: "listbox"
}, props), header ? header : null, groupedItems.map(_ref3 => {
}, props), header ? header : null, hasItems ? groupedItems.map(_ref3 => {
var {

@@ -122,3 +125,5 @@ group,

})))));
}), footer ? /*#__PURE__*/React.createElement("div", {
}) : emptyState !== null && emptyState !== void 0 ? emptyState : emptyMessage ? /*#__PURE__*/React.createElement("p", {
className: "multi-select__empty-state"
}, emptyMessage) : null, footer ? /*#__PURE__*/React.createElement("div", {
className: "multi-select__footer"

@@ -156,2 +161,4 @@ }, footer) : null));

footer: _pt.node,
emptyState: _pt.node,
emptyMessage: _pt.string,
groupFn: _pt.func,

@@ -176,2 +183,4 @@ sortFn: _pt.any,

dropdownFooter,
emptyState,
emptyMessage,
showDropdownFooter = true,

@@ -183,2 +192,5 @@ variant = "search",

id,
onSearchChange,
onOpen,
onClose,
help,

@@ -190,5 +202,23 @@ helpClassName

var [filter, setFilter] = useState("");
var handleSetDropdownOpen = newState => {
if (newState && !isDropdownOpen) {
onOpen === null || onOpen === void 0 || onOpen();
} else if (!newState && isDropdownOpen) {
onClose === null || onClose === void 0 || onClose();
}
setIsDropdownOpen(newState);
};
var [internalSelectedItems, setInternalSelectedItems] = useState([]);
var selectedItems = externalSelectedItems || internalSelectedItems;
var helpId = useId();
var updateFilter = value => {
setFilter(value);
onSearchChange === null || onSearchChange === void 0 || onSearchChange(value);
};
var resetSearch = () => {
if (!filter.length) {
return;
}
updateFilter("");
};
var updateItems = newItems => {

@@ -224,3 +254,3 @@ var uniqueItems = Array.from(new Set(newItems));

if (!isOpen) {
setFilter("");
resetSearch();
}

@@ -230,3 +260,3 @@ // Handle syncing the state when toggling the menu from within the

if (isOpen !== isDropdownOpen) {
setIsDropdownOpen(isOpen);
handleSetDropdownOpen(isOpen);
}

@@ -246,7 +276,8 @@ },

onChange: value => {
setFilter(value);
updateFilter(value);
// reopen if dropdown has been closed via ESC
setIsDropdownOpen(true);
handleSetDropdownOpen(true);
},
onFocus: () => setIsDropdownOpen(true),
onClear: resetSearch,
onFocus: () => handleSetDropdownOpen(true),
placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : "Search",

@@ -265,3 +296,3 @@ required: required,

onClick: () => {
setIsDropdownOpen(!isDropdownOpen);
handleSetDropdownOpen(!isDropdownOpen);
},

@@ -301,2 +332,4 @@ onMouseDown: event => {

footer: footer,
emptyState: emptyState,
emptyMessage: emptyMessage,
sortFn: isSortedAlphabetically ? sortAlphabetically : () => 0,

@@ -339,2 +372,4 @@ hasSelectedItemsFirst: hasSelectedItemsFirst

dropdownFooter: _pt.node,
emptyState: _pt.node,
emptyMessage: _pt.string,
showDropdownFooter: _pt.bool,

@@ -341,0 +376,0 @@ variant: _pt.oneOf(["condensed", "search"]),

@@ -96,2 +96,8 @@ @use "sass:map";

.multi-select__empty-state {
color: $colors--theme--text-muted;
margin: 0;
padding: $spv--small $sph--large;
}
.multi-select__dropdown-button {

@@ -98,0 +104,0 @@ border: 0;

@@ -12,1 +12,4 @@ import { Meta, StoryObj } from "@storybook/react";

export declare const HelpText: Story;
export declare const FormikCallbacksAndEmptyState: Story;
export declare const EmptyMessage: Story;
export declare const EmptyStateNode: Story;

@@ -9,2 +9,4 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }

import { useState } from "react";
import { Formik } from "formik";
import { FormikField } from "../../index";
import { MultiSelect } from "./MultiSelect";

@@ -25,2 +27,19 @@ var Template = props => {

export default meta;
var groupedItems = [{
label: "Almond",
value: "almond",
group: "Nuts"
}, {
label: "Cashew",
value: "cashew",
group: "Nuts"
}, {
label: "Mango",
value: "mango",
group: "Fruit"
}, {
label: "Peach",
value: "peach",
group: "Fruit"
}];
export var CondensedExample = {

@@ -118,2 +137,73 @@ args: {

})
};
var FormikCallbacksAndEmptyStateTemplate = () => {
var [selectedItems, setSelectedItems] = useState([]);
var [events, setEvents] = useState([]);
var addEvent = eventName => {
setEvents(previousEvents => [eventName, ...previousEvents].slice(0, 6));
};
return /*#__PURE__*/React.createElement("div", {
style: {
maxWidth: "28rem"
}
}, /*#__PURE__*/React.createElement(Formik, {
initialValues: {
ingredients: ""
},
onSubmit: () => {}
}, /*#__PURE__*/React.createElement(FormikField, {
name: "ingredients",
component: MultiSelect,
label: "Ingredients",
variant: "search",
placeholder: "Search ingredients",
items: groupedItems,
selectedItems: selectedItems,
onItemsUpdate: setSelectedItems,
onSearchChange: value => {
addEvent("onSearchChange(\"".concat(value, "\")"));
},
onOpen: () => addEvent("onOpen()"),
onClose: () => addEvent("onClose()"),
emptyMessage: "No ingredients found"
})), /*#__PURE__*/React.createElement("p", {
style: {
marginBottom: "0.5rem"
}
}, "Callback log:"), /*#__PURE__*/React.createElement("ul", {
style: {
margin: 0,
paddingLeft: "1.25rem"
}
}, events.map((event, index) => /*#__PURE__*/React.createElement("li", {
key: "".concat(event, "-").concat(index)
}, event))));
};
export var FormikCallbacksAndEmptyState = {
render: FormikCallbacksAndEmptyStateTemplate
};
export var EmptyMessage = {
args: {
variant: "search",
items: groupedItems,
emptyMessage: "No matching ingredients.",
placeholder: "Try typing kiwi"
}
};
export var EmptyStateNode = {
args: {
variant: "search",
items: groupedItems,
placeholder: "Try typing kiwi",
emptyState: /*#__PURE__*/React.createElement("div", {
className: "u-align--center",
style: {
padding: "0.75rem 1rem"
}
}, /*#__PURE__*/React.createElement("strong", null, "No ingredient matches."), /*#__PURE__*/React.createElement("p", {
style: {
margin: "0.25rem 0 0"
}
}, "Use a broader term."))
}
};
+1
-1
{
"name": "@canonical/react-components",
"version": "4.4.1",
"version": "4.5.0",
"main": "dist/index.js",

@@ -5,0 +5,0 @@ "module": "dist/index.js",