'use strict';

var React = require('react');
var jobberHooks = require('@jobber/hooks');
var classnames = require('classnames');
var SelectPrimitive = require('./SelectPrimitive-cjs.js');
var BottomSheet = require('./BottomSheet-cjs.js');
var Icon = require('./Icon-cjs.js');
var HelperText = require('./HelperText-cjs.js');
var FieldDescription = require('./FieldDescription-cjs.js');

var styles = {"field":"cWI-uFeNWWw-","inline":"ddkBixixBz4-","control":"_-1-lIAkgLuo-","trigger":"_7rwBeCqTgRY-","small":"_5QeBX5VxX6o-","large":"Pp5nj1nxejw-","label":"M1IjAW17-OE-","hasLabel":"_1rx-nSAJT0U-","sheetListbox":"AVkCcDISAio-","sheetOption":"_35H33txs5QU-","sheetOptionLabel":"uL9j4OZn-3c-","sheetOptionIndicator":"_7NHtDHZnkG8-","sheetGroup":"UQ1tsDd1NFs-","sheetGroupLabel":"_0kBfkWoRI5c-","sheetSeparator":"RPsN9vqlzRw-","spinning":"oOACJmrVDf0-"};

const SheetContext = React.createContext(null);
function useSheetContext() {
    const context = React.useContext(SheetContext);
    if (!context) {
        throw new Error("Select sheet parts must render inside the Select sheet");
    }
    return context;
}
const SheetGroupContext = React.createContext(null);
function SheetOption({ value, children, className, style }) {
    const { value: selectedValue, onSelect } = useSheetContext();
    const selected = value === selectedValue;
    return (React.createElement("div", { role: "option", "aria-selected": selected, "data-value": value, tabIndex: -1, className: classnames(styles.sheetOption, className), style: style, onClick: () => onSelect(value) },
        React.createElement("span", { className: styles.sheetOptionLabel }, children),
        selected && (React.createElement("span", { className: styles.sheetOptionIndicator, "aria-hidden": "true" },
            React.createElement(Icon.Icon, { name: "checkmark", size: "small" })))));
}
function SheetGroup({ children, className, style }) {
    const labelId = React.useId();
    return (React.createElement(SheetGroupContext.Provider, { value: { labelId } },
        React.createElement("div", { role: "group", "aria-labelledby": labelId, className: classnames(styles.sheetGroup, className), style: style }, children)));
}
function SheetGroupLabel({ children, className, style, }) {
    const group = React.useContext(SheetGroupContext);
    return (React.createElement("div", { id: group === null || group === void 0 ? void 0 : group.labelId, className: classnames(styles.sheetGroupLabel, className), style: style }, children));
}
function SheetSeparator({ className, style }) {
    return (React.createElement("hr", { className: classnames(styles.sheetSeparator, className), style: style, "data-testid": "ATL-Select-SheetSeparator" }));
}
const selectBottomSheetShell = {
    Item: SheetOption,
    Group: SheetGroup,
    GroupLabel: SheetGroupLabel,
    Separator: SheetSeparator,
};
const OPTION_SELECTOR = '[role="option"]';
function getOptions(list) {
    if (!list)
        return [];
    return Array.from(list.querySelectorAll(OPTION_SELECTOR));
}
function handleListboxKeyDown(event) {
    var _a, _b, _c, _d;
    const options = getOptions(event.currentTarget);
    if (options.length === 0)
        return;
    const active = document.activeElement;
    const currentIndex = active ? options.indexOf(active) : -1;
    switch (event.key) {
        case "ArrowDown":
            event.preventDefault();
            (_a = options[(currentIndex + 1 + options.length) % options.length]) === null || _a === void 0 ? void 0 : _a.focus();
            break;
        case "ArrowUp":
            event.preventDefault();
            (_b = options[(currentIndex - 1 + options.length) % options.length]) === null || _b === void 0 ? void 0 : _b.focus();
            break;
        case "Home":
            event.preventDefault();
            (_c = options[0]) === null || _c === void 0 ? void 0 : _c.focus();
            break;
        case "End":
            event.preventDefault();
            (_d = options[options.length - 1]) === null || _d === void 0 ? void 0 : _d.focus();
            break;
        case "Enter":
        case " ":
            event.preventDefault();
            active === null || active === void 0 ? void 0 : active.click();
            break;
    }
}
function SelectBottomSheetRoot({ value, onValueChange, onBlur, onFocus, disabled, invalid, renderValue, triggerId, triggerClassName, ariaLabel, children, }) {
    const [open, setOpen] = React.useState(false);
    const listRef = React.useRef(null);
    const selectedValue = value !== null && value !== void 0 ? value : undefined;
    const valueLabel = value != null ? renderValue(value) : undefined;
    function select(optionValue) {
        onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(optionValue);
        setOpen(false);
    }
    function getInitialFocus() {
        const options = getOptions(listRef.current);
        const selected = options.find(option => option.dataset.value === selectedValue);
        return selected !== null && selected !== void 0 ? selected : options[0];
    }
    return (React.createElement(SheetContext.Provider, { value: { value: selectedValue, onSelect: select } },
        React.createElement(BottomSheet.BottomSheet.Root, { open: open, onOpenChange: setOpen },
            React.createElement(BottomSheet.BottomSheet.Trigger, { render: React.createElement(SelectPrimitive.SelectPrimitive.FieldTrigger, { id: triggerId, disabled: disabled, onBlur: onBlur, onFocus: onFocus, "data-placeholder": selectedValue ? undefined : "", "data-invalid": invalid ? "" : undefined, "data-popup-open": open ? "" : undefined, className: triggerClassName, valueSlot: React.createElement(SelectPrimitive.SelectPrimitive.ValueText, null, valueLabel) }) }),
            React.createElement(BottomSheet.BottomSheet.Popup, { initialFocus: getInitialFocus },
                React.createElement(BottomSheet.BottomSheet.Content, null,
                    React.createElement("div", { ref: listRef, role: "listbox", "aria-label": ariaLabel, className: styles.sheetListbox, onKeyDown: handleListboxKeyDown }, children))))));
}

