@koobiq/react-components 0.10.0 → 0.11.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.
@@ -3,7 +3,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import { forwardRef } from "react";
4
4
  import { createCalendar } from "@internationalized/date";
5
5
  import { useLocale, useDOMRef, mergeProps, clsx } from "@koobiq/react-core";
6
- import { useDateFieldState, removeDataAttributes, useDateField, FieldErrorContext } from "@koobiq/react-primitives";
6
+ import { useDateFieldState, removeDataAttributes, useSlottedContext, FormContext, useDateField, FieldErrorContext } from "@koobiq/react-primitives";
7
7
  import s from "./DateInput.module.css.js";
8
8
  import { FieldInputDate } from "../FieldComponents/FieldInputDate/FieldInputDate.js";
9
9
  import { DateSegment } from "../DateSegment/DateSegment.js";
@@ -38,6 +38,8 @@ function DateInputRender(props, ref) {
38
38
  createCalendar
39
39
  });
40
40
  const domRef = useDOMRef(ref);
41
+ const { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
42
+ const validationBehavior = props.validationBehavior ?? formValidationBehavior ?? "aria";
41
43
  const {
42
44
  labelProps: labelPropReactAria,
43
45
  fieldProps,
@@ -45,7 +47,11 @@ function DateInputRender(props, ref) {
45
47
  errorMessageProps,
46
48
  inputProps,
47
49
  ...validation
48
- } = useDateField({ ...removeDataAttributes(props) }, state, domRef);
50
+ } = useDateField(
51
+ { ...removeDataAttributes(props), validationBehavior },
52
+ state,
53
+ domRef
54
+ );
49
55
  const { isRequired, isDisabled } = state;
50
56
  const { isInvalid } = validation;
51
57
  const rootProps = mergeProps(
@@ -4,10 +4,10 @@ export type DialogCloseButtonRef = ComponentRef<'button'>;
4
4
  export type DialogCloseButtonProps = ButtonProps;
5
5
  export declare const DialogCloseButton: import("react").ForwardRefExoticComponent<Omit<Omit<Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
6
6
  ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
7
- }, "children" | "value" | "form" | "style" | "as" | "className" | "autoFocus" | "id" | "tabIndex" | "rel" | "aria-controls" | "aria-describedby" | "aria-details" | "aria-expanded" | "aria-haspopup" | "aria-label" | "aria-labelledby" | "aria-pressed" | "onFocus" | "onBlur" | "onKeyDown" | "onKeyUp" | "onClick" | "name" | "target" | "type" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "fullWidth" | "isDisabled" | "onPress" | "onPressStart" | "onPressEnd" | "onPressChange" | "onPressUp" | "onFocusChange" | "preventFocusOnPress" | "excludeFromTabOrder" | keyof import("@react-types/shared").HoverEvents | "isLoading" | "variant" | "onlyIcon" | "startIcon" | "endIcon" | "data-testid" | keyof {
7
+ }, "children" | "value" | "form" | "style" | "as" | "className" | "autoFocus" | "id" | "tabIndex" | "rel" | "aria-controls" | "aria-describedby" | "aria-details" | "aria-expanded" | "aria-haspopup" | "aria-label" | "aria-labelledby" | "aria-pressed" | "onFocus" | "onBlur" | "onKeyDown" | "onKeyUp" | "onClick" | "name" | "target" | "type" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "variant" | "fullWidth" | "isDisabled" | "onPress" | "onPressStart" | "onPressEnd" | "onPressChange" | "onPressUp" | "onFocusChange" | "preventFocusOnPress" | "excludeFromTabOrder" | keyof import("@react-types/shared").HoverEvents | "isLoading" | "onlyIcon" | "startIcon" | "endIcon" | "data-testid" | keyof {
8
8
  progress?: boolean;
9
9
  disabled?: boolean;
10
- }> & Omit<Omit<import("@koobiq/react-primitives").ButtonBaseProps, "slot">, "children" | "style" | "className" | "fullWidth" | "variant" | "onlyIcon" | "startIcon" | "endIcon" | "data-testid" | keyof {
10
+ }> & Omit<Omit<import("@koobiq/react-primitives").ButtonBaseProps, "slot">, "children" | "style" | "className" | "variant" | "fullWidth" | "onlyIcon" | "startIcon" | "endIcon" | "data-testid" | keyof {
11
11
  progress?: boolean;
12
12
  disabled?: boolean;
13
13
  }> & {
@@ -0,0 +1,19 @@
1
+ export declare const FormComponent: import("react").ForwardRefExoticComponent<{
2
+ labelPlacement?: import("..").FormControlPropLabelPlacement | import("../../utils").ResponsiveValue<import("..").FormControlPropLabelPlacement>;
3
+ labelAlign?: import("..").FormControlPropLabelAlign | import("../../utils").ResponsiveValue<import("..").FormControlPropLabelAlign>;
4
+ labelInlineSize?: import("./types").FormPropLabelInlineSize | import("../../utils").ResponsiveValue<import("./types").FormPropLabelInlineSize>;
5
+ } & import("@koobiq/react-primitives").FormProps & import("react").RefAttributes<HTMLFormElement>>;
6
+ export declare const Fieldset: import("@koobiq/react-core").PolyForwardComponent<"div", {
7
+ className?: string;
8
+ }, import("react").ElementType>;
9
+ export declare const Legend: import("@koobiq/react-core").PolyForwardComponent<"p", Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & {
10
+ ref?: ((instance: HTMLParagraphElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLParagraphElement> | null | undefined;
11
+ }, "as" | keyof import("..").TypographyBaseProps> & import("..").TypographyBaseProps & {
12
+ as?: "p" | undefined;
13
+ }, import("react").ElementType>;
14
+ type CompoundedComponent = typeof FormComponent & {
15
+ Fieldset: typeof Fieldset;
16
+ Legend: typeof Legend;
17
+ };
18
+ export declare const Form: CompoundedComponent;
19
+ export {};
@@ -0,0 +1,63 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { polymorphicForwardRef, clsx } from "@koobiq/react-core";
4
+ import { Form as Form$1 } from "@koobiq/react-primitives";
5
+ import s from "./Form.module.css.js";
6
+ import { FormContext } from "./FormContext.js";
7
+ import { templatePresets } from "./utils.js";
8
+ import { Typography } from "../Typography/Typography.js";
9
+ import { useMatchedBreakpoints } from "../Provider/BreakpointsContext.js";
10
+ import { getResponsiveValue } from "../../utils/getResponsiveValue/getResponsiveValue.js";
11
+ const FormComponent = forwardRef((props, ref) => {
12
+ const {
13
+ labelPlacement: labelPlacementProp,
14
+ labelAlign: labelAlignProp,
15
+ labelInlineSize: labelInlineSizeProp,
16
+ className,
17
+ style,
18
+ ...other
19
+ } = props;
20
+ const breakpoints = useMatchedBreakpoints();
21
+ const labelPlacement = getResponsiveValue(labelPlacementProp, breakpoints);
22
+ const labelAlign = getResponsiveValue(labelAlignProp, breakpoints);
23
+ const labelInlineSize = getResponsiveValue(labelInlineSizeProp, breakpoints);
24
+ const orientation = labelPlacement === "side" ? "horizontal" : "vertical";
25
+ const formStyle = labelInlineSize ? {
26
+ "--template-columns": templatePresets[labelInlineSize]
27
+ } : void 0;
28
+ return /* @__PURE__ */ jsx(FormContext.Provider, { value: { labelPlacement, labelAlign }, children: /* @__PURE__ */ jsx(
29
+ Form$1,
30
+ {
31
+ "data-orientation": orientation,
32
+ className: clsx(s.base, s[orientation], className),
33
+ style: { ...style, ...formStyle },
34
+ ...other,
35
+ ref
36
+ }
37
+ ) });
38
+ });
39
+ const Fieldset = polymorphicForwardRef(
40
+ ({ className, as: Tag = "fieldset", ...other }, ref) => /* @__PURE__ */ jsx(Tag, { className: clsx(s.fieldset, className), ...other, ref })
41
+ );
42
+ const Legend = polymorphicForwardRef(
43
+ ({ className, as = "p", ...other }, ref) => /* @__PURE__ */ jsx(
44
+ Typography,
45
+ {
46
+ as,
47
+ variant: "text-big",
48
+ className: clsx(s.legend, className),
49
+ ...other,
50
+ ref
51
+ }
52
+ )
53
+ );
54
+ FormComponent.displayName = "Form";
55
+ const Form = FormComponent;
56
+ Form.Fieldset = Fieldset;
57
+ Form.Legend = Legend;
58
+ export {
59
+ Fieldset,
60
+ Form,
61
+ FormComponent,
62
+ Legend
63
+ };
@@ -0,0 +1,17 @@
1
+ const base = "kbq-form-40d37e";
2
+ const fieldset = "kbq-form-fieldset-b2924b";
3
+ const legend = "kbq-form-legend-91e738";
4
+ const horizontal = "kbq-form-horizontal-52dea8";
5
+ const s = {
6
+ base,
7
+ fieldset,
8
+ legend,
9
+ horizontal
10
+ };
11
+ export {
12
+ base,
13
+ s as default,
14
+ fieldset,
15
+ horizontal,
16
+ legend
17
+ };
@@ -0,0 +1,7 @@
1
+ import type { FormControlPropLabelAlign, FormControlPropLabelPlacement } from '../FormControl';
2
+ export type FormContextProps = {
3
+ labelPlacement?: FormControlPropLabelPlacement;
4
+ labelAlign?: FormControlPropLabelAlign;
5
+ };
6
+ export declare const FormContext: import("react").Context<FormContextProps>;
7
+ export declare const useForm: () => FormContextProps;
@@ -0,0 +1,7 @@
1
+ import { createContext, useContext } from "react";
2
+ const FormContext = createContext({});
3
+ const useForm = () => useContext(FormContext);
4
+ export {
5
+ FormContext,
6
+ useForm
7
+ };
@@ -0,0 +1,3 @@
1
+ export * from './Form';
2
+ export * from './FormContext';
3
+ export * from './types';
@@ -0,0 +1,30 @@
1
+ import type { ComponentRef } from 'react';
2
+ import type { FormProps as FormPropsPrimitive } from '@koobiq/react-primitives';
3
+ import type { ResponsiveValue } from '../../utils';
4
+ import type { FormControlPropLabelAlign, FormControlPropLabelPlacement } from '../FormControl';
5
+ export declare const formPropLabelInlineSize: readonly ["80", "128", "160", "200", "240", "280", "320", "360", "400", "1/4", "2/5", "1/2", "max-content"];
6
+ export type FormPropLabelInlineSize = (typeof formPropLabelInlineSize)[number];
7
+ export type FormProps = {
8
+ /**
9
+ * The label's overall position relative to the element it is labeling.
10
+ * Responsive values allowed.
11
+ * @default 'top'
12
+ */
13
+ labelPlacement?: FormControlPropLabelPlacement | ResponsiveValue<FormControlPropLabelPlacement>;
14
+ /**
15
+ * The label's horizontal alignment relative to the element it is labeling.
16
+ * Responsive values allowed.
17
+ * @default 'start'
18
+ */
19
+ labelAlign?: FormControlPropLabelAlign | ResponsiveValue<FormControlPropLabelAlign>;
20
+ /**
21
+ * Size of the label column when `labelPlacement="side"`.
22
+ * Ignored for `"top"`.
23
+ *
24
+ * Supports px tokens (`'80'–'400'`), fractions (`'1/4'`, `'2/5'`, `'1/2'`),
25
+ * or `'max-content'`. Responsive values allowed.
26
+ * @default 'max-content'
27
+ */
28
+ labelInlineSize?: FormPropLabelInlineSize | ResponsiveValue<FormPropLabelInlineSize>;
29
+ } & FormPropsPrimitive;
30
+ export type FormRef = ComponentRef<'form'>;
@@ -0,0 +1,18 @@
1
+ const formPropLabelInlineSize = [
2
+ "80",
3
+ "128",
4
+ "160",
5
+ "200",
6
+ "240",
7
+ "280",
8
+ "320",
9
+ "360",
10
+ "400",
11
+ "1/4",
12
+ "2/5",
13
+ "1/2",
14
+ "max-content"
15
+ ];
16
+ export {
17
+ formPropLabelInlineSize
18
+ };
@@ -0,0 +1,15 @@
1
+ export declare const templatePresets: {
2
+ 'max-content': undefined;
3
+ '1/4': string;
4
+ '2/5': string;
5
+ '1/2': string;
6
+ '80': string;
7
+ '128': string;
8
+ '160': string;
9
+ '200': string;
10
+ '240': string;
11
+ '280': string;
12
+ '320': string;
13
+ '360': string;
14
+ '400': string;
15
+ };
@@ -0,0 +1,18 @@
1
+ const templatePresets = {
2
+ "max-content": void 0,
3
+ "1/4": "1fr 3fr",
4
+ "2/5": "2fr 3fr",
5
+ "1/2": "1fr 1fr",
6
+ "80": "80px 1fr",
7
+ "128": "128px 1fr",
8
+ "160": "160px 1fr",
9
+ "200": "200px 1fr",
10
+ "240": "240px 1fr",
11
+ "280": "280px 1fr",
12
+ "320": "320px 1fr",
13
+ "360": "360px 1fr",
14
+ "400": "400px 1fr"
15
+ };
16
+ export {
17
+ templatePresets
18
+ };
@@ -1,31 +1,39 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { polymorphicForwardRef, clsx } from "@koobiq/react-core";
3
3
  import s from "./FormControl.module.css.js";
4
+ import { useForm } from "../Form/FormContext.js";
4
5
  const FormControl = polymorphicForwardRef(
5
- ({
6
- labelPlacement = "top",
7
- labelAlign = "start",
8
- as: Tag = "div",
9
- fullWidth,
10
- className,
11
- ...other
12
- }, ref) => /* @__PURE__ */ jsx(
13
- Tag,
14
- {
15
- className: clsx(
16
- s.base,
17
- className,
18
- s[labelAlign],
19
- s[labelPlacement],
20
- fullWidth && s.fullWidth
21
- ),
22
- "data-label-align": labelAlign,
23
- "data-label-placement": labelPlacement,
24
- "data-fullwidth": fullWidth || void 0,
25
- ...other,
26
- ref
27
- }
28
- )
6
+ (props, ref) => {
7
+ const {
8
+ as: Tag = "div",
9
+ fullWidth,
10
+ className,
11
+ labelAlign: labelAlignProp,
12
+ labelPlacement: labelPlacementProp,
13
+ ...other
14
+ } = props;
15
+ const { labelPlacement: formLabelPlacement, labelAlign: formLabelAlign } = useForm();
16
+ const labelPlacement = labelPlacementProp ?? formLabelPlacement ?? "top";
17
+ const labelAlign = labelAlignProp ?? formLabelAlign ?? "start";
18
+ return /* @__PURE__ */ jsx(
19
+ Tag,
20
+ {
21
+ className: clsx(
22
+ s.base,
23
+ className,
24
+ s[labelAlign],
25
+ s[labelPlacement],
26
+ fullWidth && s.fullWidth
27
+ ),
28
+ "data-slot": "form-control",
29
+ "data-label-align": labelAlign,
30
+ "data-label-placement": labelPlacement,
31
+ "data-fullwidth": fullWidth || void 0,
32
+ ...other,
33
+ ref
34
+ }
35
+ );
36
+ }
29
37
  );
30
38
  FormControl.displayName = "FormControl";
31
39
  export {
@@ -2,7 +2,7 @@ import { TextField } from '@koobiq/react-primitives';
2
2
  import { type FieldContentGroupProps, type FieldCaptionProps, type FieldInputProps, type FieldErrorProps } from '../FieldComponents';
3
3
  import { type FormControlProps } from '../FormControl';
4
4
  import { type FormControlLabelProps } from '../FormControlLabel';
5
- export declare const Input: import("react").ForwardRefExoticComponent<Omit<Omit<import("@koobiq/react-primitives").TextFieldProps<HTMLInputElement>, "children" | "validationState" | "description" | "inputElementType">, "caption" | "style" | "className" | "labelPlacement" | "labelAlign" | "fullWidth" | "variant" | "slotProps" | "data-testid" | "startAddon" | "endAddon" | "isLabelHidden" | keyof {
5
+ export declare const Input: import("react").ForwardRefExoticComponent<Omit<Omit<import("@koobiq/react-primitives").TextFieldProps<HTMLInputElement>, "children" | "validationState" | "description" | "inputElementType">, "caption" | "style" | "className" | "variant" | "labelPlacement" | "labelAlign" | "fullWidth" | "slotProps" | "data-testid" | "startAddon" | "endAddon" | "isLabelHidden" | keyof {
6
6
  disabled?: boolean;
7
7
  error?: boolean;
8
8
  required?: boolean;
@@ -2,7 +2,7 @@ import { NumberField } from '@koobiq/react-primitives';
2
2
  import { type FieldCaptionProps, type FieldContentGroupProps, type FieldInputProps, type FieldErrorProps } from '../FieldComponents';
3
3
  import { type FormControlProps } from '../FormControl';
4
4
  import { type FormControlLabelProps } from '../FormControlLabel';
5
- export declare const InputNumber: import("react").ForwardRefExoticComponent<Omit<Omit<import("@koobiq/react-primitives").NumberFieldProps, "children" | "validationState" | "description" | "inputElementType">, "caption" | "style" | "className" | "labelPlacement" | "labelAlign" | "fullWidth" | "variant" | "slotProps" | "data-testid" | "startAddon" | "endAddon" | "isLabelHidden" | keyof {
5
+ export declare const InputNumber: import("react").ForwardRefExoticComponent<Omit<Omit<import("@koobiq/react-primitives").NumberFieldProps, "children" | "validationState" | "description" | "inputElementType">, "caption" | "style" | "className" | "variant" | "labelPlacement" | "labelAlign" | "fullWidth" | "slotProps" | "data-testid" | "startAddon" | "endAddon" | "isLabelHidden" | keyof {
6
6
  disabled?: boolean;
7
7
  error?: boolean;
8
8
  required?: boolean;
@@ -2,8 +2,8 @@
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
3
  import { useListBoxSection } from "@koobiq/react-primitives";
4
4
  import { utilClasses } from "../../../../styles/utility.js";
5
- import { Typography } from "../../../Typography/Typography.js";
6
5
  import { ListOption } from "../ListOption/ListOption.js";
6
+ import { Typography } from "../../../Typography/Typography.js";
7
7
  const { listHeading } = utilClasses;
8
8
  function ListSection({ section, state }) {
9
9
  const { itemProps, headingProps, groupProps } = useListBoxSection({
@@ -1,7 +1,7 @@
1
1
  import { type FieldCaptionProps, type FieldContentGroupProps, type FieldInputProps, type FieldErrorProps } from '../FieldComponents';
2
2
  import { type FormControlProps } from '../FormControl';
3
3
  import { type FormControlLabelProps } from '../FormControlLabel';
4
- export declare const SearchInput: import("react").ForwardRefExoticComponent<Omit<Omit<import("@react-types/searchfield").AriaSearchFieldProps, "validationState" | "description">, "caption" | "style" | "className" | `data-${string}` | "labelPlacement" | "labelAlign" | "fullWidth" | "variant" | "slotProps" | "startAddon" | "endAddon" | "isLabelHidden"> & {
4
+ export declare const SearchInput: import("react").ForwardRefExoticComponent<Omit<Omit<import("@react-types/searchfield").AriaSearchFieldProps, "validationState" | "description">, "caption" | "style" | "className" | "variant" | "labelPlacement" | "labelAlign" | `data-${string}` | "fullWidth" | "slotProps" | "startAddon" | "endAddon" | "isLabelHidden"> & {
5
5
  className?: string;
6
6
  style?: import("react").CSSProperties;
7
7
  isLabelHidden?: boolean;
@@ -3,7 +3,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
3
  import { forwardRef } from "react";
4
4
  import { useDOMRef, mergeProps, clsx } from "@koobiq/react-core";
5
5
  import { IconMagnifyingGlass16, IconXmarkCircle16 } from "@koobiq/react-icons";
6
- import { useSearchFieldState, removeDataAttributes, useSearchField, FieldErrorContext } from "@koobiq/react-primitives";
6
+ import { useSearchFieldState, removeDataAttributes, useSlottedContext, FormContext, useSearchField, FieldErrorContext } from "@koobiq/react-primitives";
7
7
  import s from "./SearchInput.module.css.js";
8
8
  import { IconButton } from "../IconButton/IconButton.js";
9
9
  import { FormControl } from "../FormControl/FormControl.js";
@@ -36,6 +36,8 @@ const SearchInput = forwardRef(
36
36
  } = props;
37
37
  const state = useSearchFieldState(removeDataAttributes(props));
38
38
  const domRef = useDOMRef(ref);
39
+ const { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
40
+ const validationBehavior = props.validationBehavior ?? formValidationBehavior ?? "aria";
39
41
  const hasClearButton = state.value !== "" && !isDisabled && !isReadOnly;
40
42
  const {
41
43
  labelProps: labelPropsAria,
@@ -44,7 +46,11 @@ const SearchInput = forwardRef(
44
46
  errorMessageProps: errorMessagePropsAria,
45
47
  clearButtonProps: clearButtonPropsAria,
46
48
  ...validation
47
- } = useSearchField(removeDataAttributes(props), state, domRef);
49
+ } = useSearchField(
50
+ { ...removeDataAttributes(props), validationBehavior },
51
+ state,
52
+ domRef
53
+ );
48
54
  const { isInvalid } = validation;
49
55
  const rootProps = mergeProps(
50
56
  {
@@ -2,7 +2,7 @@ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useCallback } from "react";
3
3
  import { useLocalizedStringFormatter, useDOMRef, useElementSize, mergeProps, clsx } from "@koobiq/react-core";
4
4
  import { IconXmarkCircle16, IconChevronDownS16 } from "@koobiq/react-icons";
5
- import { useMultiSelectState, removeDataAttributes, useMultiSelect, FieldErrorContext } from "@koobiq/react-primitives";
5
+ import { useSlottedContext, FormContext, useMultiSelectState, removeDataAttributes, useMultiSelect, FieldErrorContext } from "@koobiq/react-primitives";
6
6
  import { PopoverInner } from "../Popover/PopoverInner.js";
7
7
  import intlMessages from "./intl.js";
8
8
  import s from "./Select.module.css.js";
@@ -47,12 +47,14 @@ function SelectRender(props, ref) {
47
47
  } = props;
48
48
  const t = useLocalizedStringFormatter(intlMessages);
49
49
  const domRef = useDOMRef(ref);
50
+ const { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
51
+ const validationBehavior = props.validationBehavior ?? formValidationBehavior ?? "aria";
50
52
  const state = useMultiSelectState(
51
53
  removeDataAttributes({ ...props, selectionMode })
52
54
  );
53
55
  const hasClearButton = isClearable && !isDisabled && state.selectedItems;
54
56
  const handleClear = useCallback(() => {
55
- state.selectionManager.clearSelection();
57
+ state.selectionManager.setSelectedKeys(/* @__PURE__ */ new Set());
56
58
  onClear?.();
57
59
  }, [onClear, state]);
58
60
  const {
@@ -67,7 +69,8 @@ function SelectRender(props, ref) {
67
69
  removeDataAttributes({
68
70
  ...props,
69
71
  selectionMode,
70
- disallowEmptySelection: true
72
+ disallowEmptySelection: true,
73
+ validationBehavior
71
74
  }),
72
75
  state,
73
76
  domRef
@@ -4,7 +4,7 @@ export declare const Textarea: import("react").ForwardRefExoticComponent<Omit<{
4
4
  required?: boolean;
5
5
  hiddenLabel?: boolean;
6
6
  readonly?: boolean;
7
- } & Omit<import("@koobiq/react-primitives").TextFieldProps<HTMLTextAreaElement>, "children" | "style" | "className" | "validationState" | "description" | "inputElementType">, "caption" | "style" | "className" | "cols" | "rows" | "labelPlacement" | "labelAlign" | "fullWidth" | "variant" | "slotProps" | "data-testid" | "isLabelHidden" | "expand"> & {
7
+ } & Omit<import("@koobiq/react-primitives").TextFieldProps<HTMLTextAreaElement>, "children" | "style" | "className" | "validationState" | "description" | "inputElementType">, "caption" | "style" | "className" | "cols" | "rows" | "variant" | "labelPlacement" | "labelAlign" | "fullWidth" | "slotProps" | "data-testid" | "isLabelHidden" | "expand"> & {
8
8
  className?: string;
9
9
  style?: import("react").CSSProperties;
10
10
  variant?: import("./types").TextareaPropVariant;
@@ -3,4 +3,4 @@ export declare const TextareaContextConsumer: import("react").ForwardRefExoticCo
3
3
  isRequired?: boolean;
4
4
  isInvalid?: boolean;
5
5
  isDisabled?: boolean;
6
- } & Pick<TextareaProps, "caption" | "label" | "cols" | "rows" | "labelPlacement" | "variant" | "slotProps" | "errorMessage" | "isLabelHidden" | "expand"> & import("react").RefAttributes<HTMLTextAreaElement>>;
6
+ } & Pick<TextareaProps, "caption" | "label" | "cols" | "rows" | "variant" | "labelPlacement" | "slotProps" | "errorMessage" | "isLabelHidden" | "expand"> & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -2,7 +2,7 @@ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
3
  import { useLocale, useDOMRef, mergeProps, clsx } from "@koobiq/react-core";
4
4
  import { IconClock16 } from "@koobiq/react-icons";
5
- import { useTimeFieldState, removeDataAttributes, useTimeField, FieldErrorContext } from "@koobiq/react-primitives";
5
+ import { useSlottedContext, FormContext, useTimeFieldState, removeDataAttributes, useTimeField, FieldErrorContext } from "@koobiq/react-primitives";
6
6
  import s from "./TimePicker.module.css.js";
7
7
  import { FormControl } from "../FormControl/FormControl.js";
8
8
  import { FormControlLabel } from "../FormControlLabel/FormControlLabel.js";
@@ -31,8 +31,11 @@ function TimePickerRender(props, ref) {
31
31
  startAddon,
32
32
  "data-testid": testId
33
33
  } = props;
34
+ const { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
35
+ const validationBehavior = props.validationBehavior ?? formValidationBehavior ?? "aria";
34
36
  const state = useTimeFieldState({
35
37
  ...removeDataAttributes(props),
38
+ validationBehavior,
36
39
  locale
37
40
  });
38
41
  const {
@@ -1,4 +1,4 @@
1
- export declare const Tooltip: import("react").ForwardRefExoticComponent<Omit<import("@react-types/tooltip").TooltipTriggerProps, "children" | "className" | "id" | "offset" | `data-${string}` | "variant" | "placement" | "control" | "portalContainer" | "anchorRef" | "hideArrow" | "arrowBoundaryOffset" | "crossOffset" | "delay" | "closeDelay" | keyof {
1
+ export declare const Tooltip: import("react").ForwardRefExoticComponent<Omit<import("@react-types/tooltip").TooltipTriggerProps, "children" | "className" | "id" | "offset" | "variant" | `data-${string}` | "placement" | "control" | "portalContainer" | "anchorRef" | "hideArrow" | "arrowBoundaryOffset" | "crossOffset" | "delay" | "closeDelay" | keyof {
2
2
  open?: boolean;
3
3
  disabled?: boolean;
4
4
  }> & {
@@ -37,6 +37,7 @@ export * from './DateInput';
37
37
  export * from './DatePicker';
38
38
  export * from './TimePicker';
39
39
  export * from './SearchInput';
40
+ export * from './Form';
40
41
  export * from './layout';
41
42
  export { useListData, type ListData, type ListOptions, type TimeValue, type DateValue, } from '@koobiq/react-primitives';
42
43
  export { useRouter, useLocale, type Locale, RouterProvider, useDateFormatter, } from '@koobiq/react-core';
package/dist/index.js CHANGED
@@ -82,6 +82,9 @@ import { TimePicker, TimePickerRender } from "./components/TimePicker/TimePicker
82
82
  import { timePickerPropLabelAlign, timePickerPropLabelPlacement } from "./components/TimePicker/types.js";
83
83
  import { SearchInput } from "./components/SearchInput/SearchInput.js";
84
84
  import { searchInputPropLabelAlign, searchInputPropLabelPlacement, searchInputPropVariant } from "./components/SearchInput/types.js";
85
+ import { Fieldset, Form, FormComponent, Legend } from "./components/Form/Form.js";
86
+ import { FormContext, useForm } from "./components/Form/FormContext.js";
87
+ import { formPropLabelInlineSize } from "./components/Form/types.js";
85
88
  import { flex, flexPropAlignItems, flexPropDirection, flexPropFlex, flexPropGap, flexPropJustifyContent, flexPropOrder, flexPropWrap } from "./components/layout/flex/flex.js";
86
89
  import { spacing, spacingGap } from "./components/layout/spacing/spacing.js";
87
90
  export {
@@ -101,7 +104,11 @@ export {
101
104
  DatePicker,
102
105
  DatePickerRender,
103
106
  Divider,
107
+ Fieldset,
104
108
  FlexBox,
109
+ Form,
110
+ FormComponent,
111
+ FormContext,
105
112
  FormControl,
106
113
  FormControlLabel,
107
114
  Grid,
@@ -109,6 +116,7 @@ export {
109
116
  IconButton,
110
117
  Input,
111
118
  InputNumber,
119
+ Legend,
112
120
  Link,
113
121
  List,
114
122
  ListInner,
@@ -173,6 +181,7 @@ export {
173
181
  flexPropWrap,
174
182
  formControlPropLabelAlign,
175
183
  formControlPropLabelPlacement,
184
+ formPropLabelInlineSize,
176
185
  gridPropGap,
177
186
  iconButtonPropSize,
178
187
  iconButtonPropVariant,
@@ -223,6 +232,7 @@ export {
223
232
  typographyPropVariant,
224
233
  useBreakpoints,
225
234
  useDateFormatter,
235
+ useForm,
226
236
  useListData,
227
237
  useLocale,
228
238
  useMatchedBreakpoints,
package/dist/style.css CHANGED
@@ -4086,7 +4086,7 @@
4086
4086
  }
4087
4087
 
4088
4088
  .kbq-datesegment-3b7153:focus {
4089
- color: var(--date-input-segment-color);
4089
+ color: highlighttext;
4090
4090
  background-color: highlight;
4091
4091
  outline: none;
4092
4092
  }
@@ -4159,6 +4159,54 @@
4159
4159
  .kbq-searchinput-clearButton-71f872 {
4160
4160
  margin-inline-end: calc(-1 * var(--kbq-size-xxs));
4161
4161
  }
4162
+ .kbq-form-40d37e, .kbq-form-fieldset-b2924b {
4163
+ --gap-y: var(--kbq-size-xl);
4164
+ --template-columns: max-content 1fr;
4165
+ display: grid;
4166
+ }
4167
+
4168
+ :is(.kbq-form-40d37e, .kbq-form-fieldset-b2924b) > [data-slot="form-control"] {
4169
+ width: 100%;
4170
+ }
4171
+
4172
+ :is(.kbq-form-40d37e, .kbq-form-fieldset-b2924b) > [data-slot="form-control"]:not(:last-child) {
4173
+ margin-block-end: var(--gap-y);
4174
+ }
4175
+
4176
+ :is(.kbq-form-40d37e, .kbq-form-fieldset-b2924b) > * {
4177
+ grid-column: 1 / -1;
4178
+ justify-self: start;
4179
+ }
4180
+
4181
+ .kbq-form-fieldset-b2924b {
4182
+ border: 0;
4183
+ margin: 0;
4184
+ padding: 0;
4185
+ }
4186
+
4187
+ .kbq-form-fieldset-b2924b .kbq-form-legend-91e738 {
4188
+ margin-block-end: var(--kbq-size-l);
4189
+ }
4190
+
4191
+ .kbq-form-horizontal-52dea8, .kbq-form-horizontal-52dea8 .kbq-form-fieldset-b2924b {
4192
+ grid-template-columns: var(--template-columns);
4193
+ }
4194
+
4195
+ :is(.kbq-form-horizontal-52dea8, .kbq-form-horizontal-52dea8 .kbq-form-fieldset-b2924b) > [data-slot="form-control"] {
4196
+ grid-template-columns: subgrid;
4197
+ align-items: center;
4198
+ display: grid;
4199
+ }
4200
+
4201
+ :is(.kbq-form-horizontal-52dea8, .kbq-form-horizontal-52dea8 .kbq-form-fieldset-b2924b) > [data-slot="form-control"] > :first-child {
4202
+ grid-column: 1;
4203
+ align-self: start;
4204
+ }
4205
+
4206
+ :is(.kbq-form-horizontal-52dea8, .kbq-form-horizontal-52dea8 .kbq-form-fieldset-b2924b) > [data-slot="form-control"] > :last-child {
4207
+ grid-column: 2;
4208
+ justify-self: start;
4209
+ }
4162
4210
  .kbq-spacing-mbs_0-be7021 {
4163
4211
  margin-block-start: 0;
4164
4212
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koobiq/react-components",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -28,10 +28,10 @@
28
28
  "@koobiq/design-tokens": "^3.14.0",
29
29
  "@types/react-transition-group": "^4.4.12",
30
30
  "react-transition-group": "^4.4.5",
31
- "@koobiq/react-core": "0.10.0",
32
- "@koobiq/logger": "0.10.0",
33
- "@koobiq/react-icons": "0.10.0",
34
- "@koobiq/react-primitives": "0.10.0"
31
+ "@koobiq/react-core": "0.11.1",
32
+ "@koobiq/logger": "0.11.1",
33
+ "@koobiq/react-primitives": "0.11.1",
34
+ "@koobiq/react-icons": "0.11.1"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@koobiq/design-tokens": "^3.14.0",