@flikk/ui 1.0.0-beta.6 → 1.0.0-beta.8

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.
Files changed (57) hide show
  1. package/dist/components/ai/PromptInput/PromptInput.js +5 -124
  2. package/dist/components/core/Alert/Alert.js +1 -0
  3. package/dist/components/core/Alert/Alert.theme.js +3 -7
  4. package/dist/components/core/Alert/Alert.types.d.ts +2 -1
  5. package/dist/components/core/Badge/Badge.theme.js +13 -8
  6. package/dist/components/core/Badge/Badge.types.d.ts +2 -1
  7. package/dist/components/core/Button/Button.theme.js +36 -30
  8. package/dist/components/core/Button/Button.types.d.ts +2 -1
  9. package/dist/components/core/Calendar/Calendar.theme.js +3 -3
  10. package/dist/components/core/CommandPalette/CommandPalette.theme.js +1 -1
  11. package/dist/components/core/MenuItem/MenuItem.theme.js +2 -2
  12. package/dist/components/core/OfflineIndicator/OfflineIndicator.theme.js +1 -1
  13. package/dist/components/core/Popover/PopoverContent.js +2 -0
  14. package/dist/components/core/Progress/Progress.theme.js +9 -6
  15. package/dist/components/core/Progress/Progress.types.d.ts +2 -1
  16. package/dist/components/core/Spinner/Spinner.theme.js +3 -5
  17. package/dist/components/core/Spinner/Spinner.types.d.ts +2 -1
  18. package/dist/components/data-display/KPI/KPI.theme.js +3 -4
  19. package/dist/components/data-display/KPI/KPI.types.d.ts +2 -1
  20. package/dist/components/data-display/Metric/Metric.theme.js +4 -0
  21. package/dist/components/data-display/Metric/Metric.types.d.ts +2 -1
  22. package/dist/components/data-display/Table/TableFilter.js +1 -1
  23. package/dist/components/data-display/Timeline/Timeline.theme.js +2 -2
  24. package/dist/components/effects/CustomCursor/CustomCursor.theme.js +2 -0
  25. package/dist/components/effects/CustomCursor/CustomCursor.types.d.ts +2 -1
  26. package/dist/components/forms/Checkbox/Checkbox.d.ts +3 -4
  27. package/dist/components/forms/Checkbox/Checkbox.js +33 -9
  28. package/dist/components/forms/Checkbox/Checkbox.theme.js +6 -0
  29. package/dist/components/forms/Checkbox/Checkbox.types.d.ts +28 -2
  30. package/dist/components/forms/Checkbox/CheckboxContext.d.ts +14 -0
  31. package/dist/components/forms/Checkbox/CheckboxContext.js +12 -0
  32. package/dist/components/forms/Checkbox/CheckboxGroup.d.ts +3 -0
  33. package/dist/components/forms/Checkbox/CheckboxGroup.js +40 -0
  34. package/dist/components/forms/Checkbox/index.d.ts +1 -1
  35. package/dist/components/forms/FileUpload/FileUpload.js +0 -78
  36. package/dist/components/forms/Radio/Radio.d.ts +3 -4
  37. package/dist/components/forms/Radio/Radio.js +21 -4
  38. package/dist/components/forms/Radio/Radio.theme.js +6 -0
  39. package/dist/components/forms/Radio/Radio.types.d.ts +30 -4
  40. package/dist/components/forms/Radio/RadioContext.d.ts +14 -0
  41. package/dist/components/forms/Radio/RadioContext.js +12 -0
  42. package/dist/components/forms/Radio/RadioGroup.d.ts +3 -0
  43. package/dist/components/forms/Radio/RadioGroup.js +36 -0
  44. package/dist/components/forms/Radio/index.d.ts +1 -1
  45. package/dist/components/forms/TimePicker/TimePickerContent.js +1 -78
  46. package/dist/components/forms/index.d.ts +2 -2
  47. package/dist/components/forms/index.js +0 -78
  48. package/dist/components/layout/FormLayout/FormLayoutBody.js +1 -79
  49. package/dist/hooks/useSelectPortal.d.ts +3 -2
  50. package/dist/hooks/useSelectPortal.js +44 -19
  51. package/dist/index.js +191 -197
  52. package/dist/styles.css +1 -1
  53. package/dist/utils/colorUtils.d.ts +23 -0
  54. package/dist/utils/colorUtils.js +45 -0
  55. package/dist/utils/index.d.ts +1 -0
  56. package/package.json +1 -1
  57. package/src/styles/theme.css +29 -0
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
+ import { SemanticColor } from '../../../utils/colorUtils';
2
3
  export type MetricSize = 'sm' | 'md' | 'lg';
3
- export type MetricColor = 'neutral' | 'primary' | 'success' | 'warning' | 'danger';
4
+ export type MetricColor = SemanticColor;
4
5
  export type MetricVariant = 'filled' | 'glass';
5
6
  export type TrendDirection = 'up' | 'down';
6
7
  export interface MetricProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -206,7 +206,7 @@ function TableFilter({ columns, filterConfig, onFilterChange, filterLogic: contr
206
206
  return true;
207
207
  return f.value != null && f.value !== "";
208
208
  }).length;