function DropdownItem({ value, children, className, style }) {
    return (React.createElement(SelectPrimitive.SelectPrimitive.Item, { className: className, style: style, value: value },
        React.createElement(SelectPrimitive.SelectPrimitive.ItemText, null, children),
        React.createElement(SelectPrimitive.SelectPrimitive.ItemIndicator, null)));
}
function DropdownGroup({ children, className, style }) {
    return (React.createElement(SelectPrimitive.SelectPrimitive.Group, { className: className, style: style }, children));
}
function DropdownGroupLabel({ children, className, style, }) {
    return (React.createElement(SelectPrimitive.SelectPrimitive.GroupLabel, { className: className, style: style }, children));
}
function DropdownSeparator({ className, style }) {
    return (React.createElement(SelectPrimitive.SelectPrimitive.Separator, { className: className, style: style, orientation: "horizontal" }));
}
const selectDropdownShell = {
    Item: DropdownItem,
    Group: DropdownGroup,
    GroupLabel: DropdownGroupLabel,
    Separator: DropdownSeparator,
};
function SelectDropdownRoot({ value, onValueChange, onBlur, onFocus, disabled, renderValue, triggerId, triggerClassName, children, }) {
    return (React.createElement(SelectPrimitive.SelectPrimitive.Root, { value: value !== null && value !== void 0 ? value : null, onValueChange: newValue => {
            if (typeof newValue === "string")
                onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(newValue);
        }, disabled: disabled },
        React.createElement(SelectPrimitive.SelectPrimitive.Trigger, { className: triggerClassName, id: triggerId, onBlur: onBlur, onFocus: onFocus },
            React.createElement(SelectPrimitive.SelectPrimitive.Value, null, selectedValue => typeof selectedValue === "string"
                ? renderValue(selectedValue)
                : null)),
        React.createElement(SelectPrimitive.SelectPrimitive.Portal, null,
            React.createElement(SelectPrimitive.SelectPrimitive.Positioner, null,
                React.createElement(SelectPrimitive.SelectPrimitive.Popup, null,
                    React.createElement(SelectPrimitive.SelectPrimitive.List, null, children))))));
}

