@djangocfg/ui-tools 2.1.407 → 2.1.409
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/README.md +9 -10
- package/dist/file-icon/index.cjs +449 -61
- package/dist/file-icon/index.cjs.map +1 -1
- package/dist/file-icon/index.d.cts +56 -18
- package/dist/file-icon/index.d.ts +56 -18
- package/dist/file-icon/index.mjs +448 -62
- package/dist/file-icon/index.mjs.map +1 -1
- package/dist/tree/index.cjs +49 -22
- package/dist/tree/index.cjs.map +1 -1
- package/dist/tree/index.d.cts +9 -3
- package/dist/tree/index.d.ts +9 -3
- package/dist/tree/index.mjs +49 -22
- package/dist/tree/index.mjs.map +1 -1
- package/dist/{types-B_zhyAqR.d.cts → types-eEu8SeiQ.d.cts} +4 -0
- package/dist/{types-B_zhyAqR.d.ts → types-eEu8SeiQ.d.ts} +4 -0
- package/package.json +8 -13
- package/src/components/FloatingToolbar/index.tsx +37 -3
- package/src/lib/page-snapshot/__tests__/capture-integration.test.ts +85 -0
- package/src/lib/page-snapshot/__tests__/engine.test.ts +36 -0
- package/src/lib/page-snapshot/__tests__/redaction-integration.test.ts +99 -0
- package/src/lib/page-snapshot/__tests__/tokens.test.ts +17 -0
- package/src/lib/page-snapshot/capture/__tests__/budget.test.ts +49 -0
- package/src/lib/page-snapshot/capture/__tests__/chrome-filter.test.ts +47 -0
- package/src/lib/page-snapshot/capture/__tests__/fold.test.ts +66 -0
- package/src/lib/page-snapshot/capture/__tests__/scope.test.ts +74 -0
- package/src/lib/page-snapshot/capture/__tests__/walk.test.ts +129 -0
- package/src/lib/page-snapshot/capture/accessible-name.ts +73 -0
- package/src/lib/page-snapshot/capture/budget.ts +95 -0
- package/src/lib/page-snapshot/capture/chrome-filter.ts +81 -0
- package/src/lib/page-snapshot/capture/classify.ts +111 -0
- package/src/lib/page-snapshot/capture/dom-utils.ts +111 -0
- package/src/lib/page-snapshot/capture/fold.ts +96 -0
- package/src/lib/page-snapshot/capture/scope.ts +169 -0
- package/src/lib/page-snapshot/capture/walk.ts +250 -0
- package/src/lib/page-snapshot/cst/__tests__/serialize.test.ts +50 -0
- package/src/lib/page-snapshot/cst/directives.ts +47 -0
- package/src/lib/page-snapshot/cst/payload.ts +50 -0
- package/src/lib/page-snapshot/cst/serialize.ts +84 -0
- package/src/lib/page-snapshot/cst/types.ts +115 -0
- package/src/lib/page-snapshot/engine.ts +176 -0
- package/src/lib/page-snapshot/index.ts +93 -0
- package/src/lib/page-snapshot/react/PageSnapshotChip.tsx +72 -0
- package/src/lib/page-snapshot/react/PageSnapshotPreview.tsx +78 -0
- package/src/lib/page-snapshot/react/__tests__/PageSnapshotChip.test.tsx +54 -0
- package/src/lib/page-snapshot/react/__tests__/provider.test.tsx +103 -0
- package/src/lib/page-snapshot/react/__tests__/use-page-snapshot-toggle.test.tsx +62 -0
- package/src/lib/page-snapshot/react/provider.tsx +162 -0
- package/src/lib/page-snapshot/react/use-page-snapshot-toggle.ts +47 -0
- package/src/lib/page-snapshot/react/use-page-snapshot.ts +67 -0
- package/src/lib/page-snapshot/redaction/__tests__/audit.test.ts +25 -0
- package/src/lib/page-snapshot/redaction/__tests__/heuristics.test.ts +73 -0
- package/src/lib/page-snapshot/redaction/__tests__/luhn.test.ts +26 -0
- package/src/lib/page-snapshot/redaction/__tests__/patterns.test.ts +60 -0
- package/src/lib/page-snapshot/redaction/audit.ts +58 -0
- package/src/lib/page-snapshot/redaction/heuristics.ts +75 -0
- package/src/lib/page-snapshot/redaction/index.ts +75 -0
- package/src/lib/page-snapshot/redaction/luhn.ts +25 -0
- package/src/lib/page-snapshot/redaction/patterns.ts +111 -0
- package/src/lib/page-snapshot/refs/__tests__/registry.test.ts +24 -0
- package/src/lib/page-snapshot/refs/registry.ts +46 -0
- package/src/lib/page-snapshot/staleness/__tests__/hash.test.ts +34 -0
- package/src/lib/page-snapshot/staleness/hash.ts +20 -0
- package/src/lib/page-snapshot/tokens.ts +15 -0
- package/src/tools/AudioPlayer/context/PlayerProvider.tsx +13 -14
- package/src/tools/AudioPlayer/hooks/useAudioElementEvents.ts +55 -6
- package/src/tools/AudioPlayer/parts/Meta/TimeDisplay.tsx +2 -5
- package/src/tools/Chat/README.md +277 -39
- package/src/tools/Chat/composer/Composer.tsx +471 -0
- package/src/tools/Chat/composer/ComposerActionBar.tsx +65 -0
- package/src/tools/Chat/composer/ComposerBanner.tsx +128 -0
- package/src/tools/Chat/composer/ComposerButton.tsx +64 -0
- package/src/tools/Chat/composer/ComposerFooter.tsx +90 -0
- package/src/tools/Chat/composer/ComposerMenuButton.tsx +62 -0
- package/src/tools/Chat/composer/ComposerModelPicker.tsx +104 -0
- package/src/tools/Chat/composer/ComposerRichTextarea.tsx +88 -0
- package/src/tools/Chat/composer/ComposerToolPill.tsx +95 -0
- package/src/tools/Chat/composer/index.ts +45 -0
- package/src/tools/Chat/composer/size-context.tsx +26 -0
- package/src/tools/Chat/composer/types.ts +143 -0
- package/src/tools/Chat/composer/useComposerActions.tsx +164 -0
- package/src/tools/Chat/context/ChatProvider.tsx +54 -3
- package/src/tools/Chat/core/__tests__/metadata.test.ts +69 -0
- package/src/tools/Chat/core/index.ts +23 -1
- package/src/tools/Chat/core/markdown.ts +1 -1
- package/src/tools/Chat/core/metadata.ts +47 -0
- package/src/tools/Chat/core/payload-dispatch.ts +1 -1
- package/src/tools/Chat/core/transport/http.ts +71 -32
- package/src/tools/Chat/core/transport/sse.ts +18 -10
- package/src/tools/Chat/highlight/HighlightOverlay.tsx +101 -0
- package/src/tools/Chat/highlight/README.md +103 -0
- package/src/tools/Chat/highlight/SpotlightCanvas.tsx +153 -0
- package/src/tools/Chat/highlight/__tests__/HighlightOverlay.test.tsx +112 -0
- package/src/tools/Chat/highlight/__tests__/resolveRef.test.ts +55 -0
- package/src/tools/Chat/highlight/index.ts +21 -0
- package/src/tools/Chat/highlight/resolveRef.ts +42 -0
- package/src/tools/Chat/highlight/types.ts +49 -0
- package/src/tools/Chat/highlight/useHighlightTargets.ts +128 -0
- package/src/tools/Chat/hooks/index.ts +0 -5
- package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +28 -47
- package/src/tools/Chat/hooks/useChat.ts +47 -14
- package/src/tools/Chat/hooks/useChatComposer.ts +2 -2
- package/src/tools/Chat/hooks/useChatLayout.ts +1 -1
- package/src/tools/Chat/hooks/useStreamEndFocus.ts +54 -0
- package/src/tools/Chat/index.ts +25 -219
- package/src/tools/Chat/launcher/ChatDock.tsx +1 -1
- package/src/tools/Chat/launcher/ChatLauncher.tsx +1 -1
- package/src/tools/Chat/launcher/{ChatHeader.tsx → header/ChatHeader.tsx} +24 -11
- package/src/tools/Chat/launcher/{ChatHeaderActionButton.tsx → header/ChatHeaderActionButton.tsx} +34 -3
- package/src/tools/Chat/launcher/{ChatHeaderLanguageButton.tsx → header/ChatHeaderLanguageButton.tsx} +2 -2
- package/src/tools/Chat/launcher/{ChatHeaderModeToggle.tsx → header/ChatHeaderModeToggle.tsx} +1 -1
- package/src/tools/Chat/launcher/{ChatHeaderResetButton.tsx → header/ChatHeaderResetButton.tsx} +2 -1
- package/src/tools/Chat/launcher/{HeaderSlots.tsx → header/HeaderSlots.tsx} +3 -3
- package/src/tools/Chat/launcher/header/index.ts +26 -0
- package/src/tools/Chat/launcher/index.ts +3 -10
- package/src/tools/Chat/lazy.tsx +38 -284
- package/src/tools/Chat/{components → messages}/MessageBubble.tsx +58 -5
- package/src/tools/Chat/{components → messages}/MessageList.tsx +8 -25
- package/src/tools/Chat/messages/blocks/MessageBlocks.tsx +131 -0
- package/src/tools/Chat/messages/blocks/builtin.tsx +91 -0
- package/src/tools/Chat/messages/blocks/index.ts +12 -0
- package/src/tools/Chat/messages/blocks/registry.tsx +42 -0
- package/src/tools/Chat/messages/blocks/renderers/AudioBlock.tsx +20 -0
- package/src/tools/Chat/messages/blocks/renderers/CodeBlock.tsx +19 -0
- package/src/tools/Chat/messages/blocks/renderers/GalleryBlock.tsx +26 -0
- package/src/tools/Chat/messages/blocks/renderers/ImageBlock.tsx +27 -0
- package/src/tools/Chat/messages/blocks/renderers/JsonBlock.tsx +12 -0
- package/src/tools/Chat/messages/blocks/renderers/LottieBlock.tsx +11 -0
- package/src/tools/Chat/messages/blocks/renderers/MapBlock.tsx +36 -0
- package/src/tools/Chat/messages/blocks/renderers/MermaidBlock.tsx +11 -0
- package/src/tools/Chat/messages/blocks/renderers/VideoBlock.tsx +24 -0
- package/src/tools/Chat/messages/blocks/renderers/types.ts +8 -0
- package/src/tools/Chat/{components → messages}/index.ts +11 -5
- package/src/tools/Chat/public.ts +212 -0
- package/src/tools/Chat/shell/ChatRoot.tsx +345 -0
- package/src/tools/Chat/{components → shell}/EmptyState.tsx +4 -2
- package/src/tools/Chat/shell/index.ts +15 -0
- package/src/tools/Chat/types/block.ts +120 -0
- package/src/tools/Chat/types/config.ts +0 -5
- package/src/tools/Chat/types/index.ts +17 -0
- package/src/tools/Chat/types/message.ts +3 -0
- package/src/tools/Chat/utils/index.ts +4 -0
- package/src/tools/CodeEditor/README.md +4 -6
- package/src/tools/CodeEditor/components/DiffEditor.tsx +48 -13
- package/src/tools/CodeEditor/components/Editor.tsx +96 -44
- package/src/tools/CodeEditor/context/EditorProvider.tsx +34 -17
- package/src/tools/CodeEditor/hooks/useEditorTheme.ts +92 -99
- package/src/tools/CodeEditor/hooks/useMonaco.ts +37 -22
- package/src/tools/CodeEditor/lazy.tsx +6 -0
- package/src/tools/CodeEditor/lib/index.ts +1 -1
- package/src/tools/CodeEditor/lib/themes.ts +3 -39
- package/src/tools/CronScheduler/CronScheduler.client.tsx +230 -61
- package/src/tools/CronScheduler/components/CustomInput.tsx +21 -4
- package/src/tools/CronScheduler/components/DayChips.tsx +13 -11
- package/src/tools/CronScheduler/components/MonthDayGrid.tsx +4 -4
- package/src/tools/CronScheduler/components/SchedulePreview.tsx +7 -3
- package/src/tools/CronScheduler/components/TimeSelector.tsx +1 -1
- package/src/tools/CronScheduler/index.tsx +1 -1
- package/src/tools/CronScheduler/types/index.ts +8 -3
- package/src/tools/CronScheduler/utils/cron-humanize.ts +61 -16
- package/src/tools/CronScheduler/utils/cron-parser.ts +13 -4
- package/src/tools/FileIcon/FileIcon.tsx +24 -39
- package/src/tools/FileIcon/get-file-icon.ts +73 -0
- package/src/tools/FileIcon/icons/icon-data.ts +399 -0
- package/src/tools/FileIcon/index.ts +4 -0
- package/src/tools/FileIcon/loader.ts +17 -35
- package/src/tools/FileIcon/specialFolders.ts +18 -0
- package/src/tools/Gallery/components/lightbox/GalleryLightbox.tsx +112 -35
- package/src/tools/Gallery/components/media/GalleryVideo.tsx +21 -2
- package/src/tools/Gallery/components/preview/GalleryCarousel.tsx +11 -1
- package/src/tools/Gallery/hooks/usePreloadImages.ts +54 -7
- package/src/tools/ImageViewer/components/ImageInfo.tsx +12 -1
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +51 -43
- package/src/tools/ImageViewer/components/ImageViewer.tsx +96 -24
- package/src/tools/ImageViewer/hooks/useImageLoading.ts +13 -0
- package/src/tools/ImageViewer/utils/constants.ts +3 -0
- package/src/tools/ImageViewer/utils/index.ts +1 -0
- package/src/tools/JsonForm/JsonSchemaForm.tsx +4 -1
- package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +5 -3
- package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +7 -4
- package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +3 -1
- package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +23 -3
- package/src/tools/JsonForm/widgets/ColorWidget.tsx +20 -12
- package/src/tools/JsonForm/widgets/NumberWidget.tsx +14 -9
- package/src/tools/JsonForm/widgets/RadioWidget.tsx +78 -0
- package/src/tools/JsonForm/widgets/SelectWidget.tsx +1 -0
- package/src/tools/JsonForm/widgets/SliderWidget.tsx +7 -4
- package/src/tools/JsonForm/widgets/TextWidget.tsx +41 -17
- package/src/tools/JsonForm/widgets/index.ts +1 -0
- package/src/tools/JsonTree/components/JsonContent.tsx +115 -40
- package/src/tools/LottiePlayer/LottiePlayer.client.tsx +177 -72
- package/src/tools/LottiePlayer/index.tsx +14 -4
- package/src/tools/LottiePlayer/lazy.tsx +11 -3
- package/src/tools/LottiePlayer/types.ts +31 -1
- package/src/tools/LottiePlayer/useLottie.ts +32 -9
- package/src/tools/LottiePlayer/usePrefersReducedMotion.ts +46 -0
- package/src/tools/Map/components/LayerSwitcher.tsx +54 -21
- package/src/tools/Map/components/MapCluster.tsx +28 -21
- package/src/tools/Map/components/MapContainer.tsx +11 -4
- package/src/tools/Map/components/MapLegend.tsx +46 -15
- package/src/tools/Map/components/MapMarker.tsx +31 -2
- package/src/tools/Map/hooks/useMapEvents.ts +64 -105
- package/src/tools/MarkdownEditor/MarkdownEditor.tsx +61 -6
- package/src/tools/MarkdownEditor/MentionList.tsx +37 -4
- package/src/tools/MarkdownEditor/createMentionSuggestion.ts +11 -0
- package/src/tools/MarkdownEditor/lazy.tsx +32 -7
- package/src/tools/MarkdownEditor/styles.css +13 -0
- package/src/tools/MarkdownMessage/CodeBlock.tsx +40 -17
- package/src/tools/MarkdownMessage/MarkdownMessage.tsx +26 -6
- package/src/tools/MarkdownMessage/components.tsx +22 -9
- package/src/tools/MarkdownMessage/types.ts +24 -1
- package/src/tools/Mermaid/Mermaid.client.tsx +27 -5
- package/src/tools/Mermaid/components/MermaidErrorPanel.tsx +31 -0
- package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +14 -17
- package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +264 -168
- package/src/tools/Mermaid/hooks/useMermaidValidation.ts +76 -10
- package/src/tools/Mermaid/index.tsx +6 -0
- package/src/tools/Mermaid/utils/mermaid-helpers.ts +141 -18
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +11 -1
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +49 -20
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +7 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +7 -4
- package/src/tools/OpenapiViewer/constants.ts +3 -0
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +73 -11
- package/src/tools/OpenapiViewer/utils/schemaExport.ts +26 -6
- package/src/tools/PrettyCode/PrettyCode.client.tsx +23 -16
- package/src/tools/PrettyCode/lazy.tsx +1 -1
- package/src/tools/SpeechRecognition/README.md +1 -1
- package/src/tools/SpeechRecognition/__tests__/language.test.ts +9 -3
- package/src/tools/SpeechRecognition/components/RecordingPulse.tsx +59 -0
- package/src/tools/SpeechRecognition/components/index.ts +2 -0
- package/src/tools/SpeechRecognition/core/engine/external.ts +24 -7
- package/src/tools/SpeechRecognition/core/language.ts +23 -6
- package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +36 -5
- package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +18 -11
- package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +94 -26
- package/src/tools/SpeechRecognition/widgets/index.ts +1 -1
- package/src/tools/Tree/README.md +4 -8
- package/src/tools/Tree/TreeRoot.tsx +22 -10
- package/src/tools/Tree/components/TreeContent.tsx +24 -4
- package/src/tools/Tree/components/TreeLabel.tsx +8 -2
- package/src/tools/Tree/components/TreeRow.tsx +16 -6
- package/src/tools/Tree/data/flatten.ts +10 -4
- package/src/tools/Tree/types.ts +4 -0
- package/src/tools/Uploader/components/UploadAddButton.tsx +29 -6
- package/src/tools/Uploader/components/UploadDropzone.tsx +63 -7
- package/src/tools/Uploader/components/UploadPageDropOverlay.tsx +19 -5
- package/src/tools/Uploader/components/UploadPreviewItem.tsx +47 -17
- package/src/tools/Uploader/components/UploadPreviewList.tsx +24 -12
- package/src/tools/Uploader/utils/formatters.ts +8 -3
- package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +1 -0
- package/src/tools/VideoPlayer/canvas/{jsx.d.ts → jsx-augmentation.ts} +12 -19
- package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +1 -0
- package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +1 -0
- package/src/tools/VideoPlayer/parts/fullscreen.tsx +1 -1
- package/src/tools/VideoPlayer/parts/pip.tsx +1 -1
- package/src/tools/VideoPlayer/parts/playback-rate.tsx +1 -1
- package/src/tools/VideoPlayer/parts/seek-bar.tsx +2 -2
- package/src/tools/VideoPlayer/parts/volume.tsx +2 -2
- package/src/tools/index.ts +2 -1
- package/src/tools/Chat/components/AudioToggle.tsx +0 -78
- package/src/tools/Chat/components/ChatRoot.tsx +0 -305
- package/src/tools/Chat/components/Composer.tsx +0 -216
- package/src/tools/Chat/hooks/useChatScroll.ts +0 -145
- package/src/tools/Chat/types.ts +0 -9
- package/src/tools/JsonTree/components/JsonToolbar.tsx +0 -95
- package/src/tools/JsonTree/hooks/useElementCorner.ts +0 -84
- package/src/tools/JsonTree/hooks/useNavbarHeight.ts +0 -83
- package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +0 -121
- package/src/tools/Tour/README.md +0 -373
- package/src/tools/Tour/components/Tour.tsx +0 -12
- package/src/tools/Tour/components/TourContent.tsx +0 -171
- package/src/tools/Tour/components/TourNavigation.tsx +0 -77
- package/src/tools/Tour/components/TourProgress.tsx +0 -88
- package/src/tools/Tour/components/TourSpotlight.tsx +0 -199
- package/src/tools/Tour/components/index.ts +0 -5
- package/src/tools/Tour/context/TourContext.ts +0 -19
- package/src/tools/Tour/context/TourProvider.tsx +0 -292
- package/src/tools/Tour/context/index.ts +0 -2
- package/src/tools/Tour/hooks/index.ts +0 -3
- package/src/tools/Tour/hooks/useKeyboardNavigation.ts +0 -59
- package/src/tools/Tour/hooks/useStepTarget.ts +0 -121
- package/src/tools/Tour/hooks/useTour.ts +0 -42
- package/src/tools/Tour/index.ts +0 -38
- package/src/tools/Tour/types/index.ts +0 -224
- package/src/tools/Tour/utils/dom.ts +0 -98
- package/src/tools/Tour/utils/index.ts +0 -3
- package/src/tools/Tour/utils/logger.ts +0 -3
- package/src/tools/Tour/utils/scrollIntoView.ts +0 -24
- /package/src/tools/Chat/{config.ts → constants.ts} +0 -0
- /package/src/tools/Chat/launcher/{ChatHeaderAudioToggle.tsx → header/ChatHeaderAudioToggle.tsx} +0 -0
- /package/src/tools/Chat/{components → messages}/Attachments.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/JumpToLatest.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/MessageActions.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/Sources.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/StreamingIndicator.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/ToolCalls.tsx +0 -0
- /package/src/tools/Chat/{components → shell}/ErrorBanner.tsx +0 -0
|
@@ -3,77 +3,246 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* CronScheduler Client Component
|
|
5
5
|
*
|
|
6
|
-
* Compact cron
|
|
7
|
-
*
|
|
6
|
+
* Compact cron builder. The default surface is a single popover trigger
|
|
7
|
+
* that reads like a value input ("Weekdays at 09:00") — the schedule
|
|
8
|
+
* editor lives inside the popover, following the ui-core combobox
|
|
9
|
+
* pattern. Pass `inline` to render the editor expanded without a popover.
|
|
8
10
|
*/
|
|
9
11
|
|
|
12
|
+
import { useState } from 'react';
|
|
13
|
+
import { Calendar, ChevronsUpDown, Check, Copy } from 'lucide-react';
|
|
14
|
+
import {
|
|
15
|
+
Popover,
|
|
16
|
+
PopoverContent,
|
|
17
|
+
PopoverTrigger,
|
|
18
|
+
} from '@djangocfg/ui-core/components';
|
|
10
19
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
11
20
|
import { CronSchedulerProvider } from './context/CronSchedulerContext';
|
|
12
|
-
import { useCronType } from './context/hooks';
|
|
21
|
+
import { useCronType, useCronPreview } from './context/hooks';
|
|
13
22
|
import {
|
|
14
23
|
ScheduleTypeSelector,
|
|
15
24
|
TimeSelector,
|
|
16
25
|
DayChips,
|
|
17
26
|
MonthDayGrid,
|
|
18
27
|
CustomInput,
|
|
19
|
-
SchedulePreview,
|
|
20
28
|
} from './components';
|
|
21
29
|
import type { CronSchedulerProps } from './types';
|
|
22
30
|
|
|
23
31
|
// ============================================================================
|
|
24
|
-
//
|
|
32
|
+
// Schedule editor (shared by inline + popover modes)
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
interface ScheduleEditorProps {
|
|
36
|
+
timeFormat: '12h' | '24h';
|
|
37
|
+
disabled: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ScheduleEditor({ timeFormat, disabled }: ScheduleEditorProps) {
|
|
41
|
+
const { type } = useCronType();
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="space-y-3">
|
|
45
|
+
<ScheduleTypeSelector disabled={disabled} />
|
|
46
|
+
|
|
47
|
+
{type !== 'custom' && (
|
|
48
|
+
<TimeSelector format={timeFormat} disabled={disabled} />
|
|
49
|
+
)}
|
|
50
|
+
{type === 'weekly' && <DayChips disabled={disabled} showPresets />}
|
|
51
|
+
{type === 'monthly' && <MonthDayGrid disabled={disabled} showPresets />}
|
|
52
|
+
{type === 'custom' && <CustomInput disabled={disabled} />}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Cron expression line (shared)
|
|
25
59
|
// ============================================================================
|
|
26
60
|
|
|
27
|
-
|
|
28
|
-
|
|
61
|
+
function CronExpressionLine({
|
|
62
|
+
allowCopy,
|
|
63
|
+
className,
|
|
64
|
+
}: {
|
|
65
|
+
allowCopy: boolean;
|
|
66
|
+
className?: string;
|
|
67
|
+
}) {
|
|
68
|
+
const [copied, setCopied] = useState(false);
|
|
69
|
+
const { cronExpression, isValid } = useCronPreview();
|
|
70
|
+
|
|
71
|
+
const handleCopy = async (e: React.MouseEvent) => {
|
|
72
|
+
e.stopPropagation();
|
|
73
|
+
try {
|
|
74
|
+
await navigator.clipboard.writeText(cronExpression);
|
|
75
|
+
setCopied(true);
|
|
76
|
+
setTimeout(() => setCopied(false), 2000);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error('Failed to copy:', err);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className={cn('flex items-center gap-1.5', className)}>
|
|
84
|
+
<code className="font-mono text-xs text-muted-foreground">
|
|
85
|
+
{cronExpression}
|
|
86
|
+
</code>
|
|
87
|
+
{allowCopy && (
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
onClick={handleCopy}
|
|
91
|
+
disabled={!isValid}
|
|
92
|
+
className={cn(
|
|
93
|
+
'rounded p-0.5 transition-colors',
|
|
94
|
+
'hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/50',
|
|
95
|
+
'disabled:opacity-50 disabled:cursor-not-allowed'
|
|
96
|
+
)}
|
|
97
|
+
aria-label={copied ? 'Cron expression copied' : 'Copy cron expression'}
|
|
98
|
+
title={copied ? 'Copied!' : 'Copy cron expression'}
|
|
99
|
+
>
|
|
100
|
+
{copied ? (
|
|
101
|
+
<Check aria-hidden="true" className="h-3 w-3 text-success" />
|
|
102
|
+
) : (
|
|
103
|
+
<Copy aria-hidden="true" className="h-3 w-3 text-muted-foreground" />
|
|
104
|
+
)}
|
|
105
|
+
</button>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Compact popover trigger (default surface)
|
|
113
|
+
// ============================================================================
|
|
114
|
+
|
|
115
|
+
interface CompactTriggerProps {
|
|
29
116
|
showCronExpression: boolean;
|
|
30
117
|
allowCopy: boolean;
|
|
31
118
|
timeFormat: '12h' | '24h';
|
|
32
119
|
disabled: boolean;
|
|
120
|
+
placeholder: string;
|
|
33
121
|
className?: string;
|
|
34
122
|
}
|
|
35
123
|
|
|
36
|
-
function
|
|
37
|
-
showPreview,
|
|
124
|
+
function CompactTrigger({
|
|
38
125
|
showCronExpression,
|
|
39
126
|
allowCopy,
|
|
40
127
|
timeFormat,
|
|
41
128
|
disabled,
|
|
129
|
+
placeholder,
|
|
42
130
|
className,
|
|
43
|
-
}:
|
|
44
|
-
const
|
|
131
|
+
}: CompactTriggerProps) {
|
|
132
|
+
const [open, setOpen] = useState(false);
|
|
133
|
+
const { humanDescription, isValid } = useCronPreview();
|
|
45
134
|
|
|
46
135
|
return (
|
|
47
|
-
<div className={cn('space-y-
|
|
48
|
-
{
|
|
49
|
-
|
|
136
|
+
<div className={cn('space-y-1.5', className)}>
|
|
137
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
138
|
+
<PopoverTrigger asChild>
|
|
139
|
+
<button
|
|
140
|
+
type="button"
|
|
141
|
+
role="combobox"
|
|
142
|
+
aria-expanded={open}
|
|
143
|
+
disabled={disabled}
|
|
144
|
+
className={cn(
|
|
145
|
+
'flex h-9 w-full items-center gap-2 rounded-md border px-3',
|
|
146
|
+
'border-input bg-transparent text-sm shadow-xs transition-colors',
|
|
147
|
+
'hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50',
|
|
148
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
149
|
+
!isValid && 'border-destructive/50'
|
|
150
|
+
)}
|
|
151
|
+
>
|
|
152
|
+
<Calendar
|
|
153
|
+
aria-hidden="true"
|
|
154
|
+
className={cn(
|
|
155
|
+
'h-4 w-4 shrink-0',
|
|
156
|
+
isValid ? 'text-muted-foreground' : 'text-destructive'
|
|
157
|
+
)}
|
|
158
|
+
/>
|
|
159
|
+
<span
|
|
160
|
+
className={cn(
|
|
161
|
+
'flex-1 truncate text-left',
|
|
162
|
+
!isValid && 'text-destructive'
|
|
163
|
+
)}
|
|
164
|
+
>
|
|
165
|
+
{humanDescription || placeholder}
|
|
166
|
+
</span>
|
|
167
|
+
<ChevronsUpDown
|
|
168
|
+
aria-hidden="true"
|
|
169
|
+
className="h-4 w-4 shrink-0 opacity-50"
|
|
170
|
+
/>
|
|
171
|
+
</button>
|
|
172
|
+
</PopoverTrigger>
|
|
173
|
+
<PopoverContent
|
|
174
|
+
className="w-[var(--radix-popover-trigger-width)] min-w-[320px] p-3"
|
|
175
|
+
align="start"
|
|
176
|
+
>
|
|
177
|
+
<ScheduleEditor timeFormat={timeFormat} disabled={disabled} />
|
|
178
|
+
</PopoverContent>
|
|
179
|
+
</Popover>
|
|
50
180
|
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
<TimeSelector format={timeFormat} disabled={disabled} />
|
|
181
|
+
{showCronExpression && (
|
|
182
|
+
<CronExpressionLine allowCopy={allowCopy} className="px-1" />
|
|
54
183
|
)}
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
55
187
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
)}
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// Inline variant (editor expanded, no popover)
|
|
190
|
+
// ============================================================================
|
|
60
191
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
192
|
+
interface InlineSchedulerProps extends ScheduleEditorProps {
|
|
193
|
+
showCronExpression: boolean;
|
|
194
|
+
allowCopy: boolean;
|
|
195
|
+
className?: string;
|
|
196
|
+
}
|
|
65
197
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
198
|
+
function InlineScheduler({
|
|
199
|
+
timeFormat,
|
|
200
|
+
disabled,
|
|
201
|
+
showCronExpression,
|
|
202
|
+
allowCopy,
|
|
203
|
+
className,
|
|
204
|
+
}: InlineSchedulerProps) {
|
|
205
|
+
return (
|
|
206
|
+
<div className={cn('space-y-3', className)}>
|
|
207
|
+
<ScheduleEditor timeFormat={timeFormat} disabled={disabled} />
|
|
208
|
+
<InlinePreview showCronExpression={showCronExpression} allowCopy={allowCopy} />
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
70
212
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
213
|
+
function InlinePreview({
|
|
214
|
+
showCronExpression,
|
|
215
|
+
allowCopy,
|
|
216
|
+
}: {
|
|
217
|
+
showCronExpression: boolean;
|
|
218
|
+
allowCopy: boolean;
|
|
219
|
+
}) {
|
|
220
|
+
const { humanDescription, isValid } = useCronPreview();
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<div
|
|
224
|
+
role="status"
|
|
225
|
+
aria-live="polite"
|
|
226
|
+
className={cn(
|
|
227
|
+
'flex items-center justify-between gap-2 rounded-md border px-3 py-2',
|
|
228
|
+
'bg-muted/30 border-border/50',
|
|
229
|
+
!isValid && 'border-destructive/30 bg-destructive/5'
|
|
230
|
+
)}
|
|
231
|
+
>
|
|
232
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
233
|
+
<Calendar
|
|
234
|
+
aria-hidden="true"
|
|
235
|
+
className={cn(
|
|
236
|
+
'h-4 w-4 shrink-0',
|
|
237
|
+
isValid ? 'text-primary' : 'text-destructive'
|
|
238
|
+
)}
|
|
76
239
|
/>
|
|
240
|
+
<span className={cn('truncate text-sm', !isValid && 'text-destructive')}>
|
|
241
|
+
{humanDescription}
|
|
242
|
+
</span>
|
|
243
|
+
</div>
|
|
244
|
+
{showCronExpression && (
|
|
245
|
+
<CronExpressionLine allowCopy={allowCopy} className="shrink-0" />
|
|
77
246
|
)}
|
|
78
247
|
</div>
|
|
79
248
|
);
|
|
@@ -84,39 +253,29 @@ function CronSchedulerInner({
|
|
|
84
253
|
// ============================================================================
|
|
85
254
|
|
|
86
255
|
/**
|
|
87
|
-
* CronScheduler -
|
|
256
|
+
* CronScheduler - compact cron expression builder
|
|
88
257
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
258
|
+
* Default surface is a single popover trigger that reads the schedule as
|
|
259
|
+
* plain text ("Weekdays at 09:00"). Pass `inline` for the legacy expanded
|
|
260
|
+
* layout.
|
|
91
261
|
*
|
|
92
262
|
* @example
|
|
93
|
-
*
|
|
94
|
-
* <CronScheduler
|
|
95
|
-
* value={cronExpression}
|
|
96
|
-
* onChange={setCronExpression}
|
|
97
|
-
* />
|
|
263
|
+
* <CronScheduler value={cron} onChange={setCron} showCronExpression />
|
|
98
264
|
*
|
|
99
265
|
* @example
|
|
100
|
-
* //
|
|
101
|
-
* <CronScheduler
|
|
102
|
-
* value="0 9 * * 1-5"
|
|
103
|
-
* onChange={handleChange}
|
|
104
|
-
* defaultType="weekly"
|
|
105
|
-
* showPreview
|
|
106
|
-
* showCronExpression
|
|
107
|
-
* allowCopy
|
|
108
|
-
* timeFormat="24h"
|
|
109
|
-
* />
|
|
266
|
+
* // Legacy expanded layout
|
|
267
|
+
* <CronScheduler value="0 9 * * 1-5" onChange={setCron} inline />
|
|
110
268
|
*/
|
|
111
269
|
export function CronScheduler({
|
|
112
270
|
value,
|
|
113
271
|
onChange,
|
|
114
272
|
defaultType = 'daily',
|
|
115
|
-
showPreview = true,
|
|
116
273
|
showCronExpression = false,
|
|
117
274
|
allowCopy = false,
|
|
118
275
|
timeFormat = '24h',
|
|
119
276
|
disabled = false,
|
|
277
|
+
inline = false,
|
|
278
|
+
placeholder = 'Set a schedule',
|
|
120
279
|
className,
|
|
121
280
|
}: CronSchedulerProps) {
|
|
122
281
|
return (
|
|
@@ -125,14 +284,24 @@ export function CronScheduler({
|
|
|
125
284
|
onChange={onChange}
|
|
126
285
|
defaultType={defaultType}
|
|
127
286
|
>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
287
|
+
{inline ? (
|
|
288
|
+
<InlineScheduler
|
|
289
|
+
timeFormat={timeFormat}
|
|
290
|
+
disabled={disabled}
|
|
291
|
+
showCronExpression={showCronExpression}
|
|
292
|
+
allowCopy={allowCopy}
|
|
293
|
+
className={className}
|
|
294
|
+
/>
|
|
295
|
+
) : (
|
|
296
|
+
<CompactTrigger
|
|
297
|
+
showCronExpression={showCronExpression}
|
|
298
|
+
allowCopy={allowCopy}
|
|
299
|
+
timeFormat={timeFormat}
|
|
300
|
+
disabled={disabled}
|
|
301
|
+
placeholder={placeholder}
|
|
302
|
+
className={className}
|
|
303
|
+
/>
|
|
304
|
+
)}
|
|
136
305
|
</CronSchedulerProvider>
|
|
137
306
|
);
|
|
138
307
|
}
|
|
@@ -36,32 +36,49 @@ export function CustomInput({ disabled, className }: CustomInputProps) {
|
|
|
36
36
|
setCustomCron(value);
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
const showError = !localValid && localValue.trim().length > 0;
|
|
40
|
+
|
|
39
41
|
return (
|
|
40
42
|
<div className={cn('space-y-2', className)}>
|
|
41
|
-
<
|
|
43
|
+
<label htmlFor="cron-custom-input" className="text-sm text-muted-foreground">
|
|
44
|
+
Cron expression
|
|
45
|
+
</label>
|
|
42
46
|
|
|
43
47
|
<div className="relative">
|
|
44
48
|
<Input
|
|
49
|
+
id="cron-custom-input"
|
|
45
50
|
type="text"
|
|
46
51
|
value={localValue}
|
|
47
52
|
onChange={handleChange}
|
|
48
53
|
disabled={disabled}
|
|
49
54
|
placeholder="* * * * *"
|
|
55
|
+
autoComplete="off"
|
|
56
|
+
autoCapitalize="off"
|
|
57
|
+
autoCorrect="off"
|
|
58
|
+
spellCheck={false}
|
|
59
|
+
aria-invalid={showError}
|
|
60
|
+
aria-describedby={showError ? 'cron-custom-error' : undefined}
|
|
50
61
|
className={cn(
|
|
51
62
|
'font-mono text-base pr-10 h-11',
|
|
52
|
-
|
|
63
|
+
showError && 'border-destructive focus-visible:ring-destructive/50'
|
|
53
64
|
)}
|
|
54
65
|
/>
|
|
55
66
|
<div className="absolute right-3 top-1/2 -translate-y-1/2">
|
|
56
67
|
{localValue.trim() && (
|
|
57
68
|
localValid ? (
|
|
58
|
-
<CheckCircle2 className="h-5 w-5 text-
|
|
69
|
+
<CheckCircle2 aria-hidden="true" className="h-5 w-5 text-success" />
|
|
59
70
|
) : (
|
|
60
|
-
<AlertCircle className="h-5 w-5 text-destructive" />
|
|
71
|
+
<AlertCircle aria-hidden="true" className="h-5 w-5 text-destructive" />
|
|
61
72
|
)
|
|
62
73
|
)}
|
|
63
74
|
</div>
|
|
64
75
|
</div>
|
|
76
|
+
|
|
77
|
+
{showError && (
|
|
78
|
+
<p id="cron-custom-error" role="alert" className="text-xs text-destructive">
|
|
79
|
+
Invalid cron expression — expected 5 fields: minute hour day month weekday.
|
|
80
|
+
</p>
|
|
81
|
+
)}
|
|
65
82
|
</div>
|
|
66
83
|
);
|
|
67
84
|
}
|
|
@@ -11,14 +11,14 @@ import { cn } from '@djangocfg/ui-core/lib';
|
|
|
11
11
|
import { useCronWeekDays } from '../context/hooks';
|
|
12
12
|
import type { WeekDay } from '../types';
|
|
13
13
|
|
|
14
|
-
const DAYS: { value: WeekDay; label: string }[] = [
|
|
15
|
-
{ value: 1, label: 'Mon' },
|
|
16
|
-
{ value: 2, label: 'Tue' },
|
|
17
|
-
{ value: 3, label: 'Wed' },
|
|
18
|
-
{ value: 4, label: 'Thu' },
|
|
19
|
-
{ value: 5, label: 'Fri' },
|
|
20
|
-
{ value: 6, label: 'Sat' },
|
|
21
|
-
{ value: 0, label: 'Sun' },
|
|
14
|
+
const DAYS: { value: WeekDay; label: string; full: string }[] = [
|
|
15
|
+
{ value: 1, label: 'Mon', full: 'Monday' },
|
|
16
|
+
{ value: 2, label: 'Tue', full: 'Tuesday' },
|
|
17
|
+
{ value: 3, label: 'Wed', full: 'Wednesday' },
|
|
18
|
+
{ value: 4, label: 'Thu', full: 'Thursday' },
|
|
19
|
+
{ value: 5, label: 'Fri', full: 'Friday' },
|
|
20
|
+
{ value: 6, label: 'Sat', full: 'Saturday' },
|
|
21
|
+
{ value: 0, label: 'Sun', full: 'Sunday' },
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
export interface DayChipsProps {
|
|
@@ -42,13 +42,14 @@ export function DayChips({
|
|
|
42
42
|
const isWeekendPreset = safeWeekDays.length === 2 && [0,6].every(d => safeWeekDays.includes(d as WeekDay));
|
|
43
43
|
const isEveryday = safeWeekDays.length === 7;
|
|
44
44
|
|
|
45
|
-
const dayButtons = DAYS.map(({ value, label }) => {
|
|
45
|
+
const dayButtons = DAYS.map(({ value, label, full }) => {
|
|
46
46
|
const isSelected = safeWeekDays.includes(value);
|
|
47
47
|
const isWeekendDay = value === 0 || value === 6;
|
|
48
48
|
|
|
49
49
|
return {
|
|
50
50
|
value,
|
|
51
51
|
label,
|
|
52
|
+
full,
|
|
52
53
|
isSelected,
|
|
53
54
|
isWeekendDay,
|
|
54
55
|
className: cn(
|
|
@@ -77,7 +78,7 @@ export function DayChips({
|
|
|
77
78
|
return (
|
|
78
79
|
<div className={cn('space-y-3', className)}>
|
|
79
80
|
{/* Day Grid - full width */}
|
|
80
|
-
<div className="grid grid-cols-7 gap-1">
|
|
81
|
+
<div className="grid grid-cols-7 gap-1" role="group" aria-label="Days of week">
|
|
81
82
|
{dayButtons.map((day) => (
|
|
82
83
|
<button
|
|
83
84
|
key={day.value}
|
|
@@ -85,9 +86,10 @@ export function DayChips({
|
|
|
85
86
|
disabled={disabled}
|
|
86
87
|
onClick={() => toggleWeekDay(day.value)}
|
|
87
88
|
aria-pressed={day.isSelected}
|
|
89
|
+
aria-label={day.full}
|
|
88
90
|
className={day.className}
|
|
89
91
|
>
|
|
90
|
-
<span>{day.label}</span>
|
|
92
|
+
<span aria-hidden="true">{day.label}</span>
|
|
91
93
|
</button>
|
|
92
94
|
))}
|
|
93
95
|
</div>
|
|
@@ -99,10 +99,10 @@ export function MonthDayGrid({
|
|
|
99
99
|
)}
|
|
100
100
|
|
|
101
101
|
{/* Calendar Grid - full width */}
|
|
102
|
-
<div className="grid grid-cols-7 gap-1">
|
|
102
|
+
<div className="grid grid-cols-7 gap-1" role="group" aria-label="Days of month">
|
|
103
103
|
{gridCells.map((cell) => {
|
|
104
104
|
if (cell.type === 'empty') {
|
|
105
|
-
return <div key={cell.key} className="aspect-square" />;
|
|
105
|
+
return <div key={cell.key} aria-hidden="true" className="aspect-square" />;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
return (
|
|
@@ -112,7 +112,7 @@ export function MonthDayGrid({
|
|
|
112
112
|
disabled={disabled}
|
|
113
113
|
onClick={() => toggleMonthDay(cell.day)}
|
|
114
114
|
aria-pressed={cell.isSelected}
|
|
115
|
-
aria-label={`Day ${cell.day}`}
|
|
115
|
+
aria-label={`Day ${cell.day} of month`}
|
|
116
116
|
className={cell.className}
|
|
117
117
|
>
|
|
118
118
|
{cell.day}
|
|
@@ -123,7 +123,7 @@ export function MonthDayGrid({
|
|
|
123
123
|
|
|
124
124
|
{/* Selection hint */}
|
|
125
125
|
{selectionCount > 1 && (
|
|
126
|
-
<p className="text-xs text-muted-foreground text-center">
|
|
126
|
+
<p aria-live="polite" className="text-xs text-muted-foreground text-center">
|
|
127
127
|
{selectionCount} days selected
|
|
128
128
|
</p>
|
|
129
129
|
)}
|
|
@@ -51,6 +51,8 @@ export function SchedulePreview({
|
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
53
|
<div
|
|
54
|
+
role="status"
|
|
55
|
+
aria-live="polite"
|
|
54
56
|
className={cn(
|
|
55
57
|
'px-3 py-2.5 rounded-lg border',
|
|
56
58
|
'bg-muted/30 border-border/50',
|
|
@@ -62,6 +64,7 @@ export function SchedulePreview({
|
|
|
62
64
|
<div className="flex items-center justify-between gap-2">
|
|
63
65
|
<div className="flex items-center gap-2 min-w-0">
|
|
64
66
|
<Calendar
|
|
67
|
+
aria-hidden="true"
|
|
65
68
|
className={cn(
|
|
66
69
|
'h-4 w-4 shrink-0',
|
|
67
70
|
isValid ? 'text-primary' : 'text-destructive'
|
|
@@ -88,12 +91,13 @@ export function SchedulePreview({
|
|
|
88
91
|
'hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
|
|
89
92
|
'disabled:opacity-50 disabled:cursor-not-allowed'
|
|
90
93
|
)}
|
|
94
|
+
aria-label={copied ? 'Cron expression copied' : 'Copy cron expression'}
|
|
91
95
|
title={copied ? 'Copied!' : 'Copy cron expression'}
|
|
92
96
|
>
|
|
93
97
|
{copied ? (
|
|
94
|
-
<Check className="h-3.5 w-3.5 text-
|
|
98
|
+
<Check aria-hidden="true" className="h-3.5 w-3.5 text-success" />
|
|
95
99
|
) : (
|
|
96
|
-
<Copy className="h-3.5 w-3.5 text-muted-foreground" />
|
|
100
|
+
<Copy aria-hidden="true" className="h-3.5 w-3.5 text-muted-foreground" />
|
|
97
101
|
)}
|
|
98
102
|
</button>
|
|
99
103
|
)}
|
|
@@ -108,7 +112,7 @@ export function SchedulePreview({
|
|
|
108
112
|
<code className="text-xs font-mono text-muted-foreground/60 line-through">
|
|
109
113
|
{initialValue}
|
|
110
114
|
</code>
|
|
111
|
-
<ArrowRight className="h-3 w-3 text-muted-foreground/40 shrink-0" />
|
|
115
|
+
<ArrowRight aria-hidden="true" className="h-3 w-3 text-muted-foreground/40 shrink-0" />
|
|
112
116
|
</>
|
|
113
117
|
)}
|
|
114
118
|
<code className="text-xs font-mono text-muted-foreground">
|
|
@@ -63,7 +63,7 @@ export function TimeSelector({
|
|
|
63
63
|
return (
|
|
64
64
|
<div className={cn('flex items-center gap-3', className)}>
|
|
65
65
|
<div className="flex items-center gap-2 text-muted-foreground">
|
|
66
|
-
<Clock className="h-4 w-4" />
|
|
66
|
+
<Clock aria-hidden="true" className="h-4 w-4" />
|
|
67
67
|
<span className="text-sm">Run at</span>
|
|
68
68
|
</div>
|
|
69
69
|
|
|
@@ -92,9 +92,7 @@ export interface CronSchedulerProps {
|
|
|
92
92
|
onChange?: (cron: string) => void;
|
|
93
93
|
/** Initial schedule type (default: 'daily') */
|
|
94
94
|
defaultType?: ScheduleType;
|
|
95
|
-
/** Show
|
|
96
|
-
showPreview?: boolean;
|
|
97
|
-
/** Show raw cron expression in preview (default: false) */
|
|
95
|
+
/** Show raw cron expression below the trigger (default: false) */
|
|
98
96
|
showCronExpression?: boolean;
|
|
99
97
|
/** Allow copying cron expression (default: false) */
|
|
100
98
|
allowCopy?: boolean;
|
|
@@ -102,6 +100,13 @@ export interface CronSchedulerProps {
|
|
|
102
100
|
timeFormat?: '12h' | '24h';
|
|
103
101
|
/** Disable all interactions */
|
|
104
102
|
disabled?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Render the schedule editor expanded instead of behind a popover
|
|
105
|
+
* trigger (legacy layout). Default: false — compact popover surface.
|
|
106
|
+
*/
|
|
107
|
+
inline?: boolean;
|
|
108
|
+
/** Trigger text shown when no schedule is set (compact mode only) */
|
|
109
|
+
placeholder?: string;
|
|
105
110
|
/** Additional CSS classes */
|
|
106
111
|
className?: string;
|
|
107
112
|
}
|