209
- return (jsxs(Popover, { placement: "bottom-end", offset: 8, closeOnClickOutside: false, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "outline", "aria-label": "Filter table data", size: "sm", children: [jsx(FunnelIcon, { className: "size-4", "aria-hidden": "true" }), "Filters", appliedFilterCount > 0 && (jsx("span", { className: "ml-1 inline-flex items-center justify-center size-5 rounded-full bg-[var(--color-primary)] text-white text-xs font-medium", children: appliedFilterCount }))] }) }), jsx(Popover.Content, { className: "p-0 max-w-none", children: jsxs("div", { className: cn("w-[500px] p-3", className), role: "dialog", "aria-labelledby": "table-filter-title", "aria-modal": "true", children: [jsxs("div", { className: "flex items-center justify-between mb-3", children: [jsx("div", { id: "table-filter-title", className: "text-xs uppercase font-bold text-[var(--color-text-placeholder)]", children: "Filters" }), activeFilters.length > 1 && (jsxs("div", { className: "flex items-center gap-0.5 rounded-md bg-[var(--color-background-secondary)] p-0.5", children: [jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-xs font-medium rounded transition-colors", filterLogic === "and"
209
+ return (jsxs(Popover, { placement: "bottom-end", offset: 8, closeOnClickOutside: false, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "outline", "aria-label": "Filter table data", size: "sm", children: [jsx(FunnelIcon, { className: "size-4", "aria-hidden": "true" }), "Filters", appliedFilterCount > 0 && (jsx("span", { className: "ml-1 inline-flex items-center justify-center size-5 rounded-full bg-[var(--color-primary)] text-[var(--color-primary-contrast)] text-xs font-medium", children: appliedFilterCount }))] }) }), jsx(Popover.Content, { className: "p-0 max-w-none", children: jsxs("div", { className: cn("w-[500px] p-3", className), role: "dialog", "aria-labelledby": "table-filter-title", "aria-modal": "true", children: [jsxs("div", { className: "flex items-center justify-between mb-3", children: [jsx("div", { id: "table-filter-title", className: "text-xs uppercase font-bold text-[var(--color-text-placeholder)]", children: "Filters" }), activeFilters.length > 1 && (jsxs("div", { className: "flex items-center gap-0.5 rounded-md bg-[var(--color-background-secondary)] p-0.5", children: [jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-xs font-medium rounded transition-colors", filterLogic === "and"
210
210
  ? "bg-[var(--color-background)] text-[var(--color-text-primary)] shadow-sm"
211
211
  : "text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"), onClick: () => handleSetLogic("and"), children: "AND" }), jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-xs font-medium rounded transition-colors", filterLogic === "or"
212
212
  ? "bg-[var(--color-background)] text-[var(--color-text-primary)] shadow-sm"
@@ -19,8 +19,8 @@ const timelineTheme = {
19
19
  markerStyle: "relative z-10 flex items-center justify-center shrink-0 rounded-full border-2 transition-colors duration-200",
20
20
  // Marker status-specific styles
21
21
  markerStatuses: {
22
- completed: "w-8 h-8 bg-[var(--color-success)] border-[var(--color-success)] text-white",
23
- active: "w-8 h-8 bg-[var(--color-primary)] border-[var(--color-primary)] text-white ring-4 ring-[var(--color-primary-100)]",
22
+ completed: "w-8 h-8 bg-[var(--color-success)] border-[var(--color-success)] text-[var(--color-success-contrast)]",
23
+ active: "w-8 h-8 bg-[var(--color-primary)] border-[var(--color-primary)] text-[var(--color-primary-contrast)] ring-4 ring-[var(--color-primary-100)]",
24
24
  pending: "w-8 h-8 bg-[var(--color-background)] border-[var(--color-border)]",
25
25
  },
26
26
  // Content area - vertical
@@ -13,6 +13,7 @@ const customCursorTheme = {
13
13
  neutral: "bg-[var(--color-background-secondary)]",
14
14
  dark: "bg-[var(--color-text-primary)]",
15
15
  primary: "bg-[var(--color-primary)]",
16
+ secondary: "bg-[var(--color-secondary)]",
16
17
  success: "bg-[var(--color-success)]",
17
18
  warning: "bg-[var(--color-warning)]",
18
19
  danger: "bg-[var(--color-danger)]",
@@ -26,6 +27,7 @@ const customCursorTheme = {
26
27
  neutral: "text-[var(--color-background-secondary)]",
27
28
  dark: "text-[var(--color-text-primary)]",
28
29
  primary: "text-[var(--color-primary)]",
30
+ secondary: "text-[var(--color-secondary)]",
29
31
  success: "text-[var(--color-success)]",
30
32
  warning: "text-[var(--color-warning)]",
31
33
  danger: "text-[var(--color-danger)]",
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import type { SpringOptions } from 'motion/react';
3
+ import { SemanticColor } from '../../../utils/colorUtils';
3
4
  /**
4
5
  * Alignment positions for CustomCursorFollow relative to the main cursor
5
6
  */
@@ -11,7 +12,7 @@ export type CustomCursorSize = 'sm' | 'md' | 'lg';
11
12
  /**
12
13
  * Color variants for the custom cursor
13
14
  */
14
- export type CustomCursorColor = 'neutral' | 'dark' | 'primary' | 'success' | 'warning' | 'danger';
15
+ export type CustomCursorColor = SemanticColor | 'dark';
15
16
  /**
16
17
  * Visual variants for the custom cursor
17
18
  */
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import { CheckboxProps } from "./Checkbox.types";
3
- /**
4
- * Checkbox component for selecting one or more options
5
- */
6
- export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
3
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>> & {
4
+ Group: React.ForwardRefExoticComponent<import("./Checkbox.types").CheckboxGroupProps & React.RefAttributes<HTMLFieldSetElement>>;
5
+ };
@@ -1,31 +1,52 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React__default, { useState, useRef, useEffect } from 'react';
2
+ import React__default, { useId, useState, useRef, useEffect } from 'react';
3
3
  import { checkboxTheme } from './Checkbox.theme.js';
4
4
  import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
5
5
  import { MinusIcon, CheckIcon } from '@heroicons/react/24/outline';
6
6
  import { cn } from '../../../utils/cn.js';
7
+ import { useCheckboxGroupContext } from './CheckboxContext.js';
8
+ import { CheckboxGroup } from './CheckboxGroup.js';
7
9
 
8
10
  /**
9
11
  * Checkbox component for selecting one or more options
10
12
  */
11
- const Checkbox = React__default.forwardRef(({ id, name, value, checked: controlledChecked, indeterminate = false, onChange, label, description, state = "default", size = "md", className, ...restProps }, ref) => {
13
+ const CheckboxComponent = React__default.forwardRef(({ id: idProp, name: nameProp, value, checked: controlledChecked, indeterminate = false, onChange, label, description, state: stateProp = "default", size: sizeProp = "md", className, ...restProps }, ref) => {
14
+ var _a, _b, _c, _d;
15
+ const autoId = useId();
16
+ const groupContext = useCheckboxGroupContext();
17
+ // Resolve props from group context or individual props
18
+ const id = idProp !== null && idProp !== void 0 ? idProp : autoId;
19
+ const name = (_b = (_a = groupContext === null || groupContext === void 0 ? void 0 : groupContext.name) !== null && _a !== void 0 ? _a : nameProp) !== null && _b !== void 0 ? _b : autoId;
20
+ const size = (_c = groupContext === null || groupContext === void 0 ? void 0 : groupContext.size) !== null && _c !== void 0 ? _c : sizeProp;
21
+ const state = stateProp === "disabled" ? "disabled" : ((_d = groupContext === null || groupContext === void 0 ? void 0 : groupContext.state) !== null && _d !== void 0 ? _d : stateProp);
22
+ const isDisabled = state === "disabled";
23
+ // Determine checked state
24
+ const isInGroup = groupContext !== undefined;
12
25
  const [internalChecked, setInternalChecked] = useState(false);
26
+ let isChecked;
27
+ if (isInGroup) {
28
+ isChecked = groupContext.value.includes(value);
29
+ }
30
+ else if (controlledChecked !== undefined) {
31
+ isChecked = controlledChecked;
32
+ }
33
+ else {
34
+ isChecked = internalChecked;
35
+ }
13
36
  const inputRef = useRef(null);
14
- // Determine if component is controlled or uncontrolled
15
- const isControlled = controlledChecked !== undefined;
16
- const isChecked = isControlled ? controlledChecked : internalChecked;
17
37
  // Set indeterminate property on the input element
18
38
  useEffect(() => {
19
39
  if (inputRef.current) {
20
40
  inputRef.current.indeterminate = indeterminate;
21
41
  }
22
42
  }, [indeterminate]);
23
- // Derive state flags
24
- const isDisabled = state === "disabled";
25
43
  const handleChange = (e) => {
26
44
  if (isDisabled)
27
45
  return;
28
- if (!isControlled) {
46
+ if (isInGroup) {
47
+ groupContext.onChange(value, e.target.checked);
48
+ }
49
+ else if (controlledChecked === undefined) {
29
50
  setInternalChecked(e.target.checked);
30
51
  }
31
52
  onChange === null || onChange === void 0 ? void 0 : onChange(e.target.checked, value);
@@ -38,6 +59,9 @@ const Checkbox = React__default.forwardRef(({ id, name, value, checked: controll
38
59
  ref.current = node;
39
60
  }, type: "checkbox", id: id, name: name, value: value, checked: isChecked, onChange: handleChange, disabled: isDisabled, "aria-describedby": description ? `${id}-description` : undefined, "data-state": isDisabled ? "disabled" : "default", className: cn(checkboxTheme.inputStyle, checkboxTheme.sizes[size], indeterminate && "bg-neutral-200") }), indeterminate && (jsx(MinusIcon, { className: cn("pointer-events-none col-start-1 row-start-1 self-center justify-self-center opacity-100 stroke-neutral-600 transition-opacity duration-200", size === "sm" ? "size-3" : "size-4"), strokeWidth: 3 })), isChecked && !indeterminate && (jsx(CheckIcon, { className: cn("pointer-events-none col-start-1 row-start-1 self-center justify-self-center opacity-100 stroke-white transition-opacity duration-200", size === "sm" ? "size-3" : "size-4"), strokeWidth: 3 }))] }), (label || description) && (jsxs("label", { htmlFor: id, className: cn("cursor-pointer", isDisabled && "cursor-not-allowed"), children: [label && (jsx("span", { className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[state], "mb-0"), children: label })), description && (jsx("div", { id: `${id}-description`, className: checkboxTheme.descriptionStyle, children: description }))] }))] }));
40
61
  });
41
- Checkbox.displayName = "Checkbox";
62
+ CheckboxComponent.displayName = "Checkbox";
63
+ const Checkbox = Object.assign(CheckboxComponent, {
64
+ Group: CheckboxGroup,
65
+ });
42
66
 
43
67
  export { Checkbox };
@@ -35,6 +35,12 @@ const checkboxTheme = {
35
35
  sm: "size-5 mt-0.25",
36
36
  md: "size-6",
37
37
  },
38
+ // Group styles
39
+ groupStyle: "flex flex-col gap-1.5",
40
+ groupHorizontalStyle: "flex-row flex-wrap gap-x-6 gap-y-3",
41
+ groupDescriptionStyle: "text-sm text-[var(--color-text-secondary)]/80 -mt-0.5 mb-1",
42
+ groupErrorStyle: "text-sm text-[var(--color-danger)] mt-1.5",
43
+ groupItemsStyle: "flex flex-col gap-3",
38
44
  };
39
45
 
40
46
  export { checkboxTheme };
@@ -7,12 +7,16 @@ export type CheckboxState = 'default' | 'disabled';
7
7
  * Size variants for the checkbox component
8
8
  */
9
9
  export type CheckboxSize = 'sm' | 'md';
10
+ /**
11
+ * Orientation for Checkbox.Group layout
12
+ */
13
+ export type CheckboxGroupOrientation = 'vertical' | 'horizontal';
10
14
  /**
11
15
  * Checkbox component props
12
16
  */
13
17
  export interface CheckboxProps extends Omit<React.HTMLAttributes<HTMLInputElement>, 'onChange' | 'size'> {
14
- id: string;
15
- name: string;
18
+ id?: string;
19
+ name?: string;
16
20
  value: string;
17
21
  checked?: boolean;
18
22
  indeterminate?: boolean;
@@ -23,6 +27,23 @@ export interface CheckboxProps extends Omit<React.HTMLAttributes<HTMLInputElemen
23
27
  size?: CheckboxSize;
24
28
  className?: string;
25
29
  }
30
+ /**
31
+ * Checkbox.Group component props
32
+ */
33
+ export interface CheckboxGroupProps extends Omit<React.HTMLAttributes<HTMLFieldSetElement>, 'onChange'> {
34
+ value?: string[];
35
+ defaultValue?: string[];
36
+ onChange?: (value: string[]) => void;
37
+ name?: string;
38
+ size?: CheckboxSize;
39
+ state?: CheckboxState;
40
+ orientation?: CheckboxGroupOrientation;
41
+ label?: string;
42
+ description?: string;
43
+ error?: string;
44
+ required?: boolean;
45
+ className?: string;
46
+ }
26
47
  /**
27
48
  * Checkbox theme configuration
28
49
  */
@@ -32,4 +53,9 @@ export interface CheckboxTheme {
32
53
  inputStyle: string;
33
54
  descriptionStyle: string;
34
55
  sizes: Record<CheckboxSize, string>;
56
+ groupStyle?: string;
57
+ groupHorizontalStyle?: string;
58
+ groupDescriptionStyle?: string;
59
+ groupErrorStyle?: string;
60
+ groupItemsStyle?: string;
35
61
  }
@@ -0,0 +1,14 @@
1
+ import type { CheckboxSize, CheckboxState } from "./Checkbox.types";
2
+ export interface CheckboxGroupContextValue {
3
+ name: string;
4
+ value: string[];
5
+ onChange: (itemValue: string, checked: boolean) => void;
6
+ size: CheckboxSize;
7
+ state: CheckboxState;
8
+ }
9
+ export declare const CheckboxGroupContext: import("react").Context<CheckboxGroupContextValue | undefined>;
10
+ /**
11
+ * Returns the group context, or undefined when used outside a Checkbox.Group.
12
+ * This allows standalone Checkbox usage without a Group wrapper.
13
+ */
14
+ export declare function useCheckboxGroupContext(): CheckboxGroupContextValue | undefined;
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ const CheckboxGroupContext = createContext(undefined);
4
+ /**
5
+ * Returns the group context, or undefined when used outside a Checkbox.Group.
6
+ * This allows standalone Checkbox usage without a Group wrapper.
7
+ */
8
+ function useCheckboxGroupContext() {
9
+ return useContext(CheckboxGroupContext);
10
+ }
11
+
12
+ export { CheckboxGroupContext, useCheckboxGroupContext };
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import type { CheckboxGroupProps } from "./Checkbox.types";
3
+ export declare const CheckboxGroup: React.ForwardRefExoticComponent<CheckboxGroupProps & React.RefAttributes<HTMLFieldSetElement>>;
@@ -0,0 +1,40 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import React__default, { useId, useState, useMemo } from 'react';
3
+ import { cn } from '../../../utils/cn.js';
4
+ import { checkboxTheme } from './Checkbox.theme.js';
5
+ import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
6
+ import { CheckboxGroupContext } from './CheckboxContext.js';
7
+
8
+ const CheckboxGroup = React__default.forwardRef(({ value: controlledValue, defaultValue, onChange, name, size = "md", state = "default", orientation = "vertical", label, description, error, required, className, children, ...props }, ref) => {
9
+ const autoId = useId();
10
+ const groupName = name !== null && name !== void 0 ? name : `checkbox-group-${autoId}`;
11
+ const labelId = `${autoId}-label`;
12
+ const descriptionId = `${autoId}-desc`;
13
+ const errorId = `${autoId}-error`;
14
+ // Controlled vs uncontrolled
15
+ const isControlled = controlledValue !== undefined;
16
+ const [internalValue, setInternalValue] = useState(defaultValue !== null && defaultValue !== void 0 ? defaultValue : []);
17
+ const currentValue = isControlled ? controlledValue : internalValue;
18
+ const handleChange = (itemValue, checked) => {
19
+ const next = checked
20
+ ? [...currentValue, itemValue]
21
+ : currentValue.filter((v) => v !== itemValue);
22
+ if (!isControlled) {
23
+ setInternalValue(next);
24
+ }
25
+ onChange === null || onChange === void 0 ? void 0 : onChange(next);
26
+ };
27
+ const contextValue = useMemo(() => ({
28
+ name: groupName,
29
+ value: currentValue,
30
+ onChange: handleChange,
31
+ size,
32
+ state,
33
+ }), [groupName, currentValue, size, state]);
34
+ const labelState = error ? "invalid" : state === "disabled" ? "disabled" : "default";
35
+ return (jsx(CheckboxGroupContext.Provider, { value: contextValue, children: jsxs("fieldset", { ref: ref, role: "group", "aria-labelledby": label ? labelId : undefined, "aria-describedby": description ? descriptionId : undefined, "aria-required": required || undefined, "aria-invalid": error ? true : undefined, "aria-errormessage": error ? errorId : undefined, className: cn("border-0 p-0 m-0", checkboxTheme.groupStyle, className), ...props, children: [label && (jsxs("legend", { id: labelId, className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[labelState]), children: [label, required && (jsx("span", { className: formLabelTheme.requiredIndicatorStyle, children: "*" }))] })), description && (jsx("p", { id: descriptionId, className: checkboxTheme.groupDescriptionStyle, children: description })), jsx("div", { className: cn(checkboxTheme.groupItemsStyle, orientation === "horizontal" &&
36
+ checkboxTheme.groupHorizontalStyle), children: children }), error && (jsx("p", { id: errorId, role: "alert", className: checkboxTheme.groupErrorStyle, children: error }))] }) }));
37
+ });
38
+ CheckboxGroup.displayName = "Checkbox.Group";
39
+
40
+ export { CheckboxGroup };
@@ -1,3 +1,3 @@
1
1
  export { Checkbox } from './Checkbox';
2
- export type { CheckboxProps, CheckboxSize, CheckboxState } from './Checkbox.types';
2
+ export type { CheckboxProps, CheckboxSize, CheckboxState, CheckboxGroupProps, CheckboxGroupOrientation } from './Checkbox.types';
3
3
  export { checkboxTheme } from './Checkbox.theme';
@@ -3,85 +3,7 @@ import React__default, { useMemo, useRef, useState, useCallback } from 'react';
3
3
  import { fileUploadTheme } from './FileUpload.theme.js';
4
4
  import { cn } from '../../../utils/cn.js';
5
5
  import { CloudArrowUpIcon, DocumentIcon, XMarkIcon } from '@heroicons/react/24/outline';
6
- import '../../core/Accordion/Accordion.js';
7
- import '../../core/AlertDialog/AlertDialog.js';
8
- import '../../core/AspectRatio/AspectRatio.js';
9
- import '../../core/Avatar/Avatar.js';
10
- import '../../core/AvatarGroup/AvatarGroup.js';
11
- import '../../core/Badge/Badge.js';
12
- import '../../core/Breadcrumbs/Breadcrumbs.js';
13
- import '../../core/Breadcrumbs/Breadcrumbs.theme.js';
14
6
  import { Button } from '../../core/Button/Button.js';
15
- import '../../core/ButtonGroup/ButtonGroup.js';
16
- import '../../core/ButtonGroup/ButtonGroupSeparator.js';
17
- import '../../core/ButtonGroup/ButtonGroupText.js';
18
- import '../../core/Calendar/Calendar.js';
19
- import '../../core/Calendar/CalendarMini/CalendarMini.js';
20
- import '../../core/Card/Card.js';
21
- import '../../core/CardStack/CardStack.js';
22
- import '../../core/Carousel/Carousel.js';
23
- import '../../core/CommandPalette/CommandPalette.js';
24
- import '../../core/Separator/Separator.js';
25
- import '../../core/Drawer/Drawer.js';
26
- import '../../core/Dropdown/Dropdown.js';
27
- import '../../core/Dropdown/DropdownTrigger.js';
28
- import '../../core/Dropdown/DropdownMenu.js';
29
- import '../../core/Dropdown/DropdownItem.js';
30
- import '../../core/Dropdown/DropdownSection.js';
31
- import '../../core/Dropdown/DropdownSeparator.js';
32
- import '../../core/Dropdown/Dropdown.theme.js';
33
- import '../../core/Kbd/Kbd.js';
34
- import '../../core/MenuItem/MenuItem.js';
35
- import '../../core/Link/Link.js';
36
- import '../../core/Loader/Loader.js';
37
- import '../../core/Modal/Modal.js';
38
- import '../../core/ModalStack/ModalStack.js';
39
- import '../../core/PageHeading/PageHeading.js';
40
- import '../../core/Pagination/Pagination.js';
41
- import '../../core/Popover/Popover.js';
42
- import '../../core/Popover/PopoverContext.js';
43
- import '../../core/Progress/Progress.js';
44
- import '../../core/Rating/Rating.js';
45
- import '../../core/ScrollArea/ScrollArea.js';
46
- import '../../core/ScrollArea/smooth/SmoothScrollEngine.js';
47
- import '../../core/Segmented/Segmented.js';
48
- import '../../core/Skeleton/Skeleton.js';
49
- import '../../core/SlidingNumber/SlidingNumber.js';
50
- import '../../core/Tabs/Tabs.js';
51
- import '../../core/Tabs/TabsList.js';
52
- import '../../core/Tabs/TabsTrigger.js';
53
- import '../../core/Tabs/TabsContent.js';
54
- import '../../core/Tabs/TabsContext.js';
55
- import '../../core/Tooltip/Tooltip.js';
56
- import '../../core/Tooltip/Tooltip.animations.js';
57
- import '../../core/Tree/Tree.js';
58
- import '../../core/Tag/Tag.js';
59
- import '../../core/Alert/Alert.js';
60
- import '../../core/Toast/Toast.js';
61
- import '../../core/Toast/ToastProvider.js';
62
- import '@heroicons/react/24/solid';
63
- import '../../core/Spinner/Spinner.js';
64
- import '../../core/Message/Message.js';
65
- import '../../core/Message/TypeWriter.js';
66
- import '../../core/Empty/Empty.js';
67
- import '../../core/Masonry/Masonry.js';
68
- import '../../core/DragDrop/DragDrop.js';
69
- import '../../core/Sortable/Sortable.js';
70
- import '../../core/NavItem/NavItem.js';
71
- import '../../core/Sidebar/Sidebar.js';
72
- import '../../core/Sidebar/SidebarHeader.js';
73
- import '../../core/Sidebar/SidebarContent.js';
74
- import '../../core/Sidebar/SidebarFooter.js';
75
- import '../../core/Sidebar/SidebarNav.js';
76
- import '../../core/Sidebar/SidebarNavGroup.js';
77
- import 'motion/react';
78
- import '../../core/Sidebar/SidebarToggle.js';
79
- import '../../core/Sidebar/SidebarContext.js';
80
- import '../../core/OfflineIndicator/OfflineIndicator.js';
81
- import '../../core/ContextMenu/ContextMenu.js';
82
- import '../../core/ContextMenu/ContextMenu.theme.js';
83
- import '../../core/Pill/Pill.js';
84
- import '../../core/SocialIcon/SocialIcon.js';
85
7
 
86
8
  /**
87
9
  * FileUpload component - Drag-and-drop file uploader with previews
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import { RadioProps } from "./Radio.types";
3
- /**
4
- * Radio component for selecting one option from a group
5
- */
6
- export declare const Radio: React.ForwardRefExoticComponent<RadioProps & React.RefAttributes<HTMLInputElement>>;
3
+ export declare const Radio: React.ForwardRefExoticComponent<RadioProps & React.RefAttributes<HTMLInputElement>> & {
4
+ Group: React.ForwardRefExoticComponent<import("./Radio.types").RadioGroupProps & React.RefAttributes<HTMLFieldSetElement>>;
5
+ };
@@ -1,18 +1,34 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React__default from 'react';
2
+ import React__default, { useId } from 'react';
3
3
  import { radioTheme } from './Radio.theme.js';
4
4
  import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
5
5
  import { cn } from '../../../utils/cn.js';
6
+ import { useRadioGroupContext } from './RadioContext.js';
7
+ import { RadioGroup } from './RadioGroup.js';
6
8
 
7
9
  /**
8
10
  * Radio component for selecting one option from a group
9
11
  */
10
- const Radio = React__default.forwardRef(({ id, name, value, checked, defaultChecked, onChange, label, description, state = "default", size = "md", className, ...restProps }, ref) => {
11
- const isControlled = checked !== undefined;
12
+ const RadioComponent = React__default.forwardRef(({ id: idProp, name: nameProp, value, checked: checkedProp, defaultChecked, onChange, label, description, state: stateProp = "default", size: sizeProp = "md", className, ...restProps }, ref) => {
13
+ var _a, _b, _c, _d;
14
+ const autoId = useId();
15
+ const groupContext = useRadioGroupContext();
16
+ // Resolve props from group context or individual props
17
+ const id = idProp !== null && idProp !== void 0 ? idProp : autoId;
18
+ const name = (_b = (_a = groupContext === null || groupContext === void 0 ? void 0 : groupContext.name) !== null && _a !== void 0 ? _a : nameProp) !== null && _b !== void 0 ? _b : autoId;
19
+ const size = (_c = groupContext === null || groupContext === void 0 ? void 0 : groupContext.size) !== null && _c !== void 0 ? _c : sizeProp;
20
+ const state = stateProp === "disabled" ? "disabled" : ((_d = groupContext === null || groupContext === void 0 ? void 0 : groupContext.state) !== null && _d !== void 0 ? _d : stateProp);
12
21
  const isDisabled = state === "disabled";
22
+ // Determine checked state
23
+ const isInGroup = groupContext !== undefined;
24
+ const checked = isInGroup ? groupContext.value === value : checkedProp;
25
+ const isControlled = checked !== undefined;
13
26
  const handleChange = (e) => {
14
27
  if (isDisabled)
15
28
  return;
29
+ if (isInGroup) {
30
+ groupContext.onChange(value);
31
+ }
16
32
  onChange === null || onChange === void 0 ? void 0 : onChange(e.target.checked, value);
17
33
  };
18
34
  const inputProps = isControlled
@@ -20,6 +36,7 @@ const Radio = React__default.forwardRef(({ id, name, value, checked, defaultChec
20
36
  : { defaultChecked };
21
37
  return (jsxs("div", { className: cn(radioTheme.baseStyle, className), ...restProps, children: [jsxs("div", { className: cn(radioTheme.inputContainerStyle, radioTheme.sizes[size]), children: [jsx("input", { ref: ref, type: "radio", id: id, name: name, value: value, ...inputProps, onChange: handleChange, disabled: isDisabled, "aria-describedby": description ? `${id}-description` : undefined, "data-state": isDisabled ? "disabled" : "default", className: cn("peer", radioTheme.inputStyle, radioTheme.sizes[size]) }), jsx("div", { className: cn(radioTheme.dotStyle, size === "sm" ? "size-2.5 top-0.25" : "size-3") })] }), (label || description) && (jsxs("label", { htmlFor: id, className: cn("cursor-pointer", isDisabled && "cursor-not-allowed"), children: [label && (jsx("span", { className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[state], "mb-0"), children: label })), description && (jsx("div", { id: `${id}-description`, className: radioTheme.descriptionStyle, children: description }))] }))] }));
22
38
  });
23
- Radio.displayName = "Radio";
39
+ RadioComponent.displayName = "Radio";
40
+ const Radio = Object.assign(RadioComponent, { Group: RadioGroup });
24
41
 
25
42
  export { Radio };
@@ -34,6 +34,12 @@ const radioTheme = {
34
34
  sm: "size-5 mt-0.25",
35
35
  md: "size-6",
36
36
  },
37
+ // Group styles
38
+ groupStyle: "flex flex-col gap-1.5",
39
+ groupHorizontalStyle: "flex-row flex-wrap gap-x-6 gap-y-3",
40
+ groupDescriptionStyle: "text-sm text-[var(--color-text-secondary)]/80 -mt-0.5 mb-1",
41
+ groupErrorStyle: "text-sm text-[var(--color-danger)] mt-1.5",
42
+ groupItemsStyle: "flex flex-col gap-3",
37
43
  };
38
44
 
39
45
  export { radioTheme };
@@ -7,21 +7,42 @@ export type RadioState = 'default' | 'disabled';
7
7
  * Size variants for the radio component
8
8
  */
9
9
  export type RadioSize = 'sm' | 'md';
10
+ /**
11
+ * Orientation for Radio.Group layout
12
+ */
13
+ export type RadioGroupOrientation = 'vertical' | 'horizontal';
10
14
  /**
11
15
  * Radio component props
12
16
  */
13
17
  export interface RadioProps extends Omit<React.HTMLAttributes<HTMLInputElement>, 'onChange' | 'size'> {
14
- id: string;
15
- name: string;
16
- value: string;
18
+ id?: string;
19
+ name?: string;
20
+ value: string | number;
17
21
  checked?: boolean;
18
- onChange?: (checked: boolean, value: string) => void;
22
+ onChange?: (checked: boolean, value: string | number) => void;
19
23
  label?: string;
20
24
  description?: string;
21
25
  state?: RadioState;
22
26
  size?: RadioSize;
23
27
  className?: string;
24
28
  }
29
+ /**
30
+ * Radio.Group component props
31
+ */
32
+ export interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLFieldSetElement>, 'onChange'> {
33
+ value?: string | number;
34
+ defaultValue?: string | number;
35
+ onChange?: (value: string | number) => void;
36
+ name?: string;
37
+ size?: RadioSize;
38
+ state?: RadioState;
39
+ orientation?: RadioGroupOrientation;
40
+ label?: string;
41
+ description?: string;
42
+ error?: string;
43
+ required?: boolean;
44
+ className?: string;
45
+ }
25
46
  /**
26
47
  * Radio theme configuration
27
48
  */
@@ -32,4 +53,9 @@ export interface RadioTheme {
32
53
  dotStyle: string;
33
54
  descriptionStyle: string;
34
55
  sizes: Record<RadioSize, string>;
56
+ groupStyle?: string;
57
+ groupHorizontalStyle?: string;
58
+ groupDescriptionStyle?: string;
59
+ groupErrorStyle?: string;
60
+ groupItemsStyle?: string;
35
61
  }
@@ -0,0 +1,14 @@
1
+ import type { RadioSize, RadioState } from "./Radio.types";
2
+ export interface RadioGroupContextValue {
3
+ name: string;
4
+ value: string | number | undefined;
5
+ onChange: (value: string | number) => void;
6
+ size: RadioSize;
7
+ state: RadioState;
8
+ }
9
+ export declare const RadioGroupContext: import("react").Context<RadioGroupContextValue | undefined>;
10
+ /**
11
+ * Returns the group context, or undefined when used outside a Radio.Group.
12
+ * This allows standalone Radio usage without a Group wrapper.
13
+ */
14
+ export declare function useRadioGroupContext(): RadioGroupContextValue | undefined;
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ const RadioGroupContext = createContext(undefined);
4
+ /**
5
+ * Returns the group context, or undefined when used outside a Radio.Group.
6
+ * This allows standalone Radio usage without a Group wrapper.
7
+ */
8
+ function useRadioGroupContext() {
9
+ return useContext(RadioGroupContext);
10
+ }
11
+
12
+ export { RadioGroupContext, useRadioGroupContext };
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import type { RadioGroupProps } from "./Radio.types";
3
+ export declare const RadioGroup: React.ForwardRefExoticComponent<RadioGroupProps & React.RefAttributes<HTMLFieldSetElement>>;
@@ -0,0 +1,36 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import React__default, { useId, useState, useMemo } from 'react';
3
+ import { cn } from '../../../utils/cn.js';
4
+ import { radioTheme } from './Radio.theme.js';
5
+ import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
6
+ import { RadioGroupContext } from './RadioContext.js';
7
+
8
+ const RadioGroup = React__default.forwardRef(({ value: controlledValue, defaultValue, onChange, name, size = "md", state = "default", orientation = "vertical", label, description, error, required, className, children, ...props }, ref) => {
9
+ const autoId = useId();
10
+ const groupName = name !== null && name !== void 0 ? name : `radio-group-${autoId}`;
11
+ const labelId = `${autoId}-label`;
12
+ const descriptionId = `${autoId}-desc`;
13
+ const errorId = `${autoId}-error`;
14
+ // Controlled vs uncontrolled
15
+ const isControlled = controlledValue !== undefined;
16
+ const [internalValue, setInternalValue] = useState(defaultValue);
17
+ const currentValue = isControlled ? controlledValue : internalValue;
18
+ const handleChange = (itemValue) => {
19
+ if (!isControlled) {
20
+ setInternalValue(itemValue);
21
+ }
22
+ onChange === null || onChange === void 0 ? void 0 : onChange(itemValue);
23
+ };
24
+ const contextValue = useMemo(() => ({
25
+ name: groupName,
26
+ value: currentValue,
27
+ onChange: handleChange,
28
+ size,
29
+ state,
30
+ }), [groupName, currentValue, size, state]);
31
+ const labelState = error ? "invalid" : state === "disabled" ? "disabled" : "default";
32
+ return (jsx(RadioGroupContext.Provider, { value: contextValue, children: jsxs("fieldset", { ref: ref, role: "radiogroup", "aria-labelledby": label ? labelId : undefined, "aria-describedby": description ? descriptionId : undefined, "aria-required": required || undefined, "aria-invalid": error ? true : undefined, "aria-errormessage": error ? errorId : undefined, className: cn("border-0 p-0 m-0", radioTheme.groupStyle, className), ...props, children: [label && (jsxs("legend", { id: labelId, className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[labelState]), children: [label, required && (jsx("span", { className: formLabelTheme.requiredIndicatorStyle, children: "*" }))] })), description && (jsx("p", { id: descriptionId, className: radioTheme.groupDescriptionStyle, children: description })), jsx("div", { className: cn(radioTheme.groupItemsStyle, orientation === "horizontal" && radioTheme.groupHorizontalStyle), children: children }), error && (jsx("p", { id: errorId, role: "alert", className: radioTheme.groupErrorStyle, children: error }))] }) }));
33
+ });
34
+ RadioGroup.displayName = "Radio.Group";
35
+
36
+ export { RadioGroup };
@@ -1,3 +1,3 @@
1
1
  export { Radio } from './Radio';
2
- export type { RadioProps, RadioSize, RadioState } from './Radio.types';
2
+ export type { RadioProps, RadioSize, RadioState, RadioGroupProps, RadioGroupOrientation } from './Radio.types';
3
3
  export { radioTheme } from './Radio.theme';