@waveform-playlist/annotations 5.0.0-alpha.8 → 5.0.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/index.d.mts CHANGED
@@ -104,16 +104,36 @@ interface AnnotationsTrackProps {
104
104
  }
105
105
  declare const AnnotationsTrack: FunctionComponent<AnnotationsTrackProps>;
106
106
 
107
+ /**
108
+ * Props passed to the renderAnnotationItem function for custom rendering
109
+ */
110
+ interface RenderAnnotationItemProps {
111
+ annotation: AnnotationData;
112
+ index: number;
113
+ isActive: boolean;
114
+ onClick: () => void;
115
+ formatTime: (seconds: number) => string;
116
+ }
107
117
  interface AnnotationTextProps {
108
118
  annotations: AnnotationData[];
109
119
  activeAnnotationId?: string;
110
120
  shouldScrollToActive?: boolean;
121
+ /** Where to position the active annotation when scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
122
+ scrollActivePosition?: ScrollLogicalPosition;
123
+ /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
124
+ scrollActiveContainer?: 'nearest' | 'all';
111
125
  editable?: boolean;
112
126
  controls?: AnnotationAction[];
113
127
  annotationListConfig?: AnnotationActionOptions;
114
128
  height?: number;
115
129
  onAnnotationClick?: (annotation: AnnotationData) => void;
116
130
  onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;
131
+ /**
132
+ * Custom render function for annotation items.
133
+ * When provided, completely replaces the default annotation item rendering.
134
+ * Use this to customize the appearance of each annotation in the list.
135
+ */
136
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode;
117
137
  }
118
138
  declare const AnnotationText: React.NamedExoticComponent<AnnotationTextProps>;
119
139
 
