@flikk/ui 1.0.0-beta.24 → 1.0.0-beta.26
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.js +1 -0
- package/dist/components/ai/PromptInput/VoiceRecorder.js +1 -0
- package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +1 -1
- package/dist/components/ai/TokenCounter/TokenCounter.theme.js +1 -1
- package/dist/components/charts/BarChart/BarChart.js +2 -2
- package/dist/components/charts/StackedBarChart/StackedBarChart.js +1 -1
- package/dist/components/charts/shared/BarRenderer/BarRenderer.js +2 -2
- package/dist/components/core/Accordion/Accordion.theme.js +2 -2
- package/dist/components/core/Breadcrumbs/Breadcrumbs.js +1 -1
- package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +2 -2
- package/dist/components/core/Button/Button.js +1 -1
- package/dist/components/core/Button/Button.theme.js +4 -4
- package/dist/components/core/Calendar/Calendar.js +1 -1
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.js +4 -2
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.js +2 -2
- package/dist/components/core/ContextMenu/ContextMenu.theme.js +1 -1
- package/dist/components/core/Drawer/Drawer.theme.js +2 -2
- package/dist/components/core/Dropdown/Dropdown.theme.js +2 -2
- package/dist/components/core/Empty/Empty.js +1 -1
- package/dist/components/core/Empty/Empty.theme.js +1 -1
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.d.ts +14 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.js +28 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.d.ts +6 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.js +8 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.types.d.ts +32 -0
- package/dist/components/core/ImagePlaceholder/index.d.ts +2 -0
- package/dist/components/core/Link/Link.js +1 -1
- package/dist/components/core/Message/Message.theme.js +1 -1
- package/dist/components/core/Modal/Modal.theme.js +1 -1
- package/dist/components/core/NavItem/NavItem.d.ts +1 -1
- package/dist/components/core/NavItem/NavItem.js +171 -68
- package/dist/components/core/NavItem/NavItem.theme.js +20 -12
- package/dist/components/core/NavItem/NavItem.types.d.ts +17 -39
- package/dist/components/core/Pagination/Pagination.theme.js +3 -3
- package/dist/components/core/Popover/Popover.theme.js +1 -1
- package/dist/components/core/Progress/Progress.theme.js +1 -1
- package/dist/components/core/ScrollArea/ScrollArea.js +2 -2
- package/dist/components/core/ScrollArea/ScrollArea.theme.js +1 -1
- package/dist/components/core/Segmented/Segmented.js +8 -6
- package/dist/components/core/Segmented/Segmented.theme.js +3 -3
- package/dist/components/core/Sidebar/Sidebar.d.ts +1 -1
- package/dist/components/core/Sidebar/Sidebar.js +42 -13
- package/dist/components/core/Sidebar/Sidebar.theme.js +5 -7
- package/dist/components/core/Sidebar/Sidebar.types.d.ts +33 -4
- package/dist/components/core/Sidebar/SidebarContent.js +6 -6
- package/dist/components/core/Sidebar/SidebarContext.d.ts +17 -16
- package/dist/components/core/Sidebar/SidebarContext.js +42 -19
- package/dist/components/core/Sidebar/SidebarFooter.js +4 -6
- package/dist/components/core/Sidebar/SidebarHeader.js +4 -9
- package/dist/components/core/Sidebar/SidebarLogo.js +3 -7
- package/dist/components/core/Sidebar/SidebarNav.js +4 -3
- package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -7
- package/dist/components/core/Sidebar/SidebarToggle.js +6 -1
- package/dist/components/core/Sidebar/SidebarUserProfile.js +33 -17
- package/dist/components/core/Sidebar/index.d.ts +2 -3
- package/dist/components/core/Skeleton/Skeleton.theme.js +1 -1
- package/dist/components/core/Spinner/Spinner.theme.js +1 -1
- package/dist/components/core/Tabs/Tabs.js +6 -1
- package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
- package/dist/components/core/Tabs/TabsBody.js +5 -3
- package/dist/components/core/Tag/Tag.theme.js +1 -1
- package/dist/components/core/index.d.ts +1 -0
- package/dist/components/core/index.js +2 -2
- package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
- package/dist/components/data-display/KPI/KPI.js +13 -3
- package/dist/components/data-display/KPI/KPI.theme.js +3 -3
- package/dist/components/data-display/Metric/Metric.theme.js +3 -3
- package/dist/components/data-display/Table/Table.js +4 -3
- package/dist/components/data-display/Table/Table.theme.js +11 -1
- package/dist/components/data-display/Table/Table.types.d.ts +15 -0
- package/dist/components/data-display/Table/TableColumnManager.js +1 -1
- package/dist/components/data-display/Table/index.d.ts +2 -2
- package/dist/components/data-display/Timeline/Timeline.animations.d.ts +0 -7
- package/dist/components/data-display/Timeline/Timeline.animations.js +1 -27
- package/dist/components/data-display/Timeline/Timeline.js +3 -4
- package/dist/components/data-display/Timeline/Timeline.types.d.ts +0 -13
- package/dist/components/data-display/Timeline/TimelineContent.js +3 -7
- package/dist/components/data-display/Timeline/TimelineItem.js +4 -17
- package/dist/components/data-display/Timeline/index.d.ts +2 -2
- package/dist/components/effects/Aurora/Aurora.js +79 -40
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +3 -3
- package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +13 -4
- package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +13 -4
- package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +14 -4
- package/dist/components/effects/MorphingText/MorphingText.js +40 -7
- package/dist/components/effects/StripePattern/StripePattern.d.ts +18 -0
- package/dist/components/effects/StripePattern/StripePattern.js +54 -0
- package/dist/components/effects/StripePattern/StripePattern.types.d.ts +53 -0
- package/dist/components/effects/StripePattern/index.d.ts +2 -0
- package/dist/components/effects/index.d.ts +9 -0
- package/dist/components/effects/index.js +4 -0
- package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
- package/dist/components/forms/CronInput/CronInput.theme.js +16 -16
- package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
- package/dist/components/forms/FileUpload/FileUpload.js +1 -1
- package/dist/components/forms/FileUpload/FileUploadProgress.js +27 -20
- package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
- package/dist/components/forms/Input/Input.theme.js +9 -11
- package/dist/components/forms/Mention/Mention.theme.js +3 -3
- package/dist/components/forms/Radio/Radio.theme.js +1 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.d.ts +18 -0
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +1231 -236
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.d.ts +53 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +99 -25
- package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +42 -3
- package/dist/components/forms/RichTextEditor/index.d.ts +2 -2
- package/dist/components/forms/Select/Select.js +2 -2
- package/dist/components/forms/Slider/Slider.theme.js +1 -1
- package/dist/components/forms/Switch/Switch.theme.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
- package/dist/components/forms/TimePicker/TimePickerContent.js +1 -0
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
- package/dist/components/forms/forms.theme.js +12 -12
- package/dist/components/forms/index.js +1 -0
- package/dist/components/layout/FormLayout/FormLayout.js +6 -4
- package/dist/components/layout/FormLayout/FormLayout.types.d.ts +3 -3
- package/dist/components/layout/FormLayout/FormLayoutSection.js +6 -1
- package/dist/components/layout/PageLayout/PageLayout.d.ts +2 -2
- package/dist/components/layout/PageLayout/PageLayout.js +23 -5
- package/dist/components/layout/PageLayout/PageLayout.theme.d.ts +2 -1
- package/dist/components/layout/PageLayout/PageLayout.theme.js +35 -6
- package/dist/components/layout/PageLayout/PageLayout.types.d.ts +45 -0
- package/dist/components/layout/PageLayout/PageLayoutContent.js +6 -4
- package/dist/components/layout/PageLayout/PageLayoutHeader.js +3 -3
- package/dist/components/layout/PageLayout/PageLayoutSidebar.js +5 -3
- package/dist/components/layout/PageLayout/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/theme.css +127 -92
- package/dist/components/core/Sidebar/SidebarSubmenu.d.ts +0 -7
- package/dist/components/core/Sidebar/SidebarSubmenu.js +0 -12
|
@@ -16,13 +16,13 @@ const cronInputTheme = {
|
|
|
16
16
|
// Field label
|
|
17
17
|
fieldLabelStyle: "text-xs font-medium text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
|
|
18
18
|
// Select dropdown
|
|
19
|
-
fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline
|
|
19
|
+
fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
|
|
20
20
|
"bg-white text-[var(--color-text-primary)] cursor-pointer transition-all " +
|
|
21
|
-
"focus:
|
|
21
|
+
"focus:shadow-[inset_0_0_0_2px_var(--color-primary-600)] " +
|
|
22
22
|
"focus:ring-4 focus:ring-[var(--color-primary)]/10 " +
|
|
23
23
|
"disabled:cursor-not-allowed disabled:bg-[var(--color-background-disabled)] disabled:text-[var(--color-text-disabled)] " +
|
|
24
|
-
"dark:bg-[var(--color-neutral-900)] dark:
|
|
25
|
-
"dark:focus:
|
|
24
|
+
"dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
|
|
25
|
+
"dark:focus:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
|
|
26
26
|
// Size variants for field selects
|
|
27
27
|
fieldSelectSizes: {
|
|
28
28
|
sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
|
|
@@ -30,14 +30,14 @@ const cronInputTheme = {
|
|
|
30
30
|
lg: `${formsBaseTheme.sizes.lg.text} ${formsBaseTheme.sizes.lg.padding} ${formsBaseTheme.sizes.lg.height}`,
|
|
31
31
|
},
|
|
32
32
|
// Raw input field
|
|
33
|
-
rawInputStyle: "w-full rounded-[var(--form-radius)] outline
|
|
33
|
+
rawInputStyle: "w-full rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
|
|
34
34
|
"bg-white text-[var(--color-text-primary)] font-mono transition-all " +
|
|
35
35
|
"placeholder:text-[var(--color-text-placeholder)] focus:outline-none " +
|
|
36
|
-
"focus:
|
|
36
|
+
"focus:shadow-[inset_0_0_0_2px_var(--color-primary-600)] " +
|
|
37
37
|
"focus:ring-4 focus:ring-[var(--color-primary)]/10 " +
|
|
38
38
|
"disabled:cursor-not-allowed disabled:bg-[var(--color-background-disabled)] disabled:text-[var(--color-text-disabled)] " +
|
|
39
|
-
"dark:bg-[var(--color-neutral-900)] dark:
|
|
40
|
-
"dark:focus:
|
|
39
|
+
"dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
|
|
40
|
+
"dark:focus:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
|
|
41
41
|
// Size variants for raw input
|
|
42
42
|
rawInputSizes: {
|
|
43
43
|
sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
|
|
@@ -46,26 +46,26 @@ const cronInputTheme = {
|
|
|
46
46
|
},
|
|
47
47
|
// Mode toggle button
|
|
48
48
|
modeToggleStyle: "inline-flex items-center justify-center rounded-[var(--form-radius)] px-3 py-1.5 text-xs font-medium " +
|
|
49
|
-
"cursor-pointer transition-all outline
|
|
49
|
+
"cursor-pointer transition-all outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
|
|
50
50
|
"text-[var(--color-text-secondary)] bg-white hover:bg-[var(--color-background-secondary)] " +
|
|
51
|
-
"dark:bg-[var(--color-neutral-900)] dark:
|
|
51
|
+
"dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
|
|
52
52
|
"dark:hover:bg-[var(--color-neutral-800)]",
|
|
53
53
|
// Active mode toggle
|
|
54
|
-
modeToggleActiveStyle: "
|
|
54
|
+
modeToggleActiveStyle: "shadow-[inset_0_0_0_1px_var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
|
|
55
55
|
"hover:bg-[var(--color-primary-50)] " +
|
|
56
|
-
"dark:
|
|
56
|
+
"dark:shadow-[inset_0_0_0_1px_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
59
|
presetButtonStyle: "inline-flex items-center rounded-[var(--form-radius)] px-2.5 py-1 text-xs font-medium " +
|
|
60
|
-
"cursor-pointer transition-all outline
|
|
60
|
+
"cursor-pointer transition-all outline-none shadow-[inset_0_0_0_1px_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)] " +
|
|
63
|
-
"dark:bg-[var(--color-neutral-900)] dark:
|
|
63
|
+
"dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
|
|
64
64
|
"dark:hover:bg-[var(--color-neutral-800)] dark:hover:text-[var(--color-neutral-200)]",
|
|
65
65
|
// Active preset button
|
|
66
|
-
presetButtonActiveStyle: "
|
|
66
|
+
presetButtonActiveStyle: "shadow-[inset_0_0_0_1px_var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
|
|
67
67
|
"hover:bg-[var(--color-primary-100)] " +
|
|
68
|
-
"dark:
|
|
68
|
+
"dark:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)]",
|
|
69
69
|
// Human-readable description
|
|
70
70
|
descriptionStyle: "flex items-center gap-2 text-sm text-[var(--color-text-muted)] " +
|
|
71
71
|
"dark:text-[var(--color-neutral-400)]",
|
|
@@ -26,7 +26,7 @@ const DatePickerTrigger = ({ id, disabled, isOpen, state = "default", size = "md
|
|
|
26
26
|
// Apply focused styles when open - same pattern as SelectButton
|
|
27
27
|
const activeFocusState = isOpen
|
|
28
28
|
? focusStateStyle ||
|
|
29
|
-
"
|
|
29
|
+
"shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10"
|
|
30
30
|
: "";
|
|
31
31
|
return (jsx("div", { className: "relative w-full", children: jsxs("button", { ref: triggerRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconEndPadding, triggerButtonStyle, "text-left", className), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Open calendar", "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, children: [children, jsx("span", { className: iconEndStyle, children: jsx(CalendarIcon, { className: "h-4 w-4" }) })] }) }));
|
|
32
32
|
};
|
|
@@ -35,7 +35,7 @@ const dateRangePickerTheme = {
|
|
|
35
35
|
mobilePresetsContainerStyle: "sm:hidden px-3 pt-3 pb-1",
|
|
36
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
|
-
"hover:bg-[var(--color-
|
|
38
|
+
"hover:bg-[var(--color-surface-hover)] 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)] " +
|
|
@@ -24,7 +24,7 @@ const DateRangePickerTrigger = ({ id, disabled, isOpen, state = "default", size
|
|
|
24
24
|
const triggerButtonStyle = theme.triggerButtonStyle || "";
|
|
25
25
|
const activeFocusState = isOpen
|
|
26
26
|
? focusStateStyle ||
|
|
27
|
-
"
|
|
27
|
+
"shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10"
|
|
28
28
|
: "";
|
|
29
29
|
return (jsx("div", { className: "relative w-full", children: jsxs("button", { ref: triggerRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconEndPadding, triggerButtonStyle, "text-left", className), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Open date range picker", "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, children: [children, jsx("span", { className: iconEndStyle, children: jsx(CalendarIcon, { className: "h-4 w-4" }) })] }) }));
|
|
30
30
|
};
|
|
@@ -78,7 +78,6 @@ import '../../core/Sidebar/SidebarContent.js';
|
|
|
78
78
|
import '../../core/Sidebar/SidebarFooter.js';
|
|
79
79
|
import '../../core/Sidebar/SidebarNav.js';
|
|
80
80
|
import '../../core/Sidebar/SidebarNavGroup.js';
|
|
81
|
-
import 'motion/react';
|
|
82
81
|
import '../../core/Sidebar/SidebarToggle.js';
|
|
83
82
|
import '../../core/Sidebar/SidebarMobileTrigger.js';
|
|
84
83
|
import '../../core/Sidebar/SidebarUserProfile.js';
|
|
@@ -89,6 +88,7 @@ import '../../core/ContextMenu/ContextMenu.js';
|
|
|
89
88
|
import '../../core/ContextMenu/ContextMenu.theme.js';
|
|
90
89
|
import '../../core/Pill/Pill.js';
|
|
91
90
|
import '../../core/Icon/Icon.js';
|
|
91
|
+
import '../../core/ImagePlaceholder/ImagePlaceholder.js';
|
|
92
92
|
import { FormLabel } from '../FormLabel/FormLabel.js';
|
|
93
93
|
|
|
94
94
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
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
|
-
import { DocumentIcon, TrashIcon,
|
|
4
|
+
import { DocumentIcon, TrashIcon, ArrowPathIcon, XMarkIcon } from '@heroicons/react/24/outline';
|
|
5
5
|
import { Icon } from '../../core/Icon/Icon.js';
|
|
6
6
|
import { fileTypes } from '../../core/Icon/data/fileTypes.js';
|
|
7
7
|
import { cn } from '../../../utils/cn.js';
|
|
@@ -39,27 +39,38 @@ const RadialProgress = ({ progress, status, strokeWidth, trackColor, progressCol
|
|
|
39
39
|
setShowRemove(false);
|
|
40
40
|
}, [isComplete, completionDelay]);
|
|
41
41
|
const handleClick = () => {
|
|
42
|
-
if (
|
|
43
|
-
onRetry();
|
|
42
|
+
if (!onRemove)
|
|
44
43
|
return;
|
|
44
|
+
if (confirmRemove) {
|
|
45
|
+
setConfirmOpen(true);
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
setConfirmOpen(true);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
onRemove();
|
|
52
|
-
}
|
|
47
|
+
else {
|
|
48
|
+
onRemove();
|
|
53
49
|
}
|
|
54
50
|
};
|
|
55
51
|
const handleConfirm = () => {
|
|
56
52
|
setConfirmOpen(false);
|
|
57
53
|
onRemove === null || onRemove === void 0 ? void 0 : onRemove();
|
|
58
54
|
};
|
|
59
|
-
|
|
60
|
-
const
|
|
55
|
+
// Uploading/complete: the radial doubles as the cancel/remove target.
|
|
56
|
+
const isClickable = !!onRemove;
|
|
57
|
+
const ariaLabel = onRemove ? "Remove file" : undefined;
|
|
58
|
+
// Confirm popover shared by the radial (cancel/remove) and the error-state delete button.
|
|
59
|
+
const confirmPopover = (trigger, label, offsetValue) => (jsxs(Popover, { isOpen: confirmOpen, onOpenChange: (open) => {
|
|
60
|
+
setConfirmOpen(open);
|
|
61
|
+
if (!open)
|
|
62
|
+
setIsHovered(false);
|
|
63
|
+
}, placement: "bottom-end", offset: offsetValue, triggerType: "click", children: [jsx(Popover.Trigger, { children: trigger }), jsxs(Popover.Body, { className: "flex items-center p-1 border-[0.5px] rounded-xl gap-0.5 bg-opacity-50 backdrop-blur-md", children: [jsx("span", { className: "text-sm font-semibold text-[var(--color-text-secondary)] px-3", children: label }), jsxs("div", { className: "flex gap-1", children: [jsx(Button, { size: "sm", color: "danger", variant: "filled", onClick: handleConfirm, children: "Yes" }), jsx(Button, { size: "sm", variant: "soft", color: "neutral", onClick: () => setConfirmOpen(false), children: "No" })] })] })] }));
|
|
61
64
|
// Shared remove button used after completion tick
|
|
62
65
|
const removeButton = (jsx(motion.div, { initial: shouldReduceMotion ? false : REMOVE_BUTTON_ENTER.initial, animate: REMOVE_BUTTON_ENTER.animate, transition: REMOVE_BUTTON_ENTER.transition, className: "shrink-0", children: jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Remove file", iconOnly: true, className: "rounded-full size-8", onClick: confirmRemove ? undefined : () => onRemove === null || onRemove === void 0 ? void 0 : onRemove(), children: jsx(TrashIcon, { className: "size-3.5", strokeWidth: 2 }) }) }, "remove-btn"));
|
|
66
|
+
// Error state: retry + delete buttons (no progress arc/percentage).
|
|
67
|
+
if (isError) {
|
|
68
|
+
const deleteButton = onRemove ? (jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Remove file", iconOnly: true, className: "rounded-full size-8", onClick: confirmRemove ? undefined : () => onRemove(), children: jsx(TrashIcon, { className: "size-3.5", strokeWidth: 2 }) })) : null;
|
|
69
|
+
return (jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [onRetry && (jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Retry upload", iconOnly: true, className: "rounded-full size-8", onClick: () => onRetry(), children: jsx(ArrowPathIcon, { className: "size-3.5", strokeWidth: 2 }) })), deleteButton &&
|
|
70
|
+
(confirmRemove
|
|
71
|
+
? confirmPopover(deleteButton, "Remove file?", 6)
|
|
72
|
+
: deleteButton)] }));
|
|
73
|
+
}
|
|
63
74
|
const radialElement = (jsxs("div", { className: cn("relative shrink-0", sizeClass, isClickable && "cursor-pointer"), onMouseEnter: () => setIsHovered(true), onMouseLeave: () => {
|
|
64
75
|
if (!confirmOpen)
|
|
65
76
|
setIsHovered(false);
|
|
@@ -70,18 +81,14 @@ const RadialProgress = ({ progress, status, strokeWidth, trackColor, progressCol
|
|
|
70
81
|
handleClick();
|
|
71
82
|
}
|
|
72
83
|
}
|
|
73
|
-
: undefined, children: [jsxs("svg", { viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`, className: "w-full h-full -rotate-90", children: [jsx("circle", { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: trackColor, strokeWidth: strokeWidth }), jsx(motion.circle, { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: progressColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeDasharray: circumference, initial: { strokeDashoffset: circumference }, animate: { strokeDashoffset: isComplete ? 0 : offset }, transition: shouldReduceMotion ? { duration: 0 } : PROGRESS_SPRING })] }), jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: jsxs(AnimatePresence, { mode: "wait", initial: false, children: [isUploading && !isHovered && (jsx(motion.span, { className: centerTextStyle, ...(shouldReduceMotion ? {} : CROSSFADE), children: progress }, "percent")), isUploading && isHovered && onRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(XMarkIcon, { className: "size-4 text-[var(--color-text-muted)]", strokeWidth: 2.5 }) }, "close")), isComplete && !showRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", className: cn("size-4", statusIconColor), children: jsx("path", { d: "M5 13l4.5 4.5L19 7", stroke: "currentColor", strokeWidth: 3.5, strokeLinecap: "round", strokeLinejoin: "round" }) }) }, "check"))
|
|
84
|
+
: undefined, children: [jsxs("svg", { viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`, className: "w-full h-full -rotate-90", children: [jsx("circle", { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: trackColor, strokeWidth: strokeWidth }), jsx(motion.circle, { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: progressColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeDasharray: circumference, initial: { strokeDashoffset: circumference }, animate: { strokeDashoffset: isComplete ? 0 : offset }, transition: shouldReduceMotion ? { duration: 0 } : PROGRESS_SPRING })] }), jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: jsxs(AnimatePresence, { mode: "wait", initial: false, children: [isUploading && !isHovered && (jsx(motion.span, { className: centerTextStyle, ...(shouldReduceMotion ? {} : CROSSFADE), children: progress }, "percent")), isUploading && isHovered && onRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(XMarkIcon, { className: "size-4 text-[var(--color-text-muted)]", strokeWidth: 2.5 }) }, "close")), isComplete && !showRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", className: cn("size-4", statusIconColor), children: jsx("path", { d: "M5 13l4.5 4.5L19 7", stroke: "currentColor", strokeWidth: 3.5, strokeLinecap: "round", strokeLinejoin: "round" }) }) }, "check"))] }) })] }));
|
|
74
85
|
// Determine what to render: radial indicator or remove button
|
|
75
86
|
const showRemoveButton = isComplete && showRemove && onRemove;
|
|
76
87
|
const triggerElement = showRemoveButton ? removeButton : radialElement;
|
|
77
|
-
// No confirm popover needed — return the element directly
|
|
88
|
+
// No confirm popover needed — return the element directly.
|
|
78
89
|
if (!confirmRemove || !onRemove)
|
|
79
90
|
return triggerElement;
|
|
80
|
-
return (
|
|
81
|
-
setConfirmOpen(open);
|
|
82
|
-
if (!open)
|
|
83
|
-
setIsHovered(false);
|
|
84
|
-
}, placement: "bottom-end", offset: isComplete ? 2 : 6, triggerType: "click", children: [jsx(Popover.Trigger, { children: triggerElement }), jsxs(Popover.Body, { portal: false, className: "flex items-center p-0.5 border-[0.5px] rounded-xl gap-0.5", children: [jsx("span", { className: "text-base font-medium text-[var(--color-text-secondary)] px-3", children: isComplete ? "Remove file?" : "Cancel upload?" }), jsx(Button, { size: "sm", color: "danger", variant: "filled", onClick: handleConfirm, children: "Yes" }), jsx(Button, { size: "sm", variant: "soft", color: "neutral", onClick: () => setConfirmOpen(false), children: "No" })] })] }));
|
|
91
|
+
return confirmPopover(triggerElement, isComplete ? "Remove file?" : "Cancel upload?", isComplete ? 2 : 6);
|
|
85
92
|
};
|
|
86
93
|
// --- Main Component ---
|
|
87
94
|
const FileUploadProgress = React__default.forwardRef(({ items, onRemove, onRetry, showFileSize = true, confirmRemove = true, completionDelay = 1500, className, theme: themeOverrides, ...rest }, ref) => {
|
|
@@ -103,7 +110,7 @@ const FileUploadProgress = React__default.forwardRef(({ items, onRemove, onRetry
|
|
|
103
110
|
const clampedProgress = Math.min(100, Math.max(0, item.progress));
|
|
104
111
|
const ext = getFileExtension(item.file.name);
|
|
105
112
|
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(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 }),
|
|
113
|
+
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 }), item.status === "error" && item.error ? (jsx("p", { className: (_f = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.errorTextStyle) !== null && _f !== void 0 ? _f : t.errorTextStyle, children: item.error })) : (showFileSize && (jsx("p", { className: (_g = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileSizeStyle) !== null && _g !== void 0 ? _g : t.fileSizeStyle, children: formatFileSize(item.file.size) })))] }), 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
114
|
}) }));
|
|
108
115
|
});
|
|
109
116
|
FileUploadProgress.displayName = "FileUploadProgress";
|
|
@@ -6,13 +6,13 @@ const fileUploadProgressTheme = {
|
|
|
6
6
|
fileInfoStyle: "flex-1 min-w-0",
|
|
7
7
|
fileNameStyle: "text-sm font-medium text-[var(--color-text-primary)] truncate",
|
|
8
8
|
fileSizeStyle: "text-xs text-[var(--color-text-muted)]",
|
|
9
|
-
radialTrackColor: "var(--color-
|
|
9
|
+
radialTrackColor: "var(--color-surface-sunken)",
|
|
10
10
|
radialProgressColors: {
|
|
11
11
|
uploading: "var(--color-primary)",
|
|
12
12
|
complete: "var(--color-success)",
|
|
13
13
|
error: "var(--color-danger)",
|
|
14
14
|
},
|
|
15
|
-
radialCenterTextStyle: "text-
|
|
15
|
+
radialCenterTextStyle: "text-xs tracking-tight font-semibold tabular-nums text-[var(--color-text-secondary)]",
|
|
16
16
|
statusIconColors: {
|
|
17
17
|
uploading: "",
|
|
18
18
|
complete: "text-[var(--color-success)]",
|
|
@@ -8,17 +8,15 @@ const inputTheme = {
|
|
|
8
8
|
// Base container styles
|
|
9
9
|
wrapperStyle: formsBaseTheme.wrapperStyle,
|
|
10
10
|
// Input group styles - no focus-within (focus is managed via JS for contentStart/contentEnd compatibility)
|
|
11
|
-
inputGroupStyle: "relative flex rounded-[var(--form-radius)]
|
|
11
|
+
inputGroupStyle: "relative flex rounded-[var(--form-radius)] shadow-[inset_0_0_0_1px_var(--color-border)] " +
|
|
12
12
|
"bg-white transition-all " +
|
|
13
|
-
"dark:
|
|
13
|
+
"dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:bg-[var(--color-neutral-900)]",
|
|
14
14
|
// JS-driven focus ring (applied when isFocused is true)
|
|
15
|
-
inputGroupFocusStyle: "
|
|
16
|
-
"
|
|
17
|
-
"dark:outline-[var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20",
|
|
15
|
+
inputGroupFocusStyle: "shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10 " +
|
|
16
|
+
"dark:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20",
|
|
18
17
|
// JS-driven focus ring for invalid state
|
|
19
|
-
inputGroupFocusInvalidStyle: "
|
|
20
|
-
"
|
|
21
|
-
"dark:outline-[var(--color-danger-500)] dark:ring-[var(--color-danger-500)]/20",
|
|
18
|
+
inputGroupFocusInvalidStyle: "shadow-[inset_0_0_0_2px_var(--color-danger)] ring-4 ring-[var(--color-danger)]/10 " +
|
|
19
|
+
"dark:shadow-[inset_0_0_0_2px_var(--color-danger-500)] dark:ring-[var(--color-danger-500)]/20",
|
|
22
20
|
// Base input styles - extends common form control with design tokens
|
|
23
21
|
baseStyle: `${formsBaseTheme.controlBaseStyle} py-2 px-3`,
|
|
24
22
|
// Size variants - composed from atomic tokens
|
|
@@ -31,8 +29,8 @@ const inputTheme = {
|
|
|
31
29
|
states: {
|
|
32
30
|
default: formsBaseTheme.states.default,
|
|
33
31
|
disabled: formsBaseTheme.states.disabled,
|
|
34
|
-
invalid: "
|
|
35
|
-
"dark:bg-[var(--color-danger-950)]/30 dark:
|
|
32
|
+
invalid: "shadow-[inset_0_0_0_1px_var(--color-danger)] bg-[var(--color-danger-50)] " +
|
|
33
|
+
"dark:bg-[var(--color-danger-950)]/30 dark:shadow-[inset_0_0_0_1px_var(--color-danger-500)]",
|
|
36
34
|
},
|
|
37
35
|
// Helper text styles with state handling
|
|
38
36
|
helperText: formsBaseTheme.helperText,
|
|
@@ -67,7 +65,7 @@ const inputTheme = {
|
|
|
67
65
|
// Number input controls
|
|
68
66
|
numberButtonsContainerStyle: "absolute inset-y-0 right-0 flex flex-row items-center pr-2 z-10 gap-1",
|
|
69
67
|
numberButtonStyle: "bg-[var(--color-background-secondary)] flex items-center justify-center " +
|
|
70
|
-
"text-[var(--color-text-muted)] hover:bg-[var(--color-
|
|
68
|
+
"text-[var(--color-text-muted)] hover:bg-[var(--color-surface-hover)] " +
|
|
71
69
|
"hover:text-[var(--color-text-primary)] cursor-pointer size-6 rounded-sm transition-colors " +
|
|
72
70
|
"dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-500)] " +
|
|
73
71
|
"dark:hover:bg-[var(--color-neutral-700)] dark:hover:text-[var(--color-neutral-200)]",
|
|
@@ -10,9 +10,9 @@ const mentionTheme = {
|
|
|
10
10
|
// Input group container with outline and focus ring
|
|
11
11
|
inputGroupStyle: formsBaseTheme.inputGroupBaseStyle,
|
|
12
12
|
// JS-driven focus ring (applied when editable div is focused)
|
|
13
|
-
inputGroupFocusStyle: "
|
|
13
|
+
inputGroupFocusStyle: "shadow-[inset_0_0_0_2px_var(--color-primary-600)] " +
|
|
14
14
|
"ring-4 ring-[var(--color-primary)]/10 " +
|
|
15
|
-
"dark:
|
|
15
|
+
"dark:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20",
|
|
16
16
|
// Base editable div styles
|
|
17
17
|
editableStyle: `${formsBaseTheme.controlBaseStyle} whitespace-pre-wrap break-words overflow-y-auto cursor-text`,
|
|
18
18
|
// Size variants
|
|
@@ -35,7 +35,7 @@ const mentionTheme = {
|
|
|
35
35
|
"dark:text-[var(--color-primary-400)] dark:bg-[var(--color-primary-400)]/10",
|
|
36
36
|
// Avatar image
|
|
37
37
|
suggestionAvatarStyle: "size-7 rounded-full object-cover shrink-0 " +
|
|
38
|
-
"bg-[var(--color-
|
|
38
|
+
"bg-[var(--color-surface-sunken)] dark:bg-[var(--color-neutral-700)]",
|
|
39
39
|
// Avatar fallback (initials circle)
|
|
40
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)] " +
|
|
@@ -9,7 +9,7 @@ const radioTheme = {
|
|
|
9
9
|
// Default state - light
|
|
10
10
|
"border-[var(--color-border)] bg-[var(--color-surface)] " +
|
|
11
11
|
// Default state - dark
|
|
12
|
-
"dark:bg-[var(--color-
|
|
12
|
+
"dark:bg-[var(--color-surface-raised)] " +
|
|
13
13
|
// Checked state - light
|
|
14
14
|
"checked:border-[var(--color-primary)] checked:bg-white " +
|
|
15
15
|
// Checked state - dark
|
|
@@ -1,3 +1,21 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { RichTextEditorProps } from "./RichTextEditor.types";
|
|
3
|
+
import type { FontFamilyOption } from "./RichTextEditor.types";
|
|
4
|
+
/**
|
|
5
|
+
* Curated default list of font families shipped with the editor.
|
|
6
|
+
* The `Default` entry clears the inline font-family. The rest are popular
|
|
7
|
+
* Google Fonts chosen for broad weight coverage. Each stack ends in a sensible
|
|
8
|
+
* fallback so text stays readable while the font is loading.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_FONT_FAMILY_OPTIONS: FontFamilyOption[];
|
|
11
|
+
/**
|
|
12
|
+
* Lazily injects a Google Fonts `<link rel="stylesheet">` for the given family.
|
|
13
|
+
* Idempotent: each family is requested at most once per page lifetime.
|
|
14
|
+
* SSR-safe (no-ops when `document` is undefined).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* import { loadGoogleFont } from "@flikk/ui";
|
|
18
|
+
* loadGoogleFont("Inter");
|
|
19
|
+
*/
|
|
20
|
+
export declare const loadGoogleFont: (family: string, weights?: number[]) => void;
|
|
3
21
|
export declare const RichTextEditor: React.ForwardRefExoticComponent<RichTextEditorProps & React.RefAttributes<HTMLDivElement>>;
|