@wordpress/format-library 5.48.0 → 5.49.1-next.v.202606191442.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 (46) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/build/image/index.cjs +5 -3
  3. package/build/image/index.cjs.map +3 -3
  4. package/build/language/index.cjs +6 -4
  5. package/build/language/index.cjs.map +3 -3
  6. package/build/link/css-classes-setting.cjs +1 -1
  7. package/build/link/css-classes-setting.cjs.map +3 -3
  8. package/build/math/index.cjs +30 -13
  9. package/build/math/index.cjs.map +3 -3
  10. package/build/non-breaking-space/index.cjs +1 -1
  11. package/build/non-breaking-space/index.cjs.map +1 -1
  12. package/build/text-color/inline.cjs +6 -7
  13. package/build/text-color/inline.cjs.map +3 -3
  14. package/build-module/image/index.mjs +5 -6
  15. package/build-module/image/index.mjs.map +2 -2
  16. package/build-module/language/index.mjs +7 -7
  17. package/build-module/language/index.mjs.map +2 -2
  18. package/build-module/link/css-classes-setting.mjs +3 -4
  19. package/build-module/link/css-classes-setting.mjs.map +2 -2
  20. package/build-module/math/index.mjs +37 -15
  21. package/build-module/math/index.mjs.map +2 -2
  22. package/build-module/non-breaking-space/index.mjs +1 -1
  23. package/build-module/non-breaking-space/index.mjs.map +1 -1
  24. package/build-module/text-color/inline.mjs +7 -11
  25. package/build-module/text-color/inline.mjs.map +2 -2
  26. package/package.json +22 -18
  27. package/src/image/index.js +8 -9
  28. package/src/language/index.js +8 -8
  29. package/src/link/css-classes-setting.js +3 -4
  30. package/src/math/index.js +50 -16
  31. package/src/text-color/inline.js +11 -16
  32. package/src/default-formats.native.js +0 -10
  33. package/src/link/index.native.js +0 -176
  34. package/src/link/modal-screens/link-picker-screen.native.js +0 -61
  35. package/src/link/modal-screens/link-settings-screen.native.js +0 -229
  36. package/src/link/modal-screens/screens.native.js +0 -4
  37. package/src/link/modal.native.js +0 -44
  38. package/src/link/modal.native.scss +0 -16
  39. package/src/link/test/__snapshots__/modal.native.js.snap +0 -553
  40. package/src/link/test/index.native.js +0 -145
  41. package/src/link/test/modal.native.js +0 -18
  42. package/src/text-color/index.native.js +0 -172
  43. package/src/text-color/inline.native.js +0 -169
  44. package/src/text-color/style.native.scss +0 -22
  45. package/src/text-color/test/__snapshots__/index.native.js.snap +0 -23
  46. package/src/text-color/test/index.native.js +0 -192
@@ -16,19 +16,14 @@ import {
16
16
  getColorObjectByAttributeValues,
17
17
  store as blockEditorStore,
18
18
  } from '@wordpress/block-editor';
19
- import {
20
- Popover,
21
- privateApis as componentsPrivateApis,
22
- } from '@wordpress/components';
19
+ import { Popover } from '@wordpress/components';
20
+ import { Tabs } from '@wordpress/ui';
23
21
  import { __ } from '@wordpress/i18n';
24
22
 
25
23
  /**
26
24
  * Internal dependencies
27
25
  */
28
26
  import { textColor as settings, transparentValue } from './index';
29
- import { unlock } from '../lock-unlock';
30
-
31
- const { Tabs } = unlock( componentsPrivateApis );
32
27
 
