← All changes
|
js/components/common/snippets/SnippetPreviewModal.tsx
+28
-7
3.10.2
→
trunk
View file →
| @@ -41,9 +41,16 @@ | ||
| 41 | 41 | * Tracks whether a footer action is in flight. The ref mirrors the state so |
| 42 | 42 | * `beginWorking` can reject re-entry within the same tick, before React |
| 43 | 43 | * re-renders with the disabled buttons. |
| 44 | 44 | */ |
| 45 | -const useWorkingState = () => { | |
| 45 | +export interface PreviewWorkingState { | |
| 46 | + isWorking: boolean | |
| 47 | + beginWorking: () => boolean | |
| 48 | + finishWorking: () => void | |
| 49 | + setIsWorking: (isWorking: boolean) => void | |
| 50 | +} | |
| 51 | + | |
| 52 | +const useWorkingState = (): PreviewWorkingState => { | |
| 46 | 53 | const [isWorking, setIsWorking] = useState(false) |
| 47 | 54 | const isWorkingRef = useRef(false) |
| 48 | 55 | const updateWorking = (value: boolean) => { |
| 49 | 56 | isWorkingRef.current = value |
| @@ -49,9 +56,21 @@ | ||
| 49 | 56 | isWorkingRef.current = value |
| 50 | 57 | setIsWorking(value) |
| 51 | 58 | } |
| 52 | 59 | |
| 53 | - return { isWorking, setIsWorking: updateWorking } | |
| 60 | + return { | |
| 61 | + isWorking, | |
| 62 | + beginWorking: () => { | |
| 63 | + if (isWorkingRef.current) { | |
| 64 | + return false | |
| 65 | + } | |
| 66 | + | |
| 67 | + updateWorking(true) | |
| 68 | + return true | |
| 69 | + }, | |
| 70 | + finishWorking: () => updateWorking(false), | |
| 71 | + setIsWorking: updateWorking | |
| 72 | + } | |
| 54 | 73 | } |
| 55 | 74 | |
| 56 | 75 | enum CopyStatus { Ready, Copied, Failed} |
| 57 | 76 | |
| @@ -86,17 +105,17 @@ | ||
| 86 | 105 | </Button> |
| 87 | 106 | ) |
| 88 | 107 | } |
| 89 | 108 | |
| 90 | -interface PreviewModalProps { | |
| 109 | +export interface PreviewModalProps { | |
| 91 | 110 | onRequestClose: VoidFunction |
| 92 | 111 | title: string |
| 93 | 112 | type: SnippetType |
| 94 | 113 | code: string |
| 95 | - children: ReactNode | |
| 114 | + children?: ReactNode | |
| 96 | 115 | } |
| 97 | 116 | |
| 98 | -const PreviewModal: React.FC<PreviewModalProps> = ({ onRequestClose, title, type, code, children }) => { | |
| 117 | +export const PreviewModal: React.FC<PreviewModalProps> = ({ onRequestClose, title, type, code, children }) => { | |
| 99 | 118 | const textareaRef = useRef<HTMLTextAreaElement>(null) |
| 100 | 119 | |
| 101 | 120 | useEffect(() => { |
| 102 | 121 | if (!textareaRef.current || !window.wp.codeEditor) { |
| @@ -144,9 +163,9 @@ | ||
| 144 | 163 | |
| 145 | 164 | export interface SnippetCodePreviewModalProps { |
| 146 | 165 | snippet: CloudSnippetSchema |
| 147 | 166 | setIsOpen: (isOpen: boolean) => void |
| 148 | - onDownloaded: VoidFunction | |
| 167 | + onDownloaded?: VoidFunction | |
| 149 | 168 | } |
| 150 | 169 | |
| 151 | 170 | export const CloudSnippetPreviewModal: React.FC<SnippetCodePreviewModalProps> = ({ |
| 152 | 171 | snippet, |
| @@ -226,11 +245,12 @@ | ||
| 226 | 245 | |
| 227 | 246 | export interface SnippetPreviewModalProps { |
| 228 | 247 | snippet: Snippet |
| 229 | 248 | setIsOpen: (open: boolean) => void |
| 249 | + extraActions?: (working: boolean) => ReactNode | |
| 230 | 250 | } |
| 231 | 251 | |
| 232 | -export const SnippetPreviewModal: React.FC<SnippetPreviewModalProps> = ({ snippet, setIsOpen }) => { | |
| 252 | +export const SnippetPreviewModal: React.FC<SnippetPreviewModalProps> = ({ snippet, setIsOpen, extraActions }) => { | |
| 233 | 253 | const { refreshSnippetsList } = useSnippetsList() |
| 234 | 254 | const { isWorking, setIsWorking } = useWorkingState() |
| 235 | 255 | |
| 236 | 256 | const { requestDelete, deleteDialogProps } = useDeleteSnippet({ |
| @@ -280,8 +300,9 @@ | ||
| 280 | 300 | <span>{__('Priority', 'code-snippets')}</span> |
| 281 | 301 | <span className="code-snippets-preview-modal__priority-value">{snippet.priority}</span> |
| 282 | 302 | </div> |
| 283 | 303 | |
| 304 | + {extraActions?.(isWorking)} | |
| 284 | 305 | <ConfirmDeleteDialog {...deleteDialogProps} /> |
| 285 | 306 | </div> |
| 286 | 307 | </PreviewModal> |
| 287 | 308 | ) |