@flikk/ui 1.0.0-beta.21 → 1.0.0-beta.22
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/CodeBlock/CodeBlock.theme.js +2 -2
- package/dist/components/ai/PromptInput/PromptInput.theme.js +3 -3
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +1 -1
- package/dist/components/ai/StreamingResponse/StreamingResponse.theme.js +4 -4
- package/dist/components/ai/TokenCounter/TokenCounter.theme.js +6 -6
- package/dist/components/charts/ActivityRings/ActivityRings.theme.js +2 -2
- package/dist/components/charts/DonutChart/DonutChart.theme.js +2 -2
- package/dist/components/charts/DonutChart/MultiSegmentDonutChart.theme.js +1 -1
- package/dist/components/charts/Heatmap/Heatmap.theme.js +1 -1
- package/dist/components/charts/RadarChart/RadarChart.theme.js +2 -2
- package/dist/components/charts/ScatterPlot/ScatterPlot.theme.js +2 -2
- 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.theme.js +1 -1
- package/dist/components/core/Avatar/Avatar.theme.js +10 -10
- package/dist/components/core/AvatarGroup/AvatarGroup.theme.js +1 -1
- package/dist/components/core/Badge/Badge.js +2 -12
- package/dist/components/core/Badge/Badge.theme.js +2 -2
- package/dist/components/core/Button/Button.theme.js +6 -6
- package/dist/components/core/ButtonGroup/ButtonGroup.theme.js +1 -1
- package/dist/components/core/Calendar/Calendar.theme.js +5 -5
- package/dist/components/core/Card/Card.theme.js +2 -2
- package/dist/components/core/CommandPalette/CommandPalette.theme.js +4 -4
- package/dist/components/core/Drawer/Drawer.animations.js +5 -4
- 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/Icon/Icon.d.ts +3 -0
- package/dist/components/core/Icon/Icon.js +70 -0
- package/dist/components/core/Icon/Icon.theme.d.ts +2 -0
- package/dist/components/core/Icon/Icon.theme.js +19 -0
- package/dist/components/core/Icon/Icon.types.d.ts +32 -0
- package/dist/components/core/{FileTypeIcon → Icon/data}/fileTypes.d.ts +1 -1
- package/dist/components/core/Icon/data/paymentMethods.d.ts +27 -0
- package/dist/components/core/Icon/data/paymentMethods.js +169 -0
- package/dist/components/core/Icon/index.d.ts +4 -0
- package/dist/components/core/Kbd/Kbd.theme.js +2 -2
- package/dist/components/core/MenuItem/MenuItem.theme.js +2 -2
- package/dist/components/core/Message/Message.theme.js +6 -6
- package/dist/components/core/Modal/Modal.animations.js +3 -1
- package/dist/components/core/Modal/Modal.theme.js +2 -2
- package/dist/components/core/Modal/ModalBody.js +7 -8
- 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 +2 -2
- package/dist/components/core/Pagination/Pagination.theme.js +2 -2
- package/dist/components/core/Pill/Pill.theme.js +3 -3
- package/dist/components/core/Progress/Progress.theme.js +2 -2
- package/dist/components/core/Segmented/Segmented.theme.js +3 -3
- 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 +2 -2
- package/dist/components/core/Tooltip/Tooltip.theme.js +1 -1
- package/dist/components/core/Tree/Tree.theme.js +1 -1
- package/dist/components/core/index.d.ts +1 -2
- package/dist/components/core/index.js +2 -2
- package/dist/components/data-display/DescriptionList/DescriptionList.theme.js +2 -2
- package/dist/components/data-display/Feed/Feed.theme.js +1 -1
- package/dist/components/data-display/GanttChart/GanttChart.theme.js +2 -2
- package/dist/components/data-display/KPI/KPI.theme.js +9 -9
- package/dist/components/data-display/Metric/Metric.theme.js +9 -9
- package/dist/components/data-display/Table/Table.animations.js +16 -10
- package/dist/components/data-display/Table/Table.filterUtils.js +8 -1
- package/dist/components/data-display/Table/Table.js +10 -14
- package/dist/components/data-display/Table/Table.theme.js +3 -3
- package/dist/components/data-display/Table/Table.types.d.ts +2 -0
- package/dist/components/data-display/Table/TableActions.js +3 -3
- package/dist/components/data-display/Table/TableActionsMenu.js +2 -3
- package/dist/components/data-display/Table/TableCell.js +6 -3
- package/dist/components/data-display/Table/TableDeclarative.js +5 -7
- package/dist/components/data-display/Table/TableHeader.js +5 -2
- package/dist/components/data-display/Table/TablePagination.js +2 -6
- package/dist/components/data-display/Table/TableRow.js +2 -6
- package/dist/components/data-display/Table/index.js +1 -0
- package/dist/components/effects/CustomCursor/CustomCursor.theme.js +1 -1
- package/dist/components/effects/Overlay/Overlay.js +50 -21
- package/dist/components/forms/Checkbox/Checkbox.theme.js +3 -3
- package/dist/components/forms/ColorPicker/ColorPicker.d.ts +5 -9
- package/dist/components/forms/ColorPicker/ColorPicker.js +126 -22
- package/dist/components/forms/ColorPicker/ColorPicker.theme.js +9 -6
- package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +99 -0
- package/dist/components/forms/ColorPicker/ColorPicker2DCanvas.js +43 -6
- package/dist/components/forms/ColorPicker/ColorPickerBody.js +1 -1
- package/dist/components/forms/ColorPicker/ColorPickerContext.d.ts +4 -0
- package/dist/components/forms/ColorPicker/ColorPickerContext.js +12 -0
- package/dist/components/forms/ColorPicker/ColorPickerEyeDropper.js +1 -1
- package/dist/components/forms/ColorPicker/ColorPickerFormatSelector.js +1 -1
- package/dist/components/forms/ColorPicker/ColorPickerGradient.d.ts +7 -0
- package/dist/components/forms/ColorPicker/ColorPickerGradient.js +186 -0
- package/dist/components/forms/ColorPicker/ColorPickerHeader.d.ts +14 -0
- package/dist/components/forms/ColorPicker/ColorPickerHeader.js +31 -0
- package/dist/components/forms/ColorPicker/ColorPickerImage.d.ts +6 -0
- package/dist/components/forms/ColorPicker/ColorPickerImage.js +154 -0
- package/dist/components/forms/ColorPicker/ColorPickerInput.d.ts +0 -4
- package/dist/components/forms/ColorPicker/ColorPickerInput.js +53 -61
- package/dist/components/forms/ColorPicker/ColorPickerPresets.js +13 -12
- package/dist/components/forms/ColorPicker/ColorPickerSavedColors.d.ts +3 -0
- package/dist/components/forms/ColorPicker/ColorPickerSavedColors.js +69 -0
- package/dist/components/forms/ColorPicker/ColorPickerSliders.d.ts +1 -2
- package/dist/components/forms/ColorPicker/ColorPickerSliders.js +84 -23
- package/dist/components/forms/ColorPicker/ColorPickerSwatch.d.ts +1 -1
- package/dist/components/forms/ColorPicker/ColorPickerSwatch.js +10 -9
- package/dist/components/forms/ColorPicker/ColorPickerTrigger.js +7 -3
- package/dist/components/forms/ColorPicker/index.d.ts +8 -2
- package/dist/components/forms/CronInput/CronInput.theme.js +8 -8
- package/dist/components/forms/DatePicker/DatePicker.theme.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +3 -3
- package/dist/components/forms/FileUpload/FileUpload.theme.js +4 -4
- package/dist/components/forms/FileUpload/FileUploadProgress.js +3 -3
- package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
- package/dist/components/forms/FormLabel/FormLabel.theme.js +1 -1
- package/dist/components/forms/Input/Input.js +3 -3
- package/dist/components/forms/Input/Input.theme.js +1 -1
- package/dist/components/forms/Input/Input.types.d.ts +2 -0
- package/dist/components/forms/InputCounter/InputCounter.theme.js +1 -1
- package/dist/components/forms/InputOTP/InputOTP.theme.js +1 -1
- package/dist/components/forms/Mention/Mention.theme.js +3 -3
- package/dist/components/forms/Radio/Radio.theme.js +3 -3
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +1 -1
- package/dist/components/forms/Select/Select.theme.js +1 -1
- package/dist/components/forms/SelectableCard/SelectableCard.js +42 -27
- package/dist/components/forms/SelectableCard/SelectableCard.theme.js +15 -25
- package/dist/components/forms/SelectableCard/SelectableCard.types.d.ts +16 -3
- package/dist/components/forms/SelectableCard/SelectableCardContext.d.ts +1 -0
- package/dist/components/forms/SelectableCard/SelectableCardContext.js +4 -7
- package/dist/components/forms/SelectableCard/SelectableCardGroup.js +31 -10
- package/dist/components/forms/SelectableCard/index.d.ts +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/forms.theme.js +6 -6
- package/dist/components/forms/index.js +6 -1
- package/dist/components/layout/FormLayout/FormLayout.theme.js +2 -2
- package/dist/hooks/useOverlay.d.ts +2 -0
- package/dist/hooks/useOverlay.js +34 -4
- package/dist/index.js +8 -3
- package/dist/styles.css +1 -1
- package/package.json +2 -1
- package/src/global.scss +1 -1
- package/dist/bg/bg/1.jpg +0 -0
- package/dist/bg/bg/10.jpg +0 -0
- package/dist/bg/bg/11.jpg +0 -0
- package/dist/bg/bg/14.jpg +0 -0
- package/dist/bg/bg/15.jpg +0 -0
- package/dist/bg/bg/16.jpg +0 -0
- package/dist/bg/bg/17.jpg +0 -0
- package/dist/bg/bg/18.jpg +0 -0
- package/dist/bg/bg/19.jpg +0 -0
- package/dist/bg/bg/2.jpg +0 -0
- package/dist/bg/bg/20.jpg +0 -0
- package/dist/bg/bg/21.jpg +0 -0
- package/dist/bg/bg/22.jpg +0 -0
- package/dist/bg/bg/23.jpg +0 -0
- package/dist/bg/bg/24.jpg +0 -0
- package/dist/bg/bg/3.jpg +0 -0
- package/dist/bg/bg/4.jpg +0 -0
- package/dist/bg/bg/5.jpg +0 -0
- package/dist/bg/bg/6.jpg +0 -0
- package/dist/bg/bg/7.jpg +0 -0
- package/dist/bg/bg/8.jpg +0 -0
- package/dist/bg/bg/9.jpg +0 -0
- package/dist/components/core/FileTypeIcon/FileTypeIcon.d.ts +0 -3
- package/dist/components/core/FileTypeIcon/FileTypeIcon.js +0 -33
- package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.d.ts +0 -2
- package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.js +0 -12
- package/dist/components/core/FileTypeIcon/FileTypeIcon.types.d.ts +0 -19
- package/dist/components/core/FileTypeIcon/index.d.ts +0 -2
- package/dist/components/core/SocialIcon/SocialIcon.d.ts +0 -3
- package/dist/components/core/SocialIcon/SocialIcon.js +0 -30
- package/dist/components/core/SocialIcon/SocialIcon.theme.d.ts +0 -2
- package/dist/components/core/SocialIcon/SocialIcon.theme.js +0 -12
- package/dist/components/core/SocialIcon/SocialIcon.types.d.ts +0 -18
- package/dist/components/core/SocialIcon/index.d.ts +0 -2
- /package/dist/components/core/{FileTypeIcon → Icon/data}/fileTypes.js +0 -0
- /package/dist/components/core/{SocialIcon → Icon/data}/platforms.d.ts +0 -0
- /package/dist/components/core/{SocialIcon → Icon/data}/platforms.js +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { PlusIcon } from '@heroicons/react/20/solid';
|
|
3
|
+
import { useContext } from 'react';
|
|
4
|
+
import { cn } from '../../../utils/cn.js';
|
|
5
|
+
import { Button } from '../../core/Button/Button.js';
|
|
6
|
+
import { ColorPickerContext } from './ColorPickerContext.js';
|
|
7
|
+
import { parseColor } from './colorUtils.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Detect whether a saved color string is a CSS gradient
|
|
11
|
+
*/
|
|
12
|
+
const isGradientValue = (value) => value.includes('gradient(');
|
|
13
|
+
const ColorPickerSavedColors = ({ label = 'Saved', maxColors = 16, className, ...props }) => {
|
|
14
|
+
const context = useContext(ColorPickerContext);
|
|
15
|
+
if (!context) {
|
|
16
|
+
throw new Error('ColorPickerSavedColors must be used within a ColorPicker');
|
|
17
|
+
}
|
|
18
|
+
const { color, setColor, savedColors, addSavedColor, removeSavedColor, getOutputValue, mode, theme } = context;
|
|
19
|
+
const handleSaveColor = () => {
|
|
20
|
+
if (savedColors.length >= maxColors)
|
|
21
|
+
return;
|
|
22
|
+
// Save the output value — gradient CSS string in gradient mode, solid color in solid mode
|
|
23
|
+
addSavedColor(getOutputValue());
|
|
24
|
+
};
|
|
25
|
+
const handleSelectColor = (colorValue) => {
|
|
26
|
+
// Only apply solid colors to the color state; gradients are display-only
|
|
27
|
+
if (!isGradientValue(colorValue)) {
|
|
28
|
+
const parsed = parseColor(colorValue);
|
|
29
|
+
if (parsed) {
|
|
30
|
+
setColor(parsed);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const handleKeyDown = (e, colorValue) => {
|
|
35
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
handleSelectColor(colorValue);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
// Check if a saved color matches current color
|
|
41
|
+
const isSelected = (colorValue) => {
|
|
42
|
+
if (isGradientValue(colorValue))
|
|
43
|
+
return false;
|
|
44
|
+
const parsed = parseColor(colorValue);
|
|
45
|
+
if (!parsed)
|
|
46
|
+
return false;
|
|
47
|
+
return (Math.abs(parsed.h - color.h) < 1 &&
|
|
48
|
+
Math.abs(parsed.s - color.s) < 1 &&
|
|
49
|
+
Math.abs(parsed.l - color.l) < 1);
|
|
50
|
+
};
|
|
51
|
+
// Handle double-click to remove
|
|
52
|
+
const handleDoubleClick = (index) => {
|
|
53
|
+
removeSavedColor(index);
|
|
54
|
+
};
|
|
55
|
+
return (jsxs("div", { className: cn(className), ...props, children: [jsxs("div", { className: "flex items-center justify-between mb-2", children: [label !== false && (jsx("span", { className: "text-sm font-medium text-[var(--color-text-primary)]", children: label })), savedColors.length < maxColors && (jsxs(Button, { variant: "ghost", size: "sm", color: "neutral", onClick: handleSaveColor, "aria-label": "Save current color", className: "!px-2 !py-1 !text-sm !font-medium", children: [jsx(PlusIcon, { className: "size-4" }), "Add"] }))] }), savedColors.length > 0 && (jsx("div", { className: "flex items-center gap-2 flex-wrap", children: savedColors.map((colorValue, index) => {
|
|
56
|
+
const gradient = isGradientValue(colorValue);
|
|
57
|
+
const selected = isSelected(colorValue);
|
|
58
|
+
return (jsx("button", { type: "button", tabIndex: 0, onClick: () => handleSelectColor(colorValue), onDoubleClick: () => handleDoubleClick(index), onKeyDown: (e) => handleKeyDown(e, colorValue), className: cn('size-7 rounded-full cursor-pointer transition-all flex-shrink-0', 'hover:scale-110 focus:outline-none', selected
|
|
59
|
+
? 'ring-2 ring-[var(--color-primary)] ring-offset-2 ring-offset-[var(--color-surface)]'
|
|
60
|
+
: 'ring-1 ring-black/10'), style: {
|
|
61
|
+
// Use `background` so both solid colors and CSS gradients render
|
|
62
|
+
background: gradient ? colorValue : undefined,
|
|
63
|
+
backgroundColor: gradient ? undefined : colorValue,
|
|
64
|
+
}, "aria-label": `Select saved color ${gradient ? 'gradient' : colorValue}`, title: `${colorValue} (double-click to remove)` }, `${colorValue}-${index}`));
|
|
65
|
+
}) }))] }));
|
|
66
|
+
};
|
|
67
|
+
ColorPickerSavedColors.displayName = 'ColorPickerSavedColors';
|
|
68
|
+
|
|
69
|
+
export { ColorPickerSavedColors };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ColorPickerSlidersProps } from './ColorPicker.types';
|
|
3
3
|
/**
|
|
4
|
-
* ColorPickerSliders -
|
|
5
|
-
* Matches reference design with inline values
|
|
4
|
+
* ColorPickerSliders - Hue and Alpha sliders with gradient tracks
|
|
6
5
|
*/
|
|
7
6
|
export declare const ColorPickerSliders: React.FC<ColorPickerSlidersProps>;
|
|
@@ -1,14 +1,81 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useContext, useMemo } from 'react';
|
|
2
|
+
import { useContext, useMemo, useRef, useState, useCallback, useEffect } from 'react';
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
|
-
import {
|
|
5
|
-
import '
|
|
6
|
-
import { ColorPickerContext } from './ColorPicker.js';
|
|
7
|
-
import { formatRgb } from './colorUtils.js';
|
|
4
|
+
import { ColorPickerContext } from './ColorPickerContext.js';
|
|
5
|
+
import { hslToRgb } from './colorUtils.js';
|
|
8
6
|
|
|
7
|
+
const ColorSliderTrack = ({ min, max, step, value, onChange, thumbColor, ariaLabel, trackStyle, className, }) => {
|
|
8
|
+
const trackRef = useRef(null);
|
|
9
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
10
|
+
const percentage = ((value - min) / (max - min)) * 100;
|
|
11
|
+
const getValueFromPosition = useCallback((clientX) => {
|
|
12
|
+
if (!trackRef.current)
|
|
13
|
+
return value;
|
|
14
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
15
|
+
const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
16
|
+
const rawValue = min + ratio * (max - min);
|
|
17
|
+
// Snap to step
|
|
18
|
+
const stepped = Math.round(rawValue / step) * step;
|
|
19
|
+
return Math.max(min, Math.min(max, stepped));
|
|
20
|
+
}, [min, max, step, value]);
|
|
21
|
+
const handlePointerDown = useCallback((e) => {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
setIsDragging(true);
|
|
24
|
+
const newValue = getValueFromPosition(e.clientX);
|
|
25
|
+
onChange(newValue);
|
|
26
|
+
}, [getValueFromPosition, onChange]);
|
|
27
|
+
const handlePointerMove = useCallback((e) => {
|
|
28
|
+
if (!isDragging)
|
|
29
|
+
return;
|
|
30
|
+
const newValue = getValueFromPosition(e.clientX);
|
|
31
|
+
onChange(newValue);
|
|
32
|
+
}, [isDragging, getValueFromPosition, onChange]);
|
|
33
|
+
const handlePointerUp = useCallback(() => {
|
|
34
|
+
setIsDragging(false);
|
|
35
|
+
}, []);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (isDragging) {
|
|
38
|
+
window.addEventListener('pointermove', handlePointerMove);
|
|
39
|
+
window.addEventListener('pointerup', handlePointerUp);
|
|
40
|
+
return () => {
|
|
41
|
+
window.removeEventListener('pointermove', handlePointerMove);
|
|
42
|
+
window.removeEventListener('pointerup', handlePointerUp);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}, [isDragging, handlePointerMove, handlePointerUp]);
|
|
46
|
+
const handleKeyDown = useCallback((e) => {
|
|
47
|
+
let delta = 0;
|
|
48
|
+
switch (e.key) {
|
|
49
|
+
case 'ArrowRight':
|
|
50
|
+
case 'ArrowUp':
|
|
51
|
+
delta = step;
|
|
52
|
+
break;
|
|
53
|
+
case 'ArrowLeft':
|
|
54
|
+
case 'ArrowDown':
|
|
55
|
+
delta = -step;
|
|
56
|
+
break;
|
|
57
|
+
case 'Home':
|
|
58
|
+
onChange(min);
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
return;
|
|
61
|
+
case 'End':
|
|
62
|
+
onChange(max);
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
return;
|
|
65
|
+
default:
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
onChange(Math.max(min, Math.min(max, value + delta)));
|
|
70
|
+
}, [min, max, step, value, onChange]);
|
|
71
|
+
return (jsx("div", { ref: trackRef, onPointerDown: handlePointerDown, className: cn('relative h-3 rounded-full cursor-pointer touch-none select-none', className), style: trackStyle, children: jsx("div", { className: "absolute top-1/2 size-5 rounded-full border-2 border-white shadow-md ring-1 ring-black/10 cursor-grab active:cursor-grabbing focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-1", style: {
|
|
72
|
+
left: `${percentage}%`,
|
|
73
|
+
transform: 'translate(-50%, -50%)',
|
|
74
|
+
backgroundColor: thumbColor,
|
|
75
|
+
}, onKeyDown: handleKeyDown, role: "slider", "aria-label": ariaLabel, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": value, "aria-orientation": "horizontal", tabIndex: 0 }) }));
|
|
76
|
+
};
|
|
9
77
|
/**
|
|
10
|
-
* ColorPickerSliders -
|
|
11
|
-
* Matches reference design with inline values
|
|
78
|
+
* ColorPickerSliders - Hue and Alpha sliders with gradient tracks
|
|
12
79
|
*/
|
|
13
80
|
const ColorPickerSliders = ({ showLabels = false, className, ...props }) => {
|
|
14
81
|
const context = useContext(ColorPickerContext);
|
|
@@ -20,24 +87,18 @@ const ColorPickerSliders = ({ showLabels = false, className, ...props }) => {
|
|
|
20
87
|
// Hue gradient (rainbow)
|
|
21
88
|
const hueGradient = useMemo(() => 'linear-gradient(to right, ' +
|
|
22
89
|
'#FF0000 0%, #FFFF00 17%, #00FF00 33%, #00FFFF 50%, #0000FF 67%, #FF00FF 83%, #FF0000 100%)', []);
|
|
23
|
-
// Alpha gradient
|
|
90
|
+
// Alpha gradient
|
|
24
91
|
const alphaGradient = useMemo(() => {
|
|
25
|
-
|
|
92
|
+
const rgb = hslToRgb(h, s, l);
|
|
93
|
+
return `linear-gradient(to right, rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0), rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 1))`;
|
|
26
94
|
}, [h, s, l]);
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}, className: "[&_.slider-track]:bg-[image:var(--slider-track-bg)]" }), showAlpha && (jsx(Slider, { min: 0, max: 1, step: 0.01, value: a, onChange: (value) => setAlpha(value), "aria-label": "Opacity", showValue: false, theme: {
|
|
35
|
-
trackStyle: `h-2 rounded-full`,
|
|
36
|
-
rangeStyle: 'h-full rounded-full bg-transparent',
|
|
37
|
-
thumbStyle: 'size-4 rounded-full border-2 border-white shadow-md',
|
|
38
|
-
}, style: {
|
|
39
|
-
['--slider-track-bg']: `${checkerboardBackground}, ${alphaGradient}`,
|
|
40
|
-
}, className: "[&_.slider-track]:bg-[length:8px_8px,100%] [&_.slider-track]:bg-[image:var(--slider-track-bg)]" }))] }));
|
|
95
|
+
const checkerboardBg = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==")';
|
|
96
|
+
const rgb = hslToRgb(h, s, l);
|
|
97
|
+
const thumbAlphaColor = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${a})`;
|
|
98
|
+
return (jsxs("div", { className: cn(theme.sliderContainerStyle, 'space-y-2', className), ...props, children: [jsx(ColorSliderTrack, { min: 0, max: 360, step: 1, value: h, onChange: setHue, thumbColor: `hsl(${h}, 100%, 50%)`, ariaLabel: "Hue", trackStyle: { backgroundImage: hueGradient } }), showAlpha && (jsx(ColorSliderTrack, { min: 0, max: 1, step: 0.01, value: a, onChange: setAlpha, thumbColor: thumbAlphaColor, ariaLabel: "Opacity", trackStyle: {
|
|
99
|
+
backgroundImage: `${alphaGradient}, ${checkerboardBg}`,
|
|
100
|
+
backgroundSize: '100% 100%, 8px 8px',
|
|
101
|
+
} }))] }));
|
|
41
102
|
};
|
|
42
103
|
ColorPickerSliders.displayName = 'ColorPickerSliders';
|
|
43
104
|
|
|
@@ -2,6 +2,6 @@ import React from 'react';
|
|
|
2
2
|
import type { ColorPickerSwatchProps } from './ColorPicker.types';
|
|
3
3
|
/**
|
|
4
4
|
* ColorPickerSwatch - Visual color preview with optional checkerboard background
|
|
5
|
-
* Shows the current color with transparency support
|
|
5
|
+
* Shows the current color (solid or gradient) with transparency support
|
|
6
6
|
*/
|
|
7
7
|
export declare const ColorPickerSwatch: React.FC<ColorPickerSwatchProps>;
|
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useContext } from 'react';
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
|
-
import { ColorPickerContext } from './
|
|
5
|
-
import { formatRgb
|
|
4
|
+
import { ColorPickerContext } from './ColorPickerContext.js';
|
|
5
|
+
import { formatRgb } from './colorUtils.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* ColorPickerSwatch - Visual color preview with optional checkerboard background
|
|
9
|
-
* Shows the current color with transparency support
|
|
9
|
+
* Shows the current color (solid or gradient) with transparency support
|
|
10
10
|
*/
|
|
11
11
|
const ColorPickerSwatch = ({ size = 'md', showCheckerboard = true, className, ...props }) => {
|
|
12
12
|
const context = useContext(ColorPickerContext);
|
|
13
13
|
if (!context) {
|
|
14
14
|
throw new Error('ColorPickerSwatch must be used within a ColorPicker');
|
|
15
15
|
}
|
|
16
|
-
const { color, theme } = context;
|
|
16
|
+
const { color, mode, getOutputValue, theme } = context;
|
|
17
17
|
const { h, s, l, a } = color;
|
|
18
|
-
// Convert HSL to RGB for display
|
|
19
|
-
hslToRgb(h, s, l);
|
|
20
18
|
const rgbaColor = formatRgb(h, s, l, a);
|
|
19
|
+
const isGradient = mode === 'gradient';
|
|
20
|
+
const outputValue = isGradient ? getOutputValue() : rgbaColor;
|
|
21
21
|
// Size variants
|
|
22
22
|
const sizeClasses = {
|
|
23
23
|
sm: 'size-5',
|
|
24
24
|
md: 'size-6',
|
|
25
25
|
lg: 'size-8',
|
|
26
26
|
};
|
|
27
|
-
return (jsxs("div", { className: cn(theme.swatchStyle, sizeClasses[size], className), role: "img", "aria-label": `Color: ${rgbaColor}`, ...props, children: [showCheckerboard && a < 1 && (jsx("div", { className: "absolute inset-0", style: {
|
|
27
|
+
return (jsxs("div", { className: cn(theme.swatchStyle, sizeClasses[size], className), role: "img", "aria-label": `Color: ${isGradient ? 'gradient' : rgbaColor}`, ...props, children: [showCheckerboard && !isGradient && a < 1 && (jsx("div", { className: "absolute inset-0", style: {
|
|
28
28
|
backgroundImage: 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==")',
|
|
29
29
|
backgroundSize: '8px 8px',
|
|
30
30
|
backgroundPosition: '0 0',
|
|
31
|
-
} })), jsx("div", { className: "absolute inset-0", style: {
|
|
32
|
-
|
|
31
|
+
} })), jsx("div", { className: "absolute inset-0 rounded-[inherit]", style: {
|
|
32
|
+
background: isGradient ? outputValue : undefined,
|
|
33
|
+
backgroundColor: isGradient ? undefined : rgbaColor,
|
|
33
34
|
} })] }));
|
|
34
35
|
};
|
|
35
36
|
ColorPickerSwatch.displayName = 'ColorPickerSwatch';
|
|
@@ -3,7 +3,7 @@ import { useContext, useRef, useEffect } from 'react';
|
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
4
|
import { Input } from '../Input/Input.js';
|
|
5
5
|
import '../Input/Input.theme.js';
|
|
6
|
-
import { ColorPickerContext } from './
|
|
6
|
+
import { ColorPickerContext } from './ColorPickerContext.js';
|
|
7
7
|
import { ColorPickerSwatch } from './ColorPickerSwatch.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -17,7 +17,11 @@ const ColorPickerTrigger = ({ className, ...props }) => {
|
|
|
17
17
|
if (!context) {
|
|
18
18
|
throw new Error('ColorPickerTrigger must be used within a ColorPicker');
|
|
19
19
|
}
|
|
20
|
-
const { isOpen, setIsOpen, disabled, state, getFormattedValue, triggerRef } = context;
|
|
20
|
+
const { isOpen, setIsOpen, disabled, state, mode, gradient, getFormattedValue, triggerRef } = context;
|
|
21
|
+
// Display value: for gradient mode, show stop colors comma-separated
|
|
22
|
+
const displayValue = mode === 'gradient'
|
|
23
|
+
? [...gradient.stops].sort((a, b) => a.position - b.position).map(s => s.color).join(', ')
|
|
24
|
+
: getFormattedValue();
|
|
21
25
|
// Update triggerRef with the wrapper element for positioning
|
|
22
26
|
useEffect(() => {
|
|
23
27
|
if (wrapperRef.current) {
|
|
@@ -31,7 +35,7 @@ const ColorPickerTrigger = ({ className, ...props }) => {
|
|
|
31
35
|
setIsOpen(!isOpen);
|
|
32
36
|
}
|
|
33
37
|
};
|
|
34
|
-
return (jsx("div", { ref: wrapperRef, onClick: handleWrapperClick, className: "relative", children: jsx(Input, { ref: inputRef, value:
|
|
38
|
+
return (jsx("div", { ref: wrapperRef, onClick: handleWrapperClick, className: "relative", children: jsx(Input, { ref: inputRef, value: displayValue, readOnly: true, disabled: disabled, state: state, contentStart: jsx(ColorPickerSwatch, { size: "sm" }), className: cn('cursor-pointer pointer-events-none', className), "aria-expanded": isOpen, "aria-haspopup": "dialog", ...props }) }));
|
|
35
39
|
};
|
|
36
40
|
ColorPickerTrigger.displayName = 'ColorPickerTrigger';
|
|
37
41
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* ColorPicker component exports
|
|
3
3
|
* Compound component following Flikkui patterns
|
|
4
4
|
*/
|
|
5
|
-
export { ColorPicker
|
|
5
|
+
export { ColorPicker } from './ColorPicker';
|
|
6
|
+
export { useColorPicker, ColorPickerContext } from './ColorPickerContext';
|
|
6
7
|
export { ColorPickerTrigger } from './ColorPickerTrigger';
|
|
7
8
|
export { ColorPickerBody } from './ColorPickerBody';
|
|
8
9
|
export { ColorPicker2DCanvas } from './ColorPicker2DCanvas';
|
|
@@ -12,6 +13,11 @@ export { ColorPickerInput } from './ColorPickerInput';
|
|
|
12
13
|
export { ColorPickerFormatSelector } from './ColorPickerFormatSelector';
|
|
13
14
|
export { ColorPickerEyeDropper } from './ColorPickerEyeDropper';
|
|
14
15
|
export { ColorPickerPresets } from './ColorPickerPresets';
|
|
15
|
-
export
|
|
16
|
+
export { ColorPickerSavedColors } from './ColorPickerSavedColors';
|
|
17
|
+
export { ColorPickerHeader } from './ColorPickerHeader';
|
|
18
|
+
export { ColorPickerGradient } from './ColorPickerGradient';
|
|
19
|
+
export { ColorPickerImage } from './ColorPickerImage';
|
|
20
|
+
export type { ColorPickerHeaderProps } from './ColorPickerHeader';
|
|
21
|
+
export type { ColorPickerProps, ColorPickerTriggerProps, ColorPickerBodyProps, ColorPickerSwatchProps, ColorPickerSlidersProps, ColorPickerInputProps, ColorPickerFormatSelectorProps, ColorPickerEyeDropperProps, ColorPickerPresetsProps, ColorPickerSavedColorsProps, ColorPickerGradientProps, ColorPickerImageProps, ColorPickerContextValue, ColorPickerTheme, ColorPickerThemeOverrides, ColorFormat, ColorPickerSize, ColorPickerState, ColorPickerMode, GradientType, GradientStop, GradientState, } from './ColorPicker.types';
|
|
16
22
|
export type { RGB, RGBA, HSL, HSLA, HSV, HSVA } from './colorUtils';
|
|
17
23
|
export { hexToRgb, rgbToHex, rgbToHsl, hslToRgb, rgbToHsv, hsvToRgb, validateHex, validateRgb, parseColor, formatHex, formatRgb, formatHsl, } from './colorUtils';
|
|
@@ -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-sm 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-xs 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-xs 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-xs 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-sm 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-xs text-[var(--color-text-muted)] " +
|
|
76
76
|
"dark:text-[var(--color-neutral-400)]",
|
|
77
77
|
// Section heading
|
|
78
|
-
sectionHeadingStyle: "text-
|
|
78
|
+
sectionHeadingStyle: "text-xs 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-xs 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-sm 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 " +
|
|
@@ -23,7 +23,7 @@ const dateRangePickerTheme = {
|
|
|
23
23
|
"dark:bg-[var(--color-neutral-900)] dark:border-[var(--color-neutral-700)]",
|
|
24
24
|
presetsContainerStyle: "hidden sm:flex flex-col gap-1 p-3 sm:border-r border-[var(--color-border)] bg-[var(--color-neutral-50)] sm:min-w-[180px] " +
|
|
25
25
|
"dark:bg-[var(--color-neutral-800)] ",
|
|
26
|
-
presetButtonStyle: "w-full text-left px-3 py-2 text-
|
|
26
|
+
presetButtonStyle: "w-full text-left px-3 py-2 text-sm font-medium rounded-[calc(var(--radius-base)*0.75)] transition-colors cursor-pointer " +
|
|
27
27
|
"flex items-center justify-between gap-2 " +
|
|
28
28
|
"text-[var(--color-text-secondary)] hover:bg-white hover:text-[var(--color-text-primary)] " +
|
|
29
29
|
"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 " +
|
|
@@ -33,14 +33,14 @@ const dateRangePickerTheme = {
|
|
|
33
33
|
"dark:focus-visible:ring-offset-[var(--color-neutral-800)]",
|
|
34
34
|
presetCheckmarkStyle: "size-4 text-[var(--color-primary)] shrink-0",
|
|
35
35
|
mobilePresetsContainerStyle: "sm:hidden px-3 pt-3 pb-1",
|
|
36
|
-
mobilePresetButtonStyle: "whitespace-nowrap px-3 py-1.5 text-
|
|
36
|
+
mobilePresetButtonStyle: "whitespace-nowrap px-3 py-1.5 text-xs font-medium rounded-full transition-colors cursor-pointer shrink-0 " +
|
|
37
37
|
"bg-[var(--color-background-secondary)] text-[var(--color-text-secondary)] " +
|
|
38
38
|
"hover:bg-[var(--color-background-tertiary)] hover:text-[var(--color-text-primary)] " +
|
|
39
39
|
"data-[active=true]:bg-[var(--color-primary-50)] data-[active=true]:text-[var(--color-primary)] " +
|
|
40
40
|
"dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-300)] " +
|
|
41
41
|
"dark:hover:bg-[var(--color-neutral-700)] " +
|
|
42
42
|
"dark:data-[active=true]:bg-[var(--color-primary-950)] dark:data-[active=true]:text-[var(--color-primary-300)]",
|
|
43
|
-
mobileRangeDisplayStyle: "sm:hidden text-
|
|
43
|
+
mobileRangeDisplayStyle: "sm:hidden text-xs text-center py-2 text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
|
|
44
44
|
helperTextStyle: formsBaseTheme.helperText,
|
|
45
45
|
helperTextStates: {
|
|
46
46
|
default: "text-[var(--color-text-muted)] dark:text-[var(--color-neutral-400)]",
|
|
@@ -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-sm font-medium text-[var(--color-text-primary)]",
|
|
20
20
|
// Helper text
|
|
21
|
-
helperTextStyle: "text-
|
|
21
|
+
helperTextStyle: "text-sm text-[var(--color-text-muted)] mt-1",
|
|
22
22
|
// Description below dropzone
|
|
23
|
-
descriptionStyle: "text-
|
|
23
|
+
descriptionStyle: "text-xs 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-sm 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
|
};
|
|
@@ -2,8 +2,8 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import React__default, { useState, useEffect } from 'react';
|
|
3
3
|
import { useReducedMotion, motion, AnimatePresence } from 'motion/react';
|
|
4
4
|
import { DocumentIcon, TrashIcon, XMarkIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
|
|
5
|
-
import {
|
|
6
|
-
import { fileTypes } from '../../core/
|
|
5
|
+
import { Icon } from '../../core/Icon/Icon.js';
|
|
6
|
+
import { fileTypes } from '../../core/Icon/data/fileTypes.js';
|
|
7
7
|
import { cn } from '../../../utils/cn.js';
|
|
8
8
|
import { getFileExtension, formatFileSize } from '../../../utils/formatUtils.js';
|
|
9
9
|
import { Popover } from '../../core/Popover/Popover.js';
|
|
@@ -103,7 +103,7 @@ const FileUploadProgress = React__default.forwardRef(({ items, onRemove, onRetry
|
|
|
103
103
|
const clampedProgress = Math.min(100, Math.max(0, item.progress));
|
|
104
104
|
const ext = getFileExtension(item.file.name);
|
|
105
105
|
const hasFileTypeIcon = ext !== null && isKnownFileType(ext);
|
|
106
|
-
return (jsxs("div", { className: (_a = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.itemStyle) !== null && _a !== void 0 ? _a : t.itemStyle, children: [hasFileTypeIcon ? (jsx("span", { className: "shrink-0", children: jsx(
|
|
106
|
+
return (jsxs("div", { className: (_a = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.itemStyle) !== null && _a !== void 0 ? _a : t.itemStyle, children: [hasFileTypeIcon ? (jsx("span", { className: "shrink-0", children: jsx(Icon, { icon: ext, size: "lg" }) })) : (jsx("span", { className: cn((_b = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconContainerStyle) !== null && _b !== void 0 ? _b : t.iconContainerStyle, t.iconSize), children: jsx(DocumentIcon, { className: (_c = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconStyle) !== null && _c !== void 0 ? _c : t.iconStyle }) })), jsxs("div", { className: (_d = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileInfoStyle) !== null && _d !== void 0 ? _d : t.fileInfoStyle, children: [jsx("p", { className: (_e = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileNameStyle) !== null && _e !== void 0 ? _e : t.fileNameStyle, children: item.file.name }), showFileSize && (jsx("p", { className: (_f = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileSizeStyle) !== null && _f !== void 0 ? _f : t.fileSizeStyle, children: formatFileSize(item.file.size) })), item.status === "error" && item.error && (jsx("p", { className: (_g = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.errorTextStyle) !== null && _g !== void 0 ? _g : t.errorTextStyle, children: item.error }))] }), jsx(RadialProgress, { progress: clampedProgress, status: item.status, strokeWidth: t.radialStroke, trackColor: (_h = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialTrackColor) !== null && _h !== void 0 ? _h : t.radialTrackColor, progressColor: radialProgressColors[item.status], centerTextStyle: (_j = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialCenterTextStyle) !== null && _j !== void 0 ? _j : t.radialCenterTextStyle, statusIconColor: statusIconColors[item.status], sizeClass: t.radialSize, shouldReduceMotion: shouldReduceMotion, confirmRemove: confirmRemove, completionDelay: completionDelay, onRemove: onRemove ? () => onRemove(item.id) : undefined, onRetry: onRetry ? () => onRetry(item.id) : undefined })] }, item.id));
|
|
107
107
|
}) }));
|
|
108
108
|
});
|
|
109
109
|
FileUploadProgress.displayName = "FileUploadProgress";
|
|
@@ -4,8 +4,8 @@ const fileUploadProgressTheme = {
|
|
|
4
4
|
iconContainerStyle: "flex items-center justify-center rounded-lg shrink-0 border border-[var(--color-border)] bg-[var(--color-background-secondary)]",
|
|
5
5
|
iconStyle: "shrink-0 size-5 text-[var(--color-text-muted)]",
|
|
6
6
|
fileInfoStyle: "flex-1 min-w-0",
|
|
7
|
-
fileNameStyle: "text-
|
|
8
|
-
fileSizeStyle: "text-
|
|
7
|
+
fileNameStyle: "text-sm font-medium text-[var(--color-text-primary)] truncate",
|
|
8
|
+
fileSizeStyle: "text-xs text-[var(--color-text-muted)]",
|
|
9
9
|
radialTrackColor: "var(--color-background-tertiary)",
|
|
10
10
|
radialProgressColors: {
|
|
11
11
|
uploading: "var(--color-primary)",
|
|
@@ -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-sm/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)]",
|
|
@@ -67,7 +67,7 @@ const PasswordStrengthIndicator = ({ inline = false, passwordStrengthIndicator,
|
|
|
67
67
|
// ============================================================================
|
|
68
68
|
// Main Input Component
|
|
69
69
|
// ============================================================================
|
|
70
|
-
const Input = React__default.forwardRef(({ size = "md", state = "default", className = "", label, labelClassName = "", helperText, helperTextClassName = "", wrapperClassName = "", inputGroupClassName = "", iconStart, iconEnd, contentStart, contentEnd, keyboardShortcut, id, required, type = "text", passwordToggle = type === "password", passwordStrengthIndicator, showNumberControls = false, min, max, step = 1, onChange, onFocus, onBlur, value, currencyDecimalPlaces, darkMode = false, ...props }, ref) => {
|
|
70
|
+
const Input = React__default.forwardRef(({ size = "md", state = "default", className = "", label, labelClassName = "", helperText, helperTextClassName = "", wrapperClassName = "", inputGroupClassName = "", iconStart, iconEnd, contentStart, contentEnd, keyboardShortcut, id, required, type = "text", passwordToggle = type === "password", passwordStrengthIndicator, showNumberControls = false, min, max, step = 1, onChange, onFocus, onBlur, value, currencyDecimalPlaces, darkMode = false, showTypeIcon = true, ...props }, ref) => {
|
|
71
71
|
const [isFocused, setIsFocused] = useState(false);
|
|
72
72
|
const [showPassword, setShowPassword] = useState(false);
|
|
73
73
|
const generatedId = React__default.useId();
|
|
@@ -82,8 +82,8 @@ const Input = React__default.forwardRef(({ size = "md", state = "default", class
|
|
|
82
82
|
const inputRef = useRef(null);
|
|
83
83
|
const cursorPositionRef = useRef(null);
|
|
84
84
|
// Default icons based on input type
|
|
85
|
-
const defaultPasswordIcon = type === "password" && !iconStart ? (jsx(LockClosedIcon, { className: "size-5 text-[var(--color-text-muted)]" })) : null;
|
|
86
|
-
const defaultSearchIcon = type === "search" && !iconStart ? (jsx(MagnifyingGlassIcon, { className: cn("size-5", inputTheme.typeStyles.search.iconStyle) })) : null;
|
|
85
|
+
const defaultPasswordIcon = showTypeIcon && type === "password" && !iconStart ? (jsx(LockClosedIcon, { className: "size-5 text-[var(--color-text-muted)]" })) : null;
|
|
86
|
+
const defaultSearchIcon = showTypeIcon && type === "search" && !iconStart ? (jsx(MagnifyingGlassIcon, { className: cn("size-5", inputTheme.typeStyles.search.iconStyle) })) : null;
|
|
87
87
|
// Use the provided iconStart or the default icon based on input type
|
|
88
88
|
const finalLeftIcon = iconStart || defaultPasswordIcon || defaultSearchIcon;
|
|
89
89
|
// Derived state flags for internal use
|
|
@@ -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-xs 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)]",
|
|
@@ -61,6 +61,8 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
|
|
|
61
61
|
passwordStrengthIndicator?: PasswordStrengthIndicator;
|
|
62
62
|
/** Number of decimal places for currency inputs (default: 2). Only applies when type="currency" */
|
|
63
63
|
currencyDecimalPlaces?: number;
|
|
64
|
+
/** Whether to show the automatic type-based icon (lock for password, magnifier for search). Default: true */
|
|
65
|
+
showTypeIcon?: boolean;
|
|
64
66
|
/**
|
|
65
67
|
* Force dark mode styling for the component. Use when placing the component
|
|
66
68
|
* on a dark background while the page is in light mode.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const inputCounterTheme = {
|
|
6
6
|
baseStyle: "flex items-center gap-3 transition-all p-1 border border-[var(--color-border)] rounded-[var(--form-radius)] w-fit",
|
|
7
7
|
buttonWrapperStyle: "flex-shrink-0",
|
|
8
|
-
numberStyle: "min-w-fit text-center text-
|
|
8
|
+
numberStyle: "min-w-fit text-center text-sm font-medium text-[var(--color-text-primary)] tabular-nums select-none",
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export { inputCounterTheme };
|
|
@@ -10,7 +10,7 @@ const inputOTPTheme = {
|
|
|
10
10
|
// OTP input container
|
|
11
11
|
containerStyle: 'flex items-center gap-3',
|
|
12
12
|
// Individual input field styles with design tokens
|
|
13
|
-
inputStyle: 'text-center text-
|
|
13
|
+
inputStyle: 'text-center text-lg text-[var(--color-text-primary)] h-full !p-0',
|
|
14
14
|
// Input group wrapper for grouped inputs (overrides default Input styling)
|
|
15
15
|
inputGroupStyle: 'w-10 min-w-10 h-10 min-h-10 sm:w-12 sm:min-w-12 sm:h-12 sm:min-h-12',
|
|
16
16
|
// Separator between input groups
|
|
@@ -37,13 +37,13 @@ const mentionTheme = {
|
|
|
37
37
|
suggestionAvatarStyle: "size-7 rounded-full object-cover shrink-0 " +
|
|
38
38
|
"bg-[var(--color-background-tertiary)] dark:bg-[var(--color-neutral-700)]",
|
|
39
39
|
// Avatar fallback (initials circle)
|
|
40
|
-
suggestionAvatarFallbackStyle: "size-7 rounded-full shrink-0 flex items-center justify-center text-
|
|
40
|
+
suggestionAvatarFallbackStyle: "size-7 rounded-full shrink-0 flex items-center justify-center text-xs font-medium " +
|
|
41
41
|
"bg-[var(--color-primary-100)] text-[var(--color-primary-700)] " +
|
|
42
42
|
"dark:bg-[var(--color-primary-900)] dark:text-[var(--color-primary-300)]",
|
|
43
43
|
// Suggestion label text
|
|
44
|
-
suggestionLabelStyle: "text-
|
|
44
|
+
suggestionLabelStyle: "text-sm font-medium truncate",
|
|
45
45
|
// Suggestion description text
|
|
46
|
-
suggestionDescriptionStyle: "text-
|
|
46
|
+
suggestionDescriptionStyle: "text-xs text-[var(--color-text-muted)] truncate " +
|
|
47
47
|
"dark:text-[var(--color-neutral-500)]",
|
|
48
48
|
// Empty state
|
|
49
49
|
emptyMessageStyle: formsBaseTheme.dropdownStyles.emptyMessage,
|
|
@@ -29,7 +29,7 @@ const radioTheme = {
|
|
|
29
29
|
sm: "size-2.5 mt-0.25",
|
|
30
30
|
md: "size-3",
|
|
31
31
|
},
|
|
32
|
-
descriptionStyle: "text-
|
|
32
|
+
descriptionStyle: "text-sm text-[var(--color-text-secondary)]/80 mt-0",
|
|
33
33
|
sizes: {
|
|
34
34
|
sm: "size-5 mt-0.5",
|
|
35
35
|
md: "size-6",
|
|
@@ -37,8 +37,8 @@ const radioTheme = {
|
|
|
37
37
|
// Group styles
|
|
38
38
|
groupStyle: "flex flex-col gap-1.5",
|
|
39
39
|
groupHorizontalStyle: "flex-row flex-wrap gap-x-6 gap-y-3",
|
|
40
|
-
groupDescriptionStyle: "text-
|
|
41
|
-
groupErrorStyle: "text-
|
|
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
42
|
groupItemsStyle: "flex flex-col gap-3",
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -32,7 +32,7 @@ const richTextEditorTheme = {
|
|
|
32
32
|
// Dropdown styling (font size, color picker)
|
|
33
33
|
dropdownStyle: "fixed z-[1000] min-w-[120px] py-1 bg-white/90 backdrop-blur-md rounded-[var(--form-radius)] shadow-xl ring-1 ring-[var(--color-border)] focus:outline-none",
|
|
34
34
|
// Dropdown item styling
|
|
35
|
-
dropdownItemStyle: "block w-full px-3 py-2 text-left text-
|
|
35
|
+
dropdownItemStyle: "block w-full px-3 py-2 text-left text-sm text-[var(--color-text-primary)] hover:bg-[var(--color-background-tertiary)] transition-colors duration-150 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
36
36
|
// Separator between toolbar sections
|
|
37
37
|
separatorStyle: "w-px h-6 bg-[var(--color-border)] mx-1",
|
|
38
38
|
// Color picker grid layout
|
|
@@ -60,7 +60,7 @@ const selectTheme = {
|
|
|
60
60
|
iconPadding: formsBaseTheme.iconStyles.padding,
|
|
61
61
|
// Multi-select chip styles
|
|
62
62
|
chipContainerStyle: "flex flex-nowrap gap-1 items-center min-w-0 overflow-hidden -ml-2",
|
|
63
|
-
chipOverflowStyle: "inline-flex items-center shrink-0 whitespace-nowrap px-1.5 py-0.5 text-
|
|
63
|
+
chipOverflowStyle: "inline-flex items-center shrink-0 whitespace-nowrap px-1.5 py-0.5 text-xs font-medium " +
|
|
64
64
|
"text-[var(--color-text-muted)]",
|
|
65
65
|
};
|
|
66
66
|
|