@yamada-ui/segmented-control 0.3.16 → 0.4.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.
@@ -20,7 +20,8 @@ import {
20
20
  handlerAll,
21
21
  mergeRefs,
22
22
  omitObject,
23
- useCallbackRef
23
+ useCallbackRef,
24
+ useIsMounted
24
25
  } from "@yamada-ui/utils";
25
26
  import {
26
27
  useCallback,
@@ -41,7 +42,17 @@ var SegmentedControl = forwardRef(
41
42
  "SegmentedControl",
42
43
  props
43
44
  );
44
- let { className, id, name, isReadOnly, isDisabled, children, ...rest } = omitThemeProps(mergedProps);
45
+ let {
46
+ className,
47
+ id,
48
+ name,
49
+ isReadOnly,
50
+ isDisabled,
51
+ children,
52
+ items = [],
53
+ ...rest
54
+ } = omitThemeProps(mergedProps);
55
+ const isMoutedRef = useIsMounted();
45
56
  id = id != null ? id : useId();
46
57
  name = name != null ? name : `segmented-control-${useId()}`;
47
58
  rest.onChange = useCallbackRef(rest.onChange);
@@ -51,34 +62,27 @@ var SegmentedControl = forwardRef(
51
62
  const [observerRef, containerRect] = useResizeObserver();
52
63
  const containerRef = useRef(null);
53
64
  const labelRefs = useRef(/* @__PURE__ */ new Map());
54
- const [activePosition, setActivePosition] = useState({
55
- width: 0,
56
- height: 0,
57
- x: 0,
58
- y: 0
59
- });
60
65
  const [value, setValue] = useControllableState({
61
66
  value: rest.value,
62
67
  defaultValue: rest.defaultValue,
63
68
  onChange: rest.onChange
64
69
  });
65
- useEffect(() => {
66
- return trackFocusVisible(setIsFocusVisible);
67
- }, []);
68
- useEffect(() => {
70
+ const getActivePosition = useCallback(() => {
71
+ const rect = { width: 0, height: 0, x: 0, y: 0 };
69
72
  const el = labelRefs.current.get(value);
70
73
  if (!el || !containerRef.current || !observerRef.current)
71
- return;
74
+ return rect;
72
75
  const { paddingLeft, paddingTop } = getComputedStyle(containerRef.current);
73
76
  const gutterX = parseFloat(paddingLeft) || 0;
74
77
  const gutterY = parseFloat(paddingTop) || 0;
75
78
  let { width, height } = el.getBoundingClientRect();
76
- const x = el.offsetLeft - gutterX;
77
- const y = el.offsetTop - gutterY;
78
- width = width * (el.offsetWidth / width) || 0;
79
- height = height * (el.offsetWidth / width) || 0;
80
- setActivePosition({ width, height, x, y });
81
- }, [focusedIndex, containerRect, labelRefs, observerRef, value]);
79
+ rect.x = el.offsetLeft - gutterX;
80
+ rect.y = el.offsetTop - gutterY;
81
+ rect.width = width * (el.offsetWidth / width) || 0;
82
+ rect.height = height * (el.offsetWidth / width) || 0;
83
+ return rect;
84
+ }, [observerRef, value]);
85
+ const [activePosition, setActivePosition] = useState(getActivePosition);
82
86
  const onChange = useCallback(
83
87
  (ev) => {
84
88
  if (isDisabled || isReadOnly) {
@@ -205,6 +209,12 @@ var SegmentedControl = forwardRef(
205
209
  },
206
210
  [focusedIndex, isDisabled, isFocusVisible, isReadOnly, onFocus, value]
207
211
  );
212
+ useEffect(() => {
213
+ return trackFocusVisible(setIsFocusVisible);
214
+ }, []);
215
+ useEffect(() => {
216
+ setActivePosition(getActivePosition());
217
+ }, [focusedIndex, containerRect, value, getActivePosition]);
208
218
  const css = {
209
219
  position: "relative",
210
220
  display: "inline-flex",
@@ -212,8 +222,14 @@ var SegmentedControl = forwardRef(
212
222
  ...styles.container
213
223
  };
214
224
  const validChildren = getValidChildren(children);
225
+ let computedChildren = [];
226
+ if (!validChildren.length && items.length) {
227
+ computedChildren = items.map(({ label, value: value2, ...props2 }, i) => /* @__PURE__ */ jsx(SegmentedControlButton, { value: value2, ...props2, children: label }, i));
228
+ } else {
229
+ computedChildren = validChildren;
230
+ }
215
231
  if (value == null && rest.defaultValue == null) {
216
- for (const child of validChildren) {
232
+ for (const child of computedChildren) {
217
233
  if (child.type !== SegmentedControlButton)
218
234
  continue;
219
235
  const value2 = child.props.value;
@@ -232,15 +248,15 @@ var SegmentedControl = forwardRef(
232
248
  className: cx("ui-segmented-control", className),
233
249
  __css: css,
234
250
  children: [
235
- /* @__PURE__ */ jsx(
251
+ isMoutedRef.current ? /* @__PURE__ */ jsx(
236
252
  ui.span,
237
253
  {
238
- className: "ui-segmented-control-active",
254
+ className: "ui-segmented-control__active",
239
255
  ...getActiveProps(),
240
256
  __css: styles.active
241
257
  }
242
- ),
243
- validChildren
258
+ ) : null,
259
+ computedChildren
244
260
  ]
245
261
  }
246
262
  )
@@ -285,7 +301,7 @@ var SegmentedControlButton = forwardRef(
285
301
  ui.label,
286
302
  {
287
303
  ...getLabelProps(omitObject(props, ["onChange"])),
288
- className: cx("ui-segmented-control-button", className),
304
+ className: cx("ui-segmented-control__button", className),
289
305
  __css: css,
290
306
  ...rest,
291
307
  children: [
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlProps } from './segmented-control.mjs';
1
+ export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlItem, SegmentedControlProps } from './segmented-control.mjs';
2
2
  import '@yamada-ui/core';
3
3
  import 'react';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlProps } from './segmented-control.js';
1
+ export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlItem, SegmentedControlProps } from './segmented-control.js';
2
2
  import '@yamada-ui/core';
3
3
  import 'react';
package/dist/index.js CHANGED
@@ -46,7 +46,17 @@ var SegmentedControl = (0, import_core.forwardRef)(
46
46
  "SegmentedControl",
47
47
  props
48
48
  );
49
- let { className, id, name, isReadOnly, isDisabled, children, ...rest } = (0, import_core.omitThemeProps)(mergedProps);
49
+ let {
50
+ className,
51
+ id,
52
+ name,
53
+ isReadOnly,
54
+ isDisabled,
55
+ children,
56
+ items = [],
57
+ ...rest
58
+ } = (0, import_core.omitThemeProps)(mergedProps);
59
+ const isMoutedRef = (0, import_utils.useIsMounted)();
50
60
  id = id != null ? id : (0, import_react.useId)();
51
61
  name = name != null ? name : `segmented-control-${(0, import_react.useId)()}`;
52
62
  rest.onChange = (0, import_utils.useCallbackRef)(rest.onChange);
@@ -56,34 +66,27 @@ var SegmentedControl = (0, import_core.forwardRef)(
56
66
  const [observerRef, containerRect] = (0, import_use_resize_observer.useResizeObserver)();
57
67
  const containerRef = (0, import_react.useRef)(null);
58
68
  const labelRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
59
- const [activePosition, setActivePosition] = (0, import_react.useState)({
60
- width: 0,
61
- height: 0,
62
- x: 0,
63
- y: 0
64
- });
65
69
  const [value, setValue] = (0, import_use_controllable_state.useControllableState)({
66
70
  value: rest.value,
67
71
  defaultValue: rest.defaultValue,
68
72
  onChange: rest.onChange
69
73
  });
70
- (0, import_react.useEffect)(() => {
71
- return (0, import_use_focus_visible.trackFocusVisible)(setIsFocusVisible);
72
- }, []);
73
- (0, import_react.useEffect)(() => {
74
+ const getActivePosition = (0, import_react.useCallback)(() => {
75
+ const rect = { width: 0, height: 0, x: 0, y: 0 };
74
76
  const el = labelRefs.current.get(value);
75
77
  if (!el || !containerRef.current || !observerRef.current)
76
- return;
78
+ return rect;
77
79
  const { paddingLeft, paddingTop } = getComputedStyle(containerRef.current);
78
80
  const gutterX = parseFloat(paddingLeft) || 0;
79
81
  const gutterY = parseFloat(paddingTop) || 0;
80
82
  let { width, height } = el.getBoundingClientRect();
81
- const x = el.offsetLeft - gutterX;
82
- const y = el.offsetTop - gutterY;
83
- width = width * (el.offsetWidth / width) || 0;
84
- height = height * (el.offsetWidth / width) || 0;
85
- setActivePosition({ width, height, x, y });
86
- }, [focusedIndex, containerRect, labelRefs, observerRef, value]);
83
+ rect.x = el.offsetLeft - gutterX;
84
+ rect.y = el.offsetTop - gutterY;
85
+ rect.width = width * (el.offsetWidth / width) || 0;
86
+ rect.height = height * (el.offsetWidth / width) || 0;
87
+ return rect;
88
+ }, [observerRef, value]);
89
+ const [activePosition, setActivePosition] = (0, import_react.useState)(getActivePosition);
87
90
  const onChange = (0, import_react.useCallback)(
88
91
  (ev) => {
89
92
  if (isDisabled || isReadOnly) {
@@ -210,6 +213,12 @@ var SegmentedControl = (0, import_core.forwardRef)(
210
213
  },
211
214
  [focusedIndex, isDisabled, isFocusVisible, isReadOnly, onFocus, value]
212
215
  );
216
+ (0, import_react.useEffect)(() => {
217
+ return (0, import_use_focus_visible.trackFocusVisible)(setIsFocusVisible);
218
+ }, []);
219
+ (0, import_react.useEffect)(() => {
220
+ setActivePosition(getActivePosition());
221
+ }, [focusedIndex, containerRect, value, getActivePosition]);
213
222
  const css = {
214
223
  position: "relative",
215
224
  display: "inline-flex",
@@ -217,8 +226,14 @@ var SegmentedControl = (0, import_core.forwardRef)(
217
226
  ...styles.container
218
227
  };
219
228
  const validChildren = (0, import_utils.getValidChildren)(children);
229
+ let computedChildren = [];
230
+ if (!validChildren.length && items.length) {
231
+ computedChildren = items.map(({ label, value: value2, ...props2 }, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SegmentedControlButton, { value: value2, ...props2, children: label }, i));
232
+ } else {
233
+ computedChildren = validChildren;
234
+ }
220
235
  if (value == null && rest.defaultValue == null) {
221
- for (const child of validChildren) {
236
+ for (const child of computedChildren) {
222
237
  if (child.type !== SegmentedControlButton)
223
238
  continue;
224
239
  const value2 = child.props.value;
@@ -237,15 +252,15 @@ var SegmentedControl = (0, import_core.forwardRef)(
237
252
  className: (0, import_utils.cx)("ui-segmented-control", className),
238
253
  __css: css,
239
254
  children: [
240
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
255
+ isMoutedRef.current ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
241
256
  import_core.ui.span,
242
257
  {
243
- className: "ui-segmented-control-active",
258
+ className: "ui-segmented-control__active",
244
259
  ...getActiveProps(),
245
260
  __css: styles.active
246
261
  }
247
- ),
248
- validChildren
262
+ ) : null,
263
+ computedChildren
249
264
  ]
250
265
  }
251
266
  )
@@ -290,7 +305,7 @@ var SegmentedControlButton = (0, import_core.forwardRef)(
290
305
  import_core.ui.label,
291
306
  {
292
307
  ...getLabelProps((0, import_utils.omitObject)(props, ["onChange"])),
293
- className: (0, import_utils.cx)("ui-segmented-control-button", className),
308
+ className: (0, import_utils.cx)("ui-segmented-control__button", className),
294
309
  __css: css,
295
310
  ...rest,
296
311
  children: [
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  SegmentedControl,
4
4
  SegmentedControlButton
5
- } from "./chunk-2LRRZGHE.mjs";
5
+ } from "./chunk-KEAS3GXU.mjs";
6
6
  export {
7
7
  SegmentedControl,
8
8
  SegmentedControlButton
@@ -2,6 +2,9 @@ import * as _yamada_ui_core from '@yamada-ui/core';
2
2
  import { HTMLUIProps, ThemeProps } from '@yamada-ui/core';
3
3
  import { ChangeEventHandler } from 'react';
4
4
 
5
+ type SegmentedControlItem = SegmentedControlButtonProps & {
6
+ label?: string;
7
+ };
5
8
  type SegmentedControlOptions = {
6
9
  /**
7
10
  * The HTML `name` attribute used for forms.
@@ -31,8 +34,14 @@ type SegmentedControlOptions = {
31
34
  * @default false
32
35
  */
33
36
  isDisabled?: boolean;
37
+ /**
38
+ * If provided, generate segmented control buttons but based on items.
39
+ *
40
+ * @default '[]'
41
+ */
42
+ items?: SegmentedControlItem[];
34
43
  };
35
- type SegmentedControlProps = Omit<HTMLUIProps<'div'>, 'onChange'> & ThemeProps<'SegmentedControl'> & SegmentedControlOptions;
44
+ type SegmentedControlProps = Omit<HTMLUIProps<"div">, "onChange"> & ThemeProps<"SegmentedControl"> & SegmentedControlOptions;
36
45
  declare const SegmentedControl: _yamada_ui_core.Component<"div", SegmentedControlProps>;
37
46
  type SegmentedControlButtonOptions = {
38
47
  /**
@@ -44,7 +53,7 @@ type SegmentedControlButtonOptions = {
44
53
  */
45
54
  onChange?: ChangeEventHandler<HTMLInputElement>;
46
55
  };
47
- type SegmentedControlButtonProps = Omit<HTMLUIProps<'label'>, 'onChange'> & Pick<SegmentedControlProps, 'isDisabled' | 'isReadOnly'> & SegmentedControlButtonOptions;
56
+ type SegmentedControlButtonProps = Omit<HTMLUIProps<"label">, "onChange"> & Pick<SegmentedControlProps, "isDisabled" | "isReadOnly"> & SegmentedControlButtonOptions;
48
57
  declare const SegmentedControlButton: _yamada_ui_core.Component<"input", SegmentedControlButtonProps>;
49
58
 
50
- export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlProps };
59
+ export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlItem, SegmentedControlProps };
@@ -2,6 +2,9 @@ import * as _yamada_ui_core from '@yamada-ui/core';
2
2
  import { HTMLUIProps, ThemeProps } from '@yamada-ui/core';
3
3
  import { ChangeEventHandler } from 'react';
4
4
 
5
+ type SegmentedControlItem = SegmentedControlButtonProps & {
6
+ label?: string;
7
+ };
5
8
  type SegmentedControlOptions = {
6
9
  /**
7
10
  * The HTML `name` attribute used for forms.
@@ -31,8 +34,14 @@ type SegmentedControlOptions = {
31
34
  * @default false
32
35
  */
33
36
  isDisabled?: boolean;
37
+ /**
38
+ * If provided, generate segmented control buttons but based on items.
39
+ *
40
+ * @default '[]'
41
+ */
42
+ items?: SegmentedControlItem[];
34
43
  };
35
- type SegmentedControlProps = Omit<HTMLUIProps<'div'>, 'onChange'> & ThemeProps<'SegmentedControl'> & SegmentedControlOptions;
44
+ type SegmentedControlProps = Omit<HTMLUIProps<"div">, "onChange"> & ThemeProps<"SegmentedControl"> & SegmentedControlOptions;
36
45
  declare const SegmentedControl: _yamada_ui_core.Component<"div", SegmentedControlProps>;
37
46
  type SegmentedControlButtonOptions = {
38
47
  /**
@@ -44,7 +53,7 @@ type SegmentedControlButtonOptions = {
44
53
  */
45
54
  onChange?: ChangeEventHandler<HTMLInputElement>;
46
55
  };
47
- type SegmentedControlButtonProps = Omit<HTMLUIProps<'label'>, 'onChange'> & Pick<SegmentedControlProps, 'isDisabled' | 'isReadOnly'> & SegmentedControlButtonOptions;
56
+ type SegmentedControlButtonProps = Omit<HTMLUIProps<"label">, "onChange"> & Pick<SegmentedControlProps, "isDisabled" | "isReadOnly"> & SegmentedControlButtonOptions;
48
57
  declare const SegmentedControlButton: _yamada_ui_core.Component<"input", SegmentedControlButtonProps>;
49
58
 
50
- export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlProps };
59
+ export { SegmentedControl, SegmentedControlButton, SegmentedControlButtonProps, SegmentedControlItem, SegmentedControlProps };
@@ -44,7 +44,17 @@ var SegmentedControl = (0, import_core.forwardRef)(
44
44
  "SegmentedControl",
45
45
  props
46
46
  );
47
- let { className, id, name, isReadOnly, isDisabled, children, ...rest } = (0, import_core.omitThemeProps)(mergedProps);
47
+ let {
48
+ className,
49
+ id,
50
+ name,
51
+ isReadOnly,
52
+ isDisabled,
53
+ children,
54
+ items = [],
55
+ ...rest
56
+ } = (0, import_core.omitThemeProps)(mergedProps);
57
+ const isMoutedRef = (0, import_utils.useIsMounted)();
48
58
  id = id != null ? id : (0, import_react.useId)();
49
59
  name = name != null ? name : `segmented-control-${(0, import_react.useId)()}`;
50
60
  rest.onChange = (0, import_utils.useCallbackRef)(rest.onChange);
@@ -54,34 +64,27 @@ var SegmentedControl = (0, import_core.forwardRef)(
54
64
  const [observerRef, containerRect] = (0, import_use_resize_observer.useResizeObserver)();
55
65
  const containerRef = (0, import_react.useRef)(null);
56
66
  const labelRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
57
- const [activePosition, setActivePosition] = (0, import_react.useState)({
58
- width: 0,
59
- height: 0,
60
- x: 0,
61
- y: 0
62
- });
63
67
  const [value, setValue] = (0, import_use_controllable_state.useControllableState)({
64
68
  value: rest.value,
65
69
  defaultValue: rest.defaultValue,
66
70
  onChange: rest.onChange
67
71
  });
68
- (0, import_react.useEffect)(() => {
69
- return (0, import_use_focus_visible.trackFocusVisible)(setIsFocusVisible);
70
- }, []);
71
- (0, import_react.useEffect)(() => {
72
+ const getActivePosition = (0, import_react.useCallback)(() => {
73
+ const rect = { width: 0, height: 0, x: 0, y: 0 };
72
74
  const el = labelRefs.current.get(value);
73
75
  if (!el || !containerRef.current || !observerRef.current)
74
- return;
76
+ return rect;
75
77
  const { paddingLeft, paddingTop } = getComputedStyle(containerRef.current);
76
78
  const gutterX = parseFloat(paddingLeft) || 0;
77
79
  const gutterY = parseFloat(paddingTop) || 0;
78
80
  let { width, height } = el.getBoundingClientRect();
79
- const x = el.offsetLeft - gutterX;
80
- const y = el.offsetTop - gutterY;
81
- width = width * (el.offsetWidth / width) || 0;
82
- height = height * (el.offsetWidth / width) || 0;
83
- setActivePosition({ width, height, x, y });
84
- }, [focusedIndex, containerRect, labelRefs, observerRef, value]);
81
+ rect.x = el.offsetLeft - gutterX;
82
+ rect.y = el.offsetTop - gutterY;
83
+ rect.width = width * (el.offsetWidth / width) || 0;
84
+ rect.height = height * (el.offsetWidth / width) || 0;
85
+ return rect;
86
+ }, [observerRef, value]);
87
+ const [activePosition, setActivePosition] = (0, import_react.useState)(getActivePosition);
85
88
  const onChange = (0, import_react.useCallback)(
86
89
  (ev) => {
87
90
  if (isDisabled || isReadOnly) {
@@ -208,6 +211,12 @@ var SegmentedControl = (0, import_core.forwardRef)(
208
211
  },
209
212
  [focusedIndex, isDisabled, isFocusVisible, isReadOnly, onFocus, value]
210
213
  );
214
+ (0, import_react.useEffect)(() => {
215
+ return (0, import_use_focus_visible.trackFocusVisible)(setIsFocusVisible);
216
+ }, []);
217
+ (0, import_react.useEffect)(() => {
218
+ setActivePosition(getActivePosition());
219
+ }, [focusedIndex, containerRect, value, getActivePosition]);
211
220
  const css = {
212
221
  position: "relative",
213
222
  display: "inline-flex",
@@ -215,8 +224,14 @@ var SegmentedControl = (0, import_core.forwardRef)(
215
224
  ...styles.container
216
225
  };
217
226
  const validChildren = (0, import_utils.getValidChildren)(children);
227
+ let computedChildren = [];
228
+ if (!validChildren.length && items.length) {
229
+ computedChildren = items.map(({ label, value: value2, ...props2 }, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SegmentedControlButton, { value: value2, ...props2, children: label }, i));
230
+ } else {
231
+ computedChildren = validChildren;
232
+ }
218
233
  if (value == null && rest.defaultValue == null) {
219
- for (const child of validChildren) {
234
+ for (const child of computedChildren) {
220
235
  if (child.type !== SegmentedControlButton)
221
236
  continue;
222
237
  const value2 = child.props.value;
@@ -235,15 +250,15 @@ var SegmentedControl = (0, import_core.forwardRef)(
235
250
  className: (0, import_utils.cx)("ui-segmented-control", className),
236
251
  __css: css,
237
252
  children: [
238
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
253
+ isMoutedRef.current ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
239
254
  import_core.ui.span,
240
255
  {
241
- className: "ui-segmented-control-active",
256
+ className: "ui-segmented-control__active",
242
257
  ...getActiveProps(),
243
258
  __css: styles.active
244
259
  }
245
- ),
246
- validChildren
260
+ ) : null,
261
+ computedChildren
247
262
  ]
248
263
  }
249
264
  )
@@ -288,7 +303,7 @@ var SegmentedControlButton = (0, import_core.forwardRef)(
288
303
  import_core.ui.label,
289
304
  {
290
305
  ...getLabelProps((0, import_utils.omitObject)(props, ["onChange"])),
291
- className: (0, import_utils.cx)("ui-segmented-control-button", className),
306
+ className: (0, import_utils.cx)("ui-segmented-control__button", className),
292
307
  __css: css,
293
308
  ...rest,
294
309
  children: [
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  SegmentedControl,
4
4
  SegmentedControlButton
5
- } from "./chunk-2LRRZGHE.mjs";
5
+ } from "./chunk-KEAS3GXU.mjs";
6
6
  export {
7
7
  SegmentedControl,
8
8
  SegmentedControlButton
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yamada-ui/segmented-control",
3
- "version": "0.3.16",
3
+ "version": "0.4.0",
4
4
  "description": "Yamada UI segmented control components",
5
5
  "keywords": [
6
6
  "yamada",