/**
 * Copyright IBM Corp. 2020, 2026
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { __toESM } from "../../_virtual/_rolldown/runtime.js";
import { require_classnames } from "../../node_modules/classnames/index.js";
import { pkg } from "../../settings.js";
import { getDevtoolsProps } from "../../global/js/utils/devtools.js";
import { useResizeObserver } from "../../global/js/hooks/useResizeObserver.js";
import { TagSetModal } from "./TagSetModal.js";
import { TagSetOverflow } from "./TagSetOverflow.js";
import React, { useCallback, useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { DismissibleTag, Tag } from "@carbon/react";
//#region src/components/TagSet/TagSet.tsx
var import_classnames = /* @__PURE__ */ __toESM(require_classnames());
const componentName = "TagSet";
const blockClass = `${pkg.prefix}--tag-set`;
const allTagsModalSearchThreshold = 10;
const defaults = {
	align: "start",
	measurementOffset: 0,
	overflowAlign: "bottom",
	overflowType: "default",
	onOverflowTagChange: () => {}
};
const TagSet = React.forwardRef(({ align = "start", allTagsModalTarget, className, maxVisible, multiline, overflowAutoAlign, overflowAlign = "bottom", overflowClassName, overflowType = "default", allTagsModalAriaLabel, allTagsModalTitle = "All tags", allTagsModalSearchLabel = "Search all tags", allTagsModalSearchPlaceholderText = "Search all tags", showAllTagsLabel = "View all tags", onOverflowClick, tags, containingElementRef, measurementOffset = defaults.measurementOffset, onOverflowTagChange = defaults.onOverflowTagChange, ...rest }, ref) => {
	const [displayCount, setDisplayCount] = useState(3);
	const [displayedTags, setDisplayedTags] = useState([]);
	const [hiddenSizingTags, setHiddenSizingTags] = useState([]);
	const [showAllModalOpen, setShowAllModalOpen] = useState(false);
	const localTagSetRef = useRef(null);
	const tagSetRef = ref || localTagSetRef;
	const sizingContainerRef = useRef(null);
	const displayedArea = useRef(null);
	const [sizingTags, setSizingTags] = useState([]);
	const overflowTag = useRef(null);
	const [maxVisibleCount, setMaxVisibleCount] = useState(0);
	const [popoverOpen, setPopoverOpen] = useState(false);
	const handleShowAllClick = () => {
		setShowAllModalOpen(true);
	};
	useEffect(() => {
		setMaxVisibleCount(maxVisible || tags?.length || 0);
	}, [maxVisible, tags]);
	useEffect(() => {
		const newSizingTags = [];
		setHiddenSizingTags(tags && tags.length > 0 ? tags.map(({ label, id, filter, onClose, ...other }, index) => {
			return /* @__PURE__ */ React.createElement("div", {
				key: index,
				className: `${blockClass}__sizing-tag`,
				ref: (el) => {
					if (el != null) newSizingTags[index] = el;
				}
			}, typeof onClose === "function" || filter ? /* @__PURE__ */ React.createElement(DismissibleTag, {
				...other,
				"data-original-id": id,
				text: label
			}) : /* @__PURE__ */ React.createElement(Tag, {
				...other,
				"data-original-id": id
			}, label));
		}) : []);
		setSizingTags(newSizingTags);
	}, [tags]);
	const handleTagOnClose = useCallback((onClose, index) => {
		onClose?.();
		if (index <= displayCount - 1) setPopoverOpen(false);
	}, [displayCount]);
	useEffect(() => {
		let size = "md";
		let newDisplayedTags = tags && tags.length > 0 ? tags.map(({ label, onClose, filter, ...other }, index) => {
			if (index == tags.length - 1 && other.size) size = other.size;
			if (typeof onClose === "function" || filter) return /* @__PURE__ */ React.createElement(DismissibleTag, {
				...other,
				key: `displayed-tag-${index}`,
				onClose: () => handleTagOnClose(onClose, index),
				text: label
			});
			return /* @__PURE__ */ React.createElement(Tag, {
				...other,
				key: `displayed-tag-${index}`
			}, label);
		}) : [];
		const newOverflowTags = newDisplayedTags.splice(displayCount, newDisplayedTags.length - displayCount);
		newDisplayedTags = newDisplayedTags.map((tag, index) => /* @__PURE__ */ React.createElement("div", {
			key: index,
			className: `${blockClass}__displayed-tag`
		}, tag));
		newDisplayedTags.push(/* @__PURE__ */ React.createElement(TagSetOverflow, {
			allTagsModalSearchThreshold,
			overflowAutoAlign,
			className: overflowClassName,
			onShowAllClick: handleShowAllClick,
			overflowTags: newOverflowTags,
			overflowAlign,
			overflowType,
			showAllTagsLabel,
			size,
			key: "displayed-tag-overflow",
			ref: overflowTag,
			popoverOpen,
			onOverflowClick,
			setPopoverOpen
		}));
		onOverflowTagChange?.(newOverflowTags);
		setDisplayedTags(newDisplayedTags);
	}, [
		displayCount,
		overflowAlign,
		overflowClassName,
		overflowType,
		showAllTagsLabel,
		onOverflowClick,
		tags,
		onOverflowTagChange,
		popoverOpen,
		handleTagOnClose,
		overflowAutoAlign
	]);
	const checkFullyVisibleTags = useCallback(() => {
		if (multiline) return setDisplayCount(maxVisibleCount);
		let willFit = 0;
		if (sizingTags.length > 0) {
			const optionalContainingElement = typeof containingElementRef !== "function" && containingElementRef?.current;
			const measurementOffsetValue = typeof measurementOffset === "number" ? measurementOffset : 0;
			let spaceAvailable = optionalContainingElement ? optionalContainingElement.offsetWidth - measurementOffsetValue : tagSetRef?.["current"].offsetWidth;
			for (const i in sizingTags) {
				const tagWidth = sizingTags[i]?.offsetWidth || 0;
				if (spaceAvailable >= tagWidth) {
					spaceAvailable -= tagWidth;
					willFit += 1;
				} else break;
			}
			if (willFit < sizingTags.length && overflowTag.current) while (willFit > 0 && spaceAvailable < overflowTag.current.offsetWidth) {
				willFit -= 1;
				spaceAvailable += sizingTags[willFit].offsetWidth;
			}
		}
		if (willFit < 1) setDisplayCount(0);
		else setDisplayCount(maxVisibleCount ? Math.min(willFit, maxVisibleCount) : willFit);
	}, [
		maxVisibleCount,
		multiline,
		sizingTags,
		tagSetRef,
		measurementOffset,
		containingElementRef
	]);
	useEffect(() => {
		checkFullyVisibleTags();
	}, [
		checkFullyVisibleTags,
		maxVisibleCount,
		multiline,
		sizingTags
	]);
	/* istanbul ignore next */
	const handleResize = () => {
		/* istanbul ignore next */ checkFullyVisibleTags();
	};
	/* istanbul ignore next */
	const handleSizerTagsResize = () => {
		/* istanbul ignore next */ checkFullyVisibleTags();
	};
	const handleModalClose = () => {
		setShowAllModalOpen(false);
		const launcherButton = overflowTag.current?.querySelector("button");
		setTimeout(() => launcherButton?.focus(), 0);
	};
	useResizeObserver(sizingContainerRef, handleSizerTagsResize);
	useResizeObserver(containingElementRef ? containingElementRef : tagSetRef, handleResize);
	return /* @__PURE__ */ React.createElement("div", {
		...rest,
		className: (0, import_classnames.default)([blockClass, className]),
		ref: tagSetRef,
		...getDevtoolsProps(componentName)
	}, /* @__PURE__ */ React.createElement("div", { className: (0, import_classnames.default)([`${blockClass}__space`, `${blockClass}__space--align-${align}`]) }, /* @__PURE__ */ React.createElement("div", {
		className: `${blockClass}__tag-container ${blockClass}__tag-container--hidden`,
		"aria-hidden": true,
		ref: sizingContainerRef
	}, hiddenSizingTags), /* @__PURE__ */ React.createElement("div", {
		className: (0, import_classnames.default)([`${blockClass}__tag-container`, multiline && `${blockClass}__tag-container--multiline`]),
		ref: displayedArea
	}, displayedTags)), !onOverflowClick && /* @__PURE__ */ React.createElement(TagSetModal, {
		allTags: tags,
		open: showAllModalOpen,
		title: allTagsModalTitle,
		onClose: handleModalClose,
		modalAriaLabel: allTagsModalAriaLabel,
		searchLabel: allTagsModalSearchLabel,
		searchPlaceholder: allTagsModalSearchPlaceholderText,
		portalTarget: allTagsModalTarget
	}));
});
const tagTypes = Object.keys({
	red: "Red",
	magenta: "Magenta",
	purple: "Purple",
	blue: "Blue",
	cyan: "Cyan",
	teal: "Teal",
	green: "Green",
	gray: "Gray",
	"cool-gray": "Cool-Gray",
	"warm-gray": "Warm-Gray",
	"high-contrast": "High-Contrast",
	outline: "Outline"
});
TagSet["types"] = tagTypes;
TagSet.propTypes = {
	/**
	* align the Tags displayed by the TagSet. Default start.
	*/
	align: PropTypes.oneOf([
		"start",
		"center",
		"end"
	]),
	/**
	* aria label for all tags modal with hasScrollingContent
	*/
	allTagsModalAriaLabel: PropTypes.string,
	/**
	* label text for the show all search.
	*/
	allTagsModalSearchLabel: PropTypes.string,
	/**
	* placeholder text for the show all search.
	*/
	allTagsModalSearchPlaceholderText: PropTypes.string,
	/**
	* portal target for the all tags modal
	*/
	allTagsModalTarget: PropTypes.node,
	/**
	* title for the show all modal.
	*/
	allTagsModalTitle: PropTypes.string,
	/**
	* className
	*/
	className: PropTypes.string,
	/**
	* Optional ref for custom resize container to measure available space
	* Default will measure the available space of the TagSet container itself.
	*/
	/**@ts-ignore */
	containingElementRef: PropTypes.object,
	/**
	* maximum visible tags
	*/
	maxVisible: PropTypes.number,
	/**
	* Specify offset amount for measure available space, only used when `containingElementSelector`
	* is also provided
	*/
	measurementOffset: PropTypes.number,
	/**
	* display tags in multiple lines
	*/
	multiline: PropTypes.bool,
	/**
	* An optional click handler that overrides the default functionality of displaying all tags in a modal
	*/
	onOverflowClick: PropTypes.func,
	/**
	* Handler to get overflow tags
	*/
	onOverflowTagChange: PropTypes.func,
	/**
	* overflowAlign from the standard tooltip. Default center.
	*/
	overflowAlign: PropTypes.oneOf([
		"top",
		"top-left",
		"top-right",
		"bottom",
		"bottom-left",
		"bottom-right",
		"left",
		"left-bottom",
		"left-top",
		"right",
		"right-bottom",
		"right-top"
	]),
	/**
	* Will auto-align the popover on first render if it is not visible. This prop is currently experimental and is subject to future changes.
	*/
	overflowAutoAlign: PropTypes.bool,
	/**
	* overflowClassName for the tooltip popup
	*/
	overflowClassName: PropTypes.string,
	/**
	* Type of rendering displayed inside of the tag overflow component
	*/
	overflowType: PropTypes.oneOf(["default", "tag"]),
	/**
	* label for the overflow show all tags link.
	*/
	showAllTagsLabel: PropTypes.string,
	/**
	* The tags to be shown in the TagSet. Each tag is specified as an object
	* with properties: **label**\* (required) to supply the tag content, and
	* other properties will be passed to the Carbon Tag component, such as
	* **type**, **disabled**, **ref**, **className** , and any other Tag props.
	*
	* See https://react.carbondesignsystem.com/?path=/docs/components-tag--default
	*/
	tags: PropTypes.arrayOf(PropTypes.shape({
		...Tag.propTypes,
		label: PropTypes.string.isRequired,
		type: PropTypes.oneOf(tagTypes)
	}))
};
TagSet.displayName = componentName;
//#endregion
export { TagSet as default };
