@homecode/ui 5.0.0 → 5.0.1

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.
package/dist/esm/index.js CHANGED
@@ -32,6 +32,8 @@ export { Portal } from './src/components/Portal/Portal.js';
32
32
  export { PopupMenu } from './src/components/PopupMenu/PopupMenu.js';
33
33
  export { Progress } from './src/components/Progress/Progress.js';
34
34
  export { ProgressCircular } from './src/components/ProgressCircular/ProgressCircular.js';
35
+ export { RadioButton } from './src/components/RadioButton/RadioButton.js';
36
+ export { RadioGroup } from './src/components/RadioGroup/RadioGroup.js';
35
37
  export { Router, RouterContext, RouterStore } from './src/components/Router/Router.js';
36
38
  export { RequiredStar } from './src/components/RequiredStar/RequiredStar.js';
37
39
  export { Select, SelectHelpers } from './src/components/Select/Select.js';
@@ -55,6 +55,9 @@ import '../Notifications/Notifications.styl.js';
55
55
  import '../PopupMenu/PopupMenu.styl.js';
56
56
  import '../Progress/Progress.styl.js';
57
57
  import '../ProgressCircular/ProgressCircular.styl.js';
58
+ import '../RadioGroup/RadioGroupContext.js';
59
+ import '../RadioButton/RadioButton.styl.js';
60
+ import '../RadioGroup/RadioGroup.styl.js';
58
61
  import '../Router/Router.js';
59
62
  import '../Table/Table.styl.js';
60
63
  import '../Tabs/Tabs.styl.js';
@@ -54,6 +54,9 @@ import '../Notifications/Notifications.styl.js';
54
54
  import '../PopupMenu/PopupMenu.styl.js';
55
55
  import '../Progress/Progress.styl.js';
56
56
  import '../ProgressCircular/ProgressCircular.styl.js';
57
+ import '../RadioGroup/RadioGroupContext.js';
58
+ import '../RadioButton/RadioButton.styl.js';
59
+ import '../RadioGroup/RadioGroup.styl.js';
57
60
  import '../Router/Router.js';
58
61
  import '../Table/Table.styl.js';
59
62
  import '../Tabs/Tabs.styl.js';
