@wordpress/format-library 4.30.0 → 4.32.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/default-formats.js +2 -1
  3. package/build/default-formats.js.map +1 -1
  4. package/build/link/index.js +54 -11
  5. package/build/link/index.js.map +1 -1
  6. package/build/link/inline.js +5 -2
  7. package/build/link/inline.js.map +1 -1
  8. package/build/non-breaking-space/index.js +36 -0
  9. package/build/non-breaking-space/index.js.map +1 -0
  10. package/build/text-color/index.native.js +4 -4
  11. package/build/text-color/index.native.js.map +1 -1
  12. package/build/text-color/inline.native.js +17 -38
  13. package/build/text-color/inline.native.js.map +1 -1
  14. package/build/unknown/index.js +12 -7
  15. package/build/unknown/index.js.map +1 -1
  16. package/build-module/default-formats.js +2 -1
  17. package/build-module/default-formats.js.map +1 -1
  18. package/build-module/link/index.js +55 -12
  19. package/build-module/link/index.js.map +1 -1
  20. package/build-module/link/inline.js +5 -2
  21. package/build-module/link/inline.js.map +1 -1
  22. package/build-module/non-breaking-space/index.js +29 -0
  23. package/build-module/non-breaking-space/index.js.map +1 -0
  24. package/build-module/text-color/index.native.js +1 -1
  25. package/build-module/text-color/index.native.js.map +1 -1
  26. package/build-module/text-color/inline.native.js +17 -39
  27. package/build-module/text-color/inline.native.js.map +1 -1
  28. package/build-module/unknown/index.js +13 -8
  29. package/build-module/unknown/index.js.map +1 -1
  30. package/package.json +14 -14
  31. package/src/default-formats.js +2 -0
  32. package/src/link/index.js +55 -11
  33. package/src/link/inline.js +7 -1
  34. package/src/non-breaking-space/index.js +29 -0
  35. package/src/text-color/index.native.js +1 -1
  36. package/src/text-color/inline.native.js +27 -49
  37. package/src/text-color/test/__snapshots__/index.native.js.snap +0 -6
  38. package/src/text-color/test/index.native.js +4 -39
  39. package/src/unknown/index.js +16 -10
@@ -22,7 +22,7 @@ function parseCSS(css = '') {
22
22
  return accumulator;
23
23
  }, {});
24
24
  }