33
28
  const TABS = [
34
29
  { name: 'color', title: __( 'Text' ) },
@@ -168,18 +163,18 @@ export default function InlineColorUI( {
168
163
  className="format-library__inline-color-popover"
169
164
  anchor={ popoverAnchor }
170
165
  >
171
- <Tabs>
172
- <Tabs.TabList>
166
+ <Tabs.Root defaultValue={ TABS[ 0 ].name }>
167
+ <Tabs.List>
173
168
  { TABS.map( ( tab ) => (
174
- <Tabs.Tab tabId={ tab.name } key={ tab.name }>
169
+ <Tabs.Tab value={ tab.name } key={ tab.name }>
175
170
  { tab.title }
176
171
  </Tabs.Tab>
177
172
  ) ) }
178
- </Tabs.TabList>
173
+ </Tabs.List>
179
174
  { TABS.map( ( tab ) => (
180
- <Tabs.TabPanel
181
- tabId={ tab.name }
182
- focusable={ false }
175
+ <Tabs.Panel
176
+ value={ tab.name }
177
+ tabIndex={ -1 }
183
178
  key={ tab.name }
184
179
  >
185
180
  <ColorPicker
@@ -188,9 +183,9 @@ export default function InlineColorUI( {
188
183
  value={ value }
189
184
  onChange={ onChange }
190
185
  />
191
- </Tabs.TabPanel>
186
+ </Tabs.Panel>
192
187
  ) ) }
193
- </Tabs>
188
+ </Tabs.Root>
194
189
  </Popover>
195
190
  );
196
191
  }
@@ -1,10 +0,0 @@
1
- /**
2
- * Internal dependencies
3
- */
4
- import { bold } from './bold';
5
- import { italic } from './italic';
6
- import { link } from './link';
7
- import { strikethrough } from './strikethrough';
8
- import { textColor } from './text-color';
9
-
10
- export default [ bold, italic, link, strikethrough, textColor ];
@@ -1,176 +0,0 @@
1
- /**
2
- * External dependencies
3
- */
4
- import Clipboard from '@react-native-clipboard/clipboard';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
- import { __ } from '@wordpress/i18n';
10
- import { Component } from '@wordpress/element';
11
- import { withSpokenMessages } from '@wordpress/components';
12
- import { RichTextToolbarButton } from '@wordpress/block-editor';
13
- import {
14
- applyFormat,
15
- getActiveFormat,
16
- getTextContent,
17
- isCollapsed,
18
- removeFormat,
19
- slice,
20
- } from '@wordpress/rich-text';
21
- import { isURL } from '@wordpress/url';
22
- import { link as linkIcon } from '@wordpress/icons';
23
-
24
- /**
25
- * Internal dependencies
26
- */
27
- import ModalLinkUI from './modal';
28
- import { isValidHref } from './utils';
29
-
30
- const name = 'core/link';
31
-
32
- export const link = {
33
- name,
34
- title: __( 'Link' ),
35
- tagName: 'a',
36
- className: null,
37
- attributes: {
38
- url: 'href',
39
- target: 'target',
40
- rel: 'rel',
41
- },
42
- edit: withSpokenMessages(
43
- class LinkEdit extends Component {
44
- constructor() {
45
- super( ...arguments );
46
-
47
- this.addLink = this.addLink.bind( this );
48
- this.stopAddingLink = this.stopAddingLink.bind( this );
49
- this.onRemoveFormat = this.onRemoveFormat.bind( this );
50
- this.getURLFromClipboard =
51
- this.getURLFromClipboard.bind( this );
52
- this.state = {
53
- addingLink: false,
54
- };
55
- }
56
-
57
- addLink() {
58
- const { value, onChange } = this.props;
59
- const text = getTextContent( slice( value ) );
60
-
61
- if ( text && isURL( text ) && isValidHref( text ) ) {
62
- const newValue = applyFormat( value, {
63
- type: name,
64
- attributes: { url: text },
65
- } );
66
- newValue.start = newValue.end;
67
- newValue.activeFormats = [];
68
- onChange( { ...newValue, needsSelectionUpdate: true } );
69
- } else {
70
- this.setState( { addingLink: true } );
71
- this.getURLFromClipboard();
72
- }
73
- }
74
-
75
- stopAddingLink() {
76
- this.setState( { addingLink: false, clipboardURL: undefined } );
77
- }
78
-
79
- getLinkSelection() {
80
- const { value, isActive } = this.props;
81
- const startFormat = getActiveFormat( value, 'core/link' );
82
-
83
- // If the link isn't selected, get the link manually by looking around the cursor
84
- // TODO: handle partly selected links.
85
- if ( startFormat && isCollapsed( value ) && isActive ) {
86
- let startIndex = value.start;
87
- let endIndex = value.end;
88
-
89
- while (
90
- value.formats[ startIndex ]?.find(
91
- ( format ) => format?.type === startFormat.type
92
- )
93
- ) {
94
- startIndex--;
95
- }
96
-
97
- endIndex++;
98
-
99
- while (
100
- value.formats[ endIndex ]?.find(
101
- ( format ) => format?.type === startFormat.type
102
- )
103
- ) {
104
- endIndex++;
105
- }
106
-
107
- return {
108
- ...value,
109
- start: startIndex + 1,
110
- end: endIndex,
111
- };
112
- }
113
-
114
- return value;
115
- }
116
-
117
- onRemoveFormat() {
118
- const { onChange, speak, value } = this.props;
119
- const startFormat = getActiveFormat( value, 'core/link' );
120
-
121
- // Before we try to remove anything we check if there is something at the caret position to remove.
122
- if ( isCollapsed( value ) && startFormat === undefined ) {
123
- return;
124
- }
125
-
126
- const linkSelection = this.getLinkSelection();
127
-
128
- onChange( removeFormat( linkSelection, name ) );
129
- speak( __( 'Link removed.' ), 'assertive' );
130
- }
131
-
132
- async getURLFromClipboard() {
133
- const clipboardText = await Clipboard.getString();
134
- if ( ! clipboardText ) {
135
- return;
136
- }
137
- // Check if pasted text is URL.
138
- if ( ! isURL( clipboardText ) ) {
139
- return;
140
- }
141
- this.setState( { clipboardURL: clipboardText } );
142
- }
143
-
144
- render() {
145
- const { isActive, activeAttributes, onChange } = this.props;
146
- const linkSelection = this.getLinkSelection();
147
- // If no URL is set and we have a clipboard URL let's use it.
148
- if ( ! activeAttributes.url && this.state.clipboardURL ) {
149
- activeAttributes.url = this.state.clipboardURL;
150
- }
151
- return (
152
- <>
153
- <ModalLinkUI
154
- isVisible={ this.state.addingLink }
155
- isActive={ isActive }
156
- activeAttributes={ activeAttributes }
157
- onClose={ this.stopAddingLink }
158
- onChange={ onChange }
159
- onRemove={ this.onRemoveFormat }
160
- value={ linkSelection }
161
- />
162
- <RichTextToolbarButton
163
- name="link"
164
- icon={ linkIcon }
165
- title={ __( 'Link' ) }
166
- onClick={ this.addLink }
167
- isActive={ isActive }
168
- shortcutType="primary"
169
- shortcutCharacter="k"
170
- />
171
- </>
172
- );
173
- }
174
- }
175
- ),
176
- };
@@ -1,61 +0,0 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { Keyboard } from 'react-native';
5
- import { useNavigation, useRoute } from '@react-navigation/native';
6
-
7
- /**
8
- * WordPress dependencies
9
- */
10
- import { useEffect, useMemo, useRef } from '@wordpress/element';
11
-
12
- import { LinkPicker } from '@wordpress/components';
13
-
14
- /**
15
- * Internal dependencies
16
- */
17
- import linkSettingsScreens from './screens';
18
-
19
- const LinkPickerScreen = () => {
20
- const navigation = useNavigation();
21
- const route = useRoute();
22
- const navigateToLinkTimeoutRef = useRef( null );
23
- const navigateBackTimeoutRef = useRef( null );
24
-
25
- const onLinkPicked = ( { url, title } ) => {
26
- Keyboard.dismiss();
27
- navigateToLinkTimeoutRef.current = setTimeout( () => {
28
- navigation.navigate( linkSettingsScreens.settings, {
29
- inputValue: url,
30
- text: title,
31
- } );
32
- }, 100 );
33
- };
34
-
35
- const onCancel = () => {
36
- Keyboard.dismiss();
37
- navigateBackTimeoutRef.current = setTimeout( () => {
38
- navigation.goBack();
39
- }, 100 );
40
- };
41
-
42
- useEffect( () => {
43
- return () => {
44
- clearTimeout( navigateToLinkTimeoutRef.current );
45
- clearTimeout( navigateBackTimeoutRef.current );
46
- };
47
- }, [] );
48
-
49
- const { inputValue } = route.params;
50
- return useMemo( () => {
51
- return (
52
- <LinkPicker
53
- value={ inputValue }
54
- onLinkPicked={ onLinkPicked }
55
- onCancel={ onCancel }
56
- />
57
- );
58
- }, [ inputValue ] );
59
- };
60
-
61
- export default LinkPickerScreen;
@@ -1,229 +0,0 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { useNavigation, useRoute } from '@react-navigation/native';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
- import { __ } from '@wordpress/i18n';
10
- import { useState, useContext, useEffect, useMemo } from '@wordpress/element';
11
- import { prependHTTP } from '@wordpress/url';
12
- import { BottomSheet, BottomSheetContext } from '@wordpress/components';
13
- import {
14
- create,
15
- insert,
16
- isCollapsed,
17
- applyFormat,
18
- getTextContent,
19
- slice,
20
- } from '@wordpress/rich-text';
21
- import { external, textColor } from '@wordpress/icons';
22
-
23
- /**
24
- * Internal dependencies
25
- */
26
- import { createLinkFormat, isValidHref } from '../utils';
27
- import linkSettingsScreens from './screens';
28
-
29
- import styles from '../modal.scss';
30
-
31
- const LinkSettingsScreen = ( {
32
- onRemove,
33
- onClose,
34
- onChange,
35
- speak,
36
- value,
37
- isActive,
38
- activeAttributes,
39
- isVisible,
40
- } ) => {
41
- const [ text, setText ] = useState( getTextContent( slice( value ) ) );
42
- const [ opensInNewWindow, setOpensInNewWindows ] = useState(
43
- activeAttributes.target === '_blank'
44
- );
45
- const [ linkValues, setLinkValues ] = useState( {
46
- isActiveLink: isActive,
47
- isRemovingLink: false,
48
- } );
49
-
50
- const {
51
- shouldEnableBottomSheetMaxHeight,
52
- onHandleClosingBottomSheet,
53
- listProps,
54
- } = useContext( BottomSheetContext );
55
-
56
- const navigation = useNavigation();
57
- const route = useRoute();
58
- const { inputValue = activeAttributes.url || '' } = route.params || {};
59
- const onLinkCellPressed = () => {
60
- shouldEnableBottomSheetMaxHeight( false );
61
- navigation.navigate( linkSettingsScreens.picker, { inputValue } );
62
- };
63
- useEffect( () => {
64
- onHandleClosingBottomSheet( () => {
65
- submit( inputValue, { skipStateUpdates: true } );
66
- } );
67
- }, [ inputValue, opensInNewWindow, text ] );
68
-
69
- useEffect( () => {
70
- const { isActiveLink, isRemovingLink } = linkValues;
71
- if ( !! inputValue && ! isActiveLink && isVisible ) {
72
- submitLink( { shouldCloseBottomSheet: false } );
73
- } else if (
74
- ( ( inputValue === '' && isActiveLink ) || isRemovingLink ) &&
75
- isVisible
76
- ) {
77
- removeLink( { shouldCloseBottomSheet: false } );
78
- }
79
- }, [
80
- inputValue,
81
- isVisible,
82
- linkValues.isActiveLink,
83
- linkValues.isRemovingLink,
84
- ] );
85
-
86
- const clearFormat = ( { skipStateUpdates = false } = {} ) => {
87
- onChange( { ...value, activeFormats: [] } );
88
- if ( ! skipStateUpdates ) {
89
- setLinkValues( { isActiveLink: false, isRemovingLink: true } );
90
- }
91
- };
92
-
93
- const submitLink = ( {
94
- shouldCloseBottomSheet = true,
95
- skipStateUpdates = false,
96
- } = {} ) => {
97
- const url = prependHTTP( inputValue );
98
- const linkText = text || inputValue;
99
- const format = createLinkFormat( {
100
- url,
101
- opensInNewWindow,
102
- text: linkText,
103
- } );
104
- let newAttributes;
105
- if ( isCollapsed( value ) && ! isActive ) {
106
- // Insert link.
107
- const toInsert = applyFormat(
108
- create( { text: linkText } ),
109
- format,
110
- 0,
111
- linkText.length
112
- );
113
- newAttributes = insert( value, toInsert );
114
- } else if ( text !== getTextContent( slice( value ) ) ) {
115
- // Edit text in selected link.
116
- const toInsert = applyFormat(
117
- create( { text } ),
118
- format,
119
- 0,
120
- text.length
121
- );
122
- newAttributes = insert( value, toInsert, value.start, value.end );
123
- } else {
124
- // Transform selected text into link.
125
- newAttributes = applyFormat( value, format );
126
- }
127
- // Move selection to end of link.
128
- const textLength = newAttributes.text.length;
129
- // check for zero width spaces
130
- if ( newAttributes.end > textLength ) {
131
- newAttributes.start = textLength;
132
- newAttributes.end = textLength;
133
- } else {
134
- newAttributes.start = newAttributes.end;
135
- }
136
- newAttributes.activeFormats = [];
137
- onChange( { ...newAttributes, needsSelectionUpdate: true } );
138
- if ( ! skipStateUpdates ) {
139
- setLinkValues( { isActiveLink: true, isRemovingLink: false } );
140
- }
141
-
142
- if ( ! isValidHref( url ) ) {
143
- speak(
144
- __(
145
- 'Warning: the link has been inserted but may have errors. Please test it.'
146
- ),
147
- 'assertive'
148
- );
149
- } else if ( isActive ) {
150
- speak( __( 'Link edited.' ), 'assertive' );
151
- } else {
152
- speak( __( 'Link inserted' ), 'assertive' );
153
- }
154
-
155
- if ( shouldCloseBottomSheet ) {
156
- onClose();
157
- }
158
- };
159
-
160
- const removeLink = ( {
161
- shouldCloseBottomSheet = true,
162
- skipStateUpdates = false,
163
- } = {} ) => {
164
- clearFormat( { skipStateUpdates } );
165
- onRemove();
166
- if ( shouldCloseBottomSheet ) {
167
- onClose();
168
- }
169
- };
170
-
171
- const submit = ( submitValue, { skipStateUpdates = false } = {} ) => {
172
- if ( submitValue === '' ) {
173
- removeLink( { skipStateUpdates } );
174
- } else {
175
- submitLink( { skipStateUpdates } );
176
- }
177
- };
178
-
179
- useEffect( () => {
180
- const unsubscribe = navigation.addListener( 'focus', () => {
181
- const { params = {} } = route;
182
- if ( ! text && params.text ) {
183
- setText( params.text );
184
- }
185
- } );
186
- return unsubscribe;
187
- }, [ navigation, route.params?.text, text ] );
188
-
189
- return useMemo( () => {
190
- const shouldShowLinkOptions = !! inputValue;
191
-
192
- return (
193
- <>
194
- <BottomSheet.LinkCell
195
- value={ inputValue }
196
- onPress={ onLinkCellPressed }
197
- />
198
- <BottomSheet.Cell
199
- icon={ textColor }
200
- label={ __( 'Link text' ) }
201
- value={ text }
202
- placeholder={ __( 'Add link text' ) }
203
- onChangeValue={ setText }
204
- onSubmit={ submit }
205
- separatorType={ shouldShowLinkOptions ? undefined : 'none' }
206
- />
207
- { shouldShowLinkOptions && (
208
- <>
209
- <BottomSheet.SwitchCell
210
- icon={ external }
211
- label={ __( 'Open in new tab' ) }
212
- value={ opensInNewWindow }
213
- onValueChange={ setOpensInNewWindows }
214
- separatorType="fullWidth"
215
- />
216
- <BottomSheet.Cell
217
- label={ __( 'Remove link' ) }
218
- labelStyle={ styles.clearLinkButton }
219
- separatorType="none"
220
- onPress={ removeLink }
221
- />
222
- </>
223
- ) }
224
- </>
225
- );
226
- }, [ inputValue, text, opensInNewWindow, listProps.safeAreaBottomInset ] );
227
- };
228
-
229
- export default LinkSettingsScreen;
@@ -1,4 +0,0 @@
1
- export default {
2
- settings: 'linkSettings',
3
- picker: 'linkPicker',
4
- };
@@ -1,44 +0,0 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import { useMemo } from '@wordpress/element';
5
- import { BottomSheet, withSpokenMessages } from '@wordpress/components';
6
-
7
- /**
8
- * Internal dependencies
9
- */
10
- import screens from './modal-screens/screens';
11
- import LinkSettingsScreen from './modal-screens/link-settings-screen';
12
- import LinkPickerScreen from './modal-screens/link-picker-screen';
13
-
14
- const ModalLinkUI = ( { isVisible, ...restProps } ) => {
15
- return useMemo( () => {
16
- return (
17
- <BottomSheet
18
- isVisible={ isVisible }
19
- hideHeader
20
- onClose={ restProps.onClose }
21
- hasNavigation
22
- testID="link-settings-modal"
23
- >
24
- <BottomSheet.NavigationContainer animate main>
25
- <BottomSheet.NavigationScreen name={ screens.settings }>
26
- <LinkSettingsScreen
27
- isVisible={ isVisible }
28
- { ...restProps }
29
- />
30
- </BottomSheet.NavigationScreen>
31
- <BottomSheet.NavigationScreen
32
- name={ screens.picker }
33
- isScrollable
34
- fullScreen
35
- >
36
- <LinkPickerScreen />
37
- </BottomSheet.NavigationScreen>
38
- </BottomSheet.NavigationContainer>
39
- </BottomSheet>
40
- );
41
- }, [ isVisible ] );
42
- };
43
-
44
- export default withSpokenMessages( ModalLinkUI );
@@ -1,16 +0,0 @@
1
- .clearLinkButton {
2
- color: $alert-red;
3
- }
4
-
5
- .container {
6
- padding-bottom: 0;
7
- padding-left: $block-edge-to-content;
8
- padding-right: $block-edge-to-content;
9
- padding-top: $block-edge-to-content*0.5;
10
- }
11
-
12
- .content {
13
- padding-left: $grid-unit-20;
14
- padding-right: $grid-unit-20;
15
- padding-bottom: 0;
16
- }