ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â ð shadcn/directory/udecode/plate/(plugins)/(functionality)/block-selection.cn â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â
title: åéæ© docs:
åéæ©åèœå è®žçšæ·éæ©åæäœæŽäžªææ¬åïŒèäžæ¯å䞪åè¯æå笊ã
Cmd+AïŒéæ©ææåæ·»å åéæ©åèœæå¿«çæ¹æ³æ¯äœ¿çš BlockSelectionKitïŒå®å
å«é¢é
眮ç BlockSelectionPlugin å BlockSelection UI ç»ä»¶ã
BlockSelectionïŒåšéäžçååšåŽæž²æéæ©ç©åœ¢BlockSelectionKit é»è®€å¯çšäžäžæèåïŒå¹¶æäŸé»è®€ç isSelectable é»èŸæ¥æé€åžžè§çäžå¯éæ©åïŒåŠä»£ç è¡åè¡šæ Œåå
æ Œã
import { createPlateEditor } from 'platejs/react';
import { BlockSelectionKit } from '@/components/editor/plugins/block-selection-kit';
const editor = createPlateEditor({
plugins: [
// ...å
¶ä»æä»¶
...BlockSelectionKit,
],
});
</Steps>
npm install @platejs/selection
import { BlockSelectionPlugin } from '@platejs/selection/react';
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...å
¶ä»æä»¶
BlockSelectionPlugin,
],
});
å°æ€æä»¶æŸåšä»»äœèŠç selectAll - Cmd+AïŒä»£ç åãè¡šæ ŒãåçïŒçå
¶ä»æä»¶ä¹åïŒä»¥é¿å
å²çªã
æšå¯ä»¥äœ¿çš options.isSelectable æ§å¶åªäºåæ¯å¯éæ©çãæ€åœæ°æ¥æ¶äžäžªå
çŽ åå
¶è·¯åŸïŒåŠæåå¯éæ©ååºè¿å trueã
äŸåŠïŒæé€ä»£ç è¡ãååè¡šæ Œåå æ ŒïŒ
import { BlockSelectionPlugin } from '@platejs/selection/react';
BlockSelectionPlugin.configure({
options: {
isSelectable: (element, path) => {
if (['code_line', 'column', 'td'].includes(element.type)) {
return false;
}
// æé€è¡šæ Œè¡å
çå
if (editor.api.block({ above: true, at: path, match: { type: 'tr' } })) {
return false;
}
return true;
},
},
});
åŠææšççŒèŸåšäœäºå¯æ»åšå®¹åšå ïŒæšå¯èœéèŠé çœ®éæ©åºåç蟹çåæ»åšé床ã
idïŒäŸåŠ id={editor.meta.uid}position: relativeareaOptions é
眮蟹çåæ»åšè¡äžºBlockSelectionPlugin.configure({
options: {
areaOptions: {
boundaries: `#${editor.meta.uid}`,
container: `#${editor.meta.uid}`,
behaviour: {
scrolling: {
// æšèéåºŠïŒæ¥è¿åç
speedDivider: 0.8,
},
// åŒå§éæ©åºåçéåŒ
startThreshold: 4,
},
},
},
});
æšå¯ä»¥éè¿æ·»å data-plate-selectable 屿§äžº <Editor /> ç»ä»¶ä¹å€çå
çŽ å¯çšåéæ©ã
<Cover data-plate-selectable />
<Sidebar data-plate-selectable />
䞺äºé²æ¢åšç¹å»æäºå
çŽ ïŒäŸåŠå·¥å
·æ æé®ïŒæ¶åæ¶éæ©åïŒè¯·æ·»å data-plate-prevent-unselect 屿§ã
<YourToolbarButton data-plate-prevent-unselect />
èŠåšç¹å»å¯éæ©åºåä¹å€æ¶éçœ®éæ©ïŒæšå¯ä»¥äœ¿çšç¹å»å€ççšåºæçŽæ¥è°çš APIïŒ
// 1. çŽæ¥è°çš API
editor.api.blockSelection.deselect();
// 2. ç¹å»å€éšå€ççšåº
const handleClickOutside = (event: MouseEvent) => {
if (!(event.target as HTMLElement).closest('[data-plate-selectable]')) {
editor.api.blockSelection.deselect();
}
};
</Steps>
éè¿å®äœæ·»å å°çŒèŸåšå®¹åšç .slate-selection-area ç±»æ¥è®Ÿçœ®éæ©åºåçæ ·åŒã
/* äœ¿çš Tailwind CSS å®çšç±»çç€ºäŸ */
'[&_.slate-selection-area]:border [&_.slate-selection-area]:border-primary [&_.slate-selection-area]:bg-primary/10'
äœ¿çš useBlockSelected é©åç¡®å®åæ¯åŠè¢«éäžãæšå¯ä»¥æž²æäžäžªè§è§æç€ºåšïŒåŠ BlockSelection ç»ä»¶ïŒè¯¥ç»ä»¶äžäžºæ€ç®ç讟计ã
Plate UI äœ¿çš render.belowRootNodes 䞺ææå¯éæ©åæž²ææ€ç»ä»¶ïŒ
render: {
belowRootNodes: (props) => {
if (!props.className?.includes('slate-selectable')) return null;
return <BlockSelection />;
},
},
BlockSelectionPluginåéæ©åèœçæä»¶ã
<API name="BlockSelectionPlugin"> <APIOptions> <APIItem name="areaOptions" type="PartialSelectionOptions" optional> éæ©åºåçéé¡¹ãæ¥ç [SelectionJS ææ¡£](https://github.com/Simonwep/selection-js) è·åææå¯çšé项ã{
boundaries: [`#${editor.meta.uid}`],
container: [`#${editor.meta.uid}`],
selectables: [`#${editor.meta.uid} .slate-selectable`],
selectionAreaClass: 'slate-selection-area',
}
</APIItem>
<APIItem name="enableContextMenu" type="boolean" optional>
å¯çšæçŠçšåéæ©çäžäžæèåã
- **é»è®€åŒ:** `false`
</APIItem>
<APIItem name="isSelecting" type="boolean" optional>
æç€ºåéæ©åœåæ¯åŠå€äºæŽ»åšç¶æã
- **é»è®€åŒ:** `false`
</APIItem>
<APIItem name="onKeyDownSelecting" type="(e: KeyboardEvent) => void" optional>
åšéæ©æ¶å€çé®çæäžäºä»¶çåœæ°ã
</APIItem>
<APIItem name="query" type="QueryNodeOptions" optional>
åšåéæ©æéŽæ¥è¯¢èç¹çé项ã
- **é»è®€åŒ:** `{ maxLevel: 1 }`
</APIItem>
<APIItem name="selectedIds" type="Set<string>" optional>
åœåéäžåç ID éåã
- **é»è®€åŒ:** `new Set()`
</APIItem>
<APIItem name="anchorId" type="string | null" optional>
(å
éš) åœåéæ©äžéåç IDãçšäºåºäº Shift çéæ©ã
- **é»è®€åŒ:** `null`
</APIItem>
<APIItem name="isSelectable" type="(element: TElement, path: Path) => boolean" optional>
ç¡®å®åå
çŽ æ¯åŠå¯éæ©çåœæ°ã
- **é»è®€åŒ:** `() => true`
</APIItem>
</APIOptions>
</API>
api.blockSelection.addå°äžäžªæå€äžªåæ·»å å°éæ©äžã
<API name="add"> <APIParameters> <APIItem name="id" type="string | string[]"> èŠéæ©çåç IDã </APIItem> </APIParameters> </API>api.blockSelection.clearå°éäžç ID éåé眮䞺空éã
api.blockSelection.deleteä»éæ©äžç§»é€äžäžªæå€äžªåã
<API name="delete"> <APIParameters> <APIItem name="id" type="string | string[]"> èŠä»éæ©äžç§»é€çåç IDã </APIItem> </APIParameters> </API>api.blockSelection.deselectåæ¶éæ©ææåå¹¶å° isSelecting æ å¿è®Ÿçœ®äžº falseã
api.blockSelection.focusèçŠåéæ©éŽåœ±èŸå ¥ãæ€èŸå ¥å€çéäžåçå€å¶ãå é€åç²èŽŽäºä»¶ã
api.blockSelection.getNodesè·åçŒèŸåšäžçéäžåã
<API name="getNodes"> <APIReturns type="NodeEntry[]"> éäžåçæ¡ç®æ°ç»ã </APIReturns> </API>api.blockSelection.hasæ£æ¥äžäžªæå€äžªåæ¯åŠè¢«éäžã
<API name="has"> <APIParameters> <APIItem name="id" type="string | string[]"> èŠæ£æ¥çåç IDã </APIItem> </APIParameters> <APIReturns> <APIItem type="boolean"> 忝åŠè¢«éäžã </APIItem> </APIReturns> </API>api.blockSelection.isSelectableæ ¹æ®æä»¶é项 isSelectable æ£æ¥ç»å®è·¯åŸç忝åŠå¯éæ©ã
api.blockSelection.moveSelectionå°éæ©åäžæåäžç§»åšå°äžäžäžªå¯éæ©çåã
åäžç§»åšæ¶ïŒ
api.blockSelection.selectAlléæ©çŒèŸåšäžçææå¯éæ©åã
api.blockSelection.setå°éæ©è®Ÿçœ®äžºäžäžªæå€äžªåïŒæž é€ä»»äœç°æéæ©ã
<API name="set"> <APIParameters> <APIItem name="id" type="string | string[]"> èŠéæ©çåç IDã </APIItem> </APIParameters> </API>api.blockSelection.shiftSelectionåºäºé忩屿æ¶çŒ©éæ©ã
å¯¹äº Shift+ArrowDownïŒ
Shift+ArrowUpïŒShift+ArrowUp çæåºéšåShift+ArrowDown çæé¡¶éšåtf.blockSelection.duplicateå€å¶éäžçåã
tf.blockSelection.removeNodesä»çŒèŸåšäžç§»é€éäžçèç¹ã
tf.blockSelection.selectéæ© getNodes() è¿åççŒèŸåšäžçèç¹å¹¶é眮éäžç IDã
tf.blockSelection.setNodesåšéäžçèç¹äžè®Ÿçœ®å±æ§ã
<API name="setNodes"> <APIParameters> <APIItem name="props" type="Partial<NodeProps<TElement>>"> èŠåšéäžèç¹äžè®Ÿçœ®ç屿§ã </APIItem> <APIItem name="options" type="SetNodesOptions" optional> 讟眮èç¹çé项ã </APIItem> </APIParameters> </API>tf.blockSelection.setTextsåšéäžçèç¹äžè®Ÿçœ®ææ¬å±æ§ã
<API name="setTexts"> <APIParameters> <APIItem name="props" type="Partial<NodeProps<TText>>"> èŠåšéäžèç¹äžè®Ÿçœ®çææ¬å±æ§ã </APIItem> <APIItem name="options" type="Omit<SetNodesOptions, 'at'>" optional> è®Ÿçœ®ææ¬èç¹çé项ïŒäžå æ¬ 'at' 屿§ã </APIItem> </APIParameters> </API>useBlockSelectableæäŸäœ¿åå çŽ å¯éæ©ç屿§çé©åïŒå æ¬äžäžæèåè¡äžºã
<API name="useBlockSelectable"> <APIReturns type="object"> <APIItem name="props" type="object"> èŠåºçšäºåå çŽ ç屿§ã <APISubList> <APISubListItem parent="props" name="className" type="string"> éæ©åèœæéçç±»ã - **é»è®€åŒ:** `'slate-selectable'` </APISubListItem> <APISubListItem parent="props" name="onContextMenu" type="(event: React.MouseEvent) => void"> å€çå³é®äžäžæèåè¡äžºïŒ - 䞺éäžçåæåŒäžäžæèå - 䞺 void å çŽ æåŒ - äžºå ·æ `data-plate-open-context-menu="true"` çå çŽ æåŒ - äœ¿çš Shift é®äžºå€éæ·»å åå°éæ© </APISubListItem> </APISubList> </APIItem> </APIReturns> </API>useBlockSelecteduseBlockSelectionNodesuseBlockSelectionFragmentuseBlockSelectionFragmentPropuseSelectionAreaåå§åå管çéæ©åºååèœã
â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