@flikk/ui 1.0.0-beta.7 → 1.0.0-beta.9
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/components/ai/ApprovalCard/ApprovalCard.js +1 -1
- package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
- package/dist/components/ai/PromptInput/PromptInput.js +2 -2
- package/dist/components/ai/PromptInput/PromptInput.theme.js +1 -1
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +1 -1
- package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +6 -6
- package/dist/components/ai/StreamingResponse/StreamingResponse.theme.js +4 -4
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.theme.js +2 -2
- package/dist/components/ai/TokenCounter/TokenCounter.theme.js +6 -6
- package/dist/components/charts/ActivityRings/ActivityRings.js +1 -1
- package/dist/components/charts/ActivityRings/ActivityRings.theme.js +2 -2
- package/dist/components/charts/BarChart/BarChart.js +3 -3
- package/dist/components/charts/ChartContainer.js +1 -1
- package/dist/components/charts/ComboChart/ComboChart.js +2 -2
- package/dist/components/charts/DonutChart/DonutChart.theme.js +1 -1
- package/dist/components/charts/DonutChart/MultiSegmentDonutChart.js +1 -1
- package/dist/components/charts/DonutChart/MultiSegmentDonutChart.theme.js +1 -1
- package/dist/components/charts/FunnelChart/FunnelChart.js +7 -7
- package/dist/components/charts/Heatmap/Heatmap.theme.js +1 -1
- package/dist/components/charts/Heatmap/HeatmapCell.js +1 -1
- package/dist/components/charts/Heatmap/HeatmapLegend.js +1 -1
- package/dist/components/charts/RadarChart/RadarChart.theme.js +2 -2
- package/dist/components/charts/ScatterPlot/ScatterPlot.js +1 -1
- package/dist/components/charts/ScatterPlot/ScatterPlot.theme.js +2 -2
- package/dist/components/charts/StackedBarChart/StackedBarChart.js +2 -2
- package/dist/components/charts/shared/ChartErrorBoundary/ChartErrorBoundary.js +1 -1
- package/dist/components/charts/shared/ChartLegend/ChartLegendContent.js +1 -1
- package/dist/components/charts/shared/ChartText/ChartText.js +1 -1
- package/dist/components/charts/shared/ChartText/ChartText.theme.js +1 -1
- package/dist/components/charts/shared/ChartTooltip/ChartTooltip.theme.js +4 -4
- package/dist/components/core/Alert/Alert.js +1 -0
- package/dist/components/core/Alert/Alert.theme.js +4 -8
- package/dist/components/core/Alert/Alert.types.d.ts +2 -1
- package/dist/components/core/AlertDialog/AlertDialog.js +1 -1
- package/dist/components/core/Avatar/Avatar.theme.js +5 -5
- package/dist/components/core/AvatarGroup/AvatarGroup.theme.js +1 -1
- package/dist/components/core/Badge/Badge.theme.js +11 -6
- package/dist/components/core/Badge/Badge.types.d.ts +2 -1
- package/dist/components/core/Breadcrumbs/Breadcrumbs.js +1 -1
- package/dist/components/core/Button/Button.theme.js +38 -32
- package/dist/components/core/Button/Button.types.d.ts +2 -1
- package/dist/components/core/ButtonGroup/ButtonGroup.theme.js +1 -1
- package/dist/components/core/Calendar/Calendar.js +1 -1
- package/dist/components/core/Calendar/Calendar.theme.js +5 -5
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.js +1 -1
- package/dist/components/core/Card/Card.theme.js +2 -2
- package/dist/components/core/CommandPalette/CommandItem.js +1 -1
- package/dist/components/core/CommandPalette/CommandPalette.theme.js +3 -3
- package/dist/components/core/ContextMenu/ContextMenu.theme.js +3 -3
- package/dist/components/core/ContextMenu/ContextMenuItem.js +1 -1
- package/dist/components/core/Drawer/Drawer.theme.js +2 -2
- package/dist/components/core/Dropdown/Dropdown.theme.js +1 -1
- package/dist/components/core/Empty/Empty.theme.js +2 -2
- package/dist/components/core/Kbd/Kbd.theme.js +3 -3
- package/dist/components/core/Loader/Loader.theme.js +1 -1
- package/dist/components/core/MenuItem/MenuItem.theme.js +2 -2
- package/dist/components/core/Message/Message.js +1 -1
- package/dist/components/core/Message/Message.theme.js +4 -4
- package/dist/components/core/Modal/Modal.theme.js +2 -2
- package/dist/components/core/NavItem/NavItem.js +1 -1
- package/dist/components/core/NavItem/NavItem.theme.js +1 -1
- package/dist/components/core/OfflineIndicator/OfflineIndicator.theme.js +2 -2
- package/dist/components/core/PageHeading/PageHeading.theme.js +1 -1
- package/dist/components/core/Pagination/Pagination.theme.js +2 -2
- package/dist/components/core/Pill/Pill.theme.js +3 -3
- package/dist/components/core/Popover/PopoverContent.js +2 -0
- package/dist/components/core/Progress/Progress.theme.js +10 -7
- package/dist/components/core/Progress/Progress.types.d.ts +2 -1
- package/dist/components/core/Segmented/Segmented.theme.js +3 -3
- package/dist/components/core/Sidebar/SidebarNavGroup.js +1 -1
- package/dist/components/core/Spinner/Spinner.theme.js +3 -5
- package/dist/components/core/Spinner/Spinner.types.d.ts +2 -1
- package/dist/components/core/Tabs/Tabs.theme.js +2 -2
- package/dist/components/core/Tag/Tag.theme.js +2 -2
- package/dist/components/core/Toast/Toast.theme.js +4 -4
- package/dist/components/core/Tooltip/Tooltip.theme.js +1 -1
- package/dist/components/core/Tree/Tree.theme.js +1 -1
- package/dist/components/data-display/DescriptionList/DescriptionList.theme.js +2 -2
- package/dist/components/data-display/Feed/Feed.js +1 -1
- package/dist/components/data-display/Feed/Feed.theme.js +2 -2
- package/dist/components/data-display/GanttChart/GanttChart.theme.js +2 -2
- package/dist/components/data-display/GanttChart/GanttChartPanel.js +1 -1
- package/dist/components/data-display/GanttChart/GanttMilestone.js +2 -2
- package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
- package/dist/components/data-display/GanttChart/GanttTaskBar.js +2 -2
- package/dist/components/data-display/KPI/KPI.js +1 -1
- package/dist/components/data-display/KPI/KPI.theme.js +10 -11
- package/dist/components/data-display/KPI/KPI.types.d.ts +2 -1
- package/dist/components/data-display/Metric/Metric.js +1 -1
- package/dist/components/data-display/Metric/Metric.theme.js +11 -7
- package/dist/components/data-display/Metric/Metric.types.d.ts +2 -1
- package/dist/components/data-display/Table/Table.theme.js +3 -3
- package/dist/components/data-display/Table/TableActionsMenu.js +1 -1
- package/dist/components/data-display/Table/TableColumnManager.js +1 -1
- package/dist/components/data-display/Table/TableFilter.js +3 -3
- package/dist/components/data-display/Table/TableHeader.js +1 -1
- package/dist/components/data-display/Table/TablePagination.js +1 -1
- package/dist/components/data-display/Table/TableSelectionHeader.js +1 -1
- package/dist/components/effects/CustomCursor/CustomCursor.js +1 -1
- package/dist/components/effects/CustomCursor/CustomCursor.theme.js +3 -1
- package/dist/components/effects/CustomCursor/CustomCursor.types.d.ts +2 -1
- package/dist/components/effects/StickyScroll/StickyScroll.js +1 -1
- package/dist/components/forms/Checkbox/Checkbox.d.ts +3 -4
- package/dist/components/forms/Checkbox/Checkbox.js +33 -9
- package/dist/components/forms/Checkbox/Checkbox.theme.js +7 -1
- package/dist/components/forms/Checkbox/Checkbox.types.d.ts +28 -2
- package/dist/components/forms/Checkbox/CheckboxContext.d.ts +14 -0
- package/dist/components/forms/Checkbox/CheckboxContext.js +12 -0
- package/dist/components/forms/Checkbox/CheckboxGroup.d.ts +3 -0
- package/dist/components/forms/Checkbox/CheckboxGroup.js +40 -0
- package/dist/components/forms/Checkbox/index.d.ts +1 -1
- package/dist/components/forms/ColorPicker/ColorPicker.js +1 -1
- package/dist/components/forms/ColorPicker/ColorPicker.theme.js +1 -1
- package/dist/components/forms/ColorPicker/ColorPickerInput.js +7 -7
- package/dist/components/forms/CronInput/CronInput.js +1 -1
- package/dist/components/forms/CronInput/CronInput.theme.js +8 -8
- package/dist/components/forms/DatePicker/DatePicker.theme.js +1 -1
- package/dist/components/forms/DatePicker/DatePickerContent.js +1 -1
- package/dist/components/forms/FileUpload/FileUpload.js +2 -2
- package/dist/components/forms/FileUpload/FileUpload.theme.js +4 -4
- package/dist/components/forms/FormLabel/FormLabel.theme.js +1 -1
- package/dist/components/forms/Input/Input.theme.js +1 -1
- package/dist/components/forms/InputCounter/InputCounter.theme.js +1 -1
- package/dist/components/forms/InputOTP/InputOTP.theme.js +1 -1
- package/dist/components/forms/InputTag/InputTag.js +1 -1
- package/dist/components/forms/Mention/Mention.theme.js +3 -3
- package/dist/components/forms/Radio/Radio.d.ts +3 -4
- package/dist/components/forms/Radio/Radio.js +21 -4
- package/dist/components/forms/Radio/Radio.theme.js +7 -1
- package/dist/components/forms/Radio/Radio.types.d.ts +30 -4
- package/dist/components/forms/Radio/RadioContext.d.ts +14 -0
- package/dist/components/forms/Radio/RadioContext.js +12 -0
- package/dist/components/forms/Radio/RadioGroup.d.ts +3 -0
- package/dist/components/forms/Radio/RadioGroup.js +36 -0
- package/dist/components/forms/Radio/index.d.ts +1 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +2 -2
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +1 -1
- package/dist/components/forms/Select/Select.theme.js +1 -1
- package/dist/components/forms/Signature/Signature.theme.js +1 -1
- package/dist/components/forms/Slider/Slider.theme.js +3 -3
- package/dist/components/forms/Switch/Switch.theme.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
- package/dist/components/forms/TransferList/TransferList.js +2 -2
- package/dist/components/forms/TransferList/TransferList.theme.js +6 -6
- package/dist/components/forms/forms.theme.js +6 -6
- package/dist/components/forms/index.d.ts +2 -2
- package/dist/components/layout/FormLayout/FormLayout.theme.js +4 -4
- package/dist/hooks/useSelectPortal.d.ts +3 -2
- package/dist/hooks/useSelectPortal.js +44 -19
- package/dist/styles.css +1 -1
- package/dist/utils/colorUtils.d.ts +23 -0
- package/dist/utils/colorUtils.js +45 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/styles/theme.css +19 -17
|
@@ -48,7 +48,7 @@ function TableHeaderComponent({ columns, sortConfig = [], onSortChange, freezeHe
|
|
|
48
48
|
}, row: {}, rowId: "", isHeader: true, theme: theme, children: jsx("div", { className: "flex items-center gap-2", children: selectable && selectionType === 'checkbox' && (jsx(Checkbox, { id: "table-select-all", name: "table-select-all", value: "select-all", checked: isAllSelected, indeterminate: isIndeterminate, onChange: handleSelectAll, "aria-label": "Select all rows" })) }) })), columns.map((column, index) => {
|
|
49
49
|
const currentSort = sortConfig.find(sort => sort.columnId === column.id);
|
|
50
50
|
const isSortable = column.sortable && onSortChange;
|
|
51
|
-
return (jsx(TableCell, { column: column, row: {}, rowId: "header", isHeader: true, isFrozen: freezeFirstColumn && index === 0, isLastFrozen: freezeLastColumn && index === columns.length - 1, theme: theme, children: isSortable ? (jsxs("button", { onClick: () => handleSort(column.id), className: "flex items-center gap-1 w-full text-left hover:text-[var(--color-primary)] transition-colors", "aria-label": `Sort by ${typeof column.header === 'string' ? column.header : column.id}`, children: [column.header, currentSort && (jsx("span", { className: "text-
|
|
51
|
+
return (jsx(TableCell, { column: column, row: {}, rowId: "header", isHeader: true, isFrozen: freezeFirstColumn && index === 0, isLastFrozen: freezeLastColumn && index === columns.length - 1, theme: theme, children: isSortable ? (jsxs("button", { onClick: () => handleSort(column.id), className: "flex items-center gap-1 w-full text-left hover:text-[var(--color-primary)] transition-colors", "aria-label": `Sort by ${typeof column.header === 'string' ? column.header : column.id}`, children: [column.header, currentSort && (jsx("span", { className: "text-sm", children: currentSort.direction === 'asc' ? '\u2191' : '\u2193' }))] })) : (column.header) }, column.id));
|
|
52
52
|
})] }) }));
|
|
53
53
|
}
|
|
54
54
|
const TableHeader = TableHeaderComponent;
|
|
@@ -18,7 +18,7 @@ const TablePagination = React__default.forwardRef(({ currentPage, totalItems, pa
|
|
|
18
18
|
label: option.toString(),
|
|
19
19
|
value: option,
|
|
20
20
|
}));
|
|
21
|
-
return (jsxs("div", { ref: ref, className: cn("flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 px-4 py-3 border-t border-[var(--color-border)] bg-[var(--color-background)]", className), children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-
|
|
21
|
+
return (jsxs("div", { ref: ref, className: cn("flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 px-4 py-3 border-t border-[var(--color-border)] bg-[var(--color-background)]", className), children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-base text-[var(--color-text-muted)]", children: "Rows per page:" }), jsx(Select, { value: pageSize, onChange: (value) => onPageSizeChange(value), options: pageSizeSelectOptions, size: "sm", className: "w-20" })] })), jsx("div", { className: "text-base text-[var(--color-text-muted)]", children: totalItems > 0 ? (jsxs(Fragment, { children: ["Showing ", startItem.toLocaleString(), " to ", endItem.toLocaleString(), " of", " ", totalItems.toLocaleString(), " results"] })) : ("No results") })] }), totalPages > 1 && (jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange, showPrevNext: true, showFirstLast: false, siblingCount: 1 }))] }));
|
|
22
22
|
});
|
|
23
23
|
TablePagination.displayName = "Table.Pagination";
|
|
24
24
|
|
|
@@ -11,7 +11,7 @@ import 'react';
|
|
|
11
11
|
const TableSelectionHeader = ({ selectedCount, totalCount, selectedRows, bulkActions = [], onClearSelection, className, }) => {
|
|
12
12
|
if (selectedCount === 0)
|
|
13
13
|
return null;
|
|
14
|
-
return (jsxs("div", { className: cn("flex items-center justify-between px-3 py-1 rounded-lg shadow-xl bg-[var(--color-background-secondary)] z-10", className), children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-[var(--color-text-muted)] text-
|
|
14
|
+
return (jsxs("div", { className: cn("flex items-center justify-between px-3 py-1 rounded-lg shadow-xl bg-[var(--color-background-secondary)] z-10", className), children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-[var(--color-text-muted)] text-base border-r border-[var(--color-border)] pr-3", children: selectedCount === totalCount
|
|
15
15
|
? `All ${selectedCount} selected`
|
|
16
16
|
: `${selectedCount} selected` }), bulkActions.length > 0 && (jsx("div", { className: "flex items-center gap-2", children: bulkActions.map((action) => {
|
|
17
17
|
return (jsx(Button, { color: "neutral", variant: "filled", onClick: () => action.onClick(selectedRows), className: "text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]", size: "sm", children: action.label }, action.id));
|
|
@@ -312,7 +312,7 @@ const CustomCursorFollow = React.forwardRef(({ children, sideOffset = 15, align
|
|
|
312
312
|
// Determine content based on variant
|
|
313
313
|
const renderContent = () => {
|
|
314
314
|
if (variant === 'user') {
|
|
315
|
-
return (jsxs(Fragment, { children: [avatar && jsx(Avatar, { src: avatar, alt: name || 'User', size: "xs" }), name && (jsx("span", { className: "text-white text-
|
|
315
|
+
return (jsxs(Fragment, { children: [avatar && jsx(Avatar, { src: avatar, alt: name || 'User', size: "xs" }), name && (jsx("span", { className: "text-white text-sm font-medium whitespace-nowrap", children: name }))] }));
|
|
316
316
|
}
|
|
317
317
|
return children;
|
|
318
318
|
};
|
|
@@ -6,13 +6,14 @@ const customCursorTheme = {
|
|
|
6
6
|
baseStyle: "pointer-events-none z-[9999] absolute transform-[translate(-50%,-50%)]",
|
|
7
7
|
cursorStyle: "transition-transform duration-150",
|
|
8
8
|
cursorFollowVariants: {
|
|
9
|
-
default: "rounded-[var(--radius-base)] bg-white dark:bg-[var(--color-background-secondary)] shadow-lg border border-[var(--color-border)] px-3 py-2 text-
|
|
9
|
+
default: "rounded-[var(--radius-base)] bg-white dark:bg-[var(--color-background-secondary)] shadow-lg border border-[var(--color-border)] px-3 py-2 text-base text-[var(--color-text-primary)]",
|
|
10
10
|
user: "flex items-center gap-2 rounded-full pl-1 pr-3 py-1 shadow-xl",
|
|
11
11
|
},
|
|
12
12
|
cursorFollowColors: {
|
|
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 =
|
|
15
|
+
export type CustomCursorColor = SemanticColor | 'dark';
|
|
15
16
|
/**
|
|
16
17
|
* Visual variants for the custom cursor
|
|
17
18
|
*/
|
|
@@ -108,7 +108,7 @@ const StickyScroll = React__default.forwardRef(({ sections, contentPosition = 'l
|
|
|
108
108
|
sectionRefs.current[index] = el;
|
|
109
109
|
}, className: "flex min-h-[60vh] flex-col justify-center py-16 lg:py-24", children: [jsx("h3", { className: cn('text-2xl font-semibold transition-colors duration-300 lg:text-3xl', index === activeIndex
|
|
110
110
|
? 'text-[var(--color-text-primary)]'
|
|
111
|
-
: 'text-[var(--color-text-muted)]'), children: section.title }), jsx("p", { className: cn('mt-4 max-w-lg text-
|
|
111
|
+
: 'text-[var(--color-text-muted)]'), children: section.title }), jsx("p", { className: cn('mt-4 max-w-lg text-lg leading-relaxed transition-colors duration-300 lg:text-xl', index === activeIndex
|
|
112
112
|
? 'text-[var(--color-text-secondary)]'
|
|
113
113
|
: 'text-[var(--color-text-placeholder)]'), children: section.description })] }, section.id))) }));
|
|
114
114
|
/* -------------------------------------------------------------- */
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CheckboxProps } from "./Checkbox.types";
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
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 (
|
|
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
|
-
|
|
62
|
+
CheckboxComponent.displayName = "Checkbox";
|
|
63
|
+
const Checkbox = Object.assign(CheckboxComponent, {
|
|
64
|
+
Group: CheckboxGroup,
|
|
65
|
+
});
|
|
42
66
|
|
|
43
67
|
export { Checkbox };
|
|
@@ -30,11 +30,17 @@ const checkboxTheme = {
|
|
|
30
30
|
"dark:disabled:bg-[var(--color-neutral-700)] dark:disabled:border-[var(--color-neutral-600)] " +
|
|
31
31
|
"dark:data-[state=disabled]:bg-[var(--color-neutral-700)] dark:data-[state=disabled]:border-[var(--color-neutral-600)]",
|
|
32
32
|
// Description text - light and dark
|
|
33
|
-
descriptionStyle: "text-
|
|
33
|
+
descriptionStyle: "text-base mt-0.5 " + "text-[var(--color-text-secondary)]/80 " + " ",
|
|
34
34
|
sizes: {
|
|
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-base text-[var(--color-text-secondary)]/80 -mt-0.5 mb-1",
|
|
42
|
+
groupErrorStyle: "text-base 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
|
|
15
|
-
name
|
|
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,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';
|
|
@@ -152,7 +152,7 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
|
|
|
152
152
|
getFormattedValue,
|
|
153
153
|
onChange,
|
|
154
154
|
]);
|
|
155
|
-
return (jsx(ColorPickerContext.Provider, { value: contextValue, children: jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), ...props, children: [label && (jsx(FormLabel, { htmlFor: "color-picker", required: required, state: state, children: label })), children, helperText && (jsx("div", { className: cn('mt-1.5 text-
|
|
155
|
+
return (jsx(ColorPickerContext.Provider, { value: contextValue, children: jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), ...props, children: [label && (jsx(FormLabel, { htmlFor: "color-picker", required: required, state: state, children: label })), children, helperText && (jsx("div", { className: cn('mt-1.5 text-sm text-[var(--color-text-secondary)]', state === 'invalid' && 'text-[var(--color-danger)]'), children: helperText }))] }) }));
|
|
156
156
|
});
|
|
157
157
|
ColorPickerRoot.displayName = 'ColorPicker';
|
|
158
158
|
/**
|
|
@@ -9,7 +9,7 @@ const colorPickerTheme = {
|
|
|
9
9
|
// Content matches Dropdown menu style
|
|
10
10
|
contentStyle: 'min-w-[min(280px,calc(100vw-2rem))] max-w-[320px] rounded-xl border border-[var(--color-border)] bg-white shadow-real-xl p-3 focus:outline-none',
|
|
11
11
|
sliderContainerStyle: 'space-y-2',
|
|
12
|
-
sliderLabelStyle: 'flex items-center justify-between text-
|
|
12
|
+
sliderLabelStyle: 'flex items-center justify-between text-sm font-medium text-[var(--color-text-secondary)]',
|
|
13
13
|
inputContainerStyle: 'flex items-center gap-2',
|
|
14
14
|
formatSelectorStyle: 'flex-shrink-0',
|
|
15
15
|
presetGridStyle: 'mt-3 grid grid-cols-6 sm:grid-cols-8 gap-1.5',
|
|
@@ -45,7 +45,7 @@ const ColorPickerInput = ({ className, ...props }) => {
|
|
|
45
45
|
};
|
|
46
46
|
// Render different input types based on format
|
|
47
47
|
if (format === "hex") {
|
|
48
|
-
return (jsx("div", { className: cn(theme.inputContainerStyle, className), ...props, children: jsx(Input, { type: "text", size: "sm", value: inputValue, onChange: handleChange, onBlur: handleBlur, onKeyDown: handleKeyDown, state: isInvalid ? "invalid" : "default", placeholder: "#000000", className: "flex-1 text-
|
|
48
|
+
return (jsx("div", { className: cn(theme.inputContainerStyle, className), ...props, children: jsx(Input, { type: "text", size: "sm", value: inputValue, onChange: handleChange, onBlur: handleBlur, onKeyDown: handleKeyDown, state: isInvalid ? "invalid" : "default", placeholder: "#000000", className: "flex-1 text-base font-mono", "aria-label": "Hex color value" }) }));
|
|
49
49
|
}
|
|
50
50
|
if (format === "rgb") {
|
|
51
51
|
const rgb = hslToRgb(color.h, color.s, color.l);
|
|
@@ -56,21 +56,21 @@ const ColorPickerInput = ({ className, ...props }) => {
|
|
|
56
56
|
if (parsed)
|
|
57
57
|
setColor(parsed);
|
|
58
58
|
}
|
|
59
|
-
}, className: "flex-1 text-
|
|
59
|
+
}, className: "flex-1 text-base", "aria-label": "Red", placeholder: "R" }), jsx(Input, { type: "number", size: "sm", min: 0, max: 255, value: rgb.g, onChange: (e) => {
|
|
60
60
|
const newG = parseInt(e.target.value, 10);
|
|
61
61
|
if (!isNaN(newG) && newG >= 0 && newG <= 255) {
|
|
62
62
|
const parsed = parseColor(`rgb(${rgb.r}, ${newG}, ${rgb.b})`);
|
|
63
63
|
if (parsed)
|
|
64
64
|
setColor(parsed);
|
|
65
65
|
}
|
|
66
|
-
}, className: "flex-1 text-
|
|
66
|
+
}, className: "flex-1 text-base", "aria-label": "Green", placeholder: "G" }), jsx(Input, { type: "number", size: "sm", min: 0, max: 255, value: rgb.b, onChange: (e) => {
|
|
67
67
|
const newB = parseInt(e.target.value, 10);
|
|
68
68
|
if (!isNaN(newB) && newB >= 0 && newB <= 255) {
|
|
69
69
|
const parsed = parseColor(`rgb(${rgb.r}, ${rgb.g}, ${newB})`);
|
|
70
70
|
if (parsed)
|
|
71
71
|
setColor(parsed);
|
|
72
72
|
}
|
|
73
|
-
}, className: "flex-1 text-
|
|
73
|
+
}, className: "flex-1 text-base", "aria-label": "Blue", placeholder: "B" })] }));
|
|
74
74
|
}
|
|
75
75
|
if (format === "hsl") {
|
|
76
76
|
return (jsxs("div", { className: cn(theme.inputContainerStyle, "flex gap-2", className), ...props, children: [jsx(Input, { type: "number", size: "sm", min: 0, max: 360, value: Math.round(color.h), onChange: (e) => {
|
|
@@ -78,17 +78,17 @@ const ColorPickerInput = ({ className, ...props }) => {
|
|
|
78
78
|
if (!isNaN(newH) && newH >= 0 && newH <= 360) {
|
|
79
79
|
setColor({ ...color, h: newH });
|
|
80
80
|
}
|
|
81
|
-
}, className: "flex-1 text-
|
|
81
|
+
}, className: "flex-1 text-base", "aria-label": "Hue", placeholder: "H" }), jsx(Input, { type: "number", size: "sm", min: 0, max: 100, value: Math.round(color.s), onChange: (e) => {
|
|
82
82
|
const newS = parseInt(e.target.value, 10);
|
|
83
83
|
if (!isNaN(newS) && newS >= 0 && newS <= 100) {
|
|
84
84
|
setColor({ ...color, s: newS });
|
|
85
85
|
}
|
|
86
|
-
}, className: "flex-1 text-
|
|
86
|
+
}, className: "flex-1 text-base", "aria-label": "Saturation", placeholder: "S" }), jsx(Input, { type: "number", size: "sm", min: 0, max: 100, value: Math.round(color.l), onChange: (e) => {
|
|
87
87
|
const newL = parseInt(e.target.value, 10);
|
|
88
88
|
if (!isNaN(newL) && newL >= 0 && newL <= 100) {
|
|
89
89
|
setColor({ ...color, l: newL });
|
|
90
90
|
}
|
|
91
|
-
}, className: "flex-1 text-
|
|
91
|
+
}, className: "flex-1 text-base", "aria-label": "Lightness", placeholder: "L" })] }));
|
|
92
92
|
}
|
|
93
93
|
return null;
|
|
94
94
|
};
|
|
@@ -100,7 +100,7 @@ const CronInput = React__default.forwardRef(({ value: controlledValue, defaultVa
|
|
|
100
100
|
}, [handleRawInputBlur]);
|
|
101
101
|
const showVisual = mode === "visual" || (mode === "both" && activeMode === "visual");
|
|
102
102
|
const showRaw = mode === "raw" || (mode === "both" && activeMode === "raw");
|
|
103
|
-
return (jsxs("div", { ref: ref, className: cn(theme.baseStyle, className), role: "group", "aria-label": label || "Cron expression builder", ...props, children: [label && (jsx(FormLabel, { htmlFor: `${generatedId}-cron`, state: disabled ? "disabled" : "default", children: label })), mode === "both" && (jsxs("div", { className: "flex items-center gap-1.5", children: [jsxs("button", { type: "button", onClick: () => setActiveMode("visual"), disabled: disabled, className: cn(theme.modeToggleStyle, activeMode === "visual" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "visual", children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Visual"] }), jsxs("button", { type: "button", onClick: () => setActiveMode("raw"), disabled: disabled, className: cn(theme.modeToggleStyle, activeMode === "raw" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "raw", children: [jsx(ClockIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Cron"] })] })), showPresets && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Presets" }), jsx("div", { className: "flex flex-wrap gap-1.5", children: CRON_PRESETS.map((preset) => (jsx("button", { type: "button", onClick: () => handlePresetClick(preset.value), disabled: disabled, className: cn(theme.presetButtonStyle, activePreset === preset.value && theme.presetButtonActiveStyle), title: preset.description, "aria-pressed": activePreset === preset.value, children: preset.label }, preset.value))) })] })), showVisual && (jsxs("div", { className: theme.builderStyle, children: [jsx(FieldSelect, { label: "Minute", value: fields.minute, options: minuteOptions, onChange: (v) => handleFieldChange("minute", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Hour", value: fields.hour, options: hourOptions, onChange: (v) => handleFieldChange("hour", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Day of Month", value: fields.dayOfMonth, options: dayOfMonthOptions, onChange: (v) => handleFieldChange("dayOfMonth", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Month", value: fields.month, options: monthOptions, onChange: (v) => handleFieldChange("month", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Day of Week", value: fields.dayOfWeek, options: dayOfWeekOptions, onChange: (v) => handleFieldChange("dayOfWeek", v), disabled: disabled, size: size })] })), showRaw && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Cron Expression" }), jsx("input", { type: "text", value: rawInput, onChange: handleRawInputChange, onBlur: handleRawInputBlur, onKeyDown: handleRawKeyDown, disabled: disabled, placeholder: "* * * * *", className: cn(theme.rawInputStyle, theme.rawInputSizes[size]), id: `${generatedId}-cron`, "aria-label": "Cron expression", "aria-invalid": !validateCron(rawInput), spellCheck: false, autoComplete: "off" }), !validateCron(rawInput) && rawInput !== cronValue && (jsx("div", { className: cn(theme.errorStyle, "mt-1"), children: "Invalid cron expression. Format: minute hour day month weekday" }))] })), showVisual && !showRaw && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: cn(theme.fieldLabelStyle, "shrink-0"), children: "Expression:" }), jsx("code", { className: cn("font-mono text-
|
|
103
|
+
return (jsxs("div", { ref: ref, className: cn(theme.baseStyle, className), role: "group", "aria-label": label || "Cron expression builder", ...props, children: [label && (jsx(FormLabel, { htmlFor: `${generatedId}-cron`, state: disabled ? "disabled" : "default", children: label })), mode === "both" && (jsxs("div", { className: "flex items-center gap-1.5", children: [jsxs("button", { type: "button", onClick: () => setActiveMode("visual"), disabled: disabled, className: cn(theme.modeToggleStyle, activeMode === "visual" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "visual", children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Visual"] }), jsxs("button", { type: "button", onClick: () => setActiveMode("raw"), disabled: disabled, className: cn(theme.modeToggleStyle, activeMode === "raw" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "raw", children: [jsx(ClockIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Cron"] })] })), showPresets && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Presets" }), jsx("div", { className: "flex flex-wrap gap-1.5", children: CRON_PRESETS.map((preset) => (jsx("button", { type: "button", onClick: () => handlePresetClick(preset.value), disabled: disabled, className: cn(theme.presetButtonStyle, activePreset === preset.value && theme.presetButtonActiveStyle), title: preset.description, "aria-pressed": activePreset === preset.value, children: preset.label }, preset.value))) })] })), showVisual && (jsxs("div", { className: theme.builderStyle, children: [jsx(FieldSelect, { label: "Minute", value: fields.minute, options: minuteOptions, onChange: (v) => handleFieldChange("minute", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Hour", value: fields.hour, options: hourOptions, onChange: (v) => handleFieldChange("hour", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Day of Month", value: fields.dayOfMonth, options: dayOfMonthOptions, onChange: (v) => handleFieldChange("dayOfMonth", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Month", value: fields.month, options: monthOptions, onChange: (v) => handleFieldChange("month", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Day of Week", value: fields.dayOfWeek, options: dayOfWeekOptions, onChange: (v) => handleFieldChange("dayOfWeek", v), disabled: disabled, size: size })] })), showRaw && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Cron Expression" }), jsx("input", { type: "text", value: rawInput, onChange: handleRawInputChange, onBlur: handleRawInputBlur, onKeyDown: handleRawKeyDown, disabled: disabled, placeholder: "* * * * *", className: cn(theme.rawInputStyle, theme.rawInputSizes[size]), id: `${generatedId}-cron`, "aria-label": "Cron expression", "aria-invalid": !validateCron(rawInput), spellCheck: false, autoComplete: "off" }), !validateCron(rawInput) && rawInput !== cronValue && (jsx("div", { className: cn(theme.errorStyle, "mt-1"), children: "Invalid cron expression. Format: minute hour day month weekday" }))] })), showVisual && !showRaw && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: cn(theme.fieldLabelStyle, "shrink-0"), children: "Expression:" }), jsx("code", { className: cn("font-mono text-sm px-2 py-1 rounded-[var(--form-radius)]", "bg-[var(--color-background-secondary)] text-[var(--color-text-primary)]", "dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-200)]"), children: cronValue })] })), showDescription && isValid && (jsxs("div", { className: theme.descriptionStyle, children: [jsx(ClockIcon, { className: "w-4 h-4 shrink-0", "aria-hidden": "true" }), jsx("span", { children: description })] })), showNextRuns && isValid && nextRuns.length > 0 && (jsxs("div", { className: theme.nextRunsStyle, children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1"), children: "Next runs" }), nextRuns.map((date, index) => (jsxs("div", { className: theme.nextRunItemStyle, children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }), jsx("span", { children: formatNextRun(date) })] }, index)))] }))] }));
|
|
104
104
|
});
|
|
105
105
|
CronInput.displayName = "CronInput";
|
|
106
106
|
|
|
@@ -8,13 +8,13 @@ const cronInputTheme = {
|
|
|
8
8
|
// Outer wrapper
|
|
9
9
|
baseStyle: "relative w-full flex flex-col gap-3",
|
|
10
10
|
// Label
|
|
11
|
-
labelStyle: "text-
|
|
11
|
+
labelStyle: "text-base font-medium text-[var(--color-text-primary)] dark:text-[var(--color-neutral-200)]",
|
|
12
12
|
// Visual builder grid
|
|
13
13
|
builderStyle: "grid grid-cols-5 gap-2",
|
|
14
14
|
// Individual field group
|
|
15
15
|
fieldGroupStyle: "flex flex-col gap-1",
|
|
16
16
|
// Field label
|
|
17
|
-
fieldLabelStyle: "text-
|
|
17
|
+
fieldLabelStyle: "text-sm font-medium text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
|
|
18
18
|
// Select dropdown
|
|
19
19
|
fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline outline-1 outline-[var(--color-border)] " +
|
|
20
20
|
"bg-white text-[var(--color-text-primary)] cursor-pointer transition-all " +
|
|
@@ -45,7 +45,7 @@ const cronInputTheme = {
|
|
|
45
45
|
lg: `${formsBaseTheme.sizes.lg.text} ${formsBaseTheme.sizes.lg.padding} ${formsBaseTheme.sizes.lg.height}`,
|
|
46
46
|
},
|
|
47
47
|
// Mode toggle button
|
|
48
|
-
modeToggleStyle: "inline-flex items-center justify-center rounded-[var(--form-radius)] px-3 py-1.5 text-
|
|
48
|
+
modeToggleStyle: "inline-flex items-center justify-center rounded-[var(--form-radius)] px-3 py-1.5 text-sm font-medium " +
|
|
49
49
|
"cursor-pointer transition-all outline outline-1 outline-[var(--color-border)] " +
|
|
50
50
|
"text-[var(--color-text-secondary)] bg-white hover:bg-[var(--color-background-secondary)] " +
|
|
51
51
|
"dark:bg-[var(--color-neutral-900)] dark:outline-[var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
|
|
@@ -56,7 +56,7 @@ const cronInputTheme = {
|
|
|
56
56
|
"dark:outline-[var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)] " +
|
|
57
57
|
"dark:hover:bg-[var(--color-primary-500)]/15",
|
|
58
58
|
// Preset button
|
|
59
|
-
presetButtonStyle: "inline-flex items-center rounded-[var(--form-radius)] px-2.5 py-1 text-
|
|
59
|
+
presetButtonStyle: "inline-flex items-center rounded-[var(--form-radius)] px-2.5 py-1 text-sm font-medium " +
|
|
60
60
|
"cursor-pointer transition-all outline outline-1 outline-[var(--color-border)] " +
|
|
61
61
|
"text-[var(--color-text-secondary)] bg-white hover:bg-[var(--color-background-secondary)] " +
|
|
62
62
|
"hover:text-[var(--color-text-primary)] " +
|
|
@@ -67,18 +67,18 @@ const cronInputTheme = {
|
|
|
67
67
|
"hover:bg-[var(--color-primary-100)] " +
|
|
68
68
|
"dark:outline-[var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)]",
|
|
69
69
|
// Human-readable description
|
|
70
|
-
descriptionStyle: "flex items-center gap-2 text-
|
|
70
|
+
descriptionStyle: "flex items-center gap-2 text-base text-[var(--color-text-muted)] " +
|
|
71
71
|
"dark:text-[var(--color-neutral-400)]",
|
|
72
72
|
// Next runs container
|
|
73
73
|
nextRunsStyle: "flex flex-col gap-1",
|
|
74
74
|
// Individual next run item
|
|
75
|
-
nextRunItemStyle: "flex items-center gap-2 text-
|
|
75
|
+
nextRunItemStyle: "flex items-center gap-2 text-sm text-[var(--color-text-muted)] " +
|
|
76
76
|
"dark:text-[var(--color-neutral-400)]",
|
|
77
77
|
// Section heading
|
|
78
|
-
sectionHeadingStyle: "text-
|
|
78
|
+
sectionHeadingStyle: "text-sm font-medium text-[var(--color-text-secondary)] uppercase tracking-wide " +
|
|
79
79
|
"dark:text-[var(--color-neutral-400)]",
|
|
80
80
|
// Validation error
|
|
81
|
-
errorStyle: "text-
|
|
81
|
+
errorStyle: "text-sm text-[var(--color-danger)] dark:text-[var(--color-danger-400)]",
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
export { cronInputTheme };
|
|
@@ -35,7 +35,7 @@ const datePickerTheme = {
|
|
|
35
35
|
presetsContainerStyle: "flex flex-col gap-1 p-3 border-b sm:border-b-0 sm:border-r border-[var(--color-border)] bg-[var(--color-neutral-50)] sm:min-w-[180px] " +
|
|
36
36
|
"dark:bg-[var(--color-neutral-800)] dark:border-[var(--color-neutral-700)]",
|
|
37
37
|
// Preset button - with dark mode support
|
|
38
|
-
presetButtonStyle: "w-full text-left px-3 py-2 text-
|
|
38
|
+
presetButtonStyle: "w-full text-left px-3 py-2 text-base rounded-[calc(var(--radius-base)*0.75)] transition-colors cursor-pointer " +
|
|
39
39
|
"text-[var(--color-text-secondary)] hover:bg-white hover:text-[var(--color-text-primary)] " +
|
|
40
40
|
"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 " +
|
|
41
41
|
"data-[active=true]:bg-white data-[active=true]:text-[var(--color-text-primary)] data-[active=true]:font-medium " +
|
|
@@ -213,7 +213,7 @@ const DatePickerContent = ({ isOpen, className, onClose, portal = true, placemen
|
|
|
213
213
|
const adjustedLeft = new Date(newDate);
|
|
214
214
|
adjustedLeft.setMonth(adjustedLeft.getMonth() - 1);
|
|
215
215
|
setLeftCalendarDate(adjustedLeft);
|
|
216
|
-
}, onNavigatePrev: null, onNavigateNext: handleNavigateNext, minDate: minDate, maxDate: maxDate, isDateDisabled: isDateDisabled, showToday: showToday, selectTodayByDefault: false, weekdays: weekdays, months: months, size: "md" }) })] })) }), jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-t border-[var(--color-border)] dark:border-[var(--color-neutral-700)]", children: [jsx("div", { className: "text-
|
|
216
|
+
}, onNavigatePrev: null, onNavigateNext: handleNavigateNext, minDate: minDate, maxDate: maxDate, isDateDisabled: isDateDisabled, showToday: showToday, selectTodayByDefault: false, weekdays: weekdays, months: months, size: "md" }) })] })) }), jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-t border-[var(--color-border)] dark:border-[var(--color-neutral-700)]", children: [jsx("div", { className: "text-base text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]", children: formatRangeDisplay(tempRange) }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Button, { variant: "outline", color: "neutral", size: "sm", onClick: handleCancel, children: "Cancel" }), jsx(Button, { variant: "filled", size: "sm", onClick: handleApply, disabled: !(tempRange === null || tempRange === void 0 ? void 0 : tempRange.start) || !(tempRange === null || tempRange === void 0 ? void 0 : tempRange.end), children: "Apply" })] })] })] })) : (
|
|
217
217
|
// Single calendar for single mode
|
|
218
218
|
jsx("div", { className: "flex-1 p-4", children: children || (jsx(Calendar, { mode: "single", value: selectedValue, onChange: (value) => {
|
|
219
219
|
handleDateSelect(value);
|
|
@@ -198,10 +198,10 @@ const FileUpload = React__default.forwardRef(({ accept, multiple = false, maxSiz
|
|
|
198
198
|
e.preventDefault();
|
|
199
199
|
handleClick();
|
|
200
200
|
}
|
|
201
|
-
}, children: jsxs("div", { className: theme.contentStyle, children: [jsx("div", { className: "size-11 border border-border bg-white rounded-full flex items-center justify-center mb-4", children: jsx(CloudArrowUpIcon, { className: `size-6 text-[var(--color-text-secondary)]` }) }), jsxs("p", { className: "text-
|
|
201
|
+
}, children: jsxs("div", { className: theme.contentStyle, children: [jsx("div", { className: "size-11 border border-border bg-white rounded-full flex items-center justify-center mb-4", children: jsx(CloudArrowUpIcon, { className: `size-6 text-[var(--color-text-secondary)]` }) }), jsxs("p", { className: "text-base font-medium text-[var(--color-text-primary)]", children: [jsx("span", { className: "text-[var(--color-primary)] font-semibold", children: buttonText }), " ", helperText] }), description && (jsx("p", { className: "text-sm text-[var(--color-text-muted)] mt-1", children: description }))] }) }), showPreview && selectedFiles.length > 0 && (jsx("div", { className: theme.previewContainerStyle, children: selectedFiles.map((file, index) => {
|
|
202
202
|
const previewUrl = previewUrls.get(file);
|
|
203
203
|
const isImage = file.type.startsWith("image/");
|
|
204
|
-
return (jsxs("div", { className: theme.previewItemStyle, children: [isImage && previewUrl ? (jsx("img", { src: previewUrl, alt: file.name, className: theme.previewImageStyle })) : (jsxs("div", { className: theme.previewFileStyle, children: [jsx(DocumentIcon, { className: "w-8 h-8 mx-auto mb-2 text-[var(--color-text-muted)]" }), jsx("span", { className: "text-
|
|
204
|
+
return (jsxs("div", { className: theme.previewItemStyle, children: [isImage && previewUrl ? (jsx("img", { src: previewUrl, alt: file.name, className: theme.previewImageStyle })) : (jsxs("div", { className: theme.previewFileStyle, children: [jsx(DocumentIcon, { className: "w-8 h-8 mx-auto mb-2 text-[var(--color-text-muted)]" }), jsx("span", { className: "text-sm", children: file.name }), jsx("span", { className: "text-sm text-[var(--color-text-placeholder)] mt-1", children: formatFileSize(file.size) })] })), jsx(Button, { variant: "filled", color: "danger", size: "sm", iconOnly: true, onClick: (e) => {
|
|
205
205
|
e.stopPropagation();
|
|
206
206
|
handleRemoveFile(file);
|
|
207
207
|
}, "aria-label": `Remove ${file.name}`, className: cn(theme.removeButtonStyle, "rounded-full !p-0 size-6"), children: jsx(XMarkIcon, { className: "size-4", strokeWidth: 2 }) })] }, `${file.name}-${index}`));
|
|
@@ -16,11 +16,11 @@ const fileUploadTheme = {
|
|
|
16
16
|
// Upload icon
|
|
17
17
|
iconStyle: "size-8 text-[var(--color-text-placeholder)]",
|
|
18
18
|
// Main text
|
|
19
|
-
textStyle: "text-
|
|
19
|
+
textStyle: "text-base font-medium text-[var(--color-text-primary)]",
|
|
20
20
|
// Helper text
|
|
21
|
-
helperTextStyle: "text-
|
|
21
|
+
helperTextStyle: "text-base text-[var(--color-text-muted)] mt-1",
|
|
22
22
|
// Description below dropzone
|
|
23
|
-
descriptionStyle: "text-
|
|
23
|
+
descriptionStyle: "text-sm text-[var(--color-text-muted)] mt-1",
|
|
24
24
|
// Preview container
|
|
25
25
|
previewContainerStyle: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4 mt-4",
|
|
26
26
|
// Individual preview item
|
|
@@ -28,7 +28,7 @@ const fileUploadTheme = {
|
|
|
28
28
|
// Preview image
|
|
29
29
|
previewImageStyle: "w-full h-32 object-cover",
|
|
30
30
|
// Preview file (non-image)
|
|
31
|
-
previewFileStyle: "flex items-center justify-center w-full h-32 p-3 text-
|
|
31
|
+
previewFileStyle: "flex items-center justify-center w-full h-32 p-3 text-base text-[var(--color-text-secondary)] text-center break-all",
|
|
32
32
|
// Remove button
|
|
33
33
|
removeButtonStyle: "absolute top-1 right-1 -translate-y-1 opacity-0 group-hover:opacity-100 transition-all duration-400 group-hover:-translate-y-0",
|
|
34
34
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
const formLabelTheme = {
|
|
5
5
|
// Base styles for the label element
|
|
6
|
-
baseStyle: "block text-
|
|
6
|
+
baseStyle: "block text-base/6 font-medium mb-2",
|
|
7
7
|
// State variants - using design tokens from global.scss
|
|
8
8
|
stateStyles: {
|
|
9
9
|
default: "text-[var(--color-text-primary)]",
|
|
@@ -88,7 +88,7 @@ const inputTheme = {
|
|
|
88
88
|
// Password strength indicator with design tokens
|
|
89
89
|
passwordStrengthIndicator: {
|
|
90
90
|
containerStyle: "flex items-center gap-1",
|
|
91
|
-
labelStyle: "text-
|
|
91
|
+
labelStyle: "text-sm font-semibold mr-1",
|
|
92
92
|
dotStyle: "size-1.5 rounded-full",
|
|
93
93
|
dotActiveStyle: "bg-current",
|
|
94
94
|
dotInactiveStyle: "bg-[var(--color-border)] dark:bg-[var(--color-neutral-700)]",
|