@@ -182,4 +202,4 @@ interface UseAnnotationControlsReturn {
182
202
  */
183
203
  declare const useAnnotationControls: (options?: UseAnnotationControlsOptions) => UseAnnotationControlsReturn;
184
204
 
185
- export { type AeneasFragment, Annotation, type AnnotationAction, type AnnotationActionOptions, AnnotationBox, type AnnotationBoxComponentProps, AnnotationBoxesWrapper, type AnnotationBoxesWrapperProps, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AnnotationProps, AnnotationText, type AnnotationTextProps, type Annotation$1 as AnnotationType, type AnnotationUpdateParams, AnnotationsTrack, type AnnotationsTrackProps, ContinuousPlayCheckbox, type ContinuousPlayCheckboxProps, DownloadAnnotationsButton, type DownloadAnnotationsButtonProps, EditableCheckbox, type EditableCheckboxProps, LinkEndpointsCheckbox, type LinkEndpointsCheckboxProps, type UseAnnotationControlsOptions, type UseAnnotationControlsReturn, parseAeneas, serializeAeneas, useAnnotationControls };
205
+ export { type AeneasFragment, Annotation, type AnnotationAction, type AnnotationActionOptions, AnnotationBox, type AnnotationBoxComponentProps, AnnotationBoxesWrapper, type AnnotationBoxesWrapperProps, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AnnotationProps, AnnotationText, type AnnotationTextProps, type Annotation$1 as AnnotationType, type AnnotationUpdateParams, AnnotationsTrack, type AnnotationsTrackProps, ContinuousPlayCheckbox, type ContinuousPlayCheckboxProps, DownloadAnnotationsButton, type DownloadAnnotationsButtonProps, EditableCheckbox, type EditableCheckboxProps, LinkEndpointsCheckbox, type LinkEndpointsCheckboxProps, type RenderAnnotationItemProps, type UseAnnotationControlsOptions, type UseAnnotationControlsReturn, parseAeneas, serializeAeneas, useAnnotationControls };
package/dist/index.d.ts CHANGED
@@ -104,16 +104,36 @@ interface AnnotationsTrackProps {
104
104
  }
105
105
  declare const AnnotationsTrack: FunctionComponent<AnnotationsTrackProps>;
106
106
 
107
+ /**
108
+ * Props passed to the renderAnnotationItem function for custom rendering
109
+ */
110
+ interface RenderAnnotationItemProps {
111
+ annotation: AnnotationData;
112
+ index: number;
113
+ isActive: boolean;
114
+ onClick: () => void;
115
+ formatTime: (seconds: number) => string;
116
+ }
107
117
  interface AnnotationTextProps {
108
118
  annotations: AnnotationData[];
109
119
  activeAnnotationId?: string;
110
120
  shouldScrollToActive?: boolean;
121
+ /** Where to position the active annotation when scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
122
+ scrollActivePosition?: ScrollLogicalPosition;
123
+ /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
124
+ scrollActiveContainer?: 'nearest' | 'all';
111
125
  editable?: boolean;
112
126
  controls?: AnnotationAction[];
113
127
  annotationListConfig?: AnnotationActionOptions;
114
128
  height?: number;
115
129
  onAnnotationClick?: (annotation: AnnotationData) => void;
116
130
  onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;
131
+ /**
132
+ * Custom render function for annotation items.
133
+ * When provided, completely replaces the default annotation item rendering.
134
+ * Use this to customize the appearance of each annotation in the list.
135
+ */
136
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode;
117
137
  }
118
138
  declare const AnnotationText: React.NamedExoticComponent<AnnotationTextProps>;
119
139
 
@@ -182,4 +202,4 @@ interface UseAnnotationControlsReturn {
182
202
  */
183
203
  declare const useAnnotationControls: (options?: UseAnnotationControlsOptions) => UseAnnotationControlsReturn;
184
204
 
185
- export { type AeneasFragment, Annotation, type AnnotationAction, type AnnotationActionOptions, AnnotationBox, type AnnotationBoxComponentProps, AnnotationBoxesWrapper, type AnnotationBoxesWrapperProps, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AnnotationProps, AnnotationText, type AnnotationTextProps, type Annotation$1 as AnnotationType, type AnnotationUpdateParams, AnnotationsTrack, type AnnotationsTrackProps, ContinuousPlayCheckbox, type ContinuousPlayCheckboxProps, DownloadAnnotationsButton, type DownloadAnnotationsButtonProps, EditableCheckbox, type EditableCheckboxProps, LinkEndpointsCheckbox, type LinkEndpointsCheckboxProps, type UseAnnotationControlsOptions, type UseAnnotationControlsReturn, parseAeneas, serializeAeneas, useAnnotationControls };
205
+ export { type AeneasFragment, Annotation, type AnnotationAction, type AnnotationActionOptions, AnnotationBox, type AnnotationBoxComponentProps, AnnotationBoxesWrapper, type AnnotationBoxesWrapperProps, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AnnotationProps, AnnotationText, type AnnotationTextProps, type Annotation$1 as AnnotationType, type AnnotationUpdateParams, AnnotationsTrack, type AnnotationsTrackProps, ContinuousPlayCheckbox, type ContinuousPlayCheckboxProps, DownloadAnnotationsButton, type DownloadAnnotationsButtonProps, EditableCheckbox, type EditableCheckboxProps, LinkEndpointsCheckbox, type LinkEndpointsCheckboxProps, type RenderAnnotationItemProps, type UseAnnotationControlsOptions, type UseAnnotationControlsReturn, parseAeneas, serializeAeneas, useAnnotationControls };
package/dist/index.js CHANGED
@@ -644,12 +644,15 @@ var AnnotationTextComponent = ({
644
644
  annotations,
645
645
  activeAnnotationId,
646
646
  shouldScrollToActive = false,
647
+ scrollActivePosition = "center",
648
+ scrollActiveContainer = "nearest",
647
649
  editable = false,
648
650
  controls = [],
649
651
  annotationListConfig,
650
652
  height,
651
653
  onAnnotationClick,
652
- onAnnotationUpdate
654
+ onAnnotationUpdate,
655
+ renderAnnotationItem
653
656
  }) => {
654
657
  const activeAnnotationRef = (0, import_react2.useRef)(null);
655
658
  const containerRef = (0, import_react2.useRef)(null);
@@ -668,11 +671,12 @@ var AnnotationTextComponent = ({
668
671
  if (activeAnnotationId && activeAnnotationRef.current && shouldScrollToActive) {
669
672
  activeAnnotationRef.current.scrollIntoView({
670
673
  behavior: "smooth",
671
- block: "nearest"
674
+ block: scrollActivePosition,
675
+ container: scrollActiveContainer
672
676
  });
673
677
  }
674
678
  prevActiveIdRef.current = activeAnnotationId;
675
- }, [activeAnnotationId, shouldScrollToActive]);
679
+ }, [activeAnnotationId, shouldScrollToActive, scrollActivePosition, scrollActiveContainer]);
676
680
  const formatTime = (seconds) => {
677
681
  if (isNaN(seconds) || !isFinite(seconds)) {
678
682
  return "0:00.000";
@@ -712,12 +716,29 @@ var AnnotationTextComponent = ({
712
716
  };
713
717
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Container3, { ref: containerRef, $height: height, children: annotations.map((annotation, index) => {
714
718
  const isActive = annotation.id === activeAnnotationId;
719
+ const handleClick = () => onAnnotationClick?.(annotation);
720
+ if (renderAnnotationItem) {
721
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
722
+ "div",
723
+ {
724
+ ref: isActive ? activeAnnotationRef : null,
725
+ children: renderAnnotationItem({
726
+ annotation,
727
+ index,
728
+ isActive,
729
+ onClick: handleClick,
730
+ formatTime
731
+ })
732
+ },
733
+ annotation.id
734
+ );
735
+ }
715
736
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
716
737
  AnnotationItem,
717
738
  {
718
739
  ref: isActive ? activeAnnotationRef : null,
719
740
  $isActive: isActive,
720
- onClick: () => onAnnotationClick?.(annotation),
741
+ onClick: handleClick,
721
742
  children: [
722
743
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(AnnotationHeader, { children: [
723
744
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(AnnotationInfo, { children: [
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/parsers/aeneas.ts","../src/components/Annotation.tsx","../src/components/AnnotationBox.tsx","../src/components/AnnotationBoxesWrapper.tsx","../src/components/AnnotationsTrack.tsx","../src/components/AnnotationText.tsx","../src/components/ContinuousPlayCheckbox.tsx","../src/components/LinkEndpointsCheckbox.tsx","../src/components/EditableCheckbox.tsx","../src/components/DownloadAnnotationsButton.tsx","../src/hooks/useAnnotationControls.ts"],"sourcesContent":["// Types\nexport type {\n Annotation as AnnotationType,\n AnnotationFormat,\n AnnotationListOptions,\n AnnotationEventMap\n} from './types';\n\n// Parsers\nexport { parseAeneas, serializeAeneas } from './parsers/aeneas';\nexport type { AeneasFragment } from './parsers/aeneas';\n\n// Components\nexport { Annotation } from './components/Annotation';\nexport type { AnnotationProps, AnnotationData, AnnotationAction, AnnotationActionOptions } from './components/Annotation';\n\nexport { AnnotationBox } from './components/AnnotationBox';\nexport type { AnnotationBoxComponentProps } from './components/AnnotationBox';\n\nexport { AnnotationBoxesWrapper } from './components/AnnotationBoxesWrapper';\nexport type { AnnotationBoxesWrapperProps } from './components/AnnotationBoxesWrapper';\n\nexport { AnnotationsTrack } from './components/AnnotationsTrack';\nexport type { AnnotationsTrackProps } from './components/AnnotationsTrack';\n\nexport { AnnotationText } from './components/AnnotationText';\nexport type { AnnotationTextProps } from './components/AnnotationText';\n\nexport { ContinuousPlayCheckbox } from './components/ContinuousPlayCheckbox';\nexport type { ContinuousPlayCheckboxProps } from './components/ContinuousPlayCheckbox';\n\nexport { LinkEndpointsCheckbox } from './components/LinkEndpointsCheckbox';\nexport type { LinkEndpointsCheckboxProps } from './components/LinkEndpointsCheckbox';\n\nexport { EditableCheckbox } from './components/EditableCheckbox';\nexport type { EditableCheckboxProps } from './components/EditableCheckbox';\n\nexport { DownloadAnnotationsButton } from './components/DownloadAnnotationsButton';\nexport type { DownloadAnnotationsButtonProps } from './components/DownloadAnnotationsButton';\n\n// Hooks\nexport { useAnnotationControls } from './hooks/useAnnotationControls';\nexport type {\n UseAnnotationControlsOptions,\n UseAnnotationControlsReturn,\n AnnotationUpdateParams,\n} from './hooks/useAnnotationControls';\n","import { Annotation } from '../types';\n\nexport interface AeneasFragment {\n begin: string;\n end: string;\n id: string;\n language: string;\n lines: string[];\n}\n\nexport function parseAeneas(data: AeneasFragment): Annotation {\n return {\n id: data.id,\n start: parseFloat(data.begin),\n end: parseFloat(data.end),\n lines: data.lines,\n lang: data.language,\n };\n}\n\nexport function serializeAeneas(annotation: Annotation): AeneasFragment {\n return {\n id: annotation.id,\n begin: annotation.start.toFixed(3),\n end: annotation.end.toFixed(3),\n lines: annotation.lines,\n language: annotation.lang || 'en',\n };\n}\n","import React, { FunctionComponent, useState } from 'react';\nimport styled from 'styled-components';\n\ninterface AnnotationOverlayProps {\n readonly $left: number;\n readonly $width: number;\n readonly $color: string;\n}\n\nconst AnnotationOverlay = styled.div.attrs<AnnotationOverlayProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<AnnotationOverlayProps>`\n position: absolute;\n top: 0;\n background: ${(props) => props.$color};\n height: 100%;\n z-index: 10;\n pointer-events: auto;\n opacity: 0.3;\n border: 2px solid ${(props) => props.$color};\n border-radius: 4px;\n cursor: pointer;\n\n &:hover {\n opacity: 0.5;\n border-color: ${(props) => props.$color};\n }\n`;\n\nconst AnnotationText = styled.div`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: hidden;\n text-overflow: ellipsis;\n pointer-events: none;\n white-space: pre-wrap;\n word-break: break-word;\n`;\n\nconst EditableText = styled.textarea`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.9);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: auto;\n border: 1px solid #fff;\n resize: none;\n font-family: inherit;\n\n &:focus {\n outline: none;\n border-color: #4CAF50;\n }\n`;\n\nconst ControlsBar = styled.div`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n gap: 4px;\n padding: 4px;\n justify-content: flex-start;\n align-items: center;\n`;\n\nconst ControlButton = styled.button`\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.5);\n color: white;\n padding: 4px 8px;\n font-size: 10px;\n cursor: pointer;\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n border-color: white;\n }\n\n &:active {\n background: rgba(255, 255, 255, 0.3);\n }\n`;\n\n/**\n * Configuration options passed to annotation action handlers\n */\nexport interface AnnotationActionOptions {\n /** Whether annotation endpoints are linked (moving one endpoint moves the other) */\n linkEndpoints?: boolean;\n /** Whether to continue playing after an annotation ends */\n continuousPlay?: boolean;\n /** Additional custom properties */\n [key: string]: unknown;\n}\n\nexport interface AnnotationAction {\n class?: string;\n text?: string;\n title: string;\n action: (annotation: AnnotationData, index: number, annotations: AnnotationData[], opts: AnnotationActionOptions) => void;\n}\n\nexport interface AnnotationData {\n id: string;\n start: number;\n end: number;\n lines: string[];\n language?: string;\n}\n\nexport interface AnnotationProps {\n annotation: AnnotationData;\n index: number;\n allAnnotations: AnnotationData[];\n startPosition: number; // Start position in pixels\n endPosition: number; // End position in pixels\n color?: string;\n editable?: boolean;\n controls?: AnnotationAction[];\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n annotationListConfig?: AnnotationActionOptions;\n onClick?: (annotation: AnnotationData) => void;\n}\n\nexport const Annotation: FunctionComponent<AnnotationProps> = ({\n annotation,\n index,\n allAnnotations,\n startPosition,\n endPosition,\n color = '#ff9800',\n editable = false,\n controls = [],\n onAnnotationUpdate,\n annotationListConfig,\n onClick,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editedText, setEditedText] = useState(annotation.lines.join('\\n'));\n const width = Math.max(0, endPosition - startPosition);\n\n if (width <= 0) {\n return null;\n }\n\n const handleClick = () => {\n if (onClick) {\n onClick(annotation);\n }\n };\n\n const handleDoubleClick = () => {\n if (editable) {\n setIsEditing(true);\n }\n };\n\n const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setEditedText(e.target.value);\n };\n\n const handleTextBlur = () => {\n setIsEditing(false);\n const newLines = editedText.split('\\n');\n if (newLines.join('\\n') !== annotation.lines.join('\\n')) {\n const updatedAnnotations = [...allAnnotations];\n updatedAnnotations[index] = { ...annotation, lines: newLines };\n if (onAnnotationUpdate) {\n onAnnotationUpdate(updatedAnnotations);\n }\n }\n };\n\n const handleControlClick = (control: AnnotationAction) => {\n const annotationsCopy = [...allAnnotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n if (onAnnotationUpdate) {\n onAnnotationUpdate(annotationsCopy);\n }\n };\n\n const getIconClass = (classString: string) => {\n // Convert \"fas.fa-minus\" to \"fas fa-minus\"\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <AnnotationOverlay\n $left={startPosition}\n $width={width}\n $color={color}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n >\n {controls.length > 0 && (\n <ControlsBar>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={(e) => {\n e.stopPropagation();\n handleControlClick(control);\n }}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </ControlsBar>\n )}\n {isEditing ? (\n <EditableText\n value={editedText}\n onChange={handleTextChange}\n onBlur={handleTextBlur}\n autoFocus\n onClick={(e) => e.stopPropagation()}\n onDoubleClick={(e) => e.stopPropagation()}\n />\n ) : (\n <AnnotationText>\n {annotation.lines.join('\\n')}\n </AnnotationText>\n )}\n </AnnotationOverlay>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { useDraggable } from '@dnd-kit/core';\nimport type { DraggableAttributes } from '@dnd-kit/core';\nimport type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';\n\ninterface WrapperProps {\n readonly $left: number;\n readonly $width: number;\n}\n\n// Wrapper positions the annotation and contains both Box and ResizeHandles as siblings\nconst Wrapper = styled.div.attrs<WrapperProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<WrapperProps>`\n position: absolute;\n top: 0;\n height: 100%;\n pointer-events: none; /* Let events pass through to children */\n`;\n\ninterface BoxProps {\n readonly $color: string;\n readonly $isActive?: boolean;\n}\n\nconst Box = styled.div<BoxProps>`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBackground || 'rgba(255, 200, 100, 0.95)')\n : (props.theme?.annotationBoxBackground || 'rgba(255, 255, 255, 0.85)')};\n border: ${(props) => props.$isActive ? '3px' : '2px'} solid ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBorder || '#ff9800')\n : props.$color};\n border-radius: 4px;\n cursor: pointer;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n transition: all 0.2s ease;\n box-shadow: ${(props) => props.$isActive\n ? '0 2px 8px rgba(255, 152, 0, 0.4), inset 0 0 0 1px rgba(255, 152, 0, 0.2)'\n : '0 1px 3px rgba(0, 0, 0, 0.1)'};\n\n &:hover {\n background: ${(props) => props.theme?.annotationBoxHoverBackground || 'rgba(255, 255, 255, 0.98)'};\n border-color: ${(props) => props.theme?.annotationBoxActiveBorder || '#ff9800'};\n border-width: 3px;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n }\n`;\n\nconst Label = styled.span`\n font-size: 12px;\n font-weight: 600;\n color: ${(props) => props.theme?.annotationLabelColor || '#2a2a2a'};\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding: 0 6px;\n letter-spacing: 0.3px;\n user-select: none;\n`;\n\ninterface ResizeHandleStyledProps {\n $position: 'left' | 'right';\n $isDragging?: boolean;\n}\n\n// ResizeHandles are now siblings of Box, positioned relative to Wrapper\n// Reduced from 30px/-15px to 16px/-8px to minimize overlap between adjacent annotations\nconst ResizeHandle = styled.div<ResizeHandleStyledProps>`\n position: absolute;\n top: 0;\n ${(props) => props.$position === 'left' ? 'left: -8px' : 'right: -8px'};\n width: 16px;\n height: 100%;\n cursor: ew-resize;\n z-index: 120; /* Above ClickOverlay (z-index: 100) and AnnotationBoxesWrapper (z-index: 110) */\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.2)')\n : 'transparent'};\n border-radius: 4px;\n touch-action: none; /* Important for @dnd-kit on touch devices */\n pointer-events: auto;\n\n &::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 4px;\n height: 60%;\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.8)')\n : (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.4)')};\n border-radius: 2px;\n opacity: ${(props) => props.$isDragging ? 1 : 0.6};\n transition: opacity 0.2s, background 0.2s;\n }\n\n &:hover {\n background: ${(props) => props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.1)'};\n }\n\n &:hover::before {\n opacity: 1;\n background: ${(props) => props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.7)'};\n }\n`;\n\nexport interface DragHandleProps {\n attributes: DraggableAttributes;\n listeners: SyntheticListenerMap | undefined;\n setActivatorNodeRef: (element: HTMLElement | null) => void;\n isDragging: boolean;\n}\n\nexport interface AnnotationBoxComponentProps {\n annotationId: string;\n annotationIndex: number;\n startPosition: number;\n endPosition: number;\n label?: string;\n color?: string;\n isActive?: boolean;\n onClick?: () => void;\n editable?: boolean; // Whether to show drag handles\n}\n\nexport const AnnotationBox: FunctionComponent<AnnotationBoxComponentProps> = ({\n annotationId,\n annotationIndex,\n startPosition,\n endPosition,\n label,\n color = '#ff9800',\n isActive = false,\n onClick,\n editable = true,\n}) => {\n const width = Math.max(0, endPosition - startPosition);\n\n // Left (start) boundary draggable\n const leftBoundaryId = `annotation-boundary-start-${annotationIndex}`;\n const {\n attributes: leftAttributes,\n listeners: leftListeners,\n setActivatorNodeRef: setLeftActivatorRef,\n isDragging: isLeftDragging,\n } = useDraggable({\n id: leftBoundaryId,\n data: { annotationId, annotationIndex, edge: 'start' as const },\n disabled: !editable,\n });\n\n // Right (end) boundary draggable\n const rightBoundaryId = `annotation-boundary-end-${annotationIndex}`;\n const {\n attributes: rightAttributes,\n listeners: rightListeners,\n setActivatorNodeRef: setRightActivatorRef,\n isDragging: isRightDragging,\n } = useDraggable({\n id: rightBoundaryId,\n data: { annotationId, annotationIndex, edge: 'end' as const },\n disabled: !editable,\n });\n\n if (width <= 0) {\n return null;\n }\n\n // Wrap @dnd-kit pointer handlers to also stop propagation\n // This prevents the ClickOverlay from capturing the event\n const createPointerDownHandler = (dndKitHandler?: (e: React.PointerEvent) => void) => {\n return (e: React.PointerEvent) => {\n e.stopPropagation();\n dndKitHandler?.(e);\n };\n };\n\n const handleHandleClick = (e: React.MouseEvent) => {\n // Prevent clicks on resize handles from bubbling to annotation box\n e.stopPropagation();\n };\n\n return (\n <Wrapper $left={startPosition} $width={width}>\n <Box\n $color={color}\n $isActive={isActive}\n onClick={onClick}\n >\n {label && <Label>{label}</Label>}\n </Box>\n {editable && (\n <ResizeHandle\n ref={setLeftActivatorRef}\n $position=\"left\"\n $isDragging={isLeftDragging}\n onClick={handleHandleClick}\n {...leftListeners}\n onPointerDown={createPointerDownHandler(leftListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...leftAttributes}\n />\n )}\n {editable && (\n <ResizeHandle\n ref={setRightActivatorRef}\n $position=\"right\"\n $isDragging={isRightDragging}\n onClick={handleHandleClick}\n {...rightListeners}\n onPointerDown={createPointerDownHandler(rightListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...rightAttributes}\n />\n )}\n </Wrapper>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n z-index: 110;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n`;\n\nconst BoxesContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationBoxesWrapperProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationBoxesWrapper: FunctionComponent<AnnotationBoxesWrapperProps> = ({\n children,\n className,\n height = 30,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0} />\n <BoxesContainer $offset={offset}>\n {children}\n </BoxesContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n font-weight: bold;\n`;\n\nconst AnnotationsContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationsTrackProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationsTrack: FunctionComponent<AnnotationsTrackProps> = ({\n children,\n className,\n height = 100,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0}>\n Annotations\n </ControlsPlaceholder>\n <AnnotationsContainer $offset={offset}>\n {children}\n </AnnotationsContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent, useRef, useEffect } from 'react';\nimport styled from 'styled-components';\nimport type { AnnotationData, AnnotationAction, AnnotationActionOptions } from './Annotation';\n\ninterface ContainerProps {\n $height?: number;\n}\n\nconst Container = styled.div<ContainerProps>`\n background: ${(props) => props.theme?.backgroundColor || '#fff'};\n ${(props) => props.$height ? `height: ${props.$height}px;` : 'max-height: 200px;'}\n overflow-y: auto;\n padding: 8px;\n`;\n\nconst AnnotationItem = styled.div<{ $isActive?: boolean }>`\n padding: 12px;\n margin-bottom: 6px;\n border-left: 4px solid ${(props) => (props.$isActive ? '#ff9800' : 'transparent')};\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.15)' : 'transparent')};\n border-radius: 4px;\n transition: all 0.2s;\n cursor: pointer;\n box-shadow: ${(props) => (props.$isActive ? '0 2px 8px rgba(255, 152, 0, 0.25), inset 0 0 0 1px rgba(255, 152, 0, 0.3)' : 'none')};\n\n &:hover {\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.2)' : props.theme?.annotationTextItemHoverBackground || 'rgba(0, 0, 0, 0.05)')};\n border-left-color: ${(props) => (props.$isActive ? '#ff9800' : props.theme?.borderColor || '#ddd')};\n }\n\n &:focus-visible {\n outline: 2px solid #ff9800;\n outline-offset: 2px;\n }\n`;\n\nconst AnnotationHeader = styled.div`\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n`;\n\nconst AnnotationInfo = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n`;\n\nconst AnnotationIdLabel = styled.span<{ $isEditable?: boolean }>`\n font-size: 11px;\n font-weight: 600;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n background: transparent;\n padding: 2px 6px;\n border-radius: 3px;\n min-width: 20px;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\nconst TimeRange = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: ${(props) => props.theme?.textColorMuted || '#555'};\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n letter-spacing: 0.5px;\n`;\n\nconst AnnotationControls = styled.div`\n display: flex;\n gap: 6px;\n`;\n\nconst ControlButton = styled.button`\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n color: ${(props) => props.theme?.textColor || '#333'};\n padding: 4px 8px;\n font-size: 14px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n\n &:hover {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n transform: scale(1.05);\n }\n\n &:active {\n transform: scale(0.95);\n }\n`;\n\nconst AnnotationTextContent = styled.div<{ $isEditable?: boolean }>`\n font-size: 14px;\n line-height: 1.6;\n color: ${(props) => props.theme?.textColor || '#2a2a2a'};\n white-space: pre-wrap;\n word-break: break-word;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n padding: ${(props) => (props.$isEditable ? '6px' : '0')};\n border-radius: 3px;\n min-height: 20px;\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\nexport interface AnnotationTextProps {\n annotations: AnnotationData[];\n activeAnnotationId?: string;\n shouldScrollToActive?: boolean;\n editable?: boolean;\n controls?: AnnotationAction[];\n annotationListConfig?: AnnotationActionOptions;\n height?: number;\n onAnnotationClick?: (annotation: AnnotationData) => void;\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n}\n\nconst AnnotationTextComponent: FunctionComponent<AnnotationTextProps> = ({\n annotations,\n activeAnnotationId,\n shouldScrollToActive = false,\n editable = false,\n controls = [],\n annotationListConfig,\n height,\n onAnnotationClick,\n onAnnotationUpdate,\n}) => {\n const activeAnnotationRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevActiveIdRef = useRef<string | undefined>(undefined);\n\n // Track component renders and scroll position\n useEffect(() => {\n // Render tracking removed\n });\n\n // Track scroll changes\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n // Scroll tracking removed\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, []);\n\n // Auto-scroll to active annotation when it changes\n useEffect(() => {\n // Only scroll if parent says we should (prevents scrolling on remount after pause)\n if (activeAnnotationId && activeAnnotationRef.current && shouldScrollToActive) {\n activeAnnotationRef.current.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n });\n }\n\n prevActiveIdRef.current = activeAnnotationId;\n }, [activeAnnotationId, shouldScrollToActive]);\n\n const formatTime = (seconds: number): string => {\n if (isNaN(seconds) || !isFinite(seconds)) {\n return '0:00.000';\n }\n const mins = Math.floor(seconds / 60);\n const secs = (seconds % 60).toFixed(3);\n return `${mins}:${secs.padStart(6, '0')}`;\n };\n\n const handleTextEdit = (index: number, newText: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n lines: newText.split('\\n'),\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleIdEdit = (index: number, newId: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const trimmedId = newId.trim();\n if (!trimmedId) return; // Don't allow empty IDs\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n id: trimmedId,\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleControlClick = (control: AnnotationAction, annotation: AnnotationData, index: number) => {\n if (!onAnnotationUpdate) return;\n\n const annotationsCopy = [...annotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n onAnnotationUpdate(annotationsCopy);\n };\n\n const getIconClass = (classString: string) => {\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <Container ref={containerRef} $height={height}>\n {annotations.map((annotation, index) => {\n const isActive = annotation.id === activeAnnotationId;\n return (\n <AnnotationItem\n key={annotation.id}\n ref={isActive ? activeAnnotationRef : null}\n $isActive={isActive}\n onClick={() => onAnnotationClick?.(annotation)}\n >\n <AnnotationHeader>\n <AnnotationInfo>\n <AnnotationIdLabel\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleIdEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.id}\n </AnnotationIdLabel>\n <TimeRange>\n {formatTime(annotation.start)} - {formatTime(annotation.end)}\n </TimeRange>\n </AnnotationInfo>\n {controls.length > 0 && (\n <AnnotationControls onClick={(e) => e.stopPropagation()}>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={() => handleControlClick(control, annotation, index)}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </AnnotationControls>\n )}\n </AnnotationHeader>\n <AnnotationTextContent\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleTextEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.lines.join('\\n')}\n </AnnotationTextContent>\n </AnnotationItem>\n );\n })}\n </Container>\n );\n};\n\n// Memoize to prevent unnecessary remounting when parent re-renders\nexport const AnnotationText = React.memo(AnnotationTextComponent);\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface ContinuousPlayCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling continuous play of annotations.\n * When enabled, playback continues from one annotation to the next without stopping.\n */\nexport const ContinuousPlayCheckbox: React.FC<ContinuousPlayCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"continuous-play\"\n className=\"continuous-play\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"continuous-play\">Continuous Play</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface LinkEndpointsCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling linked endpoints between annotations.\n * When enabled, the end time of one annotation is automatically linked to the start time of the next.\n */\nexport const LinkEndpointsCheckbox: React.FC<LinkEndpointsCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"link-endpoints\"\n className=\"link-endpoints\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"link-endpoints\">Link Endpoints</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface EditableCheckboxProps {\n checked: boolean;\n onChange: (enabled: boolean) => void;\n className?: string;\n}\n\nexport const EditableCheckbox: React.FC<EditableCheckboxProps> = ({\n checked,\n onChange,\n className,\n}) => {\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"editable-annotations\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n />\n <BaseCheckboxLabel htmlFor=\"editable-annotations\">Editable Annotations</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport styled from 'styled-components';\nimport { serializeAeneas } from '../parsers/aeneas';\nimport type { Annotation } from '../types';\n\nconst StyledButton = styled.button`\n padding: 0.5rem 1rem;\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n color: ${(props) => props.theme?.textColor || '#333'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n border-radius: ${(props) => props.theme?.borderRadius || '4px'};\n cursor: pointer;\n font-family: ${(props) => props.theme?.fontFamily || 'inherit'};\n font-size: ${(props) => props.theme?.fontSize || '14px'};\n font-weight: 500;\n transition: all 0.15s ease;\n\n &:hover:not(:disabled) {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n }\n\n &:focus {\n outline: none;\n box-shadow: 0 0 0 2px ${(props) => props.theme?.inputFocusBorder || '#007bff'}44;\n }\n\n &:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n`;\n\nexport interface DownloadAnnotationsButtonProps {\n annotations: Annotation[];\n filename?: string;\n disabled?: boolean;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport const DownloadAnnotationsButton: React.FC<DownloadAnnotationsButtonProps> = ({\n annotations,\n filename = 'annotations.json',\n disabled = false,\n className,\n children = 'Download JSON',\n}) => {\n const handleDownload = () => {\n if (annotations.length === 0) {\n return;\n }\n\n // Serialize annotations to Aeneas JSON format\n const jsonData = annotations.map(annotation => serializeAeneas(annotation));\n const jsonString = JSON.stringify(jsonData, null, 2);\n\n // Create a blob and download link\n const blob = new Blob([jsonString], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n\n // Trigger download\n document.body.appendChild(link);\n link.click();\n\n // Cleanup\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n };\n\n return (\n <StyledButton\n onClick={handleDownload}\n disabled={disabled || annotations.length === 0}\n className={className}\n title={annotations.length === 0 ? 'No annotations to download' : 'Download the annotations as JSON'}\n >\n {children}\n </StyledButton>\n );\n};\n","import { useState, useCallback } from 'react';\nimport type { Annotation, AnnotationListOptions } from '../types';\n\nconst LINK_THRESHOLD = 0.01; // Consider edges \"linked\" if within 10ms\n\nexport interface UseAnnotationControlsOptions {\n initialContinuousPlay?: boolean;\n initialLinkEndpoints?: boolean;\n}\n\nexport interface AnnotationUpdateParams {\n annotationIndex: number;\n newTime: number;\n isDraggingStart: boolean;\n annotations: Annotation[];\n duration: number;\n linkEndpoints: boolean;\n}\n\nexport interface UseAnnotationControlsReturn {\n continuousPlay: boolean;\n linkEndpoints: boolean;\n setContinuousPlay: (value: boolean) => void;\n setLinkEndpoints: (value: boolean) => void;\n updateAnnotationBoundaries: (params: AnnotationUpdateParams) => Annotation[];\n}\n\n/**\n * Hook for managing annotation control state and boundary logic.\n * Handles continuous play mode and linked endpoints behavior.\n */\nexport const useAnnotationControls = (\n options: UseAnnotationControlsOptions = {}\n): UseAnnotationControlsReturn => {\n const {\n initialContinuousPlay = false,\n initialLinkEndpoints = true,\n } = options;\n\n const [continuousPlay, setContinuousPlay] = useState(initialContinuousPlay);\n const [linkEndpoints, setLinkEndpoints] = useState(initialLinkEndpoints);\n\n /**\n * Updates annotation boundaries based on drag operations.\n * Handles linked endpoints and collision detection.\n * Note: linkEndpoints is passed as a parameter to ensure it uses the current value from context.\n */\n const updateAnnotationBoundaries = useCallback(\n ({\n annotationIndex,\n newTime,\n isDraggingStart,\n annotations,\n duration,\n linkEndpoints: shouldLinkEndpoints,\n }: AnnotationUpdateParams): Annotation[] => {\n const updatedAnnotations = [...annotations];\n const annotation = annotations[annotationIndex];\n\n if (isDraggingStart) {\n // Dragging start edge\n const constrainedStart = Math.min(annotation.end - 0.1, Math.max(0, newTime));\n const delta = constrainedStart - annotation.start;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n start: constrainedStart,\n };\n\n if (shouldLinkEndpoints && annotationIndex > 0) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const prevAnnotation = updatedAnnotations[annotationIndex - 1];\n\n if (Math.abs(prevAnnotation.end - annotation.start) < LINK_THRESHOLD) {\n // Already linked: move previous annotation's end together with this start\n updatedAnnotations[annotationIndex - 1] = {\n ...prevAnnotation,\n end: Math.max(prevAnnotation.start + 0.1, prevAnnotation.end + delta),\n };\n } else if (constrainedStart <= prevAnnotation.end) {\n // Dragged past previous annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n start: prevAnnotation.end,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex > 0 && constrainedStart < updatedAnnotations[annotationIndex - 1].end) {\n // Collision detection: push previous annotation's end back\n updatedAnnotations[annotationIndex - 1] = {\n ...updatedAnnotations[annotationIndex - 1],\n end: constrainedStart,\n };\n }\n } else {\n // Dragging end edge\n const constrainedEnd = Math.max(annotation.start + 0.1, Math.min(newTime, duration));\n const delta = constrainedEnd - annotation.end;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n end: constrainedEnd,\n };\n\n if (shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n if (Math.abs(nextAnnotation.start - annotation.end) < LINK_THRESHOLD) {\n // Already linked: move next annotation's start together with this end\n const newStart = nextAnnotation.start + delta;\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: Math.min(nextAnnotation.end - 0.1, newStart),\n };\n\n // Cascade linked endpoints\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (Math.abs(next.start - current.end) < LINK_THRESHOLD) {\n const nextDelta = current.end - annotations[currentIndex].end;\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: Math.min(next.end - 0.1, next.start + nextDelta),\n };\n currentIndex++;\n } else {\n break; // No more linked endpoints\n }\n }\n } else if (constrainedEnd >= nextAnnotation.start) {\n // Dragged past next annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n end: nextAnnotation.start,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1 && constrainedEnd > updatedAnnotations[annotationIndex + 1].start) {\n // Collision detection: push next annotation's start forward\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: constrainedEnd,\n };\n\n // Cascade collisions\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (current.end > next.start) {\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: current.end,\n };\n currentIndex++;\n } else {\n break; // No more collisions\n }\n }\n }\n }\n\n return updatedAnnotations;\n },\n []\n );\n\n return {\n continuousPlay,\n linkEndpoints,\n setContinuousPlay,\n setLinkEndpoints,\n updateAnnotationBoundaries,\n };\n};\n"],"mappings":"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","names":["AnnotationText","styled","import_styled_components","import_jsx_runtime","styled","import_styled_components","import_jsx_runtime","styled","import_styled_components","import_ui_components","import_jsx_runtime","Container","styled","ControlsPlaceholder","import_react","import_styled_components","import_jsx_runtime","Container","styled","ControlButton","AnnotationText","React","import_ui_components","import_jsx_runtime","import_ui_components","import_jsx_runtime","import_ui_components","import_jsx_runtime","import_styled_components","import_jsx_runtime","styled","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/parsers/aeneas.ts","../src/components/Annotation.tsx","../src/components/AnnotationBox.tsx","../src/components/AnnotationBoxesWrapper.tsx","../src/components/AnnotationsTrack.tsx","../src/components/AnnotationText.tsx","../src/components/ContinuousPlayCheckbox.tsx","../src/components/LinkEndpointsCheckbox.tsx","../src/components/EditableCheckbox.tsx","../src/components/DownloadAnnotationsButton.tsx","../src/hooks/useAnnotationControls.ts"],"sourcesContent":["// Types\nexport type {\n Annotation as AnnotationType,\n AnnotationFormat,\n AnnotationListOptions,\n AnnotationEventMap\n} from './types';\n\n// Parsers\nexport { parseAeneas, serializeAeneas } from './parsers/aeneas';\nexport type { AeneasFragment } from './parsers/aeneas';\n\n// Components\nexport { Annotation } from './components/Annotation';\nexport type { AnnotationProps, AnnotationData, AnnotationAction, AnnotationActionOptions } from './components/Annotation';\n\nexport { AnnotationBox } from './components/AnnotationBox';\nexport type { AnnotationBoxComponentProps } from './components/AnnotationBox';\n\nexport { AnnotationBoxesWrapper } from './components/AnnotationBoxesWrapper';\nexport type { AnnotationBoxesWrapperProps } from './components/AnnotationBoxesWrapper';\n\nexport { AnnotationsTrack } from './components/AnnotationsTrack';\nexport type { AnnotationsTrackProps } from './components/AnnotationsTrack';\n\nexport { AnnotationText } from './components/AnnotationText';\nexport type { AnnotationTextProps, RenderAnnotationItemProps } from './components/AnnotationText';\n\nexport { ContinuousPlayCheckbox } from './components/ContinuousPlayCheckbox';\nexport type { ContinuousPlayCheckboxProps } from './components/ContinuousPlayCheckbox';\n\nexport { LinkEndpointsCheckbox } from './components/LinkEndpointsCheckbox';\nexport type { LinkEndpointsCheckboxProps } from './components/LinkEndpointsCheckbox';\n\nexport { EditableCheckbox } from './components/EditableCheckbox';\nexport type { EditableCheckboxProps } from './components/EditableCheckbox';\n\nexport { DownloadAnnotationsButton } from './components/DownloadAnnotationsButton';\nexport type { DownloadAnnotationsButtonProps } from './components/DownloadAnnotationsButton';\n\n// Hooks\nexport { useAnnotationControls } from './hooks/useAnnotationControls';\nexport type {\n UseAnnotationControlsOptions,\n UseAnnotationControlsReturn,\n AnnotationUpdateParams,\n} from './hooks/useAnnotationControls';\n","import { Annotation } from '../types';\n\nexport interface AeneasFragment {\n begin: string;\n end: string;\n id: string;\n language: string;\n lines: string[];\n}\n\nexport function parseAeneas(data: AeneasFragment): Annotation {\n return {\n id: data.id,\n start: parseFloat(data.begin),\n end: parseFloat(data.end),\n lines: data.lines,\n lang: data.language,\n };\n}\n\nexport function serializeAeneas(annotation: Annotation): AeneasFragment {\n return {\n id: annotation.id,\n begin: annotation.start.toFixed(3),\n end: annotation.end.toFixed(3),\n lines: annotation.lines,\n language: annotation.lang || 'en',\n };\n}\n","import React, { FunctionComponent, useState } from 'react';\nimport styled from 'styled-components';\n\ninterface AnnotationOverlayProps {\n readonly $left: number;\n readonly $width: number;\n readonly $color: string;\n}\n\nconst AnnotationOverlay = styled.div.attrs<AnnotationOverlayProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<AnnotationOverlayProps>`\n position: absolute;\n top: 0;\n background: ${(props) => props.$color};\n height: 100%;\n z-index: 10;\n pointer-events: auto;\n opacity: 0.3;\n border: 2px solid ${(props) => props.$color};\n border-radius: 4px;\n cursor: pointer;\n\n &:hover {\n opacity: 0.5;\n border-color: ${(props) => props.$color};\n }\n`;\n\nconst AnnotationText = styled.div`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: hidden;\n text-overflow: ellipsis;\n pointer-events: none;\n white-space: pre-wrap;\n word-break: break-word;\n`;\n\nconst EditableText = styled.textarea`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.9);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: auto;\n border: 1px solid #fff;\n resize: none;\n font-family: inherit;\n\n &:focus {\n outline: none;\n border-color: #4CAF50;\n }\n`;\n\nconst ControlsBar = styled.div`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n gap: 4px;\n padding: 4px;\n justify-content: flex-start;\n align-items: center;\n`;\n\nconst ControlButton = styled.button`\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.5);\n color: white;\n padding: 4px 8px;\n font-size: 10px;\n cursor: pointer;\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n border-color: white;\n }\n\n &:active {\n background: rgba(255, 255, 255, 0.3);\n }\n`;\n\n/**\n * Configuration options passed to annotation action handlers\n */\nexport interface AnnotationActionOptions {\n /** Whether annotation endpoints are linked (moving one endpoint moves the other) */\n linkEndpoints?: boolean;\n /** Whether to continue playing after an annotation ends */\n continuousPlay?: boolean;\n /** Additional custom properties */\n [key: string]: unknown;\n}\n\nexport interface AnnotationAction {\n class?: string;\n text?: string;\n title: string;\n action: (annotation: AnnotationData, index: number, annotations: AnnotationData[], opts: AnnotationActionOptions) => void;\n}\n\nexport interface AnnotationData {\n id: string;\n start: number;\n end: number;\n lines: string[];\n language?: string;\n}\n\nexport interface AnnotationProps {\n annotation: AnnotationData;\n index: number;\n allAnnotations: AnnotationData[];\n startPosition: number; // Start position in pixels\n endPosition: number; // End position in pixels\n color?: string;\n editable?: boolean;\n controls?: AnnotationAction[];\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n annotationListConfig?: AnnotationActionOptions;\n onClick?: (annotation: AnnotationData) => void;\n}\n\nexport const Annotation: FunctionComponent<AnnotationProps> = ({\n annotation,\n index,\n allAnnotations,\n startPosition,\n endPosition,\n color = '#ff9800',\n editable = false,\n controls = [],\n onAnnotationUpdate,\n annotationListConfig,\n onClick,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editedText, setEditedText] = useState(annotation.lines.join('\\n'));\n const width = Math.max(0, endPosition - startPosition);\n\n if (width <= 0) {\n return null;\n }\n\n const handleClick = () => {\n if (onClick) {\n onClick(annotation);\n }\n };\n\n const handleDoubleClick = () => {\n if (editable) {\n setIsEditing(true);\n }\n };\n\n const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setEditedText(e.target.value);\n };\n\n const handleTextBlur = () => {\n setIsEditing(false);\n const newLines = editedText.split('\\n');\n if (newLines.join('\\n') !== annotation.lines.join('\\n')) {\n const updatedAnnotations = [...allAnnotations];\n updatedAnnotations[index] = { ...annotation, lines: newLines };\n if (onAnnotationUpdate) {\n onAnnotationUpdate(updatedAnnotations);\n }\n }\n };\n\n const handleControlClick = (control: AnnotationAction) => {\n const annotationsCopy = [...allAnnotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n if (onAnnotationUpdate) {\n onAnnotationUpdate(annotationsCopy);\n }\n };\n\n const getIconClass = (classString: string) => {\n // Convert \"fas.fa-minus\" to \"fas fa-minus\"\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <AnnotationOverlay\n $left={startPosition}\n $width={width}\n $color={color}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n >\n {controls.length > 0 && (\n <ControlsBar>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={(e) => {\n e.stopPropagation();\n handleControlClick(control);\n }}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </ControlsBar>\n )}\n {isEditing ? (\n <EditableText\n value={editedText}\n onChange={handleTextChange}\n onBlur={handleTextBlur}\n autoFocus\n onClick={(e) => e.stopPropagation()}\n onDoubleClick={(e) => e.stopPropagation()}\n />\n ) : (\n <AnnotationText>\n {annotation.lines.join('\\n')}\n </AnnotationText>\n )}\n </AnnotationOverlay>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { useDraggable } from '@dnd-kit/core';\nimport type { DraggableAttributes } from '@dnd-kit/core';\nimport type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';\n\ninterface WrapperProps {\n readonly $left: number;\n readonly $width: number;\n}\n\n// Wrapper positions the annotation and contains both Box and ResizeHandles as siblings\nconst Wrapper = styled.div.attrs<WrapperProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<WrapperProps>`\n position: absolute;\n top: 0;\n height: 100%;\n pointer-events: none; /* Let events pass through to children */\n`;\n\ninterface BoxProps {\n readonly $color: string;\n readonly $isActive?: boolean;\n}\n\nconst Box = styled.div<BoxProps>`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBackground || 'rgba(255, 200, 100, 0.95)')\n : (props.theme?.annotationBoxBackground || 'rgba(255, 255, 255, 0.85)')};\n border: ${(props) => props.$isActive ? '3px' : '2px'} solid ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBorder || '#ff9800')\n : props.$color};\n border-radius: 4px;\n cursor: pointer;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n transition: all 0.2s ease;\n box-shadow: ${(props) => props.$isActive\n ? '0 2px 8px rgba(255, 152, 0, 0.4), inset 0 0 0 1px rgba(255, 152, 0, 0.2)'\n : '0 1px 3px rgba(0, 0, 0, 0.1)'};\n\n &:hover {\n background: ${(props) => props.theme?.annotationBoxHoverBackground || 'rgba(255, 255, 255, 0.98)'};\n border-color: ${(props) => props.theme?.annotationBoxActiveBorder || '#ff9800'};\n border-width: 3px;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n }\n`;\n\nconst Label = styled.span`\n font-size: 12px;\n font-weight: 600;\n color: ${(props) => props.theme?.annotationLabelColor || '#2a2a2a'};\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding: 0 6px;\n letter-spacing: 0.3px;\n user-select: none;\n`;\n\ninterface ResizeHandleStyledProps {\n $position: 'left' | 'right';\n $isDragging?: boolean;\n}\n\n// ResizeHandles are now siblings of Box, positioned relative to Wrapper\n// Reduced from 30px/-15px to 16px/-8px to minimize overlap between adjacent annotations\nconst ResizeHandle = styled.div<ResizeHandleStyledProps>`\n position: absolute;\n top: 0;\n ${(props) => props.$position === 'left' ? 'left: -8px' : 'right: -8px'};\n width: 16px;\n height: 100%;\n cursor: ew-resize;\n z-index: 120; /* Above ClickOverlay (z-index: 100) and AnnotationBoxesWrapper (z-index: 110) */\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.2)')\n : 'transparent'};\n border-radius: 4px;\n touch-action: none; /* Important for @dnd-kit on touch devices */\n pointer-events: auto;\n\n &::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 4px;\n height: 60%;\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.8)')\n : (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.4)')};\n border-radius: 2px;\n opacity: ${(props) => props.$isDragging ? 1 : 0.6};\n transition: opacity 0.2s, background 0.2s;\n }\n\n &:hover {\n background: ${(props) => props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.1)'};\n }\n\n &:hover::before {\n opacity: 1;\n background: ${(props) => props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.7)'};\n }\n`;\n\nexport interface DragHandleProps {\n attributes: DraggableAttributes;\n listeners: SyntheticListenerMap | undefined;\n setActivatorNodeRef: (element: HTMLElement | null) => void;\n isDragging: boolean;\n}\n\nexport interface AnnotationBoxComponentProps {\n annotationId: string;\n annotationIndex: number;\n startPosition: number;\n endPosition: number;\n label?: string;\n color?: string;\n isActive?: boolean;\n onClick?: () => void;\n editable?: boolean; // Whether to show drag handles\n}\n\nexport const AnnotationBox: FunctionComponent<AnnotationBoxComponentProps> = ({\n annotationId,\n annotationIndex,\n startPosition,\n endPosition,\n label,\n color = '#ff9800',\n isActive = false,\n onClick,\n editable = true,\n}) => {\n const width = Math.max(0, endPosition - startPosition);\n\n // Left (start) boundary draggable\n const leftBoundaryId = `annotation-boundary-start-${annotationIndex}`;\n const {\n attributes: leftAttributes,\n listeners: leftListeners,\n setActivatorNodeRef: setLeftActivatorRef,\n isDragging: isLeftDragging,\n } = useDraggable({\n id: leftBoundaryId,\n data: { annotationId, annotationIndex, edge: 'start' as const },\n disabled: !editable,\n });\n\n // Right (end) boundary draggable\n const rightBoundaryId = `annotation-boundary-end-${annotationIndex}`;\n const {\n attributes: rightAttributes,\n listeners: rightListeners,\n setActivatorNodeRef: setRightActivatorRef,\n isDragging: isRightDragging,\n } = useDraggable({\n id: rightBoundaryId,\n data: { annotationId, annotationIndex, edge: 'end' as const },\n disabled: !editable,\n });\n\n if (width <= 0) {\n return null;\n }\n\n // Wrap @dnd-kit pointer handlers to also stop propagation\n // This prevents the ClickOverlay from capturing the event\n const createPointerDownHandler = (dndKitHandler?: (e: React.PointerEvent) => void) => {\n return (e: React.PointerEvent) => {\n e.stopPropagation();\n dndKitHandler?.(e);\n };\n };\n\n const handleHandleClick = (e: React.MouseEvent) => {\n // Prevent clicks on resize handles from bubbling to annotation box\n e.stopPropagation();\n };\n\n return (\n <Wrapper $left={startPosition} $width={width}>\n <Box\n $color={color}\n $isActive={isActive}\n onClick={onClick}\n >\n {label && <Label>{label}</Label>}\n </Box>\n {editable && (\n <ResizeHandle\n ref={setLeftActivatorRef}\n $position=\"left\"\n $isDragging={isLeftDragging}\n onClick={handleHandleClick}\n {...leftListeners}\n onPointerDown={createPointerDownHandler(leftListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...leftAttributes}\n />\n )}\n {editable && (\n <ResizeHandle\n ref={setRightActivatorRef}\n $position=\"right\"\n $isDragging={isRightDragging}\n onClick={handleHandleClick}\n {...rightListeners}\n onPointerDown={createPointerDownHandler(rightListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...rightAttributes}\n />\n )}\n </Wrapper>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n z-index: 110;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n`;\n\nconst BoxesContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationBoxesWrapperProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationBoxesWrapper: FunctionComponent<AnnotationBoxesWrapperProps> = ({\n children,\n className,\n height = 30,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0} />\n <BoxesContainer $offset={offset}>\n {children}\n </BoxesContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n font-weight: bold;\n`;\n\nconst AnnotationsContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationsTrackProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationsTrack: FunctionComponent<AnnotationsTrackProps> = ({\n children,\n className,\n height = 100,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0}>\n Annotations\n </ControlsPlaceholder>\n <AnnotationsContainer $offset={offset}>\n {children}\n </AnnotationsContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent, useRef, useEffect } from 'react';\nimport styled from 'styled-components';\nimport type { AnnotationData, AnnotationAction, AnnotationActionOptions } from './Annotation';\n\ninterface ContainerProps {\n $height?: number;\n}\n\nconst Container = styled.div<ContainerProps>`\n background: ${(props) => props.theme?.backgroundColor || '#fff'};\n ${(props) => props.$height ? `height: ${props.$height}px;` : 'max-height: 200px;'}\n overflow-y: auto;\n padding: 8px;\n`;\n\nconst AnnotationItem = styled.div<{ $isActive?: boolean }>`\n padding: 12px;\n margin-bottom: 6px;\n border-left: 4px solid ${(props) => (props.$isActive ? '#ff9800' : 'transparent')};\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.15)' : 'transparent')};\n border-radius: 4px;\n transition: all 0.2s;\n cursor: pointer;\n box-shadow: ${(props) => (props.$isActive ? '0 2px 8px rgba(255, 152, 0, 0.25), inset 0 0 0 1px rgba(255, 152, 0, 0.3)' : 'none')};\n\n &:hover {\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.2)' : props.theme?.annotationTextItemHoverBackground || 'rgba(0, 0, 0, 0.05)')};\n border-left-color: ${(props) => (props.$isActive ? '#ff9800' : props.theme?.borderColor || '#ddd')};\n }\n\n &:focus-visible {\n outline: 2px solid #ff9800;\n outline-offset: 2px;\n }\n`;\n\nconst AnnotationHeader = styled.div`\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n`;\n\nconst AnnotationInfo = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n`;\n\nconst AnnotationIdLabel = styled.span<{ $isEditable?: boolean }>`\n font-size: 11px;\n font-weight: 600;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n background: transparent;\n padding: 2px 6px;\n border-radius: 3px;\n min-width: 20px;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\nconst TimeRange = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: ${(props) => props.theme?.textColorMuted || '#555'};\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n letter-spacing: 0.5px;\n`;\n\nconst AnnotationControls = styled.div`\n display: flex;\n gap: 6px;\n`;\n\nconst ControlButton = styled.button`\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n color: ${(props) => props.theme?.textColor || '#333'};\n padding: 4px 8px;\n font-size: 14px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n\n &:hover {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n transform: scale(1.05);\n }\n\n &:active {\n transform: scale(0.95);\n }\n`;\n\nconst AnnotationTextContent = styled.div<{ $isEditable?: boolean }>`\n font-size: 14px;\n line-height: 1.6;\n color: ${(props) => props.theme?.textColor || '#2a2a2a'};\n white-space: pre-wrap;\n word-break: break-word;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n padding: ${(props) => (props.$isEditable ? '6px' : '0')};\n border-radius: 3px;\n min-height: 20px;\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\n/**\n * Props passed to the renderAnnotationItem function for custom rendering\n */\nexport interface RenderAnnotationItemProps {\n annotation: AnnotationData;\n index: number;\n isActive: boolean;\n onClick: () => void;\n formatTime: (seconds: number) => string;\n}\n\nexport interface AnnotationTextProps {\n annotations: AnnotationData[];\n activeAnnotationId?: string;\n shouldScrollToActive?: boolean;\n /** Where to position the active annotation when scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */\n scrollActivePosition?: ScrollLogicalPosition;\n /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */\n scrollActiveContainer?: 'nearest' | 'all';\n editable?: boolean;\n controls?: AnnotationAction[];\n annotationListConfig?: AnnotationActionOptions;\n height?: number;\n onAnnotationClick?: (annotation: AnnotationData) => void;\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n /**\n * Custom render function for annotation items.\n * When provided, completely replaces the default annotation item rendering.\n * Use this to customize the appearance of each annotation in the list.\n */\n renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode;\n}\n\nconst AnnotationTextComponent: FunctionComponent<AnnotationTextProps> = ({\n annotations,\n activeAnnotationId,\n shouldScrollToActive = false,\n scrollActivePosition = 'center',\n scrollActiveContainer = 'nearest',\n editable = false,\n controls = [],\n annotationListConfig,\n height,\n onAnnotationClick,\n onAnnotationUpdate,\n renderAnnotationItem,\n}) => {\n const activeAnnotationRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevActiveIdRef = useRef<string | undefined>(undefined);\n\n // Track component renders and scroll position\n useEffect(() => {\n // Render tracking removed\n });\n\n // Track scroll changes\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n // Scroll tracking removed\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, []);\n\n // Auto-scroll to active annotation when it changes\n useEffect(() => {\n // Only scroll if parent says we should (prevents scrolling on remount after pause)\n if (activeAnnotationId && activeAnnotationRef.current && shouldScrollToActive) {\n activeAnnotationRef.current.scrollIntoView({\n behavior: 'smooth',\n block: scrollActivePosition,\n container: scrollActiveContainer,\n } as ScrollIntoViewOptions);\n }\n\n prevActiveIdRef.current = activeAnnotationId;\n }, [activeAnnotationId, shouldScrollToActive, scrollActivePosition, scrollActiveContainer]);\n\n const formatTime = (seconds: number): string => {\n if (isNaN(seconds) || !isFinite(seconds)) {\n return '0:00.000';\n }\n const mins = Math.floor(seconds / 60);\n const secs = (seconds % 60).toFixed(3);\n return `${mins}:${secs.padStart(6, '0')}`;\n };\n\n const handleTextEdit = (index: number, newText: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n lines: newText.split('\\n'),\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleIdEdit = (index: number, newId: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const trimmedId = newId.trim();\n if (!trimmedId) return; // Don't allow empty IDs\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n id: trimmedId,\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleControlClick = (control: AnnotationAction, annotation: AnnotationData, index: number) => {\n if (!onAnnotationUpdate) return;\n\n const annotationsCopy = [...annotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n onAnnotationUpdate(annotationsCopy);\n };\n\n const getIconClass = (classString: string) => {\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <Container ref={containerRef} $height={height}>\n {annotations.map((annotation, index) => {\n const isActive = annotation.id === activeAnnotationId;\n const handleClick = () => onAnnotationClick?.(annotation);\n\n // Use custom render function if provided\n if (renderAnnotationItem) {\n return (\n <div\n key={annotation.id}\n ref={isActive ? activeAnnotationRef : null}\n >\n {renderAnnotationItem({\n annotation,\n index,\n isActive,\n onClick: handleClick,\n formatTime,\n })}\n </div>\n );\n }\n\n // Default rendering\n return (\n <AnnotationItem\n key={annotation.id}\n ref={isActive ? activeAnnotationRef : null}\n $isActive={isActive}\n onClick={handleClick}\n >\n <AnnotationHeader>\n <AnnotationInfo>\n <AnnotationIdLabel\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleIdEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.id}\n </AnnotationIdLabel>\n <TimeRange>\n {formatTime(annotation.start)} - {formatTime(annotation.end)}\n </TimeRange>\n </AnnotationInfo>\n {controls.length > 0 && (\n <AnnotationControls onClick={(e) => e.stopPropagation()}>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={() => handleControlClick(control, annotation, index)}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </AnnotationControls>\n )}\n </AnnotationHeader>\n <AnnotationTextContent\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleTextEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.lines.join('\\n')}\n </AnnotationTextContent>\n </AnnotationItem>\n );\n })}\n </Container>\n );\n};\n\n// Memoize to prevent unnecessary remounting when parent re-renders\nexport const AnnotationText = React.memo(AnnotationTextComponent);\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface ContinuousPlayCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling continuous play of annotations.\n * When enabled, playback continues from one annotation to the next without stopping.\n */\nexport const ContinuousPlayCheckbox: React.FC<ContinuousPlayCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"continuous-play\"\n className=\"continuous-play\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"continuous-play\">Continuous Play</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface LinkEndpointsCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling linked endpoints between annotations.\n * When enabled, the end time of one annotation is automatically linked to the start time of the next.\n */\nexport const LinkEndpointsCheckbox: React.FC<LinkEndpointsCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"link-endpoints\"\n className=\"link-endpoints\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"link-endpoints\">Link Endpoints</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface EditableCheckboxProps {\n checked: boolean;\n onChange: (enabled: boolean) => void;\n className?: string;\n}\n\nexport const EditableCheckbox: React.FC<EditableCheckboxProps> = ({\n checked,\n onChange,\n className,\n}) => {\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"editable-annotations\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n />\n <BaseCheckboxLabel htmlFor=\"editable-annotations\">Editable Annotations</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport styled from 'styled-components';\nimport { serializeAeneas } from '../parsers/aeneas';\nimport type { Annotation } from '../types';\n\nconst StyledButton = styled.button`\n padding: 0.5rem 1rem;\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n color: ${(props) => props.theme?.textColor || '#333'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n border-radius: ${(props) => props.theme?.borderRadius || '4px'};\n cursor: pointer;\n font-family: ${(props) => props.theme?.fontFamily || 'inherit'};\n font-size: ${(props) => props.theme?.fontSize || '14px'};\n font-weight: 500;\n transition: all 0.15s ease;\n\n &:hover:not(:disabled) {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n }\n\n &:focus {\n outline: none;\n box-shadow: 0 0 0 2px ${(props) => props.theme?.inputFocusBorder || '#007bff'}44;\n }\n\n &:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n`;\n\nexport interface DownloadAnnotationsButtonProps {\n annotations: Annotation[];\n filename?: string;\n disabled?: boolean;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport const DownloadAnnotationsButton: React.FC<DownloadAnnotationsButtonProps> = ({\n annotations,\n filename = 'annotations.json',\n disabled = false,\n className,\n children = 'Download JSON',\n}) => {\n const handleDownload = () => {\n if (annotations.length === 0) {\n return;\n }\n\n // Serialize annotations to Aeneas JSON format\n const jsonData = annotations.map(annotation => serializeAeneas(annotation));\n const jsonString = JSON.stringify(jsonData, null, 2);\n\n // Create a blob and download link\n const blob = new Blob([jsonString], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n\n // Trigger download\n document.body.appendChild(link);\n link.click();\n\n // Cleanup\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n };\n\n return (\n <StyledButton\n onClick={handleDownload}\n disabled={disabled || annotations.length === 0}\n className={className}\n title={annotations.length === 0 ? 'No annotations to download' : 'Download the annotations as JSON'}\n >\n {children}\n </StyledButton>\n );\n};\n","import { useState, useCallback } from 'react';\nimport type { Annotation, AnnotationListOptions } from '../types';\n\nconst LINK_THRESHOLD = 0.01; // Consider edges \"linked\" if within 10ms\n\nexport interface UseAnnotationControlsOptions {\n initialContinuousPlay?: boolean;\n initialLinkEndpoints?: boolean;\n}\n\nexport interface AnnotationUpdateParams {\n annotationIndex: number;\n newTime: number;\n isDraggingStart: boolean;\n annotations: Annotation[];\n duration: number;\n linkEndpoints: boolean;\n}\n\nexport interface UseAnnotationControlsReturn {\n continuousPlay: boolean;\n linkEndpoints: boolean;\n setContinuousPlay: (value: boolean) => void;\n setLinkEndpoints: (value: boolean) => void;\n updateAnnotationBoundaries: (params: AnnotationUpdateParams) => Annotation[];\n}\n\n/**\n * Hook for managing annotation control state and boundary logic.\n * Handles continuous play mode and linked endpoints behavior.\n */\nexport const useAnnotationControls = (\n options: UseAnnotationControlsOptions = {}\n): UseAnnotationControlsReturn => {\n const {\n initialContinuousPlay = false,\n initialLinkEndpoints = true,\n } = options;\n\n const [continuousPlay, setContinuousPlay] = useState(initialContinuousPlay);\n const [linkEndpoints, setLinkEndpoints] = useState(initialLinkEndpoints);\n\n /**\n * Updates annotation boundaries based on drag operations.\n * Handles linked endpoints and collision detection.\n * Note: linkEndpoints is passed as a parameter to ensure it uses the current value from context.\n */\n const updateAnnotationBoundaries = useCallback(\n ({\n annotationIndex,\n newTime,\n isDraggingStart,\n annotations,\n duration,\n linkEndpoints: shouldLinkEndpoints,\n }: AnnotationUpdateParams): Annotation[] => {\n const updatedAnnotations = [...annotations];\n const annotation = annotations[annotationIndex];\n\n if (isDraggingStart) {\n // Dragging start edge\n const constrainedStart = Math.min(annotation.end - 0.1, Math.max(0, newTime));\n const delta = constrainedStart - annotation.start;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n start: constrainedStart,\n };\n\n if (shouldLinkEndpoints && annotationIndex > 0) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const prevAnnotation = updatedAnnotations[annotationIndex - 1];\n\n if (Math.abs(prevAnnotation.end - annotation.start) < LINK_THRESHOLD) {\n // Already linked: move previous annotation's end together with this start\n updatedAnnotations[annotationIndex - 1] = {\n ...prevAnnotation,\n end: Math.max(prevAnnotation.start + 0.1, prevAnnotation.end + delta),\n };\n } else if (constrainedStart <= prevAnnotation.end) {\n // Dragged past previous annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n start: prevAnnotation.end,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex > 0 && constrainedStart < updatedAnnotations[annotationIndex - 1].end) {\n // Collision detection: push previous annotation's end back\n updatedAnnotations[annotationIndex - 1] = {\n ...updatedAnnotations[annotationIndex - 1],\n end: constrainedStart,\n };\n }\n } else {\n // Dragging end edge\n const constrainedEnd = Math.max(annotation.start + 0.1, Math.min(newTime, duration));\n const delta = constrainedEnd - annotation.end;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n end: constrainedEnd,\n };\n\n if (shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n if (Math.abs(nextAnnotation.start - annotation.end) < LINK_THRESHOLD) {\n // Already linked: move next annotation's start together with this end\n const newStart = nextAnnotation.start + delta;\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: Math.min(nextAnnotation.end - 0.1, newStart),\n };\n\n // Cascade linked endpoints\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (Math.abs(next.start - current.end) < LINK_THRESHOLD) {\n const nextDelta = current.end - annotations[currentIndex].end;\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: Math.min(next.end - 0.1, next.start + nextDelta),\n };\n currentIndex++;\n } else {\n break; // No more linked endpoints\n }\n }\n } else if (constrainedEnd >= nextAnnotation.start) {\n // Dragged past next annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n end: nextAnnotation.start,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1 && constrainedEnd > updatedAnnotations[annotationIndex + 1].start) {\n // Collision detection: push next annotation's start forward\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: constrainedEnd,\n };\n\n // Cascade collisions\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (current.end > next.start) {\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: current.end,\n };\n currentIndex++;\n } else {\n break; // No more collisions\n }\n }\n }\n }\n\n return updatedAnnotations;\n },\n []\n );\n\n return {\n continuousPlay,\n linkEndpoints,\n setContinuousPlay,\n setLinkEndpoints,\n updateAnnotationBoundaries,\n };\n};\n"],"mappings":"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","names":["AnnotationText","styled","import_styled_components","import_jsx_runtime","styled","import_styled_components","import_jsx_runtime","styled","import_styled_components","import_ui_components","import_jsx_runtime","Container","styled","ControlsPlaceholder","import_react","import_styled_components","import_jsx_runtime","Container","styled","ControlButton","AnnotationText","React","import_ui_components","import_jsx_runtime","import_ui_components","import_jsx_runtime","import_ui_components","import_jsx_runtime","import_styled_components","import_jsx_runtime","styled","import_react"]}
package/dist/index.mjs CHANGED
@@ -597,12 +597,15 @@ var AnnotationTextComponent = ({
597
597
  annotations,
598
598
  activeAnnotationId,
599
599
  shouldScrollToActive = false,
600
+ scrollActivePosition = "center",
601
+ scrollActiveContainer = "nearest",
600
602
  editable = false,
601
603
  controls = [],
602
604
  annotationListConfig,
603
605
  height,
604
606
  onAnnotationClick,
605
- onAnnotationUpdate
607
+ onAnnotationUpdate,
608
+ renderAnnotationItem
606
609
  }) => {
607
610
  const activeAnnotationRef = useRef(null);
608
611
  const containerRef = useRef(null);
@@ -621,11 +624,12 @@ var AnnotationTextComponent = ({
621
624
  if (activeAnnotationId && activeAnnotationRef.current && shouldScrollToActive) {
622
625
  activeAnnotationRef.current.scrollIntoView({
623
626
  behavior: "smooth",
624
- block: "nearest"
627
+ block: scrollActivePosition,
628
+ container: scrollActiveContainer
625
629
  });
626
630
  }
627
631
  prevActiveIdRef.current = activeAnnotationId;
628
- }, [activeAnnotationId, shouldScrollToActive]);
632
+ }, [activeAnnotationId, shouldScrollToActive, scrollActivePosition, scrollActiveContainer]);
629
633
  const formatTime = (seconds) => {
630
634
  if (isNaN(seconds) || !isFinite(seconds)) {
631
635
  return "0:00.000";
@@ -665,12 +669,29 @@ var AnnotationTextComponent = ({
665
669
  };
666
670
  return /* @__PURE__ */ jsx5(Container3, { ref: containerRef, $height: height, children: annotations.map((annotation, index) => {
667
671
  const isActive = annotation.id === activeAnnotationId;
672
+ const handleClick = () => onAnnotationClick?.(annotation);
673
+ if (renderAnnotationItem) {
674
+ return /* @__PURE__ */ jsx5(
675
+ "div",
676
+ {
677
+ ref: isActive ? activeAnnotationRef : null,
678
+ children: renderAnnotationItem({
679
+ annotation,
680
+ index,
681
+ isActive,
682
+ onClick: handleClick,
683
+ formatTime
684
+ })
685
+ },
686
+ annotation.id
687
+ );
688
+ }
668
689
  return /* @__PURE__ */ jsxs5(
669
690
  AnnotationItem,
670
691
  {
671
692
  ref: isActive ? activeAnnotationRef : null,
672
693
  $isActive: isActive,
673
- onClick: () => onAnnotationClick?.(annotation),
694
+ onClick: handleClick,
674
695
  children: [
675
696
  /* @__PURE__ */ jsxs5(AnnotationHeader, { children: [
676
697
  /* @__PURE__ */ jsxs5(AnnotationInfo, { children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parsers/aeneas.ts","../src/components/Annotation.tsx","../src/components/AnnotationBox.tsx","../src/components/AnnotationBoxesWrapper.tsx","../src/components/AnnotationsTrack.tsx","../src/components/AnnotationText.tsx","../src/components/ContinuousPlayCheckbox.tsx","../src/components/LinkEndpointsCheckbox.tsx","../src/components/EditableCheckbox.tsx","../src/components/DownloadAnnotationsButton.tsx","../src/hooks/useAnnotationControls.ts"],"sourcesContent":["import { Annotation } from '../types';\n\nexport interface AeneasFragment {\n begin: string;\n end: string;\n id: string;\n language: string;\n lines: string[];\n}\n\nexport function parseAeneas(data: AeneasFragment): Annotation {\n return {\n id: data.id,\n start: parseFloat(data.begin),\n end: parseFloat(data.end),\n lines: data.lines,\n lang: data.language,\n };\n}\n\nexport function serializeAeneas(annotation: Annotation): AeneasFragment {\n return {\n id: annotation.id,\n begin: annotation.start.toFixed(3),\n end: annotation.end.toFixed(3),\n lines: annotation.lines,\n language: annotation.lang || 'en',\n };\n}\n","import React, { FunctionComponent, useState } from 'react';\nimport styled from 'styled-components';\n\ninterface AnnotationOverlayProps {\n readonly $left: number;\n readonly $width: number;\n readonly $color: string;\n}\n\nconst AnnotationOverlay = styled.div.attrs<AnnotationOverlayProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<AnnotationOverlayProps>`\n position: absolute;\n top: 0;\n background: ${(props) => props.$color};\n height: 100%;\n z-index: 10;\n pointer-events: auto;\n opacity: 0.3;\n border: 2px solid ${(props) => props.$color};\n border-radius: 4px;\n cursor: pointer;\n\n &:hover {\n opacity: 0.5;\n border-color: ${(props) => props.$color};\n }\n`;\n\nconst AnnotationText = styled.div`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: hidden;\n text-overflow: ellipsis;\n pointer-events: none;\n white-space: pre-wrap;\n word-break: break-word;\n`;\n\nconst EditableText = styled.textarea`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.9);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: auto;\n border: 1px solid #fff;\n resize: none;\n font-family: inherit;\n\n &:focus {\n outline: none;\n border-color: #4CAF50;\n }\n`;\n\nconst ControlsBar = styled.div`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n gap: 4px;\n padding: 4px;\n justify-content: flex-start;\n align-items: center;\n`;\n\nconst ControlButton = styled.button`\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.5);\n color: white;\n padding: 4px 8px;\n font-size: 10px;\n cursor: pointer;\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n border-color: white;\n }\n\n &:active {\n background: rgba(255, 255, 255, 0.3);\n }\n`;\n\n/**\n * Configuration options passed to annotation action handlers\n */\nexport interface AnnotationActionOptions {\n /** Whether annotation endpoints are linked (moving one endpoint moves the other) */\n linkEndpoints?: boolean;\n /** Whether to continue playing after an annotation ends */\n continuousPlay?: boolean;\n /** Additional custom properties */\n [key: string]: unknown;\n}\n\nexport interface AnnotationAction {\n class?: string;\n text?: string;\n title: string;\n action: (annotation: AnnotationData, index: number, annotations: AnnotationData[], opts: AnnotationActionOptions) => void;\n}\n\nexport interface AnnotationData {\n id: string;\n start: number;\n end: number;\n lines: string[];\n language?: string;\n}\n\nexport interface AnnotationProps {\n annotation: AnnotationData;\n index: number;\n allAnnotations: AnnotationData[];\n startPosition: number; // Start position in pixels\n endPosition: number; // End position in pixels\n color?: string;\n editable?: boolean;\n controls?: AnnotationAction[];\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n annotationListConfig?: AnnotationActionOptions;\n onClick?: (annotation: AnnotationData) => void;\n}\n\nexport const Annotation: FunctionComponent<AnnotationProps> = ({\n annotation,\n index,\n allAnnotations,\n startPosition,\n endPosition,\n color = '#ff9800',\n editable = false,\n controls = [],\n onAnnotationUpdate,\n annotationListConfig,\n onClick,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editedText, setEditedText] = useState(annotation.lines.join('\\n'));\n const width = Math.max(0, endPosition - startPosition);\n\n if (width <= 0) {\n return null;\n }\n\n const handleClick = () => {\n if (onClick) {\n onClick(annotation);\n }\n };\n\n const handleDoubleClick = () => {\n if (editable) {\n setIsEditing(true);\n }\n };\n\n const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setEditedText(e.target.value);\n };\n\n const handleTextBlur = () => {\n setIsEditing(false);\n const newLines = editedText.split('\\n');\n if (newLines.join('\\n') !== annotation.lines.join('\\n')) {\n const updatedAnnotations = [...allAnnotations];\n updatedAnnotations[index] = { ...annotation, lines: newLines };\n if (onAnnotationUpdate) {\n onAnnotationUpdate(updatedAnnotations);\n }\n }\n };\n\n const handleControlClick = (control: AnnotationAction) => {\n const annotationsCopy = [...allAnnotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n if (onAnnotationUpdate) {\n onAnnotationUpdate(annotationsCopy);\n }\n };\n\n const getIconClass = (classString: string) => {\n // Convert \"fas.fa-minus\" to \"fas fa-minus\"\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <AnnotationOverlay\n $left={startPosition}\n $width={width}\n $color={color}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n >\n {controls.length > 0 && (\n <ControlsBar>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={(e) => {\n e.stopPropagation();\n handleControlClick(control);\n }}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </ControlsBar>\n )}\n {isEditing ? (\n <EditableText\n value={editedText}\n onChange={handleTextChange}\n onBlur={handleTextBlur}\n autoFocus\n onClick={(e) => e.stopPropagation()}\n onDoubleClick={(e) => e.stopPropagation()}\n />\n ) : (\n <AnnotationText>\n {annotation.lines.join('\\n')}\n </AnnotationText>\n )}\n </AnnotationOverlay>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { useDraggable } from '@dnd-kit/core';\nimport type { DraggableAttributes } from '@dnd-kit/core';\nimport type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';\n\ninterface WrapperProps {\n readonly $left: number;\n readonly $width: number;\n}\n\n// Wrapper positions the annotation and contains both Box and ResizeHandles as siblings\nconst Wrapper = styled.div.attrs<WrapperProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<WrapperProps>`\n position: absolute;\n top: 0;\n height: 100%;\n pointer-events: none; /* Let events pass through to children */\n`;\n\ninterface BoxProps {\n readonly $color: string;\n readonly $isActive?: boolean;\n}\n\nconst Box = styled.div<BoxProps>`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBackground || 'rgba(255, 200, 100, 0.95)')\n : (props.theme?.annotationBoxBackground || 'rgba(255, 255, 255, 0.85)')};\n border: ${(props) => props.$isActive ? '3px' : '2px'} solid ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBorder || '#ff9800')\n : props.$color};\n border-radius: 4px;\n cursor: pointer;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n transition: all 0.2s ease;\n box-shadow: ${(props) => props.$isActive\n ? '0 2px 8px rgba(255, 152, 0, 0.4), inset 0 0 0 1px rgba(255, 152, 0, 0.2)'\n : '0 1px 3px rgba(0, 0, 0, 0.1)'};\n\n &:hover {\n background: ${(props) => props.theme?.annotationBoxHoverBackground || 'rgba(255, 255, 255, 0.98)'};\n border-color: ${(props) => props.theme?.annotationBoxActiveBorder || '#ff9800'};\n border-width: 3px;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n }\n`;\n\nconst Label = styled.span`\n font-size: 12px;\n font-weight: 600;\n color: ${(props) => props.theme?.annotationLabelColor || '#2a2a2a'};\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding: 0 6px;\n letter-spacing: 0.3px;\n user-select: none;\n`;\n\ninterface ResizeHandleStyledProps {\n $position: 'left' | 'right';\n $isDragging?: boolean;\n}\n\n// ResizeHandles are now siblings of Box, positioned relative to Wrapper\n// Reduced from 30px/-15px to 16px/-8px to minimize overlap between adjacent annotations\nconst ResizeHandle = styled.div<ResizeHandleStyledProps>`\n position: absolute;\n top: 0;\n ${(props) => props.$position === 'left' ? 'left: -8px' : 'right: -8px'};\n width: 16px;\n height: 100%;\n cursor: ew-resize;\n z-index: 120; /* Above ClickOverlay (z-index: 100) and AnnotationBoxesWrapper (z-index: 110) */\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.2)')\n : 'transparent'};\n border-radius: 4px;\n touch-action: none; /* Important for @dnd-kit on touch devices */\n pointer-events: auto;\n\n &::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 4px;\n height: 60%;\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.8)')\n : (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.4)')};\n border-radius: 2px;\n opacity: ${(props) => props.$isDragging ? 1 : 0.6};\n transition: opacity 0.2s, background 0.2s;\n }\n\n &:hover {\n background: ${(props) => props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.1)'};\n }\n\n &:hover::before {\n opacity: 1;\n background: ${(props) => props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.7)'};\n }\n`;\n\nexport interface DragHandleProps {\n attributes: DraggableAttributes;\n listeners: SyntheticListenerMap | undefined;\n setActivatorNodeRef: (element: HTMLElement | null) => void;\n isDragging: boolean;\n}\n\nexport interface AnnotationBoxComponentProps {\n annotationId: string;\n annotationIndex: number;\n startPosition: number;\n endPosition: number;\n label?: string;\n color?: string;\n isActive?: boolean;\n onClick?: () => void;\n editable?: boolean; // Whether to show drag handles\n}\n\nexport const AnnotationBox: FunctionComponent<AnnotationBoxComponentProps> = ({\n annotationId,\n annotationIndex,\n startPosition,\n endPosition,\n label,\n color = '#ff9800',\n isActive = false,\n onClick,\n editable = true,\n}) => {\n const width = Math.max(0, endPosition - startPosition);\n\n // Left (start) boundary draggable\n const leftBoundaryId = `annotation-boundary-start-${annotationIndex}`;\n const {\n attributes: leftAttributes,\n listeners: leftListeners,\n setActivatorNodeRef: setLeftActivatorRef,\n isDragging: isLeftDragging,\n } = useDraggable({\n id: leftBoundaryId,\n data: { annotationId, annotationIndex, edge: 'start' as const },\n disabled: !editable,\n });\n\n // Right (end) boundary draggable\n const rightBoundaryId = `annotation-boundary-end-${annotationIndex}`;\n const {\n attributes: rightAttributes,\n listeners: rightListeners,\n setActivatorNodeRef: setRightActivatorRef,\n isDragging: isRightDragging,\n } = useDraggable({\n id: rightBoundaryId,\n data: { annotationId, annotationIndex, edge: 'end' as const },\n disabled: !editable,\n });\n\n if (width <= 0) {\n return null;\n }\n\n // Wrap @dnd-kit pointer handlers to also stop propagation\n // This prevents the ClickOverlay from capturing the event\n const createPointerDownHandler = (dndKitHandler?: (e: React.PointerEvent) => void) => {\n return (e: React.PointerEvent) => {\n e.stopPropagation();\n dndKitHandler?.(e);\n };\n };\n\n const handleHandleClick = (e: React.MouseEvent) => {\n // Prevent clicks on resize handles from bubbling to annotation box\n e.stopPropagation();\n };\n\n return (\n <Wrapper $left={startPosition} $width={width}>\n <Box\n $color={color}\n $isActive={isActive}\n onClick={onClick}\n >\n {label && <Label>{label}</Label>}\n </Box>\n {editable && (\n <ResizeHandle\n ref={setLeftActivatorRef}\n $position=\"left\"\n $isDragging={isLeftDragging}\n onClick={handleHandleClick}\n {...leftListeners}\n onPointerDown={createPointerDownHandler(leftListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...leftAttributes}\n />\n )}\n {editable && (\n <ResizeHandle\n ref={setRightActivatorRef}\n $position=\"right\"\n $isDragging={isRightDragging}\n onClick={handleHandleClick}\n {...rightListeners}\n onPointerDown={createPointerDownHandler(rightListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...rightAttributes}\n />\n )}\n </Wrapper>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n z-index: 110;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n`;\n\nconst BoxesContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationBoxesWrapperProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationBoxesWrapper: FunctionComponent<AnnotationBoxesWrapperProps> = ({\n children,\n className,\n height = 30,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0} />\n <BoxesContainer $offset={offset}>\n {children}\n </BoxesContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n font-weight: bold;\n`;\n\nconst AnnotationsContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationsTrackProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationsTrack: FunctionComponent<AnnotationsTrackProps> = ({\n children,\n className,\n height = 100,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0}>\n Annotations\n </ControlsPlaceholder>\n <AnnotationsContainer $offset={offset}>\n {children}\n </AnnotationsContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent, useRef, useEffect } from 'react';\nimport styled from 'styled-components';\nimport type { AnnotationData, AnnotationAction, AnnotationActionOptions } from './Annotation';\n\ninterface ContainerProps {\n $height?: number;\n}\n\nconst Container = styled.div<ContainerProps>`\n background: ${(props) => props.theme?.backgroundColor || '#fff'};\n ${(props) => props.$height ? `height: ${props.$height}px;` : 'max-height: 200px;'}\n overflow-y: auto;\n padding: 8px;\n`;\n\nconst AnnotationItem = styled.div<{ $isActive?: boolean }>`\n padding: 12px;\n margin-bottom: 6px;\n border-left: 4px solid ${(props) => (props.$isActive ? '#ff9800' : 'transparent')};\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.15)' : 'transparent')};\n border-radius: 4px;\n transition: all 0.2s;\n cursor: pointer;\n box-shadow: ${(props) => (props.$isActive ? '0 2px 8px rgba(255, 152, 0, 0.25), inset 0 0 0 1px rgba(255, 152, 0, 0.3)' : 'none')};\n\n &:hover {\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.2)' : props.theme?.annotationTextItemHoverBackground || 'rgba(0, 0, 0, 0.05)')};\n border-left-color: ${(props) => (props.$isActive ? '#ff9800' : props.theme?.borderColor || '#ddd')};\n }\n\n &:focus-visible {\n outline: 2px solid #ff9800;\n outline-offset: 2px;\n }\n`;\n\nconst AnnotationHeader = styled.div`\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n`;\n\nconst AnnotationInfo = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n`;\n\nconst AnnotationIdLabel = styled.span<{ $isEditable?: boolean }>`\n font-size: 11px;\n font-weight: 600;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n background: transparent;\n padding: 2px 6px;\n border-radius: 3px;\n min-width: 20px;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\nconst TimeRange = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: ${(props) => props.theme?.textColorMuted || '#555'};\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n letter-spacing: 0.5px;\n`;\n\nconst AnnotationControls = styled.div`\n display: flex;\n gap: 6px;\n`;\n\nconst ControlButton = styled.button`\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n color: ${(props) => props.theme?.textColor || '#333'};\n padding: 4px 8px;\n font-size: 14px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n\n &:hover {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n transform: scale(1.05);\n }\n\n &:active {\n transform: scale(0.95);\n }\n`;\n\nconst AnnotationTextContent = styled.div<{ $isEditable?: boolean }>`\n font-size: 14px;\n line-height: 1.6;\n color: ${(props) => props.theme?.textColor || '#2a2a2a'};\n white-space: pre-wrap;\n word-break: break-word;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n padding: ${(props) => (props.$isEditable ? '6px' : '0')};\n border-radius: 3px;\n min-height: 20px;\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\nexport interface AnnotationTextProps {\n annotations: AnnotationData[];\n activeAnnotationId?: string;\n shouldScrollToActive?: boolean;\n editable?: boolean;\n controls?: AnnotationAction[];\n annotationListConfig?: AnnotationActionOptions;\n height?: number;\n onAnnotationClick?: (annotation: AnnotationData) => void;\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n}\n\nconst AnnotationTextComponent: FunctionComponent<AnnotationTextProps> = ({\n annotations,\n activeAnnotationId,\n shouldScrollToActive = false,\n editable = false,\n controls = [],\n annotationListConfig,\n height,\n onAnnotationClick,\n onAnnotationUpdate,\n}) => {\n const activeAnnotationRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevActiveIdRef = useRef<string | undefined>(undefined);\n\n // Track component renders and scroll position\n useEffect(() => {\n // Render tracking removed\n });\n\n // Track scroll changes\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n // Scroll tracking removed\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, []);\n\n // Auto-scroll to active annotation when it changes\n useEffect(() => {\n // Only scroll if parent says we should (prevents scrolling on remount after pause)\n if (activeAnnotationId && activeAnnotationRef.current && shouldScrollToActive) {\n activeAnnotationRef.current.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n });\n }\n\n prevActiveIdRef.current = activeAnnotationId;\n }, [activeAnnotationId, shouldScrollToActive]);\n\n const formatTime = (seconds: number): string => {\n if (isNaN(seconds) || !isFinite(seconds)) {\n return '0:00.000';\n }\n const mins = Math.floor(seconds / 60);\n const secs = (seconds % 60).toFixed(3);\n return `${mins}:${secs.padStart(6, '0')}`;\n };\n\n const handleTextEdit = (index: number, newText: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n lines: newText.split('\\n'),\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleIdEdit = (index: number, newId: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const trimmedId = newId.trim();\n if (!trimmedId) return; // Don't allow empty IDs\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n id: trimmedId,\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleControlClick = (control: AnnotationAction, annotation: AnnotationData, index: number) => {\n if (!onAnnotationUpdate) return;\n\n const annotationsCopy = [...annotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n onAnnotationUpdate(annotationsCopy);\n };\n\n const getIconClass = (classString: string) => {\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <Container ref={containerRef} $height={height}>\n {annotations.map((annotation, index) => {\n const isActive = annotation.id === activeAnnotationId;\n return (\n <AnnotationItem\n key={annotation.id}\n ref={isActive ? activeAnnotationRef : null}\n $isActive={isActive}\n onClick={() => onAnnotationClick?.(annotation)}\n >\n <AnnotationHeader>\n <AnnotationInfo>\n <AnnotationIdLabel\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleIdEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.id}\n </AnnotationIdLabel>\n <TimeRange>\n {formatTime(annotation.start)} - {formatTime(annotation.end)}\n </TimeRange>\n </AnnotationInfo>\n {controls.length > 0 && (\n <AnnotationControls onClick={(e) => e.stopPropagation()}>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={() => handleControlClick(control, annotation, index)}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </AnnotationControls>\n )}\n </AnnotationHeader>\n <AnnotationTextContent\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleTextEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.lines.join('\\n')}\n </AnnotationTextContent>\n </AnnotationItem>\n );\n })}\n </Container>\n );\n};\n\n// Memoize to prevent unnecessary remounting when parent re-renders\nexport const AnnotationText = React.memo(AnnotationTextComponent);\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface ContinuousPlayCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling continuous play of annotations.\n * When enabled, playback continues from one annotation to the next without stopping.\n */\nexport const ContinuousPlayCheckbox: React.FC<ContinuousPlayCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"continuous-play\"\n className=\"continuous-play\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"continuous-play\">Continuous Play</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface LinkEndpointsCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling linked endpoints between annotations.\n * When enabled, the end time of one annotation is automatically linked to the start time of the next.\n */\nexport const LinkEndpointsCheckbox: React.FC<LinkEndpointsCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"link-endpoints\"\n className=\"link-endpoints\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"link-endpoints\">Link Endpoints</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface EditableCheckboxProps {\n checked: boolean;\n onChange: (enabled: boolean) => void;\n className?: string;\n}\n\nexport const EditableCheckbox: React.FC<EditableCheckboxProps> = ({\n checked,\n onChange,\n className,\n}) => {\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"editable-annotations\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n />\n <BaseCheckboxLabel htmlFor=\"editable-annotations\">Editable Annotations</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport styled from 'styled-components';\nimport { serializeAeneas } from '../parsers/aeneas';\nimport type { Annotation } from '../types';\n\nconst StyledButton = styled.button`\n padding: 0.5rem 1rem;\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n color: ${(props) => props.theme?.textColor || '#333'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n border-radius: ${(props) => props.theme?.borderRadius || '4px'};\n cursor: pointer;\n font-family: ${(props) => props.theme?.fontFamily || 'inherit'};\n font-size: ${(props) => props.theme?.fontSize || '14px'};\n font-weight: 500;\n transition: all 0.15s ease;\n\n &:hover:not(:disabled) {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n }\n\n &:focus {\n outline: none;\n box-shadow: 0 0 0 2px ${(props) => props.theme?.inputFocusBorder || '#007bff'}44;\n }\n\n &:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n`;\n\nexport interface DownloadAnnotationsButtonProps {\n annotations: Annotation[];\n filename?: string;\n disabled?: boolean;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport const DownloadAnnotationsButton: React.FC<DownloadAnnotationsButtonProps> = ({\n annotations,\n filename = 'annotations.json',\n disabled = false,\n className,\n children = 'Download JSON',\n}) => {\n const handleDownload = () => {\n if (annotations.length === 0) {\n return;\n }\n\n // Serialize annotations to Aeneas JSON format\n const jsonData = annotations.map(annotation => serializeAeneas(annotation));\n const jsonString = JSON.stringify(jsonData, null, 2);\n\n // Create a blob and download link\n const blob = new Blob([jsonString], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n\n // Trigger download\n document.body.appendChild(link);\n link.click();\n\n // Cleanup\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n };\n\n return (\n <StyledButton\n onClick={handleDownload}\n disabled={disabled || annotations.length === 0}\n className={className}\n title={annotations.length === 0 ? 'No annotations to download' : 'Download the annotations as JSON'}\n >\n {children}\n </StyledButton>\n );\n};\n","import { useState, useCallback } from 'react';\nimport type { Annotation, AnnotationListOptions } from '../types';\n\nconst LINK_THRESHOLD = 0.01; // Consider edges \"linked\" if within 10ms\n\nexport interface UseAnnotationControlsOptions {\n initialContinuousPlay?: boolean;\n initialLinkEndpoints?: boolean;\n}\n\nexport interface AnnotationUpdateParams {\n annotationIndex: number;\n newTime: number;\n isDraggingStart: boolean;\n annotations: Annotation[];\n duration: number;\n linkEndpoints: boolean;\n}\n\nexport interface UseAnnotationControlsReturn {\n continuousPlay: boolean;\n linkEndpoints: boolean;\n setContinuousPlay: (value: boolean) => void;\n setLinkEndpoints: (value: boolean) => void;\n updateAnnotationBoundaries: (params: AnnotationUpdateParams) => Annotation[];\n}\n\n/**\n * Hook for managing annotation control state and boundary logic.\n * Handles continuous play mode and linked endpoints behavior.\n */\nexport const useAnnotationControls = (\n options: UseAnnotationControlsOptions = {}\n): UseAnnotationControlsReturn => {\n const {\n initialContinuousPlay = false,\n initialLinkEndpoints = true,\n } = options;\n\n const [continuousPlay, setContinuousPlay] = useState(initialContinuousPlay);\n const [linkEndpoints, setLinkEndpoints] = useState(initialLinkEndpoints);\n\n /**\n * Updates annotation boundaries based on drag operations.\n * Handles linked endpoints and collision detection.\n * Note: linkEndpoints is passed as a parameter to ensure it uses the current value from context.\n */\n const updateAnnotationBoundaries = useCallback(\n ({\n annotationIndex,\n newTime,\n isDraggingStart,\n annotations,\n duration,\n linkEndpoints: shouldLinkEndpoints,\n }: AnnotationUpdateParams): Annotation[] => {\n const updatedAnnotations = [...annotations];\n const annotation = annotations[annotationIndex];\n\n if (isDraggingStart) {\n // Dragging start edge\n const constrainedStart = Math.min(annotation.end - 0.1, Math.max(0, newTime));\n const delta = constrainedStart - annotation.start;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n start: constrainedStart,\n };\n\n if (shouldLinkEndpoints && annotationIndex > 0) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const prevAnnotation = updatedAnnotations[annotationIndex - 1];\n\n if (Math.abs(prevAnnotation.end - annotation.start) < LINK_THRESHOLD) {\n // Already linked: move previous annotation's end together with this start\n updatedAnnotations[annotationIndex - 1] = {\n ...prevAnnotation,\n end: Math.max(prevAnnotation.start + 0.1, prevAnnotation.end + delta),\n };\n } else if (constrainedStart <= prevAnnotation.end) {\n // Dragged past previous annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n start: prevAnnotation.end,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex > 0 && constrainedStart < updatedAnnotations[annotationIndex - 1].end) {\n // Collision detection: push previous annotation's end back\n updatedAnnotations[annotationIndex - 1] = {\n ...updatedAnnotations[annotationIndex - 1],\n end: constrainedStart,\n };\n }\n } else {\n // Dragging end edge\n const constrainedEnd = Math.max(annotation.start + 0.1, Math.min(newTime, duration));\n const delta = constrainedEnd - annotation.end;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n end: constrainedEnd,\n };\n\n if (shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n if (Math.abs(nextAnnotation.start - annotation.end) < LINK_THRESHOLD) {\n // Already linked: move next annotation's start together with this end\n const newStart = nextAnnotation.start + delta;\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: Math.min(nextAnnotation.end - 0.1, newStart),\n };\n\n // Cascade linked endpoints\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (Math.abs(next.start - current.end) < LINK_THRESHOLD) {\n const nextDelta = current.end - annotations[currentIndex].end;\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: Math.min(next.end - 0.1, next.start + nextDelta),\n };\n currentIndex++;\n } else {\n break; // No more linked endpoints\n }\n }\n } else if (constrainedEnd >= nextAnnotation.start) {\n // Dragged past next annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n end: nextAnnotation.start,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1 && constrainedEnd > updatedAnnotations[annotationIndex + 1].start) {\n // Collision detection: push next annotation's start forward\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: constrainedEnd,\n };\n\n // Cascade collisions\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (current.end > next.start) {\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: current.end,\n };\n currentIndex++;\n } else {\n break; // No more collisions\n }\n }\n }\n }\n\n return updatedAnnotations;\n },\n []\n );\n\n return {\n continuousPlay,\n linkEndpoints,\n setContinuousPlay,\n setLinkEndpoints,\n updateAnnotationBoundaries,\n };\n};\n"],"mappings":"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","names":["styled","jsx","jsxs","styled","jsx","jsxs","styled","usePlaylistInfo","jsx","jsxs","Container","ControlsPlaceholder","React","styled","jsx","jsxs","Container","ControlButton","AnnotationText","jsx","jsxs","BaseCheckboxWrapper","BaseCheckbox","BaseCheckboxLabel","jsx","jsxs","BaseCheckboxWrapper","BaseCheckbox","BaseCheckboxLabel","jsx","jsxs","styled","jsx","styled","useState"]}
1
+ {"version":3,"sources":["../src/parsers/aeneas.ts","../src/components/Annotation.tsx","../src/components/AnnotationBox.tsx","../src/components/AnnotationBoxesWrapper.tsx","../src/components/AnnotationsTrack.tsx","../src/components/AnnotationText.tsx","../src/components/ContinuousPlayCheckbox.tsx","../src/components/LinkEndpointsCheckbox.tsx","../src/components/EditableCheckbox.tsx","../src/components/DownloadAnnotationsButton.tsx","../src/hooks/useAnnotationControls.ts"],"sourcesContent":["import { Annotation } from '../types';\n\nexport interface AeneasFragment {\n begin: string;\n end: string;\n id: string;\n language: string;\n lines: string[];\n}\n\nexport function parseAeneas(data: AeneasFragment): Annotation {\n return {\n id: data.id,\n start: parseFloat(data.begin),\n end: parseFloat(data.end),\n lines: data.lines,\n lang: data.language,\n };\n}\n\nexport function serializeAeneas(annotation: Annotation): AeneasFragment {\n return {\n id: annotation.id,\n begin: annotation.start.toFixed(3),\n end: annotation.end.toFixed(3),\n lines: annotation.lines,\n language: annotation.lang || 'en',\n };\n}\n","import React, { FunctionComponent, useState } from 'react';\nimport styled from 'styled-components';\n\ninterface AnnotationOverlayProps {\n readonly $left: number;\n readonly $width: number;\n readonly $color: string;\n}\n\nconst AnnotationOverlay = styled.div.attrs<AnnotationOverlayProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<AnnotationOverlayProps>`\n position: absolute;\n top: 0;\n background: ${(props) => props.$color};\n height: 100%;\n z-index: 10;\n pointer-events: auto;\n opacity: 0.3;\n border: 2px solid ${(props) => props.$color};\n border-radius: 4px;\n cursor: pointer;\n\n &:hover {\n opacity: 0.5;\n border-color: ${(props) => props.$color};\n }\n`;\n\nconst AnnotationText = styled.div`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: hidden;\n text-overflow: ellipsis;\n pointer-events: none;\n white-space: pre-wrap;\n word-break: break-word;\n`;\n\nconst EditableText = styled.textarea`\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.9);\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n line-height: 1.3;\n max-height: 60%;\n overflow: auto;\n border: 1px solid #fff;\n resize: none;\n font-family: inherit;\n\n &:focus {\n outline: none;\n border-color: #4CAF50;\n }\n`;\n\nconst ControlsBar = styled.div`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n gap: 4px;\n padding: 4px;\n justify-content: flex-start;\n align-items: center;\n`;\n\nconst ControlButton = styled.button`\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.5);\n color: white;\n padding: 4px 8px;\n font-size: 10px;\n cursor: pointer;\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n border-color: white;\n }\n\n &:active {\n background: rgba(255, 255, 255, 0.3);\n }\n`;\n\n/**\n * Configuration options passed to annotation action handlers\n */\nexport interface AnnotationActionOptions {\n /** Whether annotation endpoints are linked (moving one endpoint moves the other) */\n linkEndpoints?: boolean;\n /** Whether to continue playing after an annotation ends */\n continuousPlay?: boolean;\n /** Additional custom properties */\n [key: string]: unknown;\n}\n\nexport interface AnnotationAction {\n class?: string;\n text?: string;\n title: string;\n action: (annotation: AnnotationData, index: number, annotations: AnnotationData[], opts: AnnotationActionOptions) => void;\n}\n\nexport interface AnnotationData {\n id: string;\n start: number;\n end: number;\n lines: string[];\n language?: string;\n}\n\nexport interface AnnotationProps {\n annotation: AnnotationData;\n index: number;\n allAnnotations: AnnotationData[];\n startPosition: number; // Start position in pixels\n endPosition: number; // End position in pixels\n color?: string;\n editable?: boolean;\n controls?: AnnotationAction[];\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n annotationListConfig?: AnnotationActionOptions;\n onClick?: (annotation: AnnotationData) => void;\n}\n\nexport const Annotation: FunctionComponent<AnnotationProps> = ({\n annotation,\n index,\n allAnnotations,\n startPosition,\n endPosition,\n color = '#ff9800',\n editable = false,\n controls = [],\n onAnnotationUpdate,\n annotationListConfig,\n onClick,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editedText, setEditedText] = useState(annotation.lines.join('\\n'));\n const width = Math.max(0, endPosition - startPosition);\n\n if (width <= 0) {\n return null;\n }\n\n const handleClick = () => {\n if (onClick) {\n onClick(annotation);\n }\n };\n\n const handleDoubleClick = () => {\n if (editable) {\n setIsEditing(true);\n }\n };\n\n const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setEditedText(e.target.value);\n };\n\n const handleTextBlur = () => {\n setIsEditing(false);\n const newLines = editedText.split('\\n');\n if (newLines.join('\\n') !== annotation.lines.join('\\n')) {\n const updatedAnnotations = [...allAnnotations];\n updatedAnnotations[index] = { ...annotation, lines: newLines };\n if (onAnnotationUpdate) {\n onAnnotationUpdate(updatedAnnotations);\n }\n }\n };\n\n const handleControlClick = (control: AnnotationAction) => {\n const annotationsCopy = [...allAnnotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n if (onAnnotationUpdate) {\n onAnnotationUpdate(annotationsCopy);\n }\n };\n\n const getIconClass = (classString: string) => {\n // Convert \"fas.fa-minus\" to \"fas fa-minus\"\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <AnnotationOverlay\n $left={startPosition}\n $width={width}\n $color={color}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n >\n {controls.length > 0 && (\n <ControlsBar>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={(e) => {\n e.stopPropagation();\n handleControlClick(control);\n }}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </ControlsBar>\n )}\n {isEditing ? (\n <EditableText\n value={editedText}\n onChange={handleTextChange}\n onBlur={handleTextBlur}\n autoFocus\n onClick={(e) => e.stopPropagation()}\n onDoubleClick={(e) => e.stopPropagation()}\n />\n ) : (\n <AnnotationText>\n {annotation.lines.join('\\n')}\n </AnnotationText>\n )}\n </AnnotationOverlay>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { useDraggable } from '@dnd-kit/core';\nimport type { DraggableAttributes } from '@dnd-kit/core';\nimport type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';\n\ninterface WrapperProps {\n readonly $left: number;\n readonly $width: number;\n}\n\n// Wrapper positions the annotation and contains both Box and ResizeHandles as siblings\nconst Wrapper = styled.div.attrs<WrapperProps>((props) => ({\n style: {\n left: `${props.$left}px`,\n width: `${props.$width}px`,\n },\n}))<WrapperProps>`\n position: absolute;\n top: 0;\n height: 100%;\n pointer-events: none; /* Let events pass through to children */\n`;\n\ninterface BoxProps {\n readonly $color: string;\n readonly $isActive?: boolean;\n}\n\nconst Box = styled.div<BoxProps>`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBackground || 'rgba(255, 200, 100, 0.95)')\n : (props.theme?.annotationBoxBackground || 'rgba(255, 255, 255, 0.85)')};\n border: ${(props) => props.$isActive ? '3px' : '2px'} solid ${(props) => props.$isActive\n ? (props.theme?.annotationBoxActiveBorder || '#ff9800')\n : props.$color};\n border-radius: 4px;\n cursor: pointer;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n transition: all 0.2s ease;\n box-shadow: ${(props) => props.$isActive\n ? '0 2px 8px rgba(255, 152, 0, 0.4), inset 0 0 0 1px rgba(255, 152, 0, 0.2)'\n : '0 1px 3px rgba(0, 0, 0, 0.1)'};\n\n &:hover {\n background: ${(props) => props.theme?.annotationBoxHoverBackground || 'rgba(255, 255, 255, 0.98)'};\n border-color: ${(props) => props.theme?.annotationBoxActiveBorder || '#ff9800'};\n border-width: 3px;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n }\n`;\n\nconst Label = styled.span`\n font-size: 12px;\n font-weight: 600;\n color: ${(props) => props.theme?.annotationLabelColor || '#2a2a2a'};\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding: 0 6px;\n letter-spacing: 0.3px;\n user-select: none;\n`;\n\ninterface ResizeHandleStyledProps {\n $position: 'left' | 'right';\n $isDragging?: boolean;\n}\n\n// ResizeHandles are now siblings of Box, positioned relative to Wrapper\n// Reduced from 30px/-15px to 16px/-8px to minimize overlap between adjacent annotations\nconst ResizeHandle = styled.div<ResizeHandleStyledProps>`\n position: absolute;\n top: 0;\n ${(props) => props.$position === 'left' ? 'left: -8px' : 'right: -8px'};\n width: 16px;\n height: 100%;\n cursor: ew-resize;\n z-index: 120; /* Above ClickOverlay (z-index: 100) and AnnotationBoxesWrapper (z-index: 110) */\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.2)')\n : 'transparent'};\n border-radius: 4px;\n touch-action: none; /* Important for @dnd-kit on touch devices */\n pointer-events: auto;\n\n &::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 4px;\n height: 60%;\n background: ${(props) => props.$isDragging\n ? (props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.8)')\n : (props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.4)')};\n border-radius: 2px;\n opacity: ${(props) => props.$isDragging ? 1 : 0.6};\n transition: opacity 0.2s, background 0.2s;\n }\n\n &:hover {\n background: ${(props) => props.theme?.annotationResizeHandleColor || 'rgba(0, 0, 0, 0.1)'};\n }\n\n &:hover::before {\n opacity: 1;\n background: ${(props) => props.theme?.annotationResizeHandleActiveColor || 'rgba(0, 0, 0, 0.7)'};\n }\n`;\n\nexport interface DragHandleProps {\n attributes: DraggableAttributes;\n listeners: SyntheticListenerMap | undefined;\n setActivatorNodeRef: (element: HTMLElement | null) => void;\n isDragging: boolean;\n}\n\nexport interface AnnotationBoxComponentProps {\n annotationId: string;\n annotationIndex: number;\n startPosition: number;\n endPosition: number;\n label?: string;\n color?: string;\n isActive?: boolean;\n onClick?: () => void;\n editable?: boolean; // Whether to show drag handles\n}\n\nexport const AnnotationBox: FunctionComponent<AnnotationBoxComponentProps> = ({\n annotationId,\n annotationIndex,\n startPosition,\n endPosition,\n label,\n color = '#ff9800',\n isActive = false,\n onClick,\n editable = true,\n}) => {\n const width = Math.max(0, endPosition - startPosition);\n\n // Left (start) boundary draggable\n const leftBoundaryId = `annotation-boundary-start-${annotationIndex}`;\n const {\n attributes: leftAttributes,\n listeners: leftListeners,\n setActivatorNodeRef: setLeftActivatorRef,\n isDragging: isLeftDragging,\n } = useDraggable({\n id: leftBoundaryId,\n data: { annotationId, annotationIndex, edge: 'start' as const },\n disabled: !editable,\n });\n\n // Right (end) boundary draggable\n const rightBoundaryId = `annotation-boundary-end-${annotationIndex}`;\n const {\n attributes: rightAttributes,\n listeners: rightListeners,\n setActivatorNodeRef: setRightActivatorRef,\n isDragging: isRightDragging,\n } = useDraggable({\n id: rightBoundaryId,\n data: { annotationId, annotationIndex, edge: 'end' as const },\n disabled: !editable,\n });\n\n if (width <= 0) {\n return null;\n }\n\n // Wrap @dnd-kit pointer handlers to also stop propagation\n // This prevents the ClickOverlay from capturing the event\n const createPointerDownHandler = (dndKitHandler?: (e: React.PointerEvent) => void) => {\n return (e: React.PointerEvent) => {\n e.stopPropagation();\n dndKitHandler?.(e);\n };\n };\n\n const handleHandleClick = (e: React.MouseEvent) => {\n // Prevent clicks on resize handles from bubbling to annotation box\n e.stopPropagation();\n };\n\n return (\n <Wrapper $left={startPosition} $width={width}>\n <Box\n $color={color}\n $isActive={isActive}\n onClick={onClick}\n >\n {label && <Label>{label}</Label>}\n </Box>\n {editable && (\n <ResizeHandle\n ref={setLeftActivatorRef}\n $position=\"left\"\n $isDragging={isLeftDragging}\n onClick={handleHandleClick}\n {...leftListeners}\n onPointerDown={createPointerDownHandler(leftListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...leftAttributes}\n />\n )}\n {editable && (\n <ResizeHandle\n ref={setRightActivatorRef}\n $position=\"right\"\n $isDragging={isRightDragging}\n onClick={handleHandleClick}\n {...rightListeners}\n onPointerDown={createPointerDownHandler(rightListeners?.onPointerDown as ((e: React.PointerEvent) => void) | undefined)}\n {...rightAttributes}\n />\n )}\n </Wrapper>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n z-index: 110;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n`;\n\nconst BoxesContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationBoxesWrapperProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationBoxesWrapper: FunctionComponent<AnnotationBoxesWrapperProps> = ({\n children,\n className,\n height = 30,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0} />\n <BoxesContainer $offset={offset}>\n {children}\n </BoxesContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent } from 'react';\nimport styled from 'styled-components';\nimport { usePlaylistInfo } from '@waveform-playlist/ui-components';\n\ninterface ContainerProps {\n readonly $height: number;\n readonly $controlWidth: number;\n readonly $width?: number;\n}\n\nconst Container = styled.div.attrs<ContainerProps>((props) => ({\n style: {\n height: `${props.$height}px`,\n },\n}))<ContainerProps>`\n position: relative;\n display: flex;\n ${(props) => props.$width !== undefined && `width: ${props.$width}px;`}\n background: transparent;\n`;\n\nconst ControlsPlaceholder = styled.div<{ $controlWidth: number }>`\n position: sticky;\n z-index: 200;\n left: 0;\n height: 100%;\n width: ${(props) => props.$controlWidth}px;\n flex-shrink: 0;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n font-weight: bold;\n`;\n\nconst AnnotationsContainer = styled.div<{ $offset?: number }>`\n position: relative;\n flex: 1;\n padding-left: ${(props) => props.$offset || 0}px;\n`;\n\nexport interface AnnotationsTrackProps {\n className?: string;\n children?: React.ReactNode;\n height?: number;\n offset?: number;\n width?: number;\n}\n\nexport const AnnotationsTrack: FunctionComponent<AnnotationsTrackProps> = ({\n children,\n className,\n height = 100,\n offset = 0,\n width,\n}) => {\n const {\n controls: { show, width: controlWidth },\n } = usePlaylistInfo();\n\n return (\n <Container\n className={className}\n $height={height}\n $controlWidth={show ? controlWidth : 0}\n $width={width}\n >\n <ControlsPlaceholder $controlWidth={show ? controlWidth : 0}>\n Annotations\n </ControlsPlaceholder>\n <AnnotationsContainer $offset={offset}>\n {children}\n </AnnotationsContainer>\n </Container>\n );\n};\n","import React, { FunctionComponent, useRef, useEffect } from 'react';\nimport styled from 'styled-components';\nimport type { AnnotationData, AnnotationAction, AnnotationActionOptions } from './Annotation';\n\ninterface ContainerProps {\n $height?: number;\n}\n\nconst Container = styled.div<ContainerProps>`\n background: ${(props) => props.theme?.backgroundColor || '#fff'};\n ${(props) => props.$height ? `height: ${props.$height}px;` : 'max-height: 200px;'}\n overflow-y: auto;\n padding: 8px;\n`;\n\nconst AnnotationItem = styled.div<{ $isActive?: boolean }>`\n padding: 12px;\n margin-bottom: 6px;\n border-left: 4px solid ${(props) => (props.$isActive ? '#ff9800' : 'transparent')};\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.15)' : 'transparent')};\n border-radius: 4px;\n transition: all 0.2s;\n cursor: pointer;\n box-shadow: ${(props) => (props.$isActive ? '0 2px 8px rgba(255, 152, 0, 0.25), inset 0 0 0 1px rgba(255, 152, 0, 0.3)' : 'none')};\n\n &:hover {\n background: ${(props) => (props.$isActive ? 'rgba(255, 152, 0, 0.2)' : props.theme?.annotationTextItemHoverBackground || 'rgba(0, 0, 0, 0.05)')};\n border-left-color: ${(props) => (props.$isActive ? '#ff9800' : props.theme?.borderColor || '#ddd')};\n }\n\n &:focus-visible {\n outline: 2px solid #ff9800;\n outline-offset: 2px;\n }\n`;\n\nconst AnnotationHeader = styled.div`\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n`;\n\nconst AnnotationInfo = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n`;\n\nconst AnnotationIdLabel = styled.span<{ $isEditable?: boolean }>`\n font-size: 11px;\n font-weight: 600;\n color: ${(props) => props.theme?.textColorMuted || '#666'};\n background: transparent;\n padding: 2px 6px;\n border-radius: 3px;\n min-width: 20px;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\nconst TimeRange = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: ${(props) => props.theme?.textColorMuted || '#555'};\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n letter-spacing: 0.5px;\n`;\n\nconst AnnotationControls = styled.div`\n display: flex;\n gap: 6px;\n`;\n\nconst ControlButton = styled.button`\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n color: ${(props) => props.theme?.textColor || '#333'};\n padding: 4px 8px;\n font-size: 14px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n\n &:hover {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n transform: scale(1.05);\n }\n\n &:active {\n transform: scale(0.95);\n }\n`;\n\nconst AnnotationTextContent = styled.div<{ $isEditable?: boolean }>`\n font-size: 14px;\n line-height: 1.6;\n color: ${(props) => props.theme?.textColor || '#2a2a2a'};\n white-space: pre-wrap;\n word-break: break-word;\n outline: ${(props) => (props.$isEditable ? `1px dashed ${props.theme?.borderColor || '#ddd'}` : 'none')};\n padding: ${(props) => (props.$isEditable ? '6px' : '0')};\n border-radius: 3px;\n min-height: 20px;\n\n &[contenteditable='true']:focus {\n outline: 2px solid #ff9800;\n background: rgba(255, 152, 0, 0.1);\n }\n`;\n\n/**\n * Props passed to the renderAnnotationItem function for custom rendering\n */\nexport interface RenderAnnotationItemProps {\n annotation: AnnotationData;\n index: number;\n isActive: boolean;\n onClick: () => void;\n formatTime: (seconds: number) => string;\n}\n\nexport interface AnnotationTextProps {\n annotations: AnnotationData[];\n activeAnnotationId?: string;\n shouldScrollToActive?: boolean;\n /** Where to position the active annotation when scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */\n scrollActivePosition?: ScrollLogicalPosition;\n /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */\n scrollActiveContainer?: 'nearest' | 'all';\n editable?: boolean;\n controls?: AnnotationAction[];\n annotationListConfig?: AnnotationActionOptions;\n height?: number;\n onAnnotationClick?: (annotation: AnnotationData) => void;\n onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;\n /**\n * Custom render function for annotation items.\n * When provided, completely replaces the default annotation item rendering.\n * Use this to customize the appearance of each annotation in the list.\n */\n renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode;\n}\n\nconst AnnotationTextComponent: FunctionComponent<AnnotationTextProps> = ({\n annotations,\n activeAnnotationId,\n shouldScrollToActive = false,\n scrollActivePosition = 'center',\n scrollActiveContainer = 'nearest',\n editable = false,\n controls = [],\n annotationListConfig,\n height,\n onAnnotationClick,\n onAnnotationUpdate,\n renderAnnotationItem,\n}) => {\n const activeAnnotationRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevActiveIdRef = useRef<string | undefined>(undefined);\n\n // Track component renders and scroll position\n useEffect(() => {\n // Render tracking removed\n });\n\n // Track scroll changes\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n // Scroll tracking removed\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, []);\n\n // Auto-scroll to active annotation when it changes\n useEffect(() => {\n // Only scroll if parent says we should (prevents scrolling on remount after pause)\n if (activeAnnotationId && activeAnnotationRef.current && shouldScrollToActive) {\n activeAnnotationRef.current.scrollIntoView({\n behavior: 'smooth',\n block: scrollActivePosition,\n container: scrollActiveContainer,\n } as ScrollIntoViewOptions);\n }\n\n prevActiveIdRef.current = activeAnnotationId;\n }, [activeAnnotationId, shouldScrollToActive, scrollActivePosition, scrollActiveContainer]);\n\n const formatTime = (seconds: number): string => {\n if (isNaN(seconds) || !isFinite(seconds)) {\n return '0:00.000';\n }\n const mins = Math.floor(seconds / 60);\n const secs = (seconds % 60).toFixed(3);\n return `${mins}:${secs.padStart(6, '0')}`;\n };\n\n const handleTextEdit = (index: number, newText: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n lines: newText.split('\\n'),\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleIdEdit = (index: number, newId: string) => {\n if (!editable || !onAnnotationUpdate) return;\n\n const trimmedId = newId.trim();\n if (!trimmedId) return; // Don't allow empty IDs\n\n const updatedAnnotations = [...annotations];\n updatedAnnotations[index] = {\n ...updatedAnnotations[index],\n id: trimmedId,\n };\n onAnnotationUpdate(updatedAnnotations);\n };\n\n const handleControlClick = (control: AnnotationAction, annotation: AnnotationData, index: number) => {\n if (!onAnnotationUpdate) return;\n\n const annotationsCopy = [...annotations];\n control.action(annotationsCopy[index], index, annotationsCopy, annotationListConfig || {});\n onAnnotationUpdate(annotationsCopy);\n };\n\n const getIconClass = (classString: string) => {\n return classString.replace(/\\./g, ' ');\n };\n\n return (\n <Container ref={containerRef} $height={height}>\n {annotations.map((annotation, index) => {\n const isActive = annotation.id === activeAnnotationId;\n const handleClick = () => onAnnotationClick?.(annotation);\n\n // Use custom render function if provided\n if (renderAnnotationItem) {\n return (\n <div\n key={annotation.id}\n ref={isActive ? activeAnnotationRef : null}\n >\n {renderAnnotationItem({\n annotation,\n index,\n isActive,\n onClick: handleClick,\n formatTime,\n })}\n </div>\n );\n }\n\n // Default rendering\n return (\n <AnnotationItem\n key={annotation.id}\n ref={isActive ? activeAnnotationRef : null}\n $isActive={isActive}\n onClick={handleClick}\n >\n <AnnotationHeader>\n <AnnotationInfo>\n <AnnotationIdLabel\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleIdEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.id}\n </AnnotationIdLabel>\n <TimeRange>\n {formatTime(annotation.start)} - {formatTime(annotation.end)}\n </TimeRange>\n </AnnotationInfo>\n {controls.length > 0 && (\n <AnnotationControls onClick={(e) => e.stopPropagation()}>\n {controls.map((control, idx) => (\n <ControlButton\n key={idx}\n title={control.title}\n onClick={() => handleControlClick(control, annotation, index)}\n >\n {control.text ? control.text : <i className={getIconClass(control.class || '')} />}\n </ControlButton>\n ))}\n </AnnotationControls>\n )}\n </AnnotationHeader>\n <AnnotationTextContent\n $isEditable={editable}\n contentEditable={editable}\n suppressContentEditableWarning\n onBlur={(e) => handleTextEdit(index, e.currentTarget.textContent || '')}\n >\n {annotation.lines.join('\\n')}\n </AnnotationTextContent>\n </AnnotationItem>\n );\n })}\n </Container>\n );\n};\n\n// Memoize to prevent unnecessary remounting when parent re-renders\nexport const AnnotationText = React.memo(AnnotationTextComponent);\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface ContinuousPlayCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling continuous play of annotations.\n * When enabled, playback continues from one annotation to the next without stopping.\n */\nexport const ContinuousPlayCheckbox: React.FC<ContinuousPlayCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"continuous-play\"\n className=\"continuous-play\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"continuous-play\">Continuous Play</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface LinkEndpointsCheckboxProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Checkbox control for enabling/disabling linked endpoints between annotations.\n * When enabled, the end time of one annotation is automatically linked to the start time of the next.\n */\nexport const LinkEndpointsCheckbox: React.FC<LinkEndpointsCheckboxProps> = ({\n checked,\n onChange,\n disabled = false,\n className,\n}) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"link-endpoints\"\n className=\"link-endpoints\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n />\n <BaseCheckboxLabel htmlFor=\"link-endpoints\">Link Endpoints</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport { BaseCheckboxWrapper, BaseCheckbox, BaseCheckboxLabel } from '@waveform-playlist/ui-components';\n\nexport interface EditableCheckboxProps {\n checked: boolean;\n onChange: (enabled: boolean) => void;\n className?: string;\n}\n\nexport const EditableCheckbox: React.FC<EditableCheckboxProps> = ({\n checked,\n onChange,\n className,\n}) => {\n return (\n <BaseCheckboxWrapper className={className}>\n <BaseCheckbox\n type=\"checkbox\"\n id=\"editable-annotations\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n />\n <BaseCheckboxLabel htmlFor=\"editable-annotations\">Editable Annotations</BaseCheckboxLabel>\n </BaseCheckboxWrapper>\n );\n};\n","import React from 'react';\nimport styled from 'styled-components';\nimport { serializeAeneas } from '../parsers/aeneas';\nimport type { Annotation } from '../types';\n\nconst StyledButton = styled.button`\n padding: 0.5rem 1rem;\n background: ${(props) => props.theme?.surfaceColor || '#f5f5f5'};\n color: ${(props) => props.theme?.textColor || '#333'};\n border: 1px solid ${(props) => props.theme?.borderColor || '#ccc'};\n border-radius: ${(props) => props.theme?.borderRadius || '4px'};\n cursor: pointer;\n font-family: ${(props) => props.theme?.fontFamily || 'inherit'};\n font-size: ${(props) => props.theme?.fontSize || '14px'};\n font-weight: 500;\n transition: all 0.15s ease;\n\n &:hover:not(:disabled) {\n background: ${(props) => props.theme?.inputBackground || '#3d3d3d'};\n border-color: ${(props) => props.theme?.textColorMuted || '#999'};\n }\n\n &:focus {\n outline: none;\n box-shadow: 0 0 0 2px ${(props) => props.theme?.inputFocusBorder || '#007bff'}44;\n }\n\n &:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n`;\n\nexport interface DownloadAnnotationsButtonProps {\n annotations: Annotation[];\n filename?: string;\n disabled?: boolean;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport const DownloadAnnotationsButton: React.FC<DownloadAnnotationsButtonProps> = ({\n annotations,\n filename = 'annotations.json',\n disabled = false,\n className,\n children = 'Download JSON',\n}) => {\n const handleDownload = () => {\n if (annotations.length === 0) {\n return;\n }\n\n // Serialize annotations to Aeneas JSON format\n const jsonData = annotations.map(annotation => serializeAeneas(annotation));\n const jsonString = JSON.stringify(jsonData, null, 2);\n\n // Create a blob and download link\n const blob = new Blob([jsonString], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n\n // Trigger download\n document.body.appendChild(link);\n link.click();\n\n // Cleanup\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n };\n\n return (\n <StyledButton\n onClick={handleDownload}\n disabled={disabled || annotations.length === 0}\n className={className}\n title={annotations.length === 0 ? 'No annotations to download' : 'Download the annotations as JSON'}\n >\n {children}\n </StyledButton>\n );\n};\n","import { useState, useCallback } from 'react';\nimport type { Annotation, AnnotationListOptions } from '../types';\n\nconst LINK_THRESHOLD = 0.01; // Consider edges \"linked\" if within 10ms\n\nexport interface UseAnnotationControlsOptions {\n initialContinuousPlay?: boolean;\n initialLinkEndpoints?: boolean;\n}\n\nexport interface AnnotationUpdateParams {\n annotationIndex: number;\n newTime: number;\n isDraggingStart: boolean;\n annotations: Annotation[];\n duration: number;\n linkEndpoints: boolean;\n}\n\nexport interface UseAnnotationControlsReturn {\n continuousPlay: boolean;\n linkEndpoints: boolean;\n setContinuousPlay: (value: boolean) => void;\n setLinkEndpoints: (value: boolean) => void;\n updateAnnotationBoundaries: (params: AnnotationUpdateParams) => Annotation[];\n}\n\n/**\n * Hook for managing annotation control state and boundary logic.\n * Handles continuous play mode and linked endpoints behavior.\n */\nexport const useAnnotationControls = (\n options: UseAnnotationControlsOptions = {}\n): UseAnnotationControlsReturn => {\n const {\n initialContinuousPlay = false,\n initialLinkEndpoints = true,\n } = options;\n\n const [continuousPlay, setContinuousPlay] = useState(initialContinuousPlay);\n const [linkEndpoints, setLinkEndpoints] = useState(initialLinkEndpoints);\n\n /**\n * Updates annotation boundaries based on drag operations.\n * Handles linked endpoints and collision detection.\n * Note: linkEndpoints is passed as a parameter to ensure it uses the current value from context.\n */\n const updateAnnotationBoundaries = useCallback(\n ({\n annotationIndex,\n newTime,\n isDraggingStart,\n annotations,\n duration,\n linkEndpoints: shouldLinkEndpoints,\n }: AnnotationUpdateParams): Annotation[] => {\n const updatedAnnotations = [...annotations];\n const annotation = annotations[annotationIndex];\n\n if (isDraggingStart) {\n // Dragging start edge\n const constrainedStart = Math.min(annotation.end - 0.1, Math.max(0, newTime));\n const delta = constrainedStart - annotation.start;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n start: constrainedStart,\n };\n\n if (shouldLinkEndpoints && annotationIndex > 0) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const prevAnnotation = updatedAnnotations[annotationIndex - 1];\n\n if (Math.abs(prevAnnotation.end - annotation.start) < LINK_THRESHOLD) {\n // Already linked: move previous annotation's end together with this start\n updatedAnnotations[annotationIndex - 1] = {\n ...prevAnnotation,\n end: Math.max(prevAnnotation.start + 0.1, prevAnnotation.end + delta),\n };\n } else if (constrainedStart <= prevAnnotation.end) {\n // Dragged past previous annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n start: prevAnnotation.end,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex > 0 && constrainedStart < updatedAnnotations[annotationIndex - 1].end) {\n // Collision detection: push previous annotation's end back\n updatedAnnotations[annotationIndex - 1] = {\n ...updatedAnnotations[annotationIndex - 1],\n end: constrainedStart,\n };\n }\n } else {\n // Dragging end edge\n const constrainedEnd = Math.max(annotation.start + 0.1, Math.min(newTime, duration));\n const delta = constrainedEnd - annotation.end;\n\n updatedAnnotations[annotationIndex] = {\n ...annotation,\n end: constrainedEnd,\n };\n\n if (shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1) {\n // Link Endpoints mode: handle both already-linked and collision scenarios\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n if (Math.abs(nextAnnotation.start - annotation.end) < LINK_THRESHOLD) {\n // Already linked: move next annotation's start together with this end\n const newStart = nextAnnotation.start + delta;\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: Math.min(nextAnnotation.end - 0.1, newStart),\n };\n\n // Cascade linked endpoints\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (Math.abs(next.start - current.end) < LINK_THRESHOLD) {\n const nextDelta = current.end - annotations[currentIndex].end;\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: Math.min(next.end - 0.1, next.start + nextDelta),\n };\n currentIndex++;\n } else {\n break; // No more linked endpoints\n }\n }\n } else if (constrainedEnd >= nextAnnotation.start) {\n // Dragged past next annotation: snap to link them together\n updatedAnnotations[annotationIndex] = {\n ...updatedAnnotations[annotationIndex],\n end: nextAnnotation.start,\n };\n }\n } else if (!shouldLinkEndpoints && annotationIndex < updatedAnnotations.length - 1 && constrainedEnd > updatedAnnotations[annotationIndex + 1].start) {\n // Collision detection: push next annotation's start forward\n const nextAnnotation = updatedAnnotations[annotationIndex + 1];\n\n updatedAnnotations[annotationIndex + 1] = {\n ...nextAnnotation,\n start: constrainedEnd,\n };\n\n // Cascade collisions\n let currentIndex = annotationIndex + 1;\n while (currentIndex < updatedAnnotations.length - 1) {\n const current = updatedAnnotations[currentIndex];\n const next = updatedAnnotations[currentIndex + 1];\n\n if (current.end > next.start) {\n updatedAnnotations[currentIndex + 1] = {\n ...next,\n start: current.end,\n };\n currentIndex++;\n } else {\n break; // No more collisions\n }\n }\n }\n }\n\n return updatedAnnotations;\n },\n []\n );\n\n return {\n continuousPlay,\n linkEndpoints,\n setContinuousPlay,\n setLinkEndpoints,\n updateAnnotationBoundaries,\n };\n};\n"],"mappings":"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","names":["styled","jsx","jsxs","styled","jsx","jsxs","styled","usePlaylistInfo","jsx","jsxs","Container","ControlsPlaceholder","React","styled","jsx","jsxs","Container","ControlButton","AnnotationText","jsx","jsxs","BaseCheckboxWrapper","BaseCheckbox","BaseCheckboxLabel","jsx","jsxs","BaseCheckboxWrapper","BaseCheckbox","BaseCheckboxLabel","jsx","jsxs","styled","jsx","styled","useState"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waveform-playlist/annotations",
3
- "version": "5.0.0-alpha.8",
3
+ "version": "5.0.0",
4
4
  "description": "Annotation support for waveform-playlist",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -41,11 +41,12 @@
41
41
  "typescript": "^5.3.3"
42
42
  },
43
43
  "dependencies": {
44
- "@waveform-playlist/ui-components": "5.0.0-alpha.8",
45
- "@waveform-playlist/core": "5.0.0-alpha.8"
44
+ "@waveform-playlist/ui-components": "5.0.0",
45
+ "@waveform-playlist/core": "5.0.0"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@dnd-kit/core": "^6.0.0",
49
+ "@dnd-kit/modifiers": "^9.0.0",
49
50
  "react": "^18.0.0",
50
51
  "styled-components": "^6.0.0"
51
52
  },