25
- function getActiveColors(value, name, colorSettings) {
25
+ export function getActiveColors(value, name, colorSettings) {
26
26
  const activeColorFormat = getActiveFormat(value, name);
27
27
  if (!activeColorFormat) {
28
28
  return {};
@@ -32,7 +32,7 @@ function getActiveColors(value, name, colorSettings) {
32
32
  ...parseClassName(activeColorFormat.attributes.class, colorSettings)
33
33
  };
34
34
  }
35
- function setColors(value, name, colorSettings, colors) {
35
+ function setColors(value, name, colorSettings, colors, contentRef) {
36
36
  const {
37
37
  color,
38
38
  backgroundColor
@@ -40,7 +40,8 @@ function setColors(value, name, colorSettings, colors) {
40
40
  ...getActiveColors(value, name, colorSettings),
41
41
  ...colors
42
42
  };
43
- if (!color && !backgroundColor) {
43
+ if (!color) {
44
+ contentRef?.onRemoveMarkFormatting();
44
45
  return removeFormat(value, name);
45
46
  }
46
47
  const styles = [];
@@ -68,55 +69,30 @@ function setColors(value, name, colorSettings, colors) {
68
69
  attributes
69
70
  };
70
71
  const hasNoSelection = value.start === value.end;
71
- const isAtTheEnd = value.end === value.text.length;
72
- const previousCharacter = value.text.charAt(value.end - 1);
73
-
74
- // Force formatting due to limitations in the native implementation
75
- if (hasNoSelection && (value.text.length === 0 || previousCharacter === ' ' && isAtTheEnd)) {
76
- // For cases where there's no text selected, there's a space before
77
- // the current caret position and it's at the end of the text.
78
- return applyFormat(value, format, value.start - 1, value.end + 1);
79
- } else if (hasNoSelection && isAtTheEnd) {
80
- // If there's no selection and is at the end of the text
81
- // manually add the format within the current caret position.
82
- const newFormat = applyFormat(value, format);
83
- const {
84
- activeFormats
85
- } = newFormat;
86
- newFormat.formats[value.start] = [...(activeFormats?.filter(({
87
- type
88
- }) => type !== format.type) || []), format];
89
- return newFormat;
90
- } else if (hasNoSelection) {
91
- return removeFormat(value, format);
72
+ if (hasNoSelection) {
73
+ contentRef?.onMarkFormatting(color);
92
74
  }
93
75
  return applyFormat(value, format);
94
76
  }
95
77
  function ColorPicker({
96
78
  name,
97
79
  value,
98
- onChange
80
+ onChange,
81
+ contentRef
99
82
  }) {
100
83
  const property = 'color';
101
84
  const colors = useMobileGlobalStylesColors();
102
85
  const colorSettings = useMultipleOriginColorsAndGradients();
103
86
  const onColorChange = useCallback(color => {
104
- if (color !== '') {
105
- onChange(setColors(value, name, colors, {
106
- [property]: color
107
- }));
108
- // Remove formatting if the color was reset, there's no
109
- // current selection and the previous character is a space
110
- } else if (value?.start === value?.end && value.text?.charAt(value?.end - 1) === ' ') {
111
- onChange(removeFormat(value, name, value.end - 1, value.end));
112
- } else {
113
- onChange(removeFormat(value, name));
114
- }
115
- }, [colors, onChange, property]);
87
+ onChange(setColors(value, name, colors, {
88
+ [property]: color
89
+ }, contentRef));
90
+ }, [colors, contentRef, name, onChange, value]);
116
91
  const activeColors = useMemo(() => getActiveColors(value, name, colors), [name, value, colors]);
117
92
  return createElement(ColorSettings, {
118
93
  colorValue: activeColors[property],
119
94
  onColorChange: onColorChange,
95
+ onColorCleared: onColorChange,
120
96
  defaultSettings: colorSettings,
121
97
  hideNavigation: true
122
98
  });
@@ -125,7 +101,8 @@ export default function InlineColorUI({
125
101
  name,
126
102
  value,
127
103
  onChange,
128
- onClose
104
+ onClose,
105
+ contentRef
129
106
  }) {
130
107
  return createElement(BottomSheet, {
131
108
  isVisible: true,
@@ -146,7 +123,8 @@ export default function InlineColorUI({
146
123
  }, createElement(ColorPicker, {
147
124
  name: name,
148
125
  value: value,
149
- onChange: onChange
126
+ onChange: onChange,
127
+ contentRef: contentRef
150
128
  }))));
151
129
  }
152
130
  //# sourceMappingURL=inline.native.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useCallback","useMemo","applyFormat","removeFormat","getActiveFormat","getColorClassName","getColorObjectByColorValue","useMultipleOriginColorsAndGradients","BottomSheet","ColorSettings","useMobileGlobalStylesColors","transparentValue","parseClassName","parseCSS","css","split","reduce","accumulator","rule","property","value","replace","color","backgroundColor","getActiveColors","name","colorSettings","activeColorFormat","attributes","style","class","setColors","colors","styles","classNames","push","join","colorObject","slug","length","format","type","hasNoSelection","start","end","isAtTheEnd","text","previousCharacter","charAt","newFormat","activeFormats","formats","filter","ColorPicker","onChange","onColorChange","activeColors","createElement","colorValue","defaultSettings","hideNavigation","InlineColorUI","onClose","isVisible","hideHeader","contentStyle","paddingLeft","paddingRight","hasNavigation","leftButton","testID","NavigationContainer","animate","main","NavigationScreen"],"sources":["@wordpress/format-library/src/text-color/inline.native.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useCallback, useMemo } from '@wordpress/element';\nimport {\n\tapplyFormat,\n\tremoveFormat,\n\tgetActiveFormat,\n} from '@wordpress/rich-text';\nimport {\n\tgetColorClassName,\n\tgetColorObjectByColorValue,\n\tuseMultipleOriginColorsAndGradients,\n} from '@wordpress/block-editor';\nimport {\n\tBottomSheet,\n\tColorSettings,\n\tuseMobileGlobalStylesColors,\n} from '@wordpress/components';\n\n/**\n * Internal dependencies\n */\nimport { transparentValue } from './index.js';\nimport { parseClassName } from './inline.js';\n\nfunction parseCSS( css = '' ) {\n\treturn css.split( ';' ).reduce( ( accumulator, rule ) => {\n\t\tif ( rule ) {\n\t\t\tconst [ property, value ] = rule.replace( / /g, '' ).split( ':' );\n\t\t\tif ( property === 'color' ) accumulator.color = value;\n\t\t\tif ( property === 'background-color' && value !== transparentValue )\n\t\t\t\taccumulator.backgroundColor = value;\n\t\t}\n\t\treturn accumulator;\n\t}, {} );\n}\n\nfunction getActiveColors( value, name, colorSettings ) {\n\tconst activeColorFormat = getActiveFormat( value, name );\n\n\tif ( ! activeColorFormat ) {\n\t\treturn {};\n\t}\n\n\treturn {\n\t\t...parseCSS( activeColorFormat.attributes.style ),\n\t\t...parseClassName( activeColorFormat.attributes.class, colorSettings ),\n\t};\n}\n\nfunction setColors( value, name, colorSettings, colors ) {\n\tconst { color, backgroundColor } = {\n\t\t...getActiveColors( value, name, colorSettings ),\n\t\t...colors,\n\t};\n\n\tif ( ! color && ! backgroundColor ) {\n\t\treturn removeFormat( value, name );\n\t}\n\n\tconst styles = [];\n\tconst classNames = [];\n\tconst attributes = {};\n\n\tif ( backgroundColor ) {\n\t\tstyles.push( [ 'background-color', backgroundColor ].join( ':' ) );\n\t} else {\n\t\t// Override default browser color for mark element.\n\t\tstyles.push( [ 'background-color', transparentValue ].join( ':' ) );\n\t}\n\n\tif ( color ) {\n\t\tconst colorObject = getColorObjectByColorValue( colorSettings, color );\n\n\t\tif ( colorObject ) {\n\t\t\tclassNames.push( getColorClassName( 'color', colorObject.slug ) );\n\t\t\tstyles.push( [ 'color', colorObject.color ].join( ':' ) );\n\t\t} else {\n\t\t\tstyles.push( [ 'color', color ].join( ':' ) );\n\t\t}\n\t}\n\n\tif ( styles.length ) attributes.style = styles.join( ';' );\n\tif ( classNames.length ) attributes.class = classNames.join( ' ' );\n\n\tconst format = { type: name, attributes };\n\tconst hasNoSelection = value.start === value.end;\n\tconst isAtTheEnd = value.end === value.text.length;\n\tconst previousCharacter = value.text.charAt( value.end - 1 );\n\n\t// Force formatting due to limitations in the native implementation\n\tif (\n\t\thasNoSelection &&\n\t\t( value.text.length === 0 ||\n\t\t\t( previousCharacter === ' ' && isAtTheEnd ) )\n\t) {\n\t\t// For cases where there's no text selected, there's a space before\n\t\t// the current caret position and it's at the end of the text.\n\t\treturn applyFormat( value, format, value.start - 1, value.end + 1 );\n\t} else if ( hasNoSelection && isAtTheEnd ) {\n\t\t// If there's no selection and is at the end of the text\n\t\t// manually add the format within the current caret position.\n\t\tconst newFormat = applyFormat( value, format );\n\t\tconst { activeFormats } = newFormat;\n\t\tnewFormat.formats[ value.start ] = [\n\t\t\t...( activeFormats?.filter(\n\t\t\t\t( { type } ) => type !== format.type\n\t\t\t) || [] ),\n\t\t\tformat,\n\t\t];\n\t\treturn newFormat;\n\t} else if ( hasNoSelection ) {\n\t\treturn removeFormat( value, format );\n\t}\n\n\treturn applyFormat( value, format );\n}\n\nfunction ColorPicker( { name, value, onChange } ) {\n\tconst property = 'color';\n\tconst colors = useMobileGlobalStylesColors();\n\tconst colorSettings = useMultipleOriginColorsAndGradients();\n\n\tconst onColorChange = useCallback(\n\t\t( color ) => {\n\t\t\tif ( color !== '' ) {\n\t\t\t\tonChange(\n\t\t\t\t\tsetColors( value, name, colors, { [ property ]: color } )\n\t\t\t\t);\n\t\t\t\t// Remove formatting if the color was reset, there's no\n\t\t\t\t// current selection and the previous character is a space\n\t\t\t} else if (\n\t\t\t\tvalue?.start === value?.end &&\n\t\t\t\tvalue.text?.charAt( value?.end - 1 ) === ' '\n\t\t\t) {\n\t\t\t\tonChange(\n\t\t\t\t\tremoveFormat( value, name, value.end - 1, value.end )\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tonChange( removeFormat( value, name ) );\n\t\t\t}\n\t\t},\n\t\t[ colors, onChange, property ]\n\t);\n\tconst activeColors = useMemo(\n\t\t() => getActiveColors( value, name, colors ),\n\t\t[ name, value, colors ]\n\t);\n\n\treturn (\n\t\t<ColorSettings\n\t\t\tcolorValue={ activeColors[ property ] }\n\t\t\tonColorChange={ onColorChange }\n\t\t\tdefaultSettings={ colorSettings }\n\t\t\thideNavigation\n\t\t/>\n\t);\n}\n\nexport default function InlineColorUI( { name, value, onChange, onClose } ) {\n\treturn (\n\t\t<BottomSheet\n\t\t\tisVisible\n\t\t\tonClose={ onClose }\n\t\t\thideHeader\n\t\t\tcontentStyle={ { paddingLeft: 0, paddingRight: 0 } }\n\t\t\thasNavigation\n\t\t\tleftButton={ null }\n\t\t\ttestID=\"inline-text-color-modal\"\n\t\t>\n\t\t\t<BottomSheet.NavigationContainer animate main>\n\t\t\t\t<BottomSheet.NavigationScreen name=\"text-color\">\n\t\t\t\t\t<ColorPicker\n\t\t\t\t\t\tname={ name }\n\t\t\t\t\t\tvalue={ value }\n\t\t\t\t\t\tonChange={ onChange }\n\t\t\t\t\t/>\n\t\t\t\t</BottomSheet.NavigationScreen>\n\t\t\t</BottomSheet.NavigationContainer>\n\t\t</BottomSheet>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["useCallback","useMemo","applyFormat","removeFormat","getActiveFormat","getColorClassName","getColorObjectByColorValue","useMultipleOriginColorsAndGradients","BottomSheet","ColorSettings","useMobileGlobalStylesColors","transparentValue","parseClassName","parseCSS","css","split","reduce","accumulator","rule","property","value","replace","color","backgroundColor","getActiveColors","name","colorSettings","activeColorFormat","attributes","style","class","setColors","colors","contentRef","onRemoveMarkFormatting","styles","classNames","push","join","colorObject","slug","length","format","type","hasNoSelection","start","end","onMarkFormatting","ColorPicker","onChange","onColorChange","activeColors","createElement","colorValue","onColorCleared","defaultSettings","hideNavigation","InlineColorUI","onClose","isVisible","hideHeader","contentStyle","paddingLeft","paddingRight","hasNavigation","leftButton","testID","NavigationContainer","animate","main","NavigationScreen"],"sources":["@wordpress/format-library/src/text-color/inline.native.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useCallback, useMemo } from '@wordpress/element';\nimport {\n\tapplyFormat,\n\tremoveFormat,\n\tgetActiveFormat,\n} from '@wordpress/rich-text';\nimport {\n\tgetColorClassName,\n\tgetColorObjectByColorValue,\n\tuseMultipleOriginColorsAndGradients,\n} from '@wordpress/block-editor';\nimport {\n\tBottomSheet,\n\tColorSettings,\n\tuseMobileGlobalStylesColors,\n} from '@wordpress/components';\n\n/**\n * Internal dependencies\n */\nimport { transparentValue } from './index.js';\nimport { parseClassName } from './inline.js';\n\nfunction parseCSS( css = '' ) {\n\treturn css.split( ';' ).reduce( ( accumulator, rule ) => {\n\t\tif ( rule ) {\n\t\t\tconst [ property, value ] = rule.replace( / /g, '' ).split( ':' );\n\t\t\tif ( property === 'color' ) accumulator.color = value;\n\t\t\tif ( property === 'background-color' && value !== transparentValue )\n\t\t\t\taccumulator.backgroundColor = value;\n\t\t}\n\t\treturn accumulator;\n\t}, {} );\n}\n\nexport function getActiveColors( value, name, colorSettings ) {\n\tconst activeColorFormat = getActiveFormat( value, name );\n\n\tif ( ! activeColorFormat ) {\n\t\treturn {};\n\t}\n\n\treturn {\n\t\t...parseCSS( activeColorFormat.attributes.style ),\n\t\t...parseClassName( activeColorFormat.attributes.class, colorSettings ),\n\t};\n}\n\nfunction setColors( value, name, colorSettings, colors, contentRef ) {\n\tconst { color, backgroundColor } = {\n\t\t...getActiveColors( value, name, colorSettings ),\n\t\t...colors,\n\t};\n\n\tif ( ! color ) {\n\t\tcontentRef?.onRemoveMarkFormatting();\n\t\treturn removeFormat( value, name );\n\t}\n\n\tconst styles = [];\n\tconst classNames = [];\n\tconst attributes = {};\n\n\tif ( backgroundColor ) {\n\t\tstyles.push( [ 'background-color', backgroundColor ].join( ':' ) );\n\t} else {\n\t\t// Override default browser color for mark element.\n\t\tstyles.push( [ 'background-color', transparentValue ].join( ':' ) );\n\t}\n\n\tif ( color ) {\n\t\tconst colorObject = getColorObjectByColorValue( colorSettings, color );\n\n\t\tif ( colorObject ) {\n\t\t\tclassNames.push( getColorClassName( 'color', colorObject.slug ) );\n\t\t\tstyles.push( [ 'color', colorObject.color ].join( ':' ) );\n\t\t} else {\n\t\t\tstyles.push( [ 'color', color ].join( ':' ) );\n\t\t}\n\t}\n\n\tif ( styles.length ) attributes.style = styles.join( ';' );\n\tif ( classNames.length ) attributes.class = classNames.join( ' ' );\n\n\tconst format = { type: name, attributes };\n\tconst hasNoSelection = value.start === value.end;\n\n\tif ( hasNoSelection ) {\n\t\tcontentRef?.onMarkFormatting( color );\n\t}\n\treturn applyFormat( value, format );\n}\n\nfunction ColorPicker( { name, value, onChange, contentRef } ) {\n\tconst property = 'color';\n\tconst colors = useMobileGlobalStylesColors();\n\tconst colorSettings = useMultipleOriginColorsAndGradients();\n\n\tconst onColorChange = useCallback(\n\t\t( color ) => {\n\t\t\tonChange(\n\t\t\t\tsetColors(\n\t\t\t\t\tvalue,\n\t\t\t\t\tname,\n\t\t\t\t\tcolors,\n\t\t\t\t\t{ [ property ]: color },\n\t\t\t\t\tcontentRef\n\t\t\t\t)\n\t\t\t);\n\t\t},\n\t\t[ colors, contentRef, name, onChange, value ]\n\t);\n\tconst activeColors = useMemo(\n\t\t() => getActiveColors( value, name, colors ),\n\t\t[ name, value, colors ]\n\t);\n\n\treturn (\n\t\t<ColorSettings\n\t\t\tcolorValue={ activeColors[ property ] }\n\t\t\tonColorChange={ onColorChange }\n\t\t\tonColorCleared={ onColorChange }\n\t\t\tdefaultSettings={ colorSettings }\n\t\t\thideNavigation\n\t\t/>\n\t);\n}\n\nexport default function InlineColorUI( {\n\tname,\n\tvalue,\n\tonChange,\n\tonClose,\n\tcontentRef,\n} ) {\n\treturn (\n\t\t<BottomSheet\n\t\t\tisVisible\n\t\t\tonClose={ onClose }\n\t\t\thideHeader\n\t\t\tcontentStyle={ { paddingLeft: 0, paddingRight: 0 } }\n\t\t\thasNavigation\n\t\t\tleftButton={ null }\n\t\t\ttestID=\"inline-text-color-modal\"\n\t\t>\n\t\t\t<BottomSheet.NavigationContainer animate main>\n\t\t\t\t<BottomSheet.NavigationScreen name=\"text-color\">\n\t\t\t\t\t<ColorPicker\n\t\t\t\t\t\tname={ name }\n\t\t\t\t\t\tvalue={ value }\n\t\t\t\t\t\tonChange={ onChange }\n\t\t\t\t\t\tcontentRef={ contentRef }\n\t\t\t\t\t/>\n\t\t\t\t</BottomSheet.NavigationScreen>\n\t\t\t</BottomSheet.NavigationContainer>\n\t\t</BottomSheet>\n\t);\n}\n"],"mappings":"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"}
@@ -3,11 +3,20 @@ import { createElement } from "react";
3
3
  * WordPress dependencies
4
4
  */
5
5
  import { __ } from '@wordpress/i18n';
6
- import { removeFormat, slice } from '@wordpress/rich-text';
6
+ import { removeFormat, slice, isCollapsed } from '@wordpress/rich-text';
7
7
  import { RichTextToolbarButton } from '@wordpress/block-editor';
8
8
  import { help } from '@wordpress/icons';
9
9
  const name = 'core/unknown';
10
10
  const title = __('Clear Unknown Formatting');
11
+ function selectionContainsUnknownFormats(value) {
12
+ if (isCollapsed(value)) {
13
+ return false;
14
+ }
15
+ const selectedValue = slice(value);
16
+ return selectedValue.formats.some(formats => {
17
+ return formats.some(format => format.type === name);
18
+ });
19
+ }
11
20
  export const unknown = {
12
21
  name,
13
22
  title,
@@ -19,17 +28,13 @@ export const unknown = {
19
28
  onChange,
20
29
  onFocus
21
30
  }) {
31
+ if (!isActive && !selectionContainsUnknownFormats(value)) {
32
+ return null;
33
+ }
22
34
  function onClick() {
23
35
  onChange(removeFormat(value, name));
24
36
  onFocus();
25
37
  }
26
- const selectedValue = slice(value);
27
- const hasUnknownFormats = selectedValue.formats.some(formats => {
28
- return formats.some(format => format.type === name);
29
- });
30
- if (!isActive && !hasUnknownFormats) {
31
- return null;
32
- }
33
38
  return createElement(RichTextToolbarButton, {
34
39
  name: "unknown",
35
40
  icon: help,
@@ -1 +1 @@
1
- {"version":3,"names":["__","removeFormat","slice","RichTextToolbarButton","help","name","title","unknown","tagName","className","edit","isActive","value","onChange","onFocus","onClick","selectedValue","hasUnknownFormats","formats","some","format","type","createElement","icon"],"sources":["@wordpress/format-library/src/unknown/index.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\nimport { removeFormat, slice } from '@wordpress/rich-text';\nimport { RichTextToolbarButton } from '@wordpress/block-editor';\nimport { help } from '@wordpress/icons';\n\nconst name = 'core/unknown';\nconst title = __( 'Clear Unknown Formatting' );\n\nexport const unknown = {\n\tname,\n\ttitle,\n\ttagName: '*',\n\tclassName: null,\n\tedit( { isActive, value, onChange, onFocus } ) {\n\t\tfunction onClick() {\n\t\t\tonChange( removeFormat( value, name ) );\n\t\t\tonFocus();\n\t\t}\n\n\t\tconst selectedValue = slice( value );\n\t\tconst hasUnknownFormats = selectedValue.formats.some( ( formats ) => {\n\t\t\treturn formats.some( ( format ) => format.type === name );\n\t\t} );\n\n\t\tif ( ! isActive && ! hasUnknownFormats ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn (\n\t\t\t<RichTextToolbarButton\n\t\t\t\tname=\"unknown\"\n\t\t\t\ticon={ help }\n\t\t\t\ttitle={ title }\n\t\t\t\tonClick={ onClick }\n\t\t\t\tisActive\n\t\t\t/>\n\t\t);\n\t},\n};\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,EAAE,QAAQ,iBAAiB;AACpC,SAASC,YAAY,EAAEC,KAAK,QAAQ,sBAAsB;AAC1D,SAASC,qBAAqB,QAAQ,yBAAyB;AAC/D,SAASC,IAAI,QAAQ,kBAAkB;AAEvC,MAAMC,IAAI,GAAG,cAAc;AAC3B,MAAMC,KAAK,GAAGN,EAAE,CAAE,0BAA2B,CAAC;AAE9C,OAAO,MAAMO,OAAO,GAAG;EACtBF,IAAI;EACJC,KAAK;EACLE,OAAO,EAAE,GAAG;EACZC,SAAS,EAAE,IAAI;EACfC,IAAIA,CAAE;IAAEC,QAAQ;IAAEC,KAAK;IAAEC,QAAQ;IAAEC;EAAQ,CAAC,EAAG;IAC9C,SAASC,OAAOA,CAAA,EAAG;MAClBF,QAAQ,CAAEZ,YAAY,CAAEW,KAAK,EAAEP,IAAK,CAAE,CAAC;MACvCS,OAAO,CAAC,CAAC;IACV;IAEA,MAAME,aAAa,GAAGd,KAAK,CAAEU,KAAM,CAAC;IACpC,MAAMK,iBAAiB,GAAGD,aAAa,CAACE,OAAO,CAACC,IAAI,CAAID,OAAO,IAAM;MACpE,OAAOA,OAAO,CAACC,IAAI,CAAIC,MAAM,IAAMA,MAAM,CAACC,IAAI,KAAKhB,IAAK,CAAC;IAC1D,CAAE,CAAC;IAEH,IAAK,CAAEM,QAAQ,IAAI,CAAEM,iBAAiB,EAAG;MACxC,OAAO,IAAI;IACZ;IAEA,OACCK,aAAA,CAACnB,qBAAqB;MACrBE,IAAI,EAAC,SAAS;MACdkB,IAAI,EAAGnB,IAAM;MACbE,KAAK,EAAGA,KAAO;MACfS,OAAO,EAAGA,OAAS;MACnBJ,QAAQ;IAAA,CACR,CAAC;EAEJ;AACD,CAAC"}
1
+ {"version":3,"names":["__","removeFormat","slice","isCollapsed","RichTextToolbarButton","help","name","title","selectionContainsUnknownFormats","value","selectedValue","formats","some","format","type","unknown","tagName","className","edit","isActive","onChange","onFocus","onClick","createElement","icon"],"sources":["@wordpress/format-library/src/unknown/index.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\nimport { removeFormat, slice, isCollapsed } from '@wordpress/rich-text';\nimport { RichTextToolbarButton } from '@wordpress/block-editor';\nimport { help } from '@wordpress/icons';\n\nconst name = 'core/unknown';\nconst title = __( 'Clear Unknown Formatting' );\n\nfunction selectionContainsUnknownFormats( value ) {\n\tif ( isCollapsed( value ) ) {\n\t\treturn false;\n\t}\n\n\tconst selectedValue = slice( value );\n\treturn selectedValue.formats.some( ( formats ) => {\n\t\treturn formats.some( ( format ) => format.type === name );\n\t} );\n}\n\nexport const unknown = {\n\tname,\n\ttitle,\n\ttagName: '*',\n\tclassName: null,\n\tedit( { isActive, value, onChange, onFocus } ) {\n\t\tif ( ! isActive && ! selectionContainsUnknownFormats( value ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfunction onClick() {\n\t\t\tonChange( removeFormat( value, name ) );\n\t\t\tonFocus();\n\t\t}\n\n\t\treturn (\n\t\t\t<RichTextToolbarButton\n\t\t\t\tname=\"unknown\"\n\t\t\t\ticon={ help }\n\t\t\t\ttitle={ title }\n\t\t\t\tonClick={ onClick }\n\t\t\t\tisActive\n\t\t\t/>\n\t\t);\n\t},\n};\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,EAAE,QAAQ,iBAAiB;AACpC,SAASC,YAAY,EAAEC,KAAK,EAAEC,WAAW,QAAQ,sBAAsB;AACvE,SAASC,qBAAqB,QAAQ,yBAAyB;AAC/D,SAASC,IAAI,QAAQ,kBAAkB;AAEvC,MAAMC,IAAI,GAAG,cAAc;AAC3B,MAAMC,KAAK,GAAGP,EAAE,CAAE,0BAA2B,CAAC;AAE9C,SAASQ,+BAA+BA,CAAEC,KAAK,EAAG;EACjD,IAAKN,WAAW,CAAEM,KAAM,CAAC,EAAG;IAC3B,OAAO,KAAK;EACb;EAEA,MAAMC,aAAa,GAAGR,KAAK,CAAEO,KAAM,CAAC;EACpC,OAAOC,aAAa,CAACC,OAAO,CAACC,IAAI,CAAID,OAAO,IAAM;IACjD,OAAOA,OAAO,CAACC,IAAI,CAAIC,MAAM,IAAMA,MAAM,CAACC,IAAI,KAAKR,IAAK,CAAC;EAC1D,CAAE,CAAC;AACJ;AAEA,OAAO,MAAMS,OAAO,GAAG;EACtBT,IAAI;EACJC,KAAK;EACLS,OAAO,EAAE,GAAG;EACZC,SAAS,EAAE,IAAI;EACfC,IAAIA,CAAE;IAAEC,QAAQ;IAAEV,KAAK;IAAEW,QAAQ;IAAEC;EAAQ,CAAC,EAAG;IAC9C,IAAK,CAAEF,QAAQ,IAAI,CAAEX,+BAA+B,CAAEC,KAAM,CAAC,EAAG;MAC/D,OAAO,IAAI;IACZ;IAEA,SAASa,OAAOA,CAAA,EAAG;MAClBF,QAAQ,CAAEnB,YAAY,CAAEQ,KAAK,EAAEH,IAAK,CAAE,CAAC;MACvCe,OAAO,CAAC,CAAC;IACV;IAEA,OACCE,aAAA,CAACnB,qBAAqB;MACrBE,IAAI,EAAC,SAAS;MACdkB,IAAI,EAAGnB,IAAM;MACbE,KAAK,EAAGA,KAAO;MACfe,OAAO,EAAGA,OAAS;MACnBH,QAAQ;IAAA,CACR,CAAC;EAEJ;AACD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/format-library",
3
- "version": "4.30.0",
3
+ "version": "4.32.0",
4
4
  "description": "Format library for the WordPress editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -26,18 +26,18 @@
26
26
  "react-native": "src/index",
27
27
  "dependencies": {
28
28
  "@babel/runtime": "^7.16.0",
29
- "@wordpress/a11y": "^3.53.0",
30
- "@wordpress/block-editor": "^12.21.0",
31
- "@wordpress/components": "^27.1.0",
32
- "@wordpress/compose": "^6.30.0",
33
- "@wordpress/data": "^9.23.0",
34
- "@wordpress/element": "^5.30.0",
35
- "@wordpress/html-entities": "^3.53.0",
36
- "@wordpress/i18n": "^4.53.0",
37
- "@wordpress/icons": "^9.44.0",
38
- "@wordpress/private-apis": "^0.35.0",
39
- "@wordpress/rich-text": "^6.30.0",
40
- "@wordpress/url": "^3.54.0"
29
+ "@wordpress/a11y": "^3.55.0",
30
+ "@wordpress/block-editor": "^12.23.0",
31
+ "@wordpress/components": "^27.3.0",
32
+ "@wordpress/compose": "^6.32.0",
33
+ "@wordpress/data": "^9.25.0",
34
+ "@wordpress/element": "^5.32.0",
35
+ "@wordpress/html-entities": "^3.55.0",
36
+ "@wordpress/i18n": "^4.55.0",
37
+ "@wordpress/icons": "^9.46.0",
38
+ "@wordpress/private-apis": "^0.37.0",
39
+ "@wordpress/rich-text": "^6.32.0",
40
+ "@wordpress/url": "^3.56.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "react": "^18.0.0",
@@ -46,5 +46,5 @@
46
46
  "publishConfig": {
47
47
  "access": "public"
48
48
  },
49
- "gitHead": "ac3c3e465a083081a86a4da6ee6fb817b41e5130"
49
+ "gitHead": "ac2b13783c28f959770cf029a797a712f59e1958"
50
50
  }
@@ -14,6 +14,7 @@ import { superscript } from './superscript';
14
14
  import { keyboard } from './keyboard';
15
15
  import { unknown } from './unknown';
16
16
  import { language } from './language';
17
+ import { nonBreakingSpace } from './non-breaking-space';
17
18
 
18
19
  export default [
19
20
  bold,
@@ -29,4 +30,5 @@ export default [
29
30
  keyboard,
30
31
  unknown,
31
32
  language,
33
+ nonBreakingSpace,
32
34
  ];
package/src/link/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
- import { useState, useLayoutEffect } from '@wordpress/element';
5
+ import { useState, useLayoutEffect, useEffect } from '@wordpress/element';
6
6
  import {
7
7
  getTextContent,
8
8
  applyFormat,
@@ -38,10 +38,39 @@ function Edit( {
38
38
  onFocus,
39
39
  contentRef,
40
40
  } ) {
41
- const [ addingLink, setAddingLink ] = useState( false );
41
+ const [ editingLink, setEditingLink ] = useState( false );
42
+ const [ creatingLink, setCreatingLink ] = useState( false );
43
+
42
44
  // We only need to store the button element that opened the popover. We can ignore the other states, as they will be handled by the onFocus prop to return to the rich text field.
43
45
  const [ openedBy, setOpenedBy ] = useState( null );
44
46
 
47
+ // Manages whether the Link UI popover should autofocus when shown.
48
+ const [ shouldAutoFocus, setShouldAutoFocus ] = useState( true );
49
+
50
+ function setIsEditingLink( isEditing, { autoFocus = true } = {} ) {
51
+ setEditingLink( isEditing );
52
+ setShouldAutoFocus( autoFocus );
53
+ }
54
+
55
+ function setIsCreatingLink( isCreating ) {
56
+ // Don't add a new link if there is already an active link.
57
+ // The two states are mutually exclusive.
58
+ if ( isCreating === true && isActive ) {
59
+ return;
60
+ }
61
+ setCreatingLink( isCreating );
62
+ }
63
+
64
+ useEffect( () => {
65
+ // When the link becomes inactive (i.e. isActive is false), reset the editingLink state
66
+ // and the creatingLink state. This means that if the Link UI is displayed and the link
67
+ // becomes inactive (e.g. used arrow keys to move cursor outside of link bounds), the UI will close.
68
+ if ( ! isActive ) {
69
+ setEditingLink( false );
70
+ setCreatingLink( false );
71
+ }
72
+ }, [ isActive ] );
73
+
45
74
  useLayoutEffect( () => {
46
75
  const editableContentElement = contentRef.current;
47
76
  if ( ! editableContentElement ) {
@@ -52,14 +81,18 @@ function Edit( {
52
81
  // There is a situation whereby there is an existing link in the rich text
53
82
  // and the user clicks on the leftmost edge of that link and fails to activate
54
83
  // the link format, but the click event still fires on the `<a>` element.
55
- // This causes the `addingLink` state to be set to `true` and the link UI
84
+ // This causes the `editingLink` state to be set to `true` and the link UI
56
85
  // to be rendered in "creating" mode. We need to check isActive to see if
57
86
  // we have an active link format.
58
- if ( event.target.tagName !== 'A' || ! isActive ) {
87
+ if (
88
+ ! event.target.closest( '[contenteditable] a' ) || // other formats (e.g. bold) may be nested within the link.
89
+ ! isActive
90
+ ) {
91
+ setIsEditingLink( false );
59
92
  return;
60
93
  }
61
94
 
62
- setAddingLink( true );
95
+ setIsEditingLink( true, { autoFocus: false } );
63
96
  }
64
97
 
65
98
  editableContentElement.addEventListener( 'click', handleClick );
@@ -70,6 +103,7 @@ function Edit( {
70
103
  }, [ contentRef, isActive ] );
71
104
 
72
105
  function addLink( target ) {
106
+ setShouldAutoFocus( true );
73
107
  const text = getTextContent( slice( value ) );
74
108
 
75
109
  if ( ! isActive && text && isURL( text ) && isValidHref( text ) ) {
@@ -90,7 +124,11 @@ function Edit( {
90
124
  if ( target ) {
91
125
  setOpenedBy( target );
92
126
  }
93
- setAddingLink( true );
127
+ if ( ! isActive ) {
128
+ setIsCreatingLink( true );
129
+ } else {
130
+ setIsEditingLink( true );
131
+ }
94
132
  }
95
133
  }
96
134
 
@@ -109,7 +147,9 @@ function Edit( {
109
147
  // Otherwise, we rely on the passed in onFocus to return focus to the rich text field.
110
148
 
111
149
  // Close the popover
112
- setAddingLink( false );
150
+ setIsEditingLink( false );
151
+ setIsCreatingLink( false );
152
+
113
153
  // Return focus to the toolbar button or the rich text field
114
154
  if ( openedBy?.tagName === 'BUTTON' ) {
115
155
  openedBy.focus();
@@ -127,7 +167,8 @@ function Edit( {
127
167
  // 4. Press Escape
128
168
  // 5. Focus should be on the Options button
129
169
  function onFocusOutside() {
130
- setAddingLink( false );
170
+ setIsEditingLink( false );
171
+ setIsCreatingLink( false );
131
172
  setOpenedBy( null );
132
173
  }
133
174
 
@@ -136,6 +177,8 @@ function Edit( {
136
177
  speak( __( 'Link removed.' ), 'assertive' );
137
178
  }
138
179
 
180
+ const isEditingActiveLink = editingLink && isActive;
181
+
139
182
  return (
140
183
  <>
141
184
  <RichTextShortcut type="primary" character="k" onUse={ addLink } />
@@ -151,13 +194,13 @@ function Edit( {
151
194
  onClick={ ( event ) => {
152
195
  addLink( event.currentTarget );
153
196
  } }
154
- isActive={ isActive || addingLink }
197
+ isActive={ isActive || editingLink }
155
198
  shortcutType="primary"
156
199
  shortcutCharacter="k"
157
200
  aria-haspopup="true"
158
- aria-expanded={ addingLink }
201
+ aria-expanded={ editingLink }
159
202
  />
160
- { addingLink && (
203
+ { ( isEditingActiveLink || creatingLink ) && (
161
204
  <InlineLinkUI
162
205
  stopAddingLink={ stopAddingLink }
163
206
  onFocusOutside={ onFocusOutside }
@@ -166,6 +209,7 @@ function Edit( {
166
209
  value={ value }
167
210
  onChange={ onChange }
168
211
  contentRef={ contentRef }
212
+ focusOnMount={ shouldAutoFocus ? 'firstElement' : false }
169
213
  />
170
214
  ) }
171
215
  </>
@@ -46,6 +46,7 @@ function InlineLinkUI( {
46
46
  onFocusOutside,
47
47
  stopAddingLink,
48
48
  contentRef,
49
+ focusOnMount,
49
50
  } ) {
50
51
  const richLinkTextValue = getRichTextValueFromSelection( value, isActive );
51
52
 
@@ -216,7 +217,10 @@ function InlineLinkUI( {
216
217
 
217
218
  const popoverAnchor = useAnchor( {
218
219
  editableContentElement: contentRef.current,
219
- settings: { ...settings, isActive },
220
+ settings: {
221
+ ...settings,
222
+ isActive,
223
+ },
220
224
  } );
221
225
 
222
226
  async function handleCreate( pageTitle ) {
@@ -253,6 +257,8 @@ function InlineLinkUI( {
253
257
  placement="bottom"
254
258
  offset={ 10 }
255
259
  shift
260
+ focusOnMount={ focusOnMount }
261
+ constrainTabbing
256
262
  >
257
263
  <LinkControl
258
264
  value={ linkValue }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { insert } from '@wordpress/rich-text';
6
+ import { RichTextShortcut } from '@wordpress/block-editor';
7
+
8
+ const name = 'core/non-breaking-space';
9
+ const title = __( 'Non breaking space' );
10
+
11
+ export const nonBreakingSpace = {
12
+ name,
13
+ title,
14
+ tagName: 'nbsp',
15
+ className: null,
16
+ edit( { value, onChange } ) {
17
+ function addNonBreakingSpace() {
18
+ onChange( insert( value, '\u00a0' ) );
19
+ }
20
+
21
+ return (
22
+ <RichTextShortcut
23
+ type="primaryShift"
24
+ character=" "
25
+ onUse={ addNonBreakingSpace }
26
+ />
27
+ );
28
+ },
29
+ };
@@ -25,7 +25,7 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose';
25
25
  /**
26
26
  * Internal dependencies
27
27
  */
28
- import { getActiveColors } from './inline.js';
28
+ import { getActiveColors } from './inline.native.js';
29
29
  import { default as InlineColorUI } from './inline';
30
30
  import styles from './style.scss';
31
31
 
@@ -36,7 +36,7 @@ function parseCSS( css = '' ) {
36
36
  }, {} );
37
37
  }
38
38
 
39
- function getActiveColors( value, name, colorSettings ) {
39
+ export function getActiveColors( value, name, colorSettings ) {
40
40
  const activeColorFormat = getActiveFormat( value, name );
41
41
 
42
42
  if ( ! activeColorFormat ) {
@@ -49,13 +49,14 @@ function getActiveColors( value, name, colorSettings ) {
49
49
  };
50
50
  }
51
51
 
52
- function setColors( value, name, colorSettings, colors ) {
52
+ function setColors( value, name, colorSettings, colors, contentRef ) {
53
53
  const { color, backgroundColor } = {
54
54
  ...getActiveColors( value, name, colorSettings ),
55
55
  ...colors,
56
56
  };
57
57
 
58
- if ( ! color && ! backgroundColor ) {
58
+ if ( ! color ) {
59
+ contentRef?.onRemoveMarkFormatting();
59
60
  return removeFormat( value, name );
60
61
  }
61
62
 
@@ -86,62 +87,31 @@ function setColors( value, name, colorSettings, colors ) {
86
87
 
87
88
  const format = { type: name, attributes };
88
89
  const hasNoSelection = value.start === value.end;
89
- const isAtTheEnd = value.end === value.text.length;
90
- const previousCharacter = value.text.charAt( value.end - 1 );
91
-
92
- // Force formatting due to limitations in the native implementation
93
- if (
94
- hasNoSelection &&
95
- ( value.text.length === 0 ||
96
- ( previousCharacter === ' ' && isAtTheEnd ) )
97
- ) {
98
- // For cases where there's no text selected, there's a space before
99
- // the current caret position and it's at the end of the text.
100
- return applyFormat( value, format, value.start - 1, value.end + 1 );
101
- } else if ( hasNoSelection && isAtTheEnd ) {
102
- // If there's no selection and is at the end of the text
103
- // manually add the format within the current caret position.
104
- const newFormat = applyFormat( value, format );
105
- const { activeFormats } = newFormat;
106
- newFormat.formats[ value.start ] = [
107
- ...( activeFormats?.filter(
108
- ( { type } ) => type !== format.type
109
- ) || [] ),
110
- format,
111
- ];
112
- return newFormat;
113
- } else if ( hasNoSelection ) {
114
- return removeFormat( value, format );
115
- }
116
90
 
91
+ if ( hasNoSelection ) {
92
+ contentRef?.onMarkFormatting( color );
93
+ }
117
94
  return applyFormat( value, format );
118
95
  }
119
96
 
120
- function ColorPicker( { name, value, onChange } ) {
97
+ function ColorPicker( { name, value, onChange, contentRef } ) {
121
98
  const property = 'color';
122
99
  const colors = useMobileGlobalStylesColors();
123
100
  const colorSettings = useMultipleOriginColorsAndGradients();
124
101
 
125
102
  const onColorChange = useCallback(
126
103
  ( color ) => {
127
- if ( color !== '' ) {
128
- onChange(
129
- setColors( value, name, colors, { [ property ]: color } )
130
- );
131
- // Remove formatting if the color was reset, there's no
132
- // current selection and the previous character is a space
133
- } else if (
134
- value?.start === value?.end &&
135
- value.text?.charAt( value?.end - 1 ) === ' '
136
- ) {
137
- onChange(
138
- removeFormat( value, name, value.end - 1, value.end )
139
- );
140
- } else {
141
- onChange( removeFormat( value, name ) );
142
- }
104
+ onChange(
105
+ setColors(
106
+ value,
107
+ name,
108
+ colors,
109
+ { [ property ]: color },
110
+ contentRef
111
+ )
112
+ );
143
113
  },
144
- [ colors, onChange, property ]
114
+ [ colors, contentRef, name, onChange, value ]
145
115
  );
146
116
  const activeColors = useMemo(
147
117
  () => getActiveColors( value, name, colors ),
@@ -152,13 +122,20 @@ function ColorPicker( { name, value, onChange } ) {
152
122
  <ColorSettings
153
123
  colorValue={ activeColors[ property ] }
154
124
  onColorChange={ onColorChange }
125
+ onColorCleared={ onColorChange }
155
126
  defaultSettings={ colorSettings }
156
127
  hideNavigation
157
128
  />
158
129
  );
159
130
  }
160
131
 
161
- export default function InlineColorUI( { name, value, onChange, onClose } ) {
132
+ export default function InlineColorUI( {
133
+ name,
134
+ value,
135
+ onChange,
136
+ onClose,
137
+ contentRef,
138
+ } ) {
162
139
  return (
163
140
  <BottomSheet
164
141
  isVisible
@@ -175,6 +152,7 @@ export default function InlineColorUI( { name, value, onChange, onClose } ) {
175
152
  name={ name }
176
153
  value={ value }
177
154
  onChange={ onChange }
155
+ contentRef={ contentRef }
178
156
  />
179
157
  </BottomSheet.NavigationScreen>
180
158
  </BottomSheet.NavigationContainer>
@@ -6,12 +6,6 @@ exports[`Text color allows toggling the highlight color feature to selected text
6
6
  <!-- /wp:paragraph -->"
7
7
  `;
8
8
 
9
- exports[`Text color allows toggling the highlight color feature to type new text 1`] = `
10
- "<!-- wp:paragraph -->
11
- <p><mark style="background-color:rgba(0, 0, 0, 0);color:#f78da7" class="has-inline-color has-pale-pink-color"></mark></p>
12
- <!-- /wp:paragraph -->"
13
- `;
14
-
15
9
  exports[`Text color creates a paragraph block with the text color format 1`] = `
16
10
  "<!-- wp:paragraph -->
17
11
  <p>Hello <mark style="background-color:rgba(0,0,0,0);color:#cf2e2e" class="has-inline-color has-vivid-red-color">this is a test</mark></p>