@yamada-ui/segmented-control
Version:
Yamada UI segmented control components
320 lines (319 loc) • 11.3 kB
JavaScript
"use client"
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/segmented-control.tsx
var segmented_control_exports = {};
__export(segmented_control_exports, {
SegmentedControl: () => SegmentedControl,
SegmentedControlButton: () => SegmentedControlButton
});
module.exports = __toCommonJS(segmented_control_exports);
var import_core = require("@yamada-ui/core");
var import_motion = require("@yamada-ui/motion");
var import_use_controllable_state = require("@yamada-ui/use-controllable-state");
var import_use_descendant = require("@yamada-ui/use-descendant");
var import_use_focus_visible = require("@yamada-ui/use-focus-visible");
var import_utils = require("@yamada-ui/utils");
var import_react = require("react");
var import_jsx_runtime = require("react/jsx-runtime");
var { DescendantsContextProvider, useDescendant, useDescendants } = (0, import_use_descendant.createDescendant)();
var [SegmentedControlProvider, useSegmentedControl] = (0, import_utils.createContext)({
name: "SegmentedControlContext",
errorMessage: `useSegmentedControl returned is 'undefined'. Seems you forgot to wrap the components in "<SegmentedControl />"`
});
var SegmentedControl = (0, import_core.forwardRef)(
(props, ref) => {
const [styles, mergedProps] = (0, import_core.useComponentMultiStyle)(
"SegmentedControl",
props
);
const uuid = (0, import_react.useId)();
const {
id = uuid,
name = `segmented-control-${uuid}`,
className,
children,
defaultValue,
isDisabled,
disabled = isDisabled,
isReadOnly,
items = [],
readOnly = isReadOnly,
value: valueProp,
onChange: onChangeProp,
...rest
} = (0, import_core.omitThemeProps)(mergedProps);
const containerRef = (0, import_react.useRef)(null);
const descendants = useDescendants();
const [focusedIndex, setFocusedIndex] = (0, import_react.useState)(-1);
const [focusVisible, setFocusVisible] = (0, import_react.useState)(false);
const onChangeRef = (0, import_utils.useCallbackRef)(onChangeProp);
const [value, setValue] = (0, import_use_controllable_state.useControllableState)({
defaultValue,
value: valueProp,
onChange: onChangeRef
});
const onChange = (0, import_react.useCallback)(
(ev) => {
if (disabled || readOnly) {
ev.preventDefault();
return;
}
setValue(ev.target.value);
},
[disabled, readOnly, setValue]
);
const onFocus = (0, import_react.useCallback)(
(index, skip) => {
if (disabled) return;
if (skip) {
const next = descendants.enabledNextValue(index);
if (next) setFocusedIndex(next.index);
} else {
setFocusedIndex(index);
}
},
[descendants, disabled]
);
const onBlur = (0, import_react.useCallback)(() => setFocusedIndex(-1), []);
const getContainerProps = (0, import_react.useCallback)(
(props2 = {}, ref2 = null) => ({
"aria-disabled": (0, import_utils.ariaAttr)(disabled),
"data-readonly": (0, import_utils.dataAttr)(readOnly),
role: "radiogroup",
...rest,
...props2,
id,
ref: (0, import_utils.mergeRefs)(containerRef, ref2),
onBlur: (0, import_utils.handlerAll)(props2.onBlur, onBlur)
}),
[id, disabled, readOnly, onBlur, rest]
);
const getInputProps = (0, import_react.useCallback)(
({ index, ...props2 }, ref2 = null) => {
var _a, _b;
const trulyDisabled = (_a = props2.disabled) != null ? _a : disabled;
const trulyReadOnly = (_b = props2.readOnly) != null ? _b : readOnly;
const checked = props2.value === value;
return {
...props2,
id: `${id}-${index}`,
ref: ref2,
type: "radio",
name,
style: {
border: "0px",
clip: "rect(0px, 0px, 0px, 0px)",
height: "1px",
margin: "-1px",
overflow: "hidden",
padding: "0px",
position: "absolute",
whiteSpace: "nowrap",
width: "1px"
},
"aria-disabled": (0, import_utils.ariaAttr)(trulyDisabled),
"data-checked": (0, import_utils.dataAttr)(checked),
"data-focus": (0, import_utils.dataAttr)(index === focusedIndex),
"data-readonly": (0, import_utils.dataAttr)(trulyReadOnly),
checked,
disabled: trulyDisabled || trulyReadOnly,
readOnly: trulyReadOnly,
onChange: (0, import_utils.handlerAll)(
props2.onChange,
(ev) => !trulyDisabled && !trulyReadOnly ? onChange(ev) : {}
)
};
},
[disabled, readOnly, value, id, name, focusedIndex, onChange]
);
const getLabelProps = (0, import_react.useCallback)(
({ index, ...props2 }, ref2 = null) => {
var _a, _b;
const trulyDisabled = (_a = props2.disabled) != null ? _a : disabled;
const trulyReadOnly = (_b = props2.readOnly) != null ? _b : readOnly;
const checked = props2.value === value;
const focused = index === focusedIndex;
return {
...props2,
ref: ref2,
"aria-disabled": (0, import_utils.ariaAttr)(trulyDisabled),
"data-checked": (0, import_utils.dataAttr)(checked),
"data-focus": (0, import_utils.dataAttr)(focused),
"data-focus-visible": (0, import_utils.dataAttr)(focused && focusVisible),
"data-readonly": (0, import_utils.dataAttr)(trulyReadOnly),
onFocus: (0, import_utils.handlerAll)(
props2.onFocus,
() => onFocus(index, trulyDisabled || trulyReadOnly || false)
),
...trulyDisabled || trulyReadOnly ? {
_active: {},
_focus: {},
_focusVisible: {},
_hover: {},
_invalid: {}
} : {}
};
},
[focusedIndex, disabled, readOnly, focusVisible, onFocus, value]
);
(0, import_react.useEffect)(() => {
return (0, import_use_focus_visible.trackFocusVisible)(setFocusVisible);
}, []);
const css = {
alignItems: "center",
display: "inline-flex",
...styles.container
};
const validChildren = (0, import_utils.getValidChildren)(children);
let computedChildren = [];
if (!validChildren.length && items.length) {
computedChildren = items.map(({ label, value: value2, ...props2 }, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SegmentedControlButton, { value: value2, ...props2, children: label }, i));
} else {
computedChildren = validChildren;
}
if (value == null && defaultValue == null) {
for (const child of computedChildren) {
if (child.type !== SegmentedControlButton) {
if (child.type.displayName !== SegmentedControlButton.displayName)
continue;
}
const value2 = child.props.value;
setValue(value2);
break;
}
}
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DescendantsContextProvider, { value: descendants, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
SegmentedControlProvider,
{
value: { styles, value, getInputProps, getLabelProps },
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_motion.LayoutGroup, { id, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_core.ui.div,
{
...getContainerProps({}, ref),
className: (0, import_utils.cx)("ui-segmented-control", className),
__css: css,
children: computedChildren
}
) })
}
) });
}
);
SegmentedControl.displayName = "SegmentedControl";
SegmentedControl.__ui__ = "SegmentedControl";
var SegmentedControlButton = (0, import_core.forwardRef)(
({
className,
children,
isDisabled,
disabled = isDisabled,
isReadOnly,
readOnly = isReadOnly,
value,
motionProps,
onChange,
...rest
}, ref) => {
const [, mounted] = (0, import_utils.useMounted)({ rerender: true });
const {
styles,
value: selectedValue,
getInputProps,
getLabelProps
} = useSegmentedControl();
const { index, register } = useDescendant({
disabled: disabled || readOnly
});
const props = {
disabled,
index,
readOnly,
value
};
const css = {
alignItems: "center",
cursor: "pointer",
display: "inline-flex",
flex: "1 1 0%",
justifyContent: "center",
position: "relative",
...styles.button
};
const selected = value === selectedValue;
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
import_core.ui.label,
{
...getLabelProps(props),
className: (0, import_utils.cx)("ui-segmented-control__button", className),
__css: css,
...rest,
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_core.ui.input,
{
...getInputProps({ onChange, ...props }, (0, import_utils.mergeRefs)(register, ref))
}
),
selected && mounted ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SegmentedControlCursor, { ...motionProps }) : null,
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.ui.span, { zIndex: "1", children })
]
}
);
}
);
SegmentedControlButton.displayName = "SegmentedControlButton";
SegmentedControlButton.__ui__ = "SegmentedControlButton";
var SegmentedControlCursor = ({
className,
transition,
...rest
}) => {
const { styles } = useSegmentedControl();
const css = {
h: "100%",
position: "absolute",
w: "100%",
...styles.cursor
};
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_motion.motion.div,
{
className: (0, import_utils.cx)("ui-segmented-control__cursor", className),
layoutDependency: false,
layoutId: "cursor",
transition: {
type: "spring",
bounce: 0.15,
duration: 0.4,
...transition
},
__css: css,
...rest
}
);
};
SegmentedControlCursor.displayName = "SegmentedControlCursor";
SegmentedControlCursor.__ui__ = "SegmentedControlCursor";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SegmentedControl,
SegmentedControlButton
});
//# sourceMappingURL=segmented-control.js.map