Add coexistence checks to all enqueue methods to prevent loading both React and Grid.js assets simultaneously. Changes: - ReactAdmin.php: Only enqueue React assets when ?react=1 - Init.php: Skip Grid.js when React active on admin pages - Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0 - Customer.php, Product.php, License.php: Add coexistence checks Now the toggle between Classic and React versions works correctly. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
199 lines
5.7 KiB
JavaScript
199 lines
5.7 KiB
JavaScript
/**
|
|
* WordPress dependencies
|
|
*/
|
|
import { useRef, useLayoutEffect, useReducer } from '@wordpress/element';
|
|
import { useMergeRefs, useRefEffect } from '@wordpress/compose';
|
|
import { useRegistry } from '@wordpress/data';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import { create, RichTextData } from '../create';
|
|
import { apply } from '../to-dom';
|
|
import { toHTMLString } from '../to-html-string';
|
|
import { useDefaultStyle } from './use-default-style';
|
|
import { useBoundaryStyle } from './use-boundary-style';
|
|
import { useEventListeners } from './event-listeners';
|
|
export function useRichText({
|
|
value = '',
|
|
selectionStart,
|
|
selectionEnd,
|
|
placeholder,
|
|
onSelectionChange,
|
|
preserveWhiteSpace,
|
|
onChange,
|
|
__unstableDisableFormats: disableFormats,
|
|
__unstableIsSelected: isSelected,
|
|
__unstableDependencies = [],
|
|
__unstableAfterParse,
|
|
__unstableBeforeSerialize,
|
|
__unstableAddInvisibleFormats
|
|
}) {
|
|
const registry = useRegistry();
|
|
const [, forceRender] = useReducer(() => ({}));
|
|
const ref = useRef();
|
|
function createRecord() {
|
|
const {
|
|
ownerDocument: {
|
|
defaultView
|
|
}
|
|
} = ref.current;
|
|
const selection = defaultView.getSelection();
|
|
const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
return create({
|
|
element: ref.current,
|
|
range,
|
|
__unstableIsEditableTree: true
|
|
});
|
|
}
|
|
function applyRecord(newRecord, {
|
|
domOnly
|
|
} = {}) {
|
|
apply({
|
|
value: newRecord,
|
|
current: ref.current,
|
|
prepareEditableTree: __unstableAddInvisibleFormats,
|
|
__unstableDomOnly: domOnly,
|
|
placeholder
|
|
});
|
|
}
|
|
|
|
// Internal values are updated synchronously, unlike props and state.
|
|
const _value = useRef(value);
|
|
const record = useRef();
|
|
function setRecordFromProps() {
|
|
_value.current = value;
|
|
record.current = value;
|
|
if (!(value instanceof RichTextData)) {
|
|
record.current = value ? RichTextData.fromHTMLString(value, {
|
|
preserveWhiteSpace
|
|
}) : RichTextData.empty();
|
|
}
|
|
// To do: make rich text internally work with RichTextData.
|
|
record.current = {
|
|
text: record.current.text,
|
|
formats: record.current.formats,
|
|
replacements: record.current.replacements
|
|
};
|
|
if (disableFormats) {
|
|
record.current.formats = Array(value.length);
|
|
record.current.replacements = Array(value.length);
|
|
}
|
|
if (__unstableAfterParse) {
|
|
record.current.formats = __unstableAfterParse(record.current);
|
|
}
|
|
record.current.start = selectionStart;
|
|
record.current.end = selectionEnd;
|
|
}
|
|
const hadSelectionUpdate = useRef(false);
|
|
if (!record.current) {
|
|
hadSelectionUpdate.current = isSelected;
|
|
setRecordFromProps();
|
|
} else if (selectionStart !== record.current.start || selectionEnd !== record.current.end) {
|
|
hadSelectionUpdate.current = isSelected;
|
|
record.current = {
|
|
...record.current,
|
|
start: selectionStart,
|
|
end: selectionEnd,
|
|
activeFormats: undefined
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Sync the value to global state. The node tree and selection will also be
|
|
* updated if differences are found.
|
|
*
|
|
* @param {Object} newRecord The record to sync and apply.
|
|
*/
|
|
function handleChange(newRecord) {
|
|
record.current = newRecord;
|
|
applyRecord(newRecord);
|
|
if (disableFormats) {
|
|
_value.current = newRecord.text;
|
|
} else {
|
|
const newFormats = __unstableBeforeSerialize ? __unstableBeforeSerialize(newRecord) : newRecord.formats;
|
|
newRecord = {
|
|
...newRecord,
|
|
formats: newFormats
|
|
};
|
|
if (typeof value === 'string') {
|
|
_value.current = toHTMLString({
|
|
value: newRecord,
|
|
preserveWhiteSpace
|
|
});
|
|
} else {
|
|
_value.current = new RichTextData(newRecord);
|
|
}
|
|
}
|
|
const {
|
|
start,
|
|
end,
|
|
formats,
|
|
text
|
|
} = record.current;
|
|
|
|
// Selection must be updated first, so it is recorded in history when
|
|
// the content change happens.
|
|
// We batch both calls to only attempt to rerender once.
|
|
registry.batch(() => {
|
|
onSelectionChange(start, end);
|
|
onChange(_value.current, {
|
|
__unstableFormats: formats,
|
|
__unstableText: text
|
|
});
|
|
});
|
|
forceRender();
|
|
}
|
|
function applyFromProps() {
|
|
setRecordFromProps();
|
|
applyRecord(record.current);
|
|
}
|
|
const didMount = useRef(false);
|
|
|
|
// Value updates must happen synchonously to avoid overwriting newer values.
|
|
useLayoutEffect(() => {
|
|
if (didMount.current && value !== _value.current) {
|
|
applyFromProps();
|
|
forceRender();
|
|
}
|
|
}, [value]);
|
|
|
|
// Value updates must happen synchonously to avoid overwriting newer values.
|
|
useLayoutEffect(() => {
|
|
if (!hadSelectionUpdate.current) {
|
|
return;
|
|
}
|
|
if (ref.current.ownerDocument.activeElement !== ref.current) {
|
|
ref.current.focus();
|
|
}
|
|
applyRecord(record.current);
|
|
hadSelectionUpdate.current = false;
|
|
}, [hadSelectionUpdate.current]);
|
|
const mergedRefs = useMergeRefs([ref, useDefaultStyle(), useBoundaryStyle({
|
|
record
|
|
}), useEventListeners({
|
|
record,
|
|
handleChange,
|
|
applyRecord,
|
|
createRecord,
|
|
isSelected,
|
|
onSelectionChange,
|
|
forceRender
|
|
}), useRefEffect(() => {
|
|
applyFromProps();
|
|
didMount.current = true;
|
|
}, [placeholder, ...__unstableDependencies])]);
|
|
return {
|
|
value: record.current,
|
|
// A function to get the most recent value so event handlers in
|
|
// useRichText implementations have access to it. For example when
|
|
// listening to input events, we internally update the state, but this
|
|
// state is not yet available to the input event handler because React
|
|
// may re-render asynchronously.
|
|
getValue: () => record.current,
|
|
onChange: handleChange,
|
|
ref: mergedRefs
|
|
};
|
|
}
|
|
export default function __experimentalRichText() {}
|
|
//# sourceMappingURL=index.js.map
|