@@ -0,0 +1,33 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import 'react';
4
+ import 'timen';
5
+ import { useToggleState } from '../../hooks/useToggleState.js';
6
+ import { useRadioGroup } from '../RadioGroup/RadioGroupContext.js';
7
+ import S from './RadioButton.styl.js';
8
+
9
+ const RadioButton = ({ className, label = '', size: sizeProp, variant: variantProp, error: errorProp, value, checked: checkedProp, disabled: disabledProp, name: nameProp, onChange, id, onFocus, onBlur, ...props }) => {
10
+ const group = useRadioGroup();
11
+ const size = sizeProp ?? group?.size ?? 'm';
12
+ const variant = variantProp ?? group?.variant ?? 'default';
13
+ const error = errorProp ?? group?.error;
14
+ const disabled = Boolean(disabledProp || group?.disabled);
15
+ const name = group ? group.name : nameProp;
16
+ const checked = group
17
+ ? group.value !== undefined && group.value === value
18
+ : Boolean(checkedProp);
19
+ const { id: componentId, isActive, isFocused, handlers, } = useToggleState({
20
+ id,
21
+ onFocus,
22
+ onBlur,
23
+ });
24
+ const handleChange = (e) => {
25
+ if (group)
26
+ group.onChange(value);
27
+ onChange?.(e);
28
+ };
29
+ const classes = cn(S.root, S[`size-${size}`], S[`variant-${variant}`], checked && S.checked, disabled && S.disabled, error && S.hasError, isActive && S.isActive, isFocused && S.isFocused, className);
30
+ return (jsxs("label", { className: classes, onPointerDown: handlers.onPointerDown, onPointerUp: handlers.onPointerUp, children: [jsxs("div", { className: S.controlWrapper, children: [jsx("input", { className: S.control, ...props, onChange: handleChange, onFocus: handlers.onFocus, onBlur: handlers.onBlur, id: componentId, type: "radio", name: name, value: String(value), checked: checked, disabled: disabled, tabIndex: 0 }), jsx("span", { className: S.dot, "aria-hidden": true })] }), label] }));
31
+ };
32
+
33
+ export { RadioButton };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".RadioButton_root__-zReK{align-items:center;box-sizing:border-box;color:inherit;cursor:pointer;display:inline-flex;text-decoration:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.RadioButton_disabled__OuVm5{opacity:.4;pointer-events:none}.RadioButton_controlWrapper__xtZkJ{display:block;margin-right:1em;position:relative;transition:.2s ease-out;transition-property:opacity,box-shadow}.RadioButton_variant-default__r2D0X .RadioButton_controlWrapper__xtZkJ{background-color:var(--accent-color-alpha-100)}.RadioButton_variant-outlined__ZE2em .RadioButton_controlWrapper__xtZkJ{background-color:transparent;box-shadow:inset 0 0 0 2px var(--accent-color)}.RadioButton_root__-zReK:hover .RadioButton_controlWrapper__xtZkJ{background-color:var(--active-color-alpha-100)}.RadioButton_isActive__hAdvm .RadioButton_controlWrapper__xtZkJ,.RadioButton_isFocused__pQaTx .RadioButton_controlWrapper__xtZkJ{box-shadow:inset 0 0 0 2px var(--active-color)!important}.RadioButton_hasError__SFhRz .RadioButton_controlWrapper__xtZkJ{box-shadow:inset 0 0 0 2px var(--danger-color)!important}.RadioButton_isActive__hAdvm .RadioButton_controlWrapper__xtZkJ{background-color:var(--active-color-alpha-100);opacity:.7}.RadioButton_control__RLcpz{-webkit-appearance:none;-moz-appearance:none;appearance:none;box-shadow:inset 0 0 0 2px none;box-sizing:border-box;cursor:pointer;transition:.2s ease-out;transition-property:background-color,box-shadow,opacity;transition:.1s ease-out;transition-property:background-color,color}.RadioButton_control__RLcpz:focus,.RadioButton_control__RLcpz:hover{background-color:var(--active-color-alpha-100)}.RadioButton_control__RLcpz[disabled]{background-color:var(--accent-color-alpha-100);opacity:.4;pointer-events:none}.RadioButton_dot__m6MWL{background-color:var(--active-color);border-radius:50%;height:42%;left:50%;opacity:0;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%) scale(.4);transition:.1s ease-in;transition-property:transform,opacity;width:42%}.RadioButton_checked__X45GC .RadioButton_dot__m6MWL{opacity:1;transform:translate(-50%,-50%) scale(1.8)}.RadioButton_size-xs__gBuwV{font-size:14px}.RadioButton_size-xs__gBuwV .RadioButton_controlWrapper__xtZkJ{border-radius:4px;border-radius:12px;min-height:24px;min-width:24px}.RadioButton_size-s__2fKr7{font-size:16px}.RadioButton_size-s__2fKr7 .RadioButton_controlWrapper__xtZkJ{border-radius:4px;border-radius:16px;min-height:32px;min-width:32px}.RadioButton_size-m__cQ-gf{font-size:18px}.RadioButton_size-m__cQ-gf .RadioButton_controlWrapper__xtZkJ{border-radius:6px;border-radius:20px;min-height:40px;min-width:40px}.RadioButton_size-l__h3Alz{font-size:22px}.RadioButton_size-l__h3Alz .RadioButton_controlWrapper__xtZkJ{border-radius:8px;border-radius:24px;min-height:48px;min-width:48px}.RadioButton_size-xl__evU9a{font-size:26px}.RadioButton_size-xl__evU9a .RadioButton_controlWrapper__xtZkJ{border-radius:10px;border-radius:28px;min-height:56px;min-width:56px}";
4
+ var S = {"root":"RadioButton_root__-zReK","disabled":"RadioButton_disabled__OuVm5","controlWrapper":"RadioButton_controlWrapper__xtZkJ","variant-default":"RadioButton_variant-default__r2D0X","variant-outlined":"RadioButton_variant-outlined__ZE2em","isActive":"RadioButton_isActive__hAdvm","isFocused":"RadioButton_isFocused__pQaTx","hasError":"RadioButton_hasError__SFhRz","control":"RadioButton_control__RLcpz","dot":"RadioButton_dot__m6MWL","checked":"RadioButton_checked__X45GC","size-xs":"RadioButton_size-xs__gBuwV","size-s":"RadioButton_size-s__2fKr7","size-m":"RadioButton_size-m__cQ-gf","size-l":"RadioButton_size-l__h3Alz","size-xl":"RadioButton_size-xl__evU9a"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,31 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useId, useState, useCallback, useMemo } from 'react';
3
+ import cn from 'classnames';
4
+ import { RadioGroupContext } from './RadioGroupContext.js';
5
+ import S from './RadioGroup.styl.js';
6
+
7
+ const RadioGroup = ({ className, children, label, value, defaultValue, onChange, name: nameProp, size = 'm', variant = 'default', error, disabled, orientation = 'vertical', ...rest }) => {
8
+ const reactId = useId();
9
+ const name = nameProp ?? `radio${reactId.replace(/:/g, '')}`;
10
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
11
+ const isControlled = value !== undefined;
12
+ const selectedValue = isControlled ? value : uncontrolled;
13
+ const setValue = useCallback((next) => {
14
+ if (!isControlled)
15
+ setUncontrolled(next);
16
+ onChange?.(next);
17
+ }, [isControlled, onChange]);
18
+ const contextValue = useMemo(() => ({
19
+ name,
20
+ value: selectedValue,
21
+ onChange: setValue,
22
+ size,
23
+ variant,
24
+ error,
25
+ disabled,
26
+ }), [name, selectedValue, setValue, size, variant, error, disabled]);
27
+ const inner = (jsx("div", { className: cn(S.inner, orientation === 'horizontal' && S.horizontal), children: jsx(RadioGroupContext.Provider, { value: contextValue, children: children }) }));
28
+ return (jsxs("fieldset", { className: cn(S.root, className), disabled: disabled, ...rest, children: [label != null && label !== '' && (jsx("legend", { className: S.legend, children: label })), inner] }));
29
+ };
30
+
31
+ export { RadioGroup };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".RadioGroup_root__f0yTC{border:none;margin:0;min-width:0;padding:0}.RadioGroup_legend__Fq1Yg{margin:0 0 .5em;padding:0}.RadioGroup_inner__GZ2--{align-items:flex-start;display:flex;flex-direction:column;gap:.5em}.RadioGroup_inner__GZ2--.RadioGroup_horizontal__72oyb{align-items:center;flex-direction:row;flex-wrap:wrap}";
4
+ var S = {"root":"RadioGroup_root__f0yTC","legend":"RadioGroup_legend__Fq1Yg","inner":"RadioGroup_inner__GZ2--","horizontal":"RadioGroup_horizontal__72oyb"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,8 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ const RadioGroupContext = createContext(null);
4
+ function useRadioGroup() {
5
+ return useContext(RadioGroupContext);
6
+ }
7
+
8
+ export { RadioGroupContext, useRadioGroup };
@@ -0,0 +1,3 @@
1
+ import { FC } from 'react';
2
+ import * as T from './RadioButton.types';
3
+ export declare const RadioButton: FC<T.Props>;
@@ -0,0 +1,12 @@
1
+ import { ReactNode, InputHTMLAttributes } from 'react';
2
+ import { Size, ComponentType } from '../../types';
3
+ export type Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type' | 'value'> & ComponentType & {
4
+ label?: ReactNode;
5
+ /** Option value; compared to the group’s `value` when inside `RadioGroup` */
6
+ value: string | number;
7
+ checked?: boolean;
8
+ disabled?: boolean;
9
+ error?: string | boolean;
10
+ size?: Size;
11
+ variant?: 'default' | 'outlined';
12
+ };
@@ -0,0 +1,3 @@
1
+ import { FC } from 'react';
2
+ import type { Props } from './RadioGroup.types';
3
+ export declare const RadioGroup: FC<Props>;
@@ -0,0 +1,30 @@
1
+ import { ReactNode, HTMLAttributes } from 'react';
2
+ import { Size, ComponentType } from '../../types';
3
+ export type RadioGroupContextValue = {
4
+ name: string;
5
+ value: string | number | undefined;
6
+ onChange: (value: string | number) => void;
7
+ size: Size;
8
+ variant: 'default' | 'outlined';
9
+ error?: string | boolean;
10
+ disabled?: boolean;
11
+ };
12
+ export type Props = Omit<HTMLAttributes<HTMLFieldSetElement>, 'onChange'> & ComponentType & {
13
+ children: ReactNode;
14
+ /** Current value when controlled */
15
+ value?: string | number;
16
+ /** Initial value when uncontrolled */
17
+ defaultValue?: string | number;
18
+ /** Called when the selected option changes */
19
+ onChange?: (value: string | number) => void;
20
+ /** Shared `name` for native radio inputs; generated if omitted */
21
+ name?: string;
22
+ /** Group heading; renders as `legend` */
23
+ label?: ReactNode;
24
+ /** Size passed to `RadioButton` children via context */
25
+ size?: Size;
26
+ variant?: 'default' | 'outlined';
27
+ error?: string | boolean;
28
+ disabled?: boolean;
29
+ orientation?: 'vertical' | 'horizontal';
30
+ };
@@ -0,0 +1,3 @@
1
+ import type { RadioGroupContextValue } from './RadioGroup.types';
2
+ export declare const RadioGroupContext: import("react").Context<RadioGroupContextValue>;
3
+ export declare function useRadioGroup(): RadioGroupContextValue | null;
@@ -13,7 +13,7 @@ export declare const Scroll: import("react").ForwardRefExoticComponent<import(".
13
13
  x?: boolean;
14
14
  y?: boolean;
15
15
  size?: import("../../types").Size;
16
- fadeSize?: import("../../types").Size | "xl";
16
+ fadeSize?: import("../../types").Size;
17
17
  smooth?: boolean;
18
18
  autoHide?: boolean;
19
19
  offset?: {
@@ -32,6 +32,8 @@ export * from './Portal/Portal';
32
32
  export * from './PopupMenu/PopupMenu';
33
33
  export * from './Progress/Progress';
34
34
  export * from './ProgressCircular/ProgressCircular';
35
+ export * from './RadioButton/RadioButton';
36
+ export * from './RadioGroup/RadioGroup';
35
37
  export * from './Router/Router';
36
38
  export * from './RequiredStar/RequiredStar';
37
39
  export * from './Select/Select';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homecode/ui",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "React UI components library",
5
5
  "scripts": {
6
6
  "tests": "jest",