const SMALL_SCREEN_BREAKPOINT = jobberHooks.BREAKPOINT_SIZES.sm;
const SelectShellContext = React.createContext(null);
function useSelectShell() {
    const shell = React.useContext(SelectShellContext);
    if (!shell) {
        throw new Error("Select.* components must be rendered inside Select");
    }
    return shell;
}
/**
 * Resolves the field's `id` (falling back to a generated id, since the id wires
 * the label and imperative focus) and wires the imperative `focus()` handle to
 * the trigger element. `name` is intentionally not synthesized: an unset `name`
 * stays `undefined` so the field is simply excluded from form submission rather
 * than submitted under a generated `useId()` value.
 */
function useSelectField(ref, idProp) {
    const generatedId = React.useId();
    const id = idProp !== null && idProp !== void 0 ? idProp : generatedId;
    React.useImperativeHandle(ref, () => ({
        focus: () => {
            var _a;
            if (typeof document !== "undefined") {
                (_a = document.getElementById(id)) === null || _a === void 0 ? void 0 : _a.focus();
            }
        },
    }), [id]);
    return { id };
}
/**
 * A prop-driven, labelled Select. On small web screens the options open in a
 * `BottomSheet` instead of an anchored dropdown.
 */
function Select({ label, description, error, invalid, value, onValueChange, onBlur, onFocus, renderValue, name, id: idProp, ref, disabled, size, inline, children, }) {
    const { id } = useSelectField(ref, idProp);
    const renderSelectedValue = renderValue !== null && renderValue !== void 0 ? renderValue : capitalize;
    const hasError = Boolean(error);
    const isInvalid = hasError || Boolean(invalid);
    const showDescription = !inline && Boolean(description) && !hasError;
    const showError = !inline && hasError;
    const { width } = jobberHooks.useWindowDimensions();
    const isBottomSheet = width !== undefined && width <= SMALL_SCREEN_BREAKPOINT;
    const shell = isBottomSheet ? selectBottomSheetShell : selectDropdownShell;
    const ShellRoot = isBottomSheet ? SelectBottomSheetRoot : SelectDropdownRoot;
    return (React.createElement(FieldDescription.FieldRoot, { className: classnames(styles.field, inline && styles.inline, size && styles[size], label && styles.hasLabel), disabled: disabled, invalid: isInvalid || undefined, name: name },
        React.createElement("div", { className: styles.control },
            label && (React.createElement(FieldDescription.FieldLabel, { className: styles.label, htmlFor: id }, label)),
            React.createElement(SelectShellContext.Provider, { value: shell },
                React.createElement(ShellRoot, { value: value, onValueChange: onValueChange, onBlur: onBlur, onFocus: onFocus, disabled: disabled, invalid: isInvalid, renderValue: renderSelectedValue, triggerId: id, triggerClassName: styles.trigger, ariaLabel: label }, children))),
        showDescription && (React.createElement(FieldDescription.FieldDescription, { render: React.createElement(HelperText.HelperText, { message: description }) })),
        showError && (React.createElement(FieldDescription.FieldError, { match: true, render: React.createElement(HelperText.HelperText, { message: error, status: "critical" }) }))));
}
/**
 * Default value renderer for the closed trigger: capitalizes the value (e.g.
 * `"active"` → `"Active"`). Consumers that need a different display pass
 * `renderValue`.
 */
function capitalize(value) {
    return value.length > 0
        ? value.charAt(0).toUpperCase() + value.slice(1)
        : value;
}
function SelectItem(props) {
    const { Item } = useSelectShell();
    return React.createElement(Item, Object.assign({}, props));
}
function SelectGroup(props) {
    const { Group } = useSelectShell();
    return React.createElement(Group, Object.assign({}, props));
}
function SelectGroupLabel(props) {
    const { GroupLabel } = useSelectShell();
    return React.createElement(GroupLabel, Object.assign({}, props));
}
function SelectSeparator(props) {
    const { Separator } = useSelectShell();
    return React.createElement(Separator, Object.assign({}, props));
}
Select.displayName = "Select";
SelectItem.displayName = "Select.Item";
SelectGroup.displayName = "Select.Group";
SelectGroupLabel.displayName = "Select.GroupLabel";
SelectSeparator.displayName = "Select.Separator";
Select.Item = SelectItem;
Select.Group = SelectGroup;
Select.GroupLabel = SelectGroupLabel;
Select.Separator = SelectSeparator;

exports.Select = Select;
