@hyperframes/studio 0.8.50 → 0.8.53-desktop.0
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/assets/{hyperframes-player-CxxDxHTW.js → hyperframes-player-PTEnAHhg.js} +3 -3
- package/dist/assets/{index-DUAIWxkI.js → index--myXp8ui.js} +1 -1
- package/dist/assets/{index-Dt3qBI-9.js → index-BjslOS9g.js} +1 -1
- package/dist/assets/index-BnXZuIJD.css +1 -0
- package/dist/assets/index-CNyviK_l.js +390 -0
- package/dist/index.css +29 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +825 -24
- package/dist/index.html +2 -2
- package/dist/index.js +8911 -9853
- package/dist/index.js.map +1 -1
- package/dist/styles/tailwind-preset.js.map +1 -1
- package/package.json +13 -12
- package/src/App.tsx +145 -163
- package/src/captions/components/CaptionAnimationPanel.tsx +4 -4
- package/src/captions/components/CaptionOverlay.sender.test.tsx +52 -0
- package/src/captions/components/CaptionOverlay.tsx +8 -4
- package/src/captions/components/CaptionOverlayUtils.ts +2 -3
- package/src/captions/components/CaptionPropertyPanel.tsx +3 -3
- package/src/captions/components/CaptionTimeline.tsx +1 -1
- package/src/captions/components/shared.tsx +2 -2
- package/src/components/AskAgentModal.tsx +5 -5
- package/src/components/EditorShell.selectionSync.test.tsx +9 -4
- package/src/components/EditorShell.tsx +59 -62
- package/src/components/ExternalFileConflictBanner.tsx +16 -16
- package/src/components/LintModal.tsx +6 -16
- package/src/components/MediaPreview.tsx +2 -2
- package/src/components/RightPanelTabs.test.tsx +151 -0
- package/src/components/RightPanelTabs.tsx +59 -0
- package/src/components/SaveQueuePausedBanner.tsx +2 -2
- package/src/components/StudioHeader.dom.test.tsx +181 -0
- package/src/components/StudioHeader.test.ts +0 -12
- package/src/components/StudioHeader.tsx +118 -221
- package/src/components/StudioLeftPanels.tsx +202 -0
- package/src/components/StudioOverlays.tsx +1 -1
- package/src/components/{StudioRightPanel.tsx → StudioRightPanels.tsx} +57 -194
- package/src/components/{StudioRightPanel.types.ts → StudioRightPanels.types.ts} +4 -3
- package/src/components/StudioToast.tsx +2 -2
- package/src/components/TimelineHistoryButtons.dom.test.tsx +117 -0
- package/src/components/TimelineHistoryButtons.tsx +54 -0
- package/src/components/TimelineToolbar.test.tsx +8 -0
- package/src/components/TimelineToolbar.tsx +8 -12
- package/src/components/dock/Dock.test.tsx +274 -0
- package/src/components/dock/Dock.tsx +291 -0
- package/src/components/dock/dock.css +28 -0
- package/src/components/dock/dockAccessibility.test.ts +166 -0
- package/src/components/dock/dockAccessibility.ts +98 -0
- package/src/components/dock/dockLayout.test.ts +134 -0
- package/src/components/dock/dockLayout.ts +105 -0
- package/src/components/dock/dockLayoutSchema.ts +66 -0
- package/src/components/dock/dockLayoutStore.test.ts +28 -0
- package/src/components/dock/dockLayoutStore.ts +108 -0
- package/src/components/dock/dockTestHarness.ts +11 -0
- package/src/components/dock/panelRegistry.ts +67 -0
- package/src/components/editor/AnimationCard.tsx +4 -4
- package/src/components/editor/AnimationCardParts.tsx +6 -6
- package/src/components/editor/BlockParamsPanel.tsx +4 -4
- package/src/components/editor/BorderRadiusEditor.tsx +1 -1
- package/src/components/editor/CanvasContextMenu.tsx +1 -1
- package/src/components/editor/ComputedTweenNotice.tsx +1 -1
- package/src/components/editor/DomEditOverlay.tsx +1 -1
- package/src/components/editor/EaseCurveSection.tsx +1 -1
- package/src/components/editor/EaseParamFields.tsx +5 -5
- package/src/components/editor/FileTree.tsx +4 -4
- package/src/components/editor/FileTreeIcons.tsx +1 -1
- package/src/components/editor/FileTreeNodes.tsx +13 -13
- package/src/components/editor/InlineTextToolbar.tsx +1 -1
- package/src/components/editor/InspectorHeaderActions.tsx +3 -3
- package/src/components/editor/KeyframeDiamond.tsx +1 -1
- package/src/components/editor/KeyframeEaseList.tsx +1 -1
- package/src/components/editor/LayersPanel.test.ts +97 -1
- package/src/components/editor/LayersPanel.tsx +7 -5
- package/src/components/editor/MarqueeOverlay.tsx +1 -1
- package/src/components/editor/OffCanvasIndicators.tsx +1 -1
- package/src/components/editor/PreviewGuides.tsx +1 -1
- package/src/components/editor/PromotableControl.tsx +2 -2
- package/src/components/editor/PropertyPanelEmptyState.tsx +7 -7
- package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
- package/src/components/editor/SnapToolbar.test.tsx +0 -3
- package/src/components/editor/SnapToolbar.tsx +2 -2
- package/src/components/editor/TimelineFxPopover.tsx +1 -1
- package/src/components/editor/TopologyLens.test.tsx +28 -0
- package/src/components/editor/TopologyLens.tsx +7 -5
- package/src/components/editor/Transform3DCube.tsx +2 -2
- package/src/components/editor/audioFxRevealTarget.ts +1 -0
- package/src/components/editor/domEditing.test.ts +1 -1
- package/src/components/editor/domEditingAgentPrompt.test.ts +8 -6
- package/src/components/editor/domEditingAgentPrompt.ts +4 -3
- package/src/components/editor/propertyPanelColor.tsx +11 -11
- package/src/components/editor/propertyPanelColorCurveGraph.tsx +1 -1
- package/src/components/editor/propertyPanelColorGradingControls.tsx +7 -9
- package/src/components/editor/propertyPanelColorGradingSection.tsx +6 -6
- package/src/components/editor/propertyPanelColorGradingSlider.tsx +5 -5
- package/src/components/editor/propertyPanelColorWheels.tsx +1 -1
- package/src/components/editor/propertyPanelCommitField.tsx +1 -1
- package/src/components/editor/propertyPanelFill.tsx +4 -4
- package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
- package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +7 -7
- package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
- package/src/components/editor/propertyPanelFlatMediaSection.tsx +3 -3
- package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +1 -1
- package/src/components/editor/propertyPanelFlatPrimitives.tsx +10 -10
- package/src/components/editor/propertyPanelFlatSelectRow.tsx +3 -3
- package/src/components/editor/propertyPanelFlatTextSection.test.tsx +8 -9
- package/src/components/editor/propertyPanelFlatTextSection.tsx +5 -5
- package/src/components/editor/propertyPanelFlatToggle.tsx +1 -1
- package/src/components/editor/propertyPanelFont.tsx +5 -5
- package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.test.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.tsx +6 -6
- package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
- package/src/components/editor/propertyPanelFxPresetStyle.ts +2 -2
- package/src/components/editor/propertyPanelGradingNumberField.tsx +1 -1
- package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
- package/src/components/editor/propertyPanelPrimitives.tsx +7 -7
- package/src/components/editor/propertyPanelSections.tsx +8 -8
- package/src/components/editor/useColorGradingController.test.ts +38 -0
- package/src/components/editor/useColorGradingController.ts +9 -1
- package/src/components/editor/useColorGradingPreviews.test.ts +76 -0
- package/src/components/editor/useColorGradingPreviews.ts +11 -1
- package/src/components/editor/usePreviewCompositionRect.test.tsx +95 -0
- package/src/components/editor/usePreviewCompositionRect.ts +21 -0
- package/src/components/feedback/StudioFeedbackCard.tsx +7 -7
- package/src/components/feedback/feedbackTrigger.ts +0 -1
- package/src/components/nle/AssetPreviewOverlay.tsx +6 -2
- package/src/components/nle/CompositionBreadcrumb.tsx +3 -3
- package/src/components/nle/NLEContext.tsx +0 -43
- package/src/components/nle/NLEPreview.tsx +3 -3
- package/src/components/nle/PreviewOverlays.tsx +6 -6
- package/src/components/nle/PreviewPane.tsx +3 -3
- package/src/components/nle/TimelinePane.tsx +53 -67
- package/src/components/panels/SlideshowPanel.tsx +3 -3
- package/src/components/panels/SlideshowSubPanels.tsx +20 -17
- package/src/components/panels/VariablesBindElement.tsx +2 -2
- package/src/components/panels/VariablesDeclarationForm.tsx +2 -2
- package/src/components/panels/VariablesOtherCompositions.tsx +1 -1
- package/src/components/panels/VariablesPanel.tsx +4 -4
- package/src/components/panels/VariablesValueControls.tsx +2 -2
- package/src/components/pointerTargetSize.test.tsx +8 -0
- package/src/components/renders/FfmpegRequiredNotice.tsx +5 -5
- package/src/components/renders/RenderQueue.test.tsx +7 -0
- package/src/components/renders/RenderQueue.tsx +7 -7
- package/src/components/renders/RenderQueueItem.tsx +6 -6
- package/src/components/renders/RenderQueuePanel.tsx +1 -1
- package/src/components/sidebar/AssetCard.tsx +8 -8
- package/src/components/sidebar/AssetContextMenu.tsx +8 -8
- package/src/components/sidebar/AssetsTab.tsx +2 -2
- package/src/components/sidebar/AudioRow.tsx +6 -6
- package/src/components/sidebar/BlocksTab.tsx +6 -6
- package/src/components/sidebar/{LeftSidebar.masterComposition.test.tsx → CompositionsPanel.masterComposition.test.tsx} +6 -9
- package/src/components/sidebar/CompositionsPanel.tsx +15 -0
- package/src/components/sidebar/CompositionsTab.tsx +5 -5
- package/src/components/sidebar/GlobalAssetsView.tsx +1 -1
- package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
- package/src/components/sidebar/SidebarLintButton.test.tsx +53 -0
- package/src/components/sidebar/SidebarLintButton.tsx +50 -0
- package/src/components/timelineToolbarStyles.ts +5 -0
- package/src/components/ui/Button.test.tsx +252 -0
- package/src/components/ui/Button.tsx +89 -126
- package/src/components/ui/IconButton.tsx +38 -0
- package/src/components/ui/Input.tsx +115 -0
- package/src/components/ui/Menu.test.tsx +374 -0
- package/src/components/ui/Menu.tsx +213 -0
- package/src/components/ui/NumberField.tsx +122 -0
- package/src/components/ui/Popover.tsx +74 -0
- package/src/components/ui/SearchInput.tsx +2 -2
- package/src/components/ui/Select.tsx +100 -0
- package/src/components/ui/Slider.tsx +153 -0
- package/src/components/ui/Tabs.test.tsx +98 -0
- package/src/components/ui/Tabs.tsx +71 -0
- package/src/components/ui/Toggle.tsx +63 -0
- package/src/components/ui/Tooltip.test.tsx +110 -0
- package/src/components/ui/Tooltip.tsx +38 -112
- package/src/components/ui/cn.test.ts +30 -0
- package/src/components/ui/cn.ts +25 -0
- package/src/components/ui/index.ts +29 -2
- package/src/components/ui/mountHost.testHelpers.ts +24 -0
- package/src/components/ui/valueControls.test.tsx +524 -0
- package/src/contexts/PanelLayoutContext.tsx +3 -57
- package/src/hooks/appHotkeysDispatch.ts +3 -4
- package/src/hooks/timelineEditPermission.ts +31 -0
- package/src/hooks/useAppHotkeys.previewForwarding.test.tsx +0 -2
- package/src/hooks/useAppHotkeys.test.ts +0 -1
- package/src/hooks/useAppHotkeys.textEditing.test.tsx +0 -3
- package/src/hooks/useAppHotkeys.ts +21 -84
- package/src/hooks/useCaptionDetection.sender.test.tsx +46 -0
- package/src/hooks/useCaptionDetection.ts +3 -1
- package/src/hooks/useDomEditPreviewSync.ts +4 -6
- package/src/hooks/useDomEditSession.ts +0 -7
- package/src/hooks/useDomEditWiring.ts +4 -9
- package/src/hooks/useEditHistoryActions.test.tsx +90 -0
- package/src/hooks/useEditHistoryActions.ts +106 -0
- package/src/hooks/useFileManager.ts +21 -123
- package/src/hooks/useLintModal.test.tsx +65 -0
- package/src/hooks/useLintModal.ts +3 -0
- package/src/hooks/usePanelLayout.test.ts +108 -296
- package/src/hooks/usePanelLayout.ts +50 -255
- package/src/hooks/usePersistentEditHistory.ts +1 -1
- package/src/hooks/useProjectFileWriter.ts +150 -0
- package/src/hooks/useRightPanelIntents.test.ts +181 -0
- package/src/hooks/useRightPanelIntents.ts +63 -0
- package/src/hooks/useSdkSession.lifecycle.test.tsx +49 -4
- package/src/hooks/useSdkSession.ts +43 -10
- package/src/hooks/useServerConnection.hashProject.test.tsx +94 -0
- package/src/hooks/useServerConnection.ts +43 -10
- package/src/hooks/useSlideshowTabState.test.ts +9 -31
- package/src/hooks/useSlideshowTabState.ts +6 -19
- package/src/hooks/useStudioContextValue.test.ts +6 -18
- package/src/hooks/useStudioContextValue.ts +5 -26
- package/src/hooks/useTimelineAssetDropOps.test.tsx +41 -1
- package/src/hooks/useTimelineAssetDropOps.ts +52 -11
- package/src/hooks/useTimelineDeleteOps.test.tsx +111 -0
- package/src/hooks/useTimelineEditing.test.tsx +322 -3
- package/src/hooks/useTimelineEditing.ts +103 -16
- package/src/hooks/useTimelineEditingTypes.ts +3 -0
- package/src/hooks/useTrackPendingTimelineEdit.test.tsx +62 -0
- package/src/hooks/useTrackPendingTimelineEdit.ts +22 -0
- package/src/hostMount.test.tsx +222 -0
- package/src/index.ts +87 -0
- package/src/main.tsx +9 -3
- package/src/player/components/AudioWaveform.tsx +1 -1
- package/src/player/components/AutomationSelectionMenu.tsx +3 -3
- package/src/player/components/ClipContextMenu.tsx +3 -3
- package/src/player/components/CompositionThumbnail.test.ts +0 -3
- package/src/player/components/CompositionThumbnail.tsx +3 -4
- package/src/player/components/EditModal.tsx +1 -1
- package/src/player/components/ImageThumbnail.tsx +1 -1
- package/src/player/components/KeyframeDiamondContextMenu.tsx +4 -4
- package/src/player/components/LayerDisclosureRow.tsx +2 -2
- package/src/player/components/PlayerControls.tsx +1 -1
- package/src/player/components/ShortcutsPanel.tsx +9 -9
- package/src/player/components/SpeedMenu.tsx +3 -5
- package/src/player/components/Timeline.tsx +3 -2
- package/src/player/components/TimelineCanvas.tsx +21 -14
- package/src/player/components/TimelineClip.tsx +0 -1
- package/src/player/components/TimelineDiamondConnectors.tsx +1 -1
- package/src/player/components/TimelineEmptyState.tsx +5 -5
- package/src/player/components/TimelineFxButton.tsx +6 -6
- package/src/player/components/TimelineGroupHeader.tsx +5 -5
- package/src/player/components/TimelineGroupLaneLabels.tsx +1 -1
- package/src/player/components/TimelineGroupRow.tsx +1 -1
- package/src/player/components/TimelineLanes.test.tsx +32 -0
- package/src/player/components/TimelineLanes.tsx +2 -5
- package/src/player/components/TimelineLayerGroupHeader.tsx +2 -2
- package/src/player/components/TimelineRuler.tsx +1 -1
- package/src/player/components/TimelineShortcutHint.tsx +1 -1
- package/src/player/components/TimelineTrackHeader.test.tsx +26 -5
- package/src/player/components/TimelineTrackHeader.tsx +2 -2
- package/src/player/components/TimelineTrackPlainHeader.tsx +3 -3
- package/src/player/components/TimelineTypes.ts +2 -1
- package/src/player/components/TrackGapContextMenu.tsx +1 -1
- package/src/player/components/VideoThumbnail.tsx +4 -2
- package/src/player/components/VolumeControl.tsx +2 -2
- package/src/player/components/timelineCallbacks.ts +8 -8
- package/src/player/components/timelineClipDragPreview.ts +51 -27
- package/src/player/components/timelineClipDragTypes.ts +3 -0
- package/src/player/components/timelineDragDrop.test.tsx +61 -1
- package/src/player/components/timelineDragDrop.ts +57 -15
- package/src/player/components/timelineLaneProps.ts +3 -0
- package/src/player/components/timelineSnapping.test.ts +27 -0
- package/src/player/components/timelineSnapping.ts +14 -1
- package/src/player/components/timelineTheme.test.ts +4 -4
- package/src/player/components/timelineTheme.ts +30 -30
- package/src/player/components/trackHeaderLabelRows.tsx +4 -4
- package/src/player/components/useTimelineClipDrag.resize.test.tsx +136 -2
- package/src/player/components/useTimelineClipDrag.ts +30 -3
- package/src/player/lib/describeClips.ts +3 -54
- package/src/player/lib/playbackShortcuts.ts +2 -0
- package/src/player/lib/timelinePerformanceDiagnostics.test.ts +3 -2
- package/src/player/lib/timelinePerformanceDiagnostics.ts +1 -1
- package/src/player/store/previewIframeStore.notify.test.tsx +75 -0
- package/src/player/store/previewIframeStore.test.tsx +29 -0
- package/src/player/store/previewIframeStore.ts +25 -0
- package/src/renderQueueExports.test.tsx +58 -0
- package/src/styles/classCandidates.test.ts +105 -0
- package/src/styles/classCandidates.ts +281 -0
- package/src/styles/hex-baseline.json +84 -0
- package/src/styles/hexRatchet.test.ts +201 -0
- package/src/styles/iconTokens.ts +20 -0
- package/src/styles/palette-reset.css +6 -0
- package/src/styles/studio.css +24 -21
- package/src/styles/styleSources.test.ts +20 -0
- package/src/styles/styleSources.ts +47 -0
- package/src/styles/tailwind-preset.shared.js +3 -0
- package/src/styles/theme.css +270 -0
- package/src/styles/theme.test.ts +183 -0
- package/src/styles/tokenGate.test.ts +109 -0
- package/src/utils/sourcePatcher.ts +1 -1
- package/src/utils/studioHelpers.test.ts +18 -0
- package/src/utils/studioHelpers.ts +11 -8
- package/src/utils/studioUiPreferences.test.ts +10 -16
- package/src/utils/studioUiPreferences.ts +7 -16
- package/src/utils/timelineDropTrackInsert.test.ts +134 -0
- package/src/utils/timelineDropTrackInsert.ts +83 -0
- package/src/utils/typingTarget.ts +4 -0
- package/dist/assets/index-n2ml4tUn.js +0 -442
- package/dist/assets/index-pO6p0H27.css +0 -1
- package/src/components/PanelTabButton.tsx +0 -31
- package/src/components/StudioLeftSidebar.tsx +0 -204
- package/src/components/nle/TimelineResizeDivider.tsx +0 -101
- package/src/components/sidebar/LeftSidebar.storage.test.ts +0 -28
- package/src/components/sidebar/LeftSidebar.tsx +0 -334
- package/src/components/storyboard/AgentChatMessageButton.test.tsx +0 -47
- package/src/components/storyboard/AgentChatMessageButton.tsx +0 -45
- package/src/components/storyboard/FramePoster.test.tsx +0 -61
- package/src/components/storyboard/FramePoster.tsx +0 -86
- package/src/components/storyboard/StoryboardDirection.tsx +0 -45
- package/src/components/storyboard/StoryboardFrameFocus.tsx +0 -412
- package/src/components/storyboard/StoryboardFrameTile.tsx +0 -117
- package/src/components/storyboard/StoryboardGrid.tsx +0 -55
- package/src/components/storyboard/StoryboardLoaded.tsx +0 -307
- package/src/components/storyboard/StoryboardReviewGuide.tsx +0 -300
- package/src/components/storyboard/StoryboardScriptPanel.tsx +0 -26
- package/src/components/storyboard/StoryboardSourceEditor.tsx +0 -231
- package/src/components/storyboard/StoryboardStatusLegend.tsx +0 -21
- package/src/components/storyboard/StoryboardView.tsx +0 -169
- package/src/components/storyboard/StoryboardViewModeGuard.test.tsx +0 -187
- package/src/components/storyboard/frameComments.test.ts +0 -95
- package/src/components/storyboard/frameComments.ts +0 -115
- package/src/components/storyboard/frameStatus.ts +0 -36
- package/src/components/storyboard/storyboardReviewStage.test.ts +0 -40
- package/src/components/storyboard/storyboardReviewStage.ts +0 -45
- package/src/components/storyboard/useFrameComments.ts +0 -98
- package/src/contexts/ViewModeContext.tsx +0 -142
- package/src/hooks/useInspectorSplitResize.ts +0 -51
- package/src/hooks/useProjectSignaturePoll.test.tsx +0 -135
- package/src/hooks/useProjectSignaturePoll.ts +0 -68
- package/src/hooks/useStoryboard.ts +0 -99
- package/src/utils/fitPanels.test.ts +0 -164
- package/src/utils/fitPanels.ts +0 -151
package/src/styles/studio.css
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
@
|
|
2
|
-
@
|
|
3
|
-
@
|
|
1
|
+
@import "tailwindcss" source(none);
|
|
2
|
+
@import "./palette-reset.css";
|
|
3
|
+
@import "./theme.css";
|
|
4
|
+
|
|
5
|
+
/* Explicit sources: Studio's own TypeScript and its shell HTML. Automatic
|
|
6
|
+
* detection would walk up to the repo root and scan `data/projects`, gitignored user content. */
|
|
7
|
+
@source "../**/*.{ts,tsx}";
|
|
8
|
+
@source "../../index.html";
|
|
9
|
+
|
|
10
|
+
/* Tailwind v4 preflight no longer gives enabled buttons a pointer cursor. */
|
|
11
|
+
@layer base {
|
|
12
|
+
button:not(:disabled),
|
|
13
|
+
[role="button"]:not(:disabled) {
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
/*
|
|
6
19
|
* Studio is a dark-only UI — pin the user-agent color scheme to dark so that
|
|
@@ -14,9 +27,9 @@
|
|
|
14
27
|
body {
|
|
15
28
|
margin: 0;
|
|
16
29
|
padding: 0;
|
|
17
|
-
background:
|
|
18
|
-
color:
|
|
19
|
-
font-family: -
|
|
30
|
+
background: var(--color-bg-0);
|
|
31
|
+
color: var(--color-text-body);
|
|
32
|
+
font-family: var(--font-sans);
|
|
20
33
|
overflow: hidden;
|
|
21
34
|
}
|
|
22
35
|
|
|
@@ -290,7 +303,7 @@ body {
|
|
|
290
303
|
left: 12px;
|
|
291
304
|
overflow: hidden;
|
|
292
305
|
color: rgba(255, 255, 255, 0.34);
|
|
293
|
-
font-family:
|
|
306
|
+
font-family: var(--font-mono);
|
|
294
307
|
font-size: 9px;
|
|
295
308
|
font-variant-numeric: tabular-nums;
|
|
296
309
|
line-height: 1;
|
|
@@ -328,7 +341,7 @@ body {
|
|
|
328
341
|
}
|
|
329
342
|
|
|
330
343
|
.cm-editor .cm-scroller {
|
|
331
|
-
font-family:
|
|
344
|
+
font-family: var(--font-mono);
|
|
332
345
|
}
|
|
333
346
|
|
|
334
347
|
.cm-editor.cm-focused {
|
|
@@ -385,12 +398,7 @@ body {
|
|
|
385
398
|
}
|
|
386
399
|
|
|
387
400
|
.hf-loader-title {
|
|
388
|
-
font-family:
|
|
389
|
-
Inter,
|
|
390
|
-
-apple-system,
|
|
391
|
-
BlinkMacSystemFont,
|
|
392
|
-
"Segoe UI",
|
|
393
|
-
sans-serif;
|
|
401
|
+
font-family: var(--font-sans);
|
|
394
402
|
font-size: 1rem;
|
|
395
403
|
font-weight: 600;
|
|
396
404
|
letter-spacing: 0;
|
|
@@ -406,12 +414,7 @@ body {
|
|
|
406
414
|
min-height: 2.5rem;
|
|
407
415
|
overflow: hidden;
|
|
408
416
|
color: var(--hf-text-secondary, rgba(244, 244, 245, 0.68));
|
|
409
|
-
font-family:
|
|
410
|
-
Inter,
|
|
411
|
-
-apple-system,
|
|
412
|
-
BlinkMacSystemFont,
|
|
413
|
-
"Segoe UI",
|
|
414
|
-
sans-serif;
|
|
417
|
+
font-family: var(--font-sans);
|
|
415
418
|
font-size: 0.82rem;
|
|
416
419
|
line-height: 1.6;
|
|
417
420
|
}
|
|
@@ -423,7 +426,7 @@ body {
|
|
|
423
426
|
text-overflow: ellipsis;
|
|
424
427
|
white-space: nowrap;
|
|
425
428
|
color: var(--hf-text-tertiary, rgba(244, 244, 245, 0.46));
|
|
426
|
-
font-family:
|
|
429
|
+
font-family: var(--font-mono);
|
|
427
430
|
font-size: 0.75rem;
|
|
428
431
|
letter-spacing: 0;
|
|
429
432
|
font-variant-numeric: tabular-nums;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { listSourceFiles, toPosixPath } from "./styleSources";
|
|
3
|
+
|
|
4
|
+
describe("style source paths", () => {
|
|
5
|
+
it("turns a Windows-style relative path into the forward-slash form the baseline uses", () => {
|
|
6
|
+
expect(toPosixPath("packages\\studio\\src\\App.tsx")).toBe("packages/studio/src/App.tsx");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("leaves a forward-slash path alone", () => {
|
|
10
|
+
expect(toPosixPath("packages/studio/src/App.tsx")).toBe("packages/studio/src/App.tsx");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("hands the keep filter and the map key the same forward-slash path", () => {
|
|
14
|
+
const seen: string[] = [];
|
|
15
|
+
const files = listSourceFiles((file) => (seen.push(file), file.endsWith("styleSources.ts")));
|
|
16
|
+
|
|
17
|
+
expect([...files.keys()]).toEqual(["styles/styleSources.ts"]);
|
|
18
|
+
expect(seen.every((file) => !file.includes("\\"))).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Where the style tests read from: Tailwind's entry resolved from `node_modules`, and the file list
|
|
2
|
+
// that `@source` in `studio.css` describes, shared so the gate, ratchet and theme test agree.
|
|
3
|
+
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
export const STYLES_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const SRC_DIR = path.dirname(STYLES_DIR);
|
|
11
|
+
export const REPO_ROOT = path.resolve(SRC_DIR, "../../..");
|
|
12
|
+
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
export const TAILWIND_DIR = path.dirname(require.resolve("tailwindcss/package.json"));
|
|
15
|
+
|
|
16
|
+
/** Resolves `@import` for Tailwind's compiler: bare `tailwindcss`, or a path. */
|
|
17
|
+
export function loadStylesheet(id: string, base: string) {
|
|
18
|
+
const file = id === "tailwindcss" ? path.join(TAILWIND_DIR, "index.css") : path.resolve(base, id);
|
|
19
|
+
return { path: file, base: path.dirname(file), content: readFileSync(file, "utf8") };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Forward slashes on every platform, so keys match the baseline file and the gate's messages. */
|
|
23
|
+
export const toPosixPath = (relativePath: string): string => relativePath.replace(/\\/g, "/");
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Studio's own sources, keyed by path relative to `from`, for every file the
|
|
27
|
+
* caller keeps. Build output and dependencies are never walked.
|
|
28
|
+
*/
|
|
29
|
+
export function listSourceFiles(
|
|
30
|
+
keep: (relativePath: string) => boolean,
|
|
31
|
+
from: string = SRC_DIR,
|
|
32
|
+
): Map<string, string> {
|
|
33
|
+
const files = new Map<string, string>();
|
|
34
|
+
const walk = (dir: string) => {
|
|
35
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
36
|
+
const full = path.join(dir, entry.name);
|
|
37
|
+
if (entry.isDirectory()) {
|
|
38
|
+
if (entry.name !== "node_modules" && entry.name !== "dist") walk(full);
|
|
39
|
+
} else {
|
|
40
|
+
const relative = toPosixPath(path.relative(from, full));
|
|
41
|
+
if (keep(relative)) files.set(relative, readFileSync(full, "utf8"));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
walk(SRC_DIR);
|
|
46
|
+
return files;
|
|
47
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/* Studio's design tokens, the one place a design value is decided. Tailwind emits
|
|
2
|
+
* each as a utility and a CSS custom property; `@theme static` keeps unused
|
|
3
|
+
* tokens in `:root` so plain CSS and canvas code can still read them. */
|
|
4
|
+
|
|
5
|
+
@theme static {
|
|
6
|
+
/* ---------------------------------------------------------------- colour */
|
|
7
|
+
|
|
8
|
+
/* Background levels, darkest (app shell) to lightest (inset panel body). */
|
|
9
|
+
--color-bg-0: #0a0a0a;
|
|
10
|
+
--color-bg-1: #0c0c0e;
|
|
11
|
+
--color-bg-2: #121214;
|
|
12
|
+
|
|
13
|
+
/* Raised surfaces. */
|
|
14
|
+
--color-surface: #18181b;
|
|
15
|
+
--color-surface-alt: #141414;
|
|
16
|
+
--color-input: #161618;
|
|
17
|
+
--color-hover: #27272a;
|
|
18
|
+
|
|
19
|
+
/* Separators, weakest to strongest. */
|
|
20
|
+
--color-hairline: #1a1a1c;
|
|
21
|
+
--color-border: #1e1e1e;
|
|
22
|
+
--color-border-input: #27272a;
|
|
23
|
+
--color-border-strong: #262626;
|
|
24
|
+
|
|
25
|
+
/* Text, brightest (0) to dimmest (5). */
|
|
26
|
+
--color-text-0: #fafafa;
|
|
27
|
+
--color-text-1: #e4e4e7;
|
|
28
|
+
--color-text-2: #a1a1aa;
|
|
29
|
+
--color-text-3: #71717a;
|
|
30
|
+
--color-text-4: #52525b;
|
|
31
|
+
--color-text-5: #3f3f46;
|
|
32
|
+
--color-text-body: #e5e5e5;
|
|
33
|
+
--color-text-muted: #737373;
|
|
34
|
+
|
|
35
|
+
/* Roles. Selection and playhead are reserved and differ from the accent so a
|
|
36
|
+
* selected clip, the playhead and an accented control stay tellable apart. */
|
|
37
|
+
--color-accent: #3ce6ac;
|
|
38
|
+
--color-selection: #4ba3d2;
|
|
39
|
+
--color-playhead: #ffffff;
|
|
40
|
+
--color-danger: #ef4444;
|
|
41
|
+
--color-media: #00e3ff;
|
|
42
|
+
--color-container: #f5a623;
|
|
43
|
+
|
|
44
|
+
/* The two stops of the HeyGen brand gradient, worn by the header logo. Fixed brand values
|
|
45
|
+
* rather than roles, so they are not reachable as a background or text colour by mistake. */
|
|
46
|
+
--color-brand-gradient-from: #06e3fa;
|
|
47
|
+
--color-brand-gradient-to: #4fdb5e;
|
|
48
|
+
|
|
49
|
+
/* The timeline's own surfaces: darker and bluer than the shared scale, so they
|
|
50
|
+
* get their own names instead of snapping to the nearest --color-bg/-surface
|
|
51
|
+
* step (AD147: a host themes the timeline by overriding these). */
|
|
52
|
+
--timeline-shell-bg: #0a0a0b;
|
|
53
|
+
--timeline-shell-border: rgba(255, 255, 255, 0.05);
|
|
54
|
+
--timeline-ruler-border: rgba(255, 255, 255, 0.16);
|
|
55
|
+
--timeline-row-bg: #101014;
|
|
56
|
+
--timeline-row-border: rgba(255, 255, 255, 0.06);
|
|
57
|
+
--timeline-gutter-bg: #0e0f12;
|
|
58
|
+
--timeline-gutter-border: rgba(255, 255, 255, 0.1);
|
|
59
|
+
--timeline-text-primary: rgba(255, 255, 255, 0.92);
|
|
60
|
+
--timeline-text-secondary: rgba(255, 255, 255, 0.62);
|
|
61
|
+
--timeline-tick-text: rgba(255, 255, 255, 0.34);
|
|
62
|
+
--timeline-tick-major: rgba(255, 255, 255, 0.1);
|
|
63
|
+
--timeline-tick-minor: rgba(255, 255, 255, 0.06);
|
|
64
|
+
--timeline-clip-bg: #141922;
|
|
65
|
+
--timeline-clip-bg-active: #181e28;
|
|
66
|
+
--timeline-clip-border: rgba(255, 255, 255, 0.1);
|
|
67
|
+
--timeline-clip-border-hover: rgba(255, 255, 255, 0.18);
|
|
68
|
+
--timeline-clip-border-active: rgba(255, 255, 255, 0.24);
|
|
69
|
+
--timeline-handle: rgba(255, 255, 255, 0.2);
|
|
70
|
+
--timeline-resize-seam: rgba(255, 255, 255, 0.12);
|
|
71
|
+
--timeline-resize-active: rgba(255, 255, 255, 0.24);
|
|
72
|
+
--timeline-track-clip-fill: rgba(255, 255, 255, 0.055);
|
|
73
|
+
--timeline-track-clip-active: rgba(60, 230, 172, 0.16);
|
|
74
|
+
--timeline-track-label: rgba(255, 255, 255, 0.5);
|
|
75
|
+
|
|
76
|
+
/* -------------------------------------------------------------- geometry */
|
|
77
|
+
|
|
78
|
+
--radius-sm: 0.25rem;
|
|
79
|
+
--radius-md: 0.375rem;
|
|
80
|
+
--radius-lg: 0.5rem;
|
|
81
|
+
|
|
82
|
+
/* The one radius every push-button wears, named by its role so a button does
|
|
83
|
+
* not have to know which step of the scale it sits on. */
|
|
84
|
+
--radius-button: var(--radius-md);
|
|
85
|
+
|
|
86
|
+
/* Control heights: 24, 28 and 32 px. `--spacing-*` gives `h-ctl`, `min-h-ctl`
|
|
87
|
+
* and friends. */
|
|
88
|
+
--spacing-ctl-sm: 24px;
|
|
89
|
+
--spacing-ctl: 28px;
|
|
90
|
+
--spacing-ctl-lg: 32px;
|
|
91
|
+
|
|
92
|
+
/* ------------------------------------------------------------------ type */
|
|
93
|
+
|
|
94
|
+
/* Dense UI type sizes named by pixel value. `step` avoids a clash with
|
|
95
|
+
* Tailwind's own `--text-*` scale, whose `xs`, `sm` and `lg` are unchanged. */
|
|
96
|
+
--text-step-7: 7px;
|
|
97
|
+
--text-step-8: 8px;
|
|
98
|
+
--text-step-9: 9px;
|
|
99
|
+
--text-step-10: 10px;
|
|
100
|
+
--text-step-11: 11px;
|
|
101
|
+
--text-step-12: 12px;
|
|
102
|
+
--text-step-13: 13px;
|
|
103
|
+
--text-step-14: 14px;
|
|
104
|
+
--text-step-15: 15px;
|
|
105
|
+
--text-step-16: 16px;
|
|
106
|
+
--text-step-17: 17px;
|
|
107
|
+
--text-step-18: 18px;
|
|
108
|
+
|
|
109
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
110
|
+
--font-mono: "JetBrains Mono", "IBM Plex Mono", "SF Mono", "Fira Code", monospace;
|
|
111
|
+
|
|
112
|
+
/* ---------------------------------------------------------------- shadow */
|
|
113
|
+
|
|
114
|
+
/* Floating chrome over a near-black canvas: the hairline ring does the edge
|
|
115
|
+
* definition that a light-mode drop shadow cannot. */
|
|
116
|
+
--shadow-menu: 0 8px 24px rgb(0 0 0 / 0.45), 0 0 0 1px rgb(0 0 0 / 0.4);
|
|
117
|
+
--shadow-popover: 0 16px 40px rgb(0 0 0 / 0.55), 0 0 0 1px rgb(0 0 0 / 0.45);
|
|
118
|
+
|
|
119
|
+
/* The primary button is the one light surface in a dark UI, so it reads as a
|
|
120
|
+
* raised key rather than a floating panel: a tight contact shadow, a soft
|
|
121
|
+
* ambient one, and an inner top highlight. */
|
|
122
|
+
--shadow-btn-primary:
|
|
123
|
+
0 1px 2px rgb(0 0 0 / 0.6), 0 2px 6px rgb(0 0 0 / 0.35), inset 0 1px 0 rgb(255 255 255 / 0.65);
|
|
124
|
+
|
|
125
|
+
/* ---------------------------------------------------------------- motion */
|
|
126
|
+
|
|
127
|
+
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
|
|
128
|
+
--ease-out-expo: cubic-bezier(0.23, 1, 0.32, 1);
|
|
129
|
+
--ease-in-out-circ: cubic-bezier(0.77, 0, 0.175, 1);
|
|
130
|
+
|
|
131
|
+
/* The curve for a small state change (hover, press, focus), named by role so
|
|
132
|
+
* a control does not have to pick one. The other two stay for motion that is
|
|
133
|
+
* meant to be noticed. */
|
|
134
|
+
--ease-standard: var(--ease-out-quint);
|
|
135
|
+
|
|
136
|
+
/* Durations have no Tailwind namespace, so these are plain variables paired
|
|
137
|
+
* with the `@utility` rules at the bottom of this file. All are at or under
|
|
138
|
+
* 200 ms. */
|
|
139
|
+
--duration-focus: 100ms;
|
|
140
|
+
--duration-press: 120ms;
|
|
141
|
+
--duration-hover: 150ms;
|
|
142
|
+
--duration-expand: 160ms;
|
|
143
|
+
--duration-open: 180ms;
|
|
144
|
+
|
|
145
|
+
/* ------------------------------------------------------------------ icon */
|
|
146
|
+
|
|
147
|
+
/* Read by `readIconTokens` and handed to Phosphor's `IconContext`. */
|
|
148
|
+
--icon-size: 16px;
|
|
149
|
+
--icon-weight: regular;
|
|
150
|
+
|
|
151
|
+
/* ------------------------------------------------- deprecated: old names */
|
|
152
|
+
|
|
153
|
+
/* The `studio.*` and `panel.*` scales, aliases of the tokens above so existing
|
|
154
|
+
* markup keeps working during the sweep. U12 removes them from Studio's
|
|
155
|
+
* source; the published JS preset keeps them one more major. */
|
|
156
|
+
--color-studio-bg: var(--color-bg-0);
|
|
157
|
+
--color-studio-surface: var(--color-surface-alt);
|
|
158
|
+
--color-studio-border: var(--color-border-strong);
|
|
159
|
+
--color-studio-text: var(--color-text-body);
|
|
160
|
+
--color-studio-muted: var(--color-text-muted);
|
|
161
|
+
--color-studio-accent: var(--color-accent);
|
|
162
|
+
--color-panel-bg: var(--color-bg-1);
|
|
163
|
+
--color-panel-bg-inset: var(--color-bg-2);
|
|
164
|
+
--color-panel-input: var(--color-input);
|
|
165
|
+
--color-panel-surface: var(--color-surface);
|
|
166
|
+
--color-panel-hover: var(--color-hover);
|
|
167
|
+
--color-panel-border: var(--color-border);
|
|
168
|
+
--color-panel-border-input: var(--color-border-input);
|
|
169
|
+
--color-panel-hairline: var(--color-hairline);
|
|
170
|
+
--color-panel-text-0: var(--color-text-0);
|
|
171
|
+
--color-panel-text-1: var(--color-text-1);
|
|
172
|
+
--color-panel-text-2: var(--color-text-2);
|
|
173
|
+
--color-panel-text-3: var(--color-text-3);
|
|
174
|
+
--color-panel-text-4: var(--color-text-4);
|
|
175
|
+
--color-panel-text-5: var(--color-text-5);
|
|
176
|
+
--color-panel-bg-soft: var(--color-bg-2);
|
|
177
|
+
--color-panel-bg-2: var(--color-bg-2);
|
|
178
|
+
--color-panel-accent: var(--color-accent);
|
|
179
|
+
--color-panel-danger: var(--color-danger);
|
|
180
|
+
--color-panel-media: var(--color-media);
|
|
181
|
+
--color-panel-container: var(--color-container);
|
|
182
|
+
|
|
183
|
+
/* Names Studio's markup invented that no config ever defined, so the classes
|
|
184
|
+
* compiled to nothing. Aliased to the token that was meant, rather than
|
|
185
|
+
* given values of their own, so there is still one source per decision.
|
|
186
|
+
* U12 rewrites the call sites and deletes these. */
|
|
187
|
+
--color-surface-hover: var(--color-hover);
|
|
188
|
+
--color-accent-red: var(--color-danger);
|
|
189
|
+
--text-2xs: var(--text-step-10);
|
|
190
|
+
|
|
191
|
+
/* ------------------------------------------- deprecated: Tailwind palette */
|
|
192
|
+
|
|
193
|
+
/* Verbatim Tailwind 4.3.3 defaults for stock colours markup still names, so
|
|
194
|
+
* `--color-*: initial` does not blank them. U12 deletes this block;
|
|
195
|
+
* `theme.test.ts` fails if a value drifts from upstream. */
|
|
196
|
+
--color-amber-50: oklch(98.7% 0.022 95.277);
|
|
197
|
+
--color-amber-100: oklch(96.2% 0.059 95.617);
|
|
198
|
+
--color-amber-200: oklch(92.4% 0.12 95.746);
|
|
199
|
+
--color-amber-300: oklch(87.9% 0.169 91.605);
|
|
200
|
+
--color-amber-400: oklch(82.8% 0.189 84.429);
|
|
201
|
+
--color-amber-500: oklch(76.9% 0.188 70.08);
|
|
202
|
+
--color-amber-900: oklch(41.4% 0.112 45.904);
|
|
203
|
+
--color-amber-950: oklch(27.9% 0.077 45.635);
|
|
204
|
+
--color-black: #000;
|
|
205
|
+
--color-blue-400: oklch(70.7% 0.165 254.624);
|
|
206
|
+
--color-blue-500: oklch(62.3% 0.214 259.815);
|
|
207
|
+
--color-cyan-400: oklch(78.9% 0.154 211.53);
|
|
208
|
+
--color-cyan-500: oklch(71.5% 0.143 215.221);
|
|
209
|
+
--color-emerald-300: oklch(84.5% 0.143 164.978);
|
|
210
|
+
--color-emerald-400: oklch(76.5% 0.177 163.223);
|
|
211
|
+
--color-emerald-500: oklch(69.6% 0.17 162.48);
|
|
212
|
+
--color-emerald-600: oklch(59.6% 0.145 163.225);
|
|
213
|
+
--color-emerald-700: oklch(50.8% 0.118 165.612);
|
|
214
|
+
--color-green-400: oklch(79.2% 0.209 151.711);
|
|
215
|
+
--color-green-500: oklch(72.3% 0.219 149.579);
|
|
216
|
+
--color-green-600: oklch(62.7% 0.194 149.214);
|
|
217
|
+
--color-neutral-50: oklch(98.5% 0 none);
|
|
218
|
+
--color-neutral-100: oklch(97% 0 none);
|
|
219
|
+
--color-neutral-200: oklch(92.2% 0 none);
|
|
220
|
+
--color-neutral-300: oklch(87% 0 none);
|
|
221
|
+
--color-neutral-400: oklch(70.8% 0 none);
|
|
222
|
+
--color-neutral-500: oklch(55.6% 0 none);
|
|
223
|
+
--color-neutral-600: oklch(43.9% 0 none);
|
|
224
|
+
--color-neutral-700: oklch(37.1% 0 none);
|
|
225
|
+
--color-neutral-800: oklch(26.9% 0 none);
|
|
226
|
+
--color-neutral-900: oklch(20.5% 0 none);
|
|
227
|
+
--color-neutral-950: oklch(14.5% 0 none);
|
|
228
|
+
--color-orange-300: oklch(83.7% 0.128 66.29);
|
|
229
|
+
--color-orange-400: oklch(75% 0.183 55.934);
|
|
230
|
+
--color-pink-400: oklch(71.8% 0.202 349.761);
|
|
231
|
+
--color-pink-500: oklch(65.6% 0.241 354.308);
|
|
232
|
+
--color-purple-200: oklch(90.2% 0.063 306.703);
|
|
233
|
+
--color-purple-300: oklch(82.7% 0.119 306.383);
|
|
234
|
+
--color-purple-400: oklch(71.4% 0.203 305.504);
|
|
235
|
+
--color-purple-500: oklch(62.7% 0.265 303.9);
|
|
236
|
+
--color-purple-900: oklch(38.1% 0.176 304.987);
|
|
237
|
+
--color-red-100: oklch(93.6% 0.032 17.717);
|
|
238
|
+
--color-red-200: oklch(88.5% 0.062 18.334);
|
|
239
|
+
--color-red-300: oklch(80.8% 0.114 19.571);
|
|
240
|
+
--color-red-400: oklch(70.4% 0.191 22.216);
|
|
241
|
+
--color-red-500: oklch(63.7% 0.237 25.331);
|
|
242
|
+
--color-red-600: oklch(57.7% 0.245 27.325);
|
|
243
|
+
--color-red-700: oklch(50.5% 0.213 27.518);
|
|
244
|
+
--color-red-800: oklch(44.4% 0.177 26.899);
|
|
245
|
+
--color-red-900: oklch(39.6% 0.141 25.723);
|
|
246
|
+
--color-red-950: oklch(25.8% 0.092 26.042);
|
|
247
|
+
--color-rose-400: oklch(71.2% 0.194 13.428);
|
|
248
|
+
--color-rose-500: oklch(64.5% 0.246 16.439);
|
|
249
|
+
--color-sky-200: oklch(90.1% 0.058 230.902);
|
|
250
|
+
--color-sky-300: oklch(82.8% 0.111 230.318);
|
|
251
|
+
--color-sky-400: oklch(74.6% 0.16 232.661);
|
|
252
|
+
--color-sky-500: oklch(68.5% 0.169 237.323);
|
|
253
|
+
--color-sky-700: oklch(50% 0.134 242.749);
|
|
254
|
+
--color-sky-900: oklch(39.1% 0.09 240.876);
|
|
255
|
+
--color-sky-950: oklch(29.3% 0.066 243.157);
|
|
256
|
+
--color-violet-400: oklch(70.2% 0.183 293.541);
|
|
257
|
+
--color-violet-500: oklch(60.6% 0.25 292.717);
|
|
258
|
+
--color-white: #fff;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* Motion durations as utilities, since Tailwind has no `--duration-*`
|
|
262
|
+
* namespace. Each one zeroes itself under `prefers-reduced-motion`, so a
|
|
263
|
+
* caller cannot forget the reduced-motion case. */
|
|
264
|
+
|
|
265
|
+
@utility duration-* {
|
|
266
|
+
transition-duration: --value(--duration-*);
|
|
267
|
+
@media (prefers-reduced-motion: reduce) {
|
|
268
|
+
transition-duration: 0ms;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
/** Guards the ways `theme.css` can silently break: a dropped CSS custom
|
|
4
|
+
* property, a utility that stops compiling, the stock Tailwind palette
|
|
5
|
+
* leaking back in, or the JS preset / legacy colours drifting from it. */
|
|
6
|
+
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import React, { act } from "react";
|
|
10
|
+
import { createRoot } from "react-dom/client";
|
|
11
|
+
import { Gear, IconContext } from "@phosphor-icons/react";
|
|
12
|
+
import { compile } from "tailwindcss";
|
|
13
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
14
|
+
import studioPreset from "./tailwind-preset.shared.js";
|
|
15
|
+
import { readIconTokens } from "./iconTokens";
|
|
16
|
+
import { loadStylesheet, STYLES_DIR, TAILWIND_DIR } from "./styleSources";
|
|
17
|
+
|
|
18
|
+
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
|
19
|
+
|
|
20
|
+
async function buildSource(source: string, candidates: string[]): Promise<string> {
|
|
21
|
+
const compiled = await compile(source, { base: STYLES_DIR, loadStylesheet });
|
|
22
|
+
return compiled.build(candidates);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const build = (entry: string, candidates: string[]) =>
|
|
26
|
+
buildSource(readFileSync(path.join(STYLES_DIR, entry), "utf8"), candidates);
|
|
27
|
+
|
|
28
|
+
function rootVariables(css: string): Map<string, string> {
|
|
29
|
+
const block = css.match(/:root, :host \{([\s\S]*?)\n {2}\}/);
|
|
30
|
+
const vars = new Map<string, string>();
|
|
31
|
+
for (const line of (block?.[1] ?? "").split(";")) {
|
|
32
|
+
const match = line.match(/(--[a-z0-9-]+):([\s\S]+)/i);
|
|
33
|
+
if (match) vars.set(match[1], match[2].trim().replace(/\s+/g, " "));
|
|
34
|
+
}
|
|
35
|
+
return vars;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const themeSource = readFileSync(path.join(STYLES_DIR, "theme.css"), "utf8");
|
|
39
|
+
|
|
40
|
+
function declaredValue(name: string): string {
|
|
41
|
+
const match = themeSource.match(new RegExp(`\\n\\s*${name}:\\s*([^;]+);`));
|
|
42
|
+
if (!match) throw new Error(`theme.css does not declare ${name}`);
|
|
43
|
+
return match[1].trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
document.body.innerHTML = "";
|
|
48
|
+
document.documentElement.removeAttribute("style");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("studio theme", () => {
|
|
52
|
+
it("emits the semantic palette as custom properties and as utilities", async () => {
|
|
53
|
+
const css = await build("studio.css", ["bg-accent", "text-text-2", "border-border"]);
|
|
54
|
+
|
|
55
|
+
expect(rootVariables(css).get("--color-accent")).toBe("#3ce6ac");
|
|
56
|
+
expect(css).toContain(".bg-accent {");
|
|
57
|
+
expect(css).toContain("background-color: var(--color-accent)");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("resolves an alpha modifier on a plain hex token through color-mix", async () => {
|
|
61
|
+
const css = await build("studio.css", ["bg-accent/30"]);
|
|
62
|
+
|
|
63
|
+
expect(css).toMatch(/\.bg-accent\\\/30 \{[\s\S]*?color-mix\(/);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("drops every Tailwind default color Studio does not use", async () => {
|
|
67
|
+
// `palette-reset.css` clears the stock palette. The entries Studio's
|
|
68
|
+
// markup still references are re-declared as deprecated aliases (U12
|
|
69
|
+
// removes them); anything outside that set must no longer resolve.
|
|
70
|
+
const css = await build("studio.css", ["bg-neutral-750", "text-teal-500", "bg-neutral-800"]);
|
|
71
|
+
|
|
72
|
+
expect(css).not.toContain("bg-neutral-750");
|
|
73
|
+
expect(css).not.toContain("text-teal-500");
|
|
74
|
+
expect(css).toContain(".bg-neutral-800 {");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("leaves a host's stock Tailwind colors alone when only theme.css is imported", async () => {
|
|
78
|
+
const css = await buildSource('@import "tailwindcss";\n@import "./theme.css";', [
|
|
79
|
+
"bg-teal-500",
|
|
80
|
+
"text-accent",
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
expect(css).toContain(".bg-teal-500 {");
|
|
84
|
+
expect(css).toContain(".text-accent {");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("keeps selection, playhead and accent as three distinct colors", () => {
|
|
88
|
+
const accent = declaredValue("--color-accent");
|
|
89
|
+
const selection = declaredValue("--color-selection");
|
|
90
|
+
const playhead = declaredValue("--color-playhead");
|
|
91
|
+
|
|
92
|
+
expect(new Set([accent, selection, playhead]).size).toBe(3);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("names every micro type step in use and leaves the Tailwind sizes alone", async () => {
|
|
96
|
+
const steps = [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
|
|
97
|
+
const css = await build(
|
|
98
|
+
"studio.css",
|
|
99
|
+
steps.map((step) => `text-step-${step}`).concat(["text-xs", "text-sm", "text-lg"]),
|
|
100
|
+
);
|
|
101
|
+
const vars = rootVariables(css);
|
|
102
|
+
|
|
103
|
+
for (const step of steps) {
|
|
104
|
+
expect(vars.get(`--text-step-${step}`)).toBe(`${step}px`);
|
|
105
|
+
expect(css).toContain(`.text-step-${step} {`);
|
|
106
|
+
}
|
|
107
|
+
expect(vars.get("--text-xs")).toBe("0.75rem");
|
|
108
|
+
expect(vars.get("--text-sm")).toBe("0.875rem");
|
|
109
|
+
expect(vars.get("--text-lg")).toBe("1.125rem");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("compiles a motion-duration utility with a reduced-motion variant", async () => {
|
|
113
|
+
const css = await build("studio.css", ["duration-press", "duration-open"]);
|
|
114
|
+
|
|
115
|
+
expect(css).toMatch(
|
|
116
|
+
/\.duration-press \{[\s\S]*?transition-duration: var\(--duration-press\)[\s\S]*?prefers-reduced-motion: reduce[\s\S]*?transition-duration: 0ms/,
|
|
117
|
+
);
|
|
118
|
+
expect(css).toContain(".duration-open {");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("keeps every legacy Tailwind palette entry at its upstream default value", async () => {
|
|
122
|
+
// These are copies of Tailwind's own values, kept only so existing markup
|
|
123
|
+
// renders unchanged. A Tailwind upgrade that moves one of them would
|
|
124
|
+
// otherwise silently change Studio's colors.
|
|
125
|
+
const upstream = new Map(
|
|
126
|
+
[
|
|
127
|
+
...readFileSync(path.join(TAILWIND_DIR, "theme.css"), "utf8").matchAll(
|
|
128
|
+
/\n\s*(--color-[a-z]+-(?:50|\d00|950)):\s*([^;]+);/g,
|
|
129
|
+
),
|
|
130
|
+
].map(([, name, value]) => [name, value.trim()]),
|
|
131
|
+
);
|
|
132
|
+
const legacy = [...themeSource.matchAll(/\n\s*(--color-[a-z]+-(?:50|\d00|950)):\s*([^;]+);/g)];
|
|
133
|
+
|
|
134
|
+
expect(legacy.length).toBeGreaterThan(0);
|
|
135
|
+
for (const [, name, value] of legacy) {
|
|
136
|
+
expect(upstream.has(name), `${name} is not a Tailwind default`).toBe(true);
|
|
137
|
+
expect(`${name}: ${value.trim()}`).toBe(`${name}: ${upstream.get(name)}`);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("keeps the deprecated JS preset in step with the CSS it shadows", () => {
|
|
142
|
+
const colors = studioPreset.theme.extend.colors;
|
|
143
|
+
|
|
144
|
+
expect(colors.studio.accent.toLowerCase()).toBe(declaredValue("--color-accent"));
|
|
145
|
+
expect(colors.panel.surface.toLowerCase()).toBe(declaredValue("--color-surface"));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("reads the icon defaults off the theme rather than hard-coding them", () => {
|
|
149
|
+
document.documentElement.style.setProperty("--icon-size", "14px");
|
|
150
|
+
document.documentElement.style.setProperty("--icon-weight", "bold");
|
|
151
|
+
|
|
152
|
+
expect(readIconTokens()).toEqual({ size: "14px", weight: "bold" });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("gives a child icon the token size and weight when it sets neither", () => {
|
|
156
|
+
document.documentElement.style.setProperty("--icon-size", "14px");
|
|
157
|
+
document.documentElement.style.setProperty("--icon-weight", "bold");
|
|
158
|
+
|
|
159
|
+
const host = document.createElement("div");
|
|
160
|
+
document.body.append(host);
|
|
161
|
+
const root = createRoot(host);
|
|
162
|
+
act(() => {
|
|
163
|
+
root.render(
|
|
164
|
+
React.createElement(
|
|
165
|
+
IconContext.Provider,
|
|
166
|
+
{ value: readIconTokens() },
|
|
167
|
+
React.createElement(Gear, null),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
const inherited = host.querySelector("svg");
|
|
172
|
+
const inheritedShape = inherited?.innerHTML;
|
|
173
|
+
act(() => {
|
|
174
|
+
root.render(React.createElement(Gear, { size: 14, weight: "bold" }));
|
|
175
|
+
});
|
|
176
|
+
const explicitShape = host.querySelector("svg")?.innerHTML;
|
|
177
|
+
act(() => root.unmount());
|
|
178
|
+
|
|
179
|
+
expect(inherited?.getAttribute("width")).toBe("14px");
|
|
180
|
+
expect(inherited?.getAttribute("height")).toBe("14px");
|
|
181
|
+
expect(inheritedShape).toBe(explicitShape);
|
|
182
|
+
});
|
|
183
|
+
});
|