@siratik/wp-component-library 0.1.1 → 0.1.2

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 (96) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +43 -5
  3. package/components/attachment-image/README.md +118 -0
  4. package/components/attachment-image/index.js +105 -0
  5. package/components/attributes-panel/README.md +92 -0
  6. package/components/attributes-panel/index.js +324 -0
  7. package/components/badge/README.md +61 -0
  8. package/components/badge/index.js +105 -0
  9. package/components/block-appender/README.md +158 -0
  10. package/components/block-appender/index.js +135 -0
  11. package/components/block-extension/index.js +214 -0
  12. package/components/business-hours/SpecialHoursControl.js +211 -0
  13. package/components/business-hours/WeeklyHoursControl.js +419 -0
  14. package/components/business-hours/index.js +8 -0
  15. package/components/button/README.md +172 -0
  16. package/components/button/index.js +84 -0
  17. package/components/captcha-placeholder/CloudflareTurnstile.js +111 -0
  18. package/components/captcha-placeholder/GoogleRecaptcha.js +132 -0
  19. package/components/captcha-placeholder/HCaptcha.js +99 -0
  20. package/components/captcha-placeholder/README.md +228 -0
  21. package/components/captcha-placeholder/index.js +39 -0
  22. package/components/captcha-placeholder/styles.js +33 -0
  23. package/components/geocoder/AddressEntryControl.js +390 -0
  24. package/components/geocoder/GeocoderSearchControl.js +353 -0
  25. package/components/geocoder/countryOptions.js +66 -0
  26. package/components/geocoder/geocoder.js +400 -0
  27. package/components/geocoder/index.js +16 -0
  28. package/components/icon-picker/Icon.js +53 -0
  29. package/components/icon-picker/IconPicker.js +70 -0
  30. package/components/icon-picker/IconPickerModal.js +474 -0
  31. package/components/icon-picker/IconPickerToolbarButton.js +60 -0
  32. package/components/icon-picker/InlineIconPicker.js +92 -0
  33. package/components/icon-picker/api.js +181 -0
  34. package/components/icon-picker/config-bootstrap.js +108 -0
  35. package/components/icon-picker/hooks.js +157 -0
  36. package/components/icon-picker/index.js +39 -0
  37. package/components/icon-picker/load-script.js +33 -0
  38. package/components/icon-picker/loaders.js +79 -0
  39. package/components/icon-picker/store.js +223 -0
  40. package/components/icon-picker/styles.js +232 -0
  41. package/components/icon-picker/utils.js +138 -0
  42. package/components/layout/README.md +268 -0
  43. package/components/link-tools-panel/README.md +49 -0
  44. package/components/link-tools-panel/index.js +198 -0
  45. package/components/link-tools-panel/styles.js +90 -0
  46. package/components/media/README.md +288 -0
  47. package/components/media/SettingsMediaUpload.js +187 -0
  48. package/components/media/editor-media-upload.js +65 -0
  49. package/components/media/image-controls.js +196 -0
  50. package/components/media/index.js +13 -0
  51. package/components/media/inspector-media-upload.js +290 -0
  52. package/components/media/toolbar-media-upload.js +53 -0
  53. package/components/media/utils/aspect-ratios.js +118 -0
  54. package/components/meta/MetaPanel.js +75 -0
  55. package/components/meta/README.md +46 -0
  56. package/components/meta/index.js +6 -0
  57. package/components/meta/meta-gated-editor.js +282 -0
  58. package/components/query/README.md +340 -0
  59. package/components/query/cardTemplatePartPanel.js +69 -0
  60. package/components/query/cardTemplatePartSelect.js +165 -0
  61. package/components/query/cardTemplatePartUtils.js +119 -0
  62. package/components/query/columnCountControl.js +63 -0
  63. package/components/query/displayTypeSelect.js +52 -0
  64. package/components/query/examples.js +166 -0
  65. package/components/query/hideCurrentPostControl.js +47 -0
  66. package/components/query/index.js +20 -0
  67. package/components/query/manualPostSelector.js +125 -0
  68. package/components/query/manualTermSelector.js +141 -0
  69. package/components/query/orderBySelect.js +95 -0
  70. package/components/query/postTypeSelect.js +67 -0
  71. package/components/query/postsPerPageControl.js +51 -0
  72. package/components/query/selectionModeControl.js +61 -0
  73. package/components/query/taxonomySelect.js +139 -0
  74. package/components/query/utils.js +75 -0
  75. package/components/repeater/README.md +159 -0
  76. package/components/repeater/index.js +829 -0
  77. package/components/segmented-bar/README.md +30 -0
  78. package/components/segmented-bar/index.js +68 -0
  79. package/components/sortable-select/README.md +153 -0
  80. package/components/sortable-select/custom-sortable-token.js +127 -0
  81. package/components/sortable-select/index.js +693 -0
  82. package/components/style-picker/README.md +36 -0
  83. package/components/style-picker/index.js +92 -0
  84. package/components/variable-field/README.md +299 -0
  85. package/components/variable-field/index.js +592 -0
  86. package/components/variable-field/value-to-chip-html.js +38 -0
  87. package/components/variable-inserter/README.md +68 -0
  88. package/components/variable-inserter/index.js +168 -0
  89. package/constants/statusColors.js +1 -1
  90. package/editor.js +16 -0
  91. package/index.js +127 -0
  92. package/package.json +21 -13
  93. package/utils/kitaris-localize.js +128 -0
  94. package/utils/slug-aware-color-setter.js +27 -0
  95. package/build/index.asset.php +0 -20
  96. package/build/index.js +0 -1242
@@ -0,0 +1,268 @@
1
+ # Layout Components
2
+
3
+ A comprehensive set of layout control components for WordPress blocks, providing flexbox-based alignment and positioning controls for both toolbar and inspector contexts.
4
+
5
+ ## Features
6
+
7
+ - Complete flexbox layout control system
8
+ - Toolbar and inspector panel variations
9
+ - Orientation switching (horizontal/vertical)
10
+ - Justification control (main axis alignment)
11
+ - Alignment control (cross axis alignment)
12
+ - Content alignment (text alignment)
13
+ - Flex wrap control
14
+ - Layout width control (full/constrained)
15
+ - Responsive and accessible UI
16
+
17
+ ## Components
18
+
19
+ ### Toolbar Components
20
+ For use in block toolbars:
21
+ - `AlignmentToolbar` - Cross axis alignment
22
+ - `JustificationToolbar` - Main axis alignment
23
+ - `OrientationToolbar` - Flex direction control
24
+ - `ContentAlignmentToolbar` - Text alignment
25
+
26
+ ### Inspector Components
27
+ For use in inspector panels:
28
+ - `AlignmentSettings` - Cross axis alignment settings
29
+ - `JustificationSettings` - Main axis alignment settings
30
+ - `OrientationSettings` - Flex direction settings
31
+ - `ContentAlignmentSettings` - Text alignment settings
32
+ - `AllowWrapSettings` - Flex wrap toggle
33
+ - `LayoutPanel` - Complete layout panel with all controls
34
+ - `LayoutWidthControl` - Full width vs constrained toggle
35
+
36
+ ## Usage
37
+
38
+ ```jsx
39
+ import {
40
+ LayoutPanel,
41
+ OrientationToolbar,
42
+ JustificationToolbar,
43
+ AlignmentToolbar
44
+ } from '@siratik/wp-component-library/components/layout';
45
+
46
+ // In block toolbar
47
+ <BlockControls>
48
+ <OrientationToolbar
49
+ value={orientation}
50
+ onChange={setOrientation}
51
+ />
52
+ <JustificationToolbar
53
+ value={justification}
54
+ onChange={setJustification}
55
+ orientation={orientation}
56
+ />
57
+ </BlockControls>
58
+
59
+ // In inspector controls
60
+ <InspectorControls>
61
+ <LayoutPanel
62
+ orientation={orientation}
63
+ onOrientationChange={setOrientation}
64
+ justification={justification}
65
+ onJustificationChange={setJustification}
66
+ alignment={alignment}
67
+ onAlignmentChange={setAlignment}
68
+ allowWrap={allowWrap}
69
+ onAllowWrapChange={setAllowWrap}
70
+ showOrientationControl={true}
71
+ showJustificationControl={true}
72
+ showAlignmentControl={true}
73
+ showAllowWrapControl={true}
74
+ />
75
+ </InspectorControls>
76
+ ```
77
+
78
+ ## Layout Panel Props
79
+
80
+ | Prop | Type | Default | Description |
81
+ |------|------|---------|-------------|
82
+ | `orientation` | `string` | `"horizontal"` | Flex direction: "horizontal" or "vertical" |
83
+ | `onOrientationChange` | `function` | - | Orientation change handler |
84
+ | `justification` | `string` | `"flex-start"` | Main axis alignment |
85
+ | `onJustificationChange` | `function` | - | Justification change handler |
86
+ | `alignment` | `string` | `"flex-start"` | Cross axis alignment |
87
+ | `onAlignmentChange` | `function` | - | Alignment change handler |
88
+ | `contentAlignment` | `string` | `"left"` | Text alignment within items |
89
+ | `onContentAlignmentChange` | `function` | - | Content alignment change handler |
90
+ | `allowWrap` | `boolean` | `false` | Allow flex items to wrap |
91
+ | `onAllowWrapChange` | `function` | - | Wrap change handler |
92
+ | `showOrientationControl` | `boolean` | `true` | Show orientation control |
93
+ | `showJustificationControl` | `boolean` | `true` | Show justification control |
94
+ | `showAlignmentControl` | `boolean` | `true` | Show alignment control |
95
+ | `showContentAlignmentControl` | `boolean` | `false` | Show content alignment control |
96
+ | `showAllowWrapControl` | `boolean` | `true` | Show wrap control |
97
+ | `group` | `string` | `"styles"` | Inspector control group |
98
+ | `resetAll` | `function` | - | Reset all values handler |
99
+
100
+ ## Individual Control Props
101
+
102
+ All individual controls follow a similar pattern:
103
+ ```jsx
104
+ <ControlName
105
+ value={currentValue}
106
+ onChange={handleChange}
107
+ orientation={orientation} // For context-aware controls
108
+ />
109
+ ```
110
+
111
+ ## Alignment Values
112
+
113
+ ### Justification (Main Axis)
114
+ - `flex-start` - Start of container
115
+ - `center` - Center of container
116
+ - `flex-end` - End of container
117
+ - `space-between` - Space between items
118
+
119
+ ### Alignment (Cross Axis)
120
+ - `flex-start` - Start of container
121
+ - `center` - Center of container
122
+ - `flex-end` - End of container
123
+ - `stretch` - Stretch to fill container
124
+
125
+ ### Content Alignment (Text)
126
+ - `left` - Left aligned text
127
+ - `center` - Center aligned text
128
+ - `right` - Right aligned text
129
+
130
+ ## CSS Generation
131
+
132
+ The components are designed to work with CSS classes or inline styles:
133
+
134
+ ```jsx
135
+ // Generate CSS classes
136
+ const layoutClasses = classnames({
137
+ [`is-orientation-${orientation}`]: orientation,
138
+ [`is-justified-${justification}`]: justification,
139
+ [`is-aligned-${alignment}`]: alignment,
140
+ 'is-wrap-allowed': allowWrap
141
+ });
142
+
143
+ // Or use inline styles
144
+ const layoutStyles = {
145
+ display: 'flex',
146
+ flexDirection: orientation === 'vertical' ? 'column' : 'row',
147
+ justifyContent: justification,
148
+ alignItems: alignment,
149
+ flexWrap: allowWrap ? 'wrap' : 'nowrap'
150
+ };
151
+ ```
152
+
153
+ ## Examples
154
+
155
+ ### Basic Row Layout
156
+ ```jsx
157
+ function RowBlock({ attributes, setAttributes }) {
158
+ const { orientation = 'horizontal', justification = 'flex-start' } = attributes;
159
+
160
+ return (
161
+ <>
162
+ <BlockControls>
163
+ <JustificationToolbar
164
+ value={justification}
165
+ onChange={(value) => setAttributes({ justification: value })}
166
+ orientation={orientation}
167
+ />
168
+ </BlockControls>
169
+
170
+ <div className={`row is-justified-${justification}`}>
171
+ <InnerBlocks />
172
+ </div>
173
+ </>
174
+ );
175
+ }
176
+ ```
177
+
178
+ ### Advanced Grid Layout
179
+ ```jsx
180
+ function GridBlock({ attributes, setAttributes }) {
181
+ return (
182
+ <InspectorControls>
183
+ <LayoutPanel
184
+ {...attributes}
185
+ onOrientationChange={(orientation) => setAttributes({ orientation })}
186
+ onJustificationChange={(justification) => setAttributes({ justification })}
187
+ onAlignmentChange={(alignment) => setAttributes({ alignment })}
188
+ onAllowWrapChange={(allowWrap) => setAttributes({ allowWrap })}
189
+ showContentAlignmentControl={true}
190
+ onContentAlignmentChange={(contentAlignment) => setAttributes({ contentAlignment })}
191
+ />
192
+ </InspectorControls>
193
+ );
194
+ }
195
+ ```
196
+
197
+ ### Responsive Column Layout
198
+ ```jsx
199
+ function ColumnLayout({ attributes, setAttributes }) {
200
+ const { orientation, alignment, allowWrap } = attributes;
201
+
202
+ return (
203
+ <>
204
+ <InspectorControls>
205
+ <PanelBody title="Layout">
206
+ <OrientationSettings
207
+ value={orientation}
208
+ onChange={(value) => setAttributes({ orientation: value })}
209
+ />
210
+ <AlignmentSettings
211
+ value={alignment}
212
+ onChange={(value) => setAttributes({ alignment: value })}
213
+ orientation={orientation}
214
+ />
215
+ <AllowWrapSettings
216
+ value={allowWrap}
217
+ onChange={(value) => setAttributes({ allowWrap: value })}
218
+ />
219
+ </PanelBody>
220
+ </InspectorControls>
221
+
222
+ <div
223
+ style={{
224
+ display: 'flex',
225
+ flexDirection: orientation === 'vertical' ? 'column' : 'row',
226
+ alignItems: alignment,
227
+ flexWrap: allowWrap ? 'wrap' : 'nowrap'
228
+ }}
229
+ >
230
+ <InnerBlocks />
231
+ </div>
232
+ </>
233
+ );
234
+ }
235
+ ```
236
+
237
+ ## Layout Width Control
238
+
239
+ Control whether content uses full width or is constrained:
240
+
241
+ ```jsx
242
+ <LayoutWidthControl
243
+ layout={layout}
244
+ onChange={(newLayout) => setAttributes({ layout: newLayout })}
245
+ />
246
+
247
+ // Layout object structure:
248
+ {
249
+ type: 'constrained' | 'default',
250
+ contentSize: '840px', // For constrained layout
251
+ wideSize: '1200px' // For wide alignment
252
+ }
253
+ ```
254
+
255
+ ## Accessibility
256
+
257
+ - All controls include proper ARIA labels
258
+ - Keyboard navigation fully supported
259
+ - Visual feedback for current selections
260
+ - Screen reader friendly descriptions
261
+
262
+ ## Notes
263
+
264
+ - Orientation affects available justification/alignment options
265
+ - Icons rotate appropriately for vertical orientation
266
+ - Controls integrate with WordPress ToolsPanel for consistent UX
267
+ - Styled with Emotion for customizable theming
268
+ - All controls are fully controlled components
@@ -0,0 +1,49 @@
1
+ # Link Tools Panel
2
+
3
+ Link settings for a block: a URL (WordPress's link search), "Use post permalink", "Open in new tab" and, opt-in, the link's `rel`.
4
+ WordPress's `LinkControl` is laid out for popovers; here it sits flush and fills the panel's width.
5
+
6
+ ## Usage
7
+
8
+ ```jsx
9
+ import { LinkToolsPanel, LinkToolsPanelItems } from '@siratik/wp-component-library';
10
+
11
+ // Its own "Link" panel (sidebar or a toolbar popover)
12
+ <LinkToolsPanel
13
+ link={ link }
14
+ opensInNewTab={ opensInNewTab }
15
+ isPermalink={ isPermalink }
16
+ onChange={ ( changes ) => setAttributes( changes ) }
17
+ panelId={ `${ clientId }-link` }
18
+ />
19
+
20
+ // Inside a panel the block already has
21
+ <ToolsPanel label="Settings">
22
+ <LinkToolsPanelItems
23
+ link={ link }
24
+ opensInNewTab={ opensInNewTab }
25
+ isPermalink={ isPermalink }
26
+ onChange={ ( changes ) => setAttributes( changes ) }
27
+ />
28
+ </ToolsPanel>
29
+ ```
30
+
31
+ ## Props
32
+
33
+ | Prop | Type | Default | Description |
34
+ |------|------|---------|-------------|
35
+ | `link` | `string` | `''` | Link URL |
36
+ | `opensInNewTab` | `boolean` | `false` | Whether the link opens in a new tab |
37
+ | `isPermalink` | `boolean` | `false` | Use the current post's permalink instead of `link` |
38
+ | `onChange` | `Function` | - | Called with the changed values, e.g. `{ link }` or `{ opensInNewTab }` |
39
+ | `panelId` | `string` | - | The surrounding panel's `panelId`. Items only register with a panel whose id matches |
40
+ | `isShownByDefault` | `boolean` | `true` | Whether URL and "Open in new tab" show before they have a value |
41
+ | `showPermalink` | `boolean` | `true` | Whether to offer "Use post permalink"; pass `false` for blocks with no such setting |
42
+ | `permalinkHelp` | `string` | generic | Help text for "Use post permalink" |
43
+ | `newTabHelp` | `string` | - | Help text shown while "Open in new tab" is on |
44
+ | `showRel` | `boolean` | `false` | Whether to offer "Link rel"; only for blocks that save and render it |
45
+ | `rel` | `string` | `''` | Link rel, e.g. `nofollow sponsored` |
46
+
47
+ `LinkToolsPanel` also accepts `label` (panel title, default "Link") and `className`.
48
+
49
+ `LINK_DEFAULTS` holds the default values (`{ link: '', opensInNewTab: false, isPermalink: false, rel: '' }`). `LinkToolsPanel`'s reset only clears `rel` when `showRel` is on.
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Link Tools Panel
3
+ *
4
+ * Link settings for a block: a URL (WordPress's link search), "Use post
5
+ * permalink", "Open in new tab" and, when the block asks for it, the link's
6
+ * rel (e.g. nofollow).
7
+ *
8
+ * - `LinkToolsPanelItems`: the controls as tools panel items, for a block
9
+ * that already has a ToolsPanel to put them in.
10
+ * - `LinkToolsPanel`: the same items in their own "Link" panel.
11
+ */
12
+ import { __experimentalLinkControl as LinkControl } from "@wordpress/block-editor";
13
+ import {
14
+ TextControl,
15
+ ToggleControl,
16
+ __experimentalToolsPanel as ToolsPanel,
17
+ __experimentalToolsPanelItem as ToolsPanelItem,
18
+ } from "@wordpress/components";
19
+ import { __ } from "@wordpress/i18n";
20
+
21
+ import { LinkField } from "./styles";
22
+
23
+ export const LINK_DEFAULTS = {
24
+ link: "",
25
+ opensInNewTab: false,
26
+ isPermalink: false,
27
+ rel: "",
28
+ };
29
+
30
+ /**
31
+ * Link controls as tools panel items.
32
+ *
33
+ * @param {Object} props
34
+ * @param {string} props.link Link URL.
35
+ * @param {boolean} props.opensInNewTab Whether the link opens in a new tab.
36
+ * @param {boolean} props.isPermalink Whether the current post's permalink is used.
37
+ * @param {Function} props.onChange Called with the changed values, e.g. `{ link }`.
38
+ * @param {string} [props.panelId] The surrounding ToolsPanel's `panelId`, if it has one. Items only register with a panel whose id matches.
39
+ * @param {boolean} [props.isShownByDefault=true] Whether URL and "Open in new tab" show before they have a value; when false they are added from the panel menu.
40
+ * @param {boolean} [props.showPermalink=true] Whether to offer "Use post permalink", for blocks that have no such setting.
41
+ * @param {string} [props.permalinkHelp] Help text for "Use post permalink".
42
+ * @param {string} [props.newTabHelp] Help text shown while "Open in new tab" is on.
43
+ * @param {boolean} [props.showRel=false] Whether to offer the link's rel, for blocks that save and render it.
44
+ * @param {string} [props.rel] Link rel, e.g. "nofollow sponsored".
45
+ */
46
+ export function LinkToolsPanelItems({
47
+ link = LINK_DEFAULTS.link,
48
+ opensInNewTab = LINK_DEFAULTS.opensInNewTab,
49
+ isPermalink = LINK_DEFAULTS.isPermalink,
50
+ onChange,
51
+ panelId,
52
+ isShownByDefault = true,
53
+ showPermalink = true,
54
+ permalinkHelp = __(
55
+ "Automatically use the current post's permalink as the link.",
56
+ "wp-component-library",
57
+ ),
58
+ newTabHelp,
59
+ showRel = false,
60
+ rel = LINK_DEFAULTS.rel,
61
+ }) {
62
+ return (
63
+ <>
64
+ {showPermalink && (
65
+ <ToolsPanelItem
66
+ panelId={panelId}
67
+ hasValue={() =>
68
+ isPermalink !== LINK_DEFAULTS.isPermalink
69
+ }
70
+ label={__("Use post permalink", "wp-component-library")}
71
+ onDeselect={() =>
72
+ onChange({ isPermalink: LINK_DEFAULTS.isPermalink })
73
+ }
74
+ isShownByDefault={false}
75
+ >
76
+ <ToggleControl
77
+ __nextHasNoMarginBottom
78
+ label={__(
79
+ "Use post permalink",
80
+ "wp-component-library",
81
+ )}
82
+ checked={isPermalink}
83
+ onChange={(value) => onChange({ isPermalink: value })}
84
+ help={permalinkHelp}
85
+ />
86
+ </ToolsPanelItem>
87
+ )}
88
+
89
+ {!isPermalink && (
90
+ <ToolsPanelItem
91
+ panelId={panelId}
92
+ hasValue={() => link !== LINK_DEFAULTS.link}
93
+ label={__("URL", "wp-component-library")}
94
+ onDeselect={() => onChange({ link: LINK_DEFAULTS.link })}
95
+ isShownByDefault={isShownByDefault}
96
+ >
97
+ <LinkField>
98
+ <LinkControl
99
+ searchInputPlaceholder={__(
100
+ "Search content or type URL",
101
+ "wp-component-library",
102
+ )}
103
+ value={{ url: link }}
104
+ onChange={({ url }) => onChange({ link: url })}
105
+ onRemove={() =>
106
+ onChange({ link: LINK_DEFAULTS.link })
107
+ }
108
+ showInitialSuggestions={true}
109
+ settings={[]}
110
+ />
111
+ </LinkField>
112
+ </ToolsPanelItem>
113
+ )}
114
+
115
+ <ToolsPanelItem
116
+ panelId={panelId}
117
+ hasValue={() =>
118
+ opensInNewTab !== LINK_DEFAULTS.opensInNewTab
119
+ }
120
+ label={__("Open in new tab", "wp-component-library")}
121
+ onDeselect={() =>
122
+ onChange({ opensInNewTab: LINK_DEFAULTS.opensInNewTab })
123
+ }
124
+ isShownByDefault={isShownByDefault}
125
+ >
126
+ <ToggleControl
127
+ __nextHasNoMarginBottom
128
+ label={__("Open in new tab", "wp-component-library")}
129
+ checked={opensInNewTab}
130
+ onChange={(value) => onChange({ opensInNewTab: value })}
131
+ help={opensInNewTab ? newTabHelp : undefined}
132
+ />
133
+ </ToolsPanelItem>
134
+
135
+ {showRel && (
136
+ <ToolsPanelItem
137
+ panelId={panelId}
138
+ hasValue={() => !!rel}
139
+ label={__("Link rel", "wp-component-library")}
140
+ onDeselect={() => onChange({ rel: LINK_DEFAULTS.rel })}
141
+ isShownByDefault={false}
142
+ >
143
+ <TextControl
144
+ __next40pxDefaultSize
145
+ __nextHasNoMarginBottom
146
+ label={__("Link rel", "wp-component-library")}
147
+ help={__(
148
+ "Space-separated values, e.g. nofollow or sponsored.",
149
+ "wp-component-library",
150
+ )}
151
+ value={rel}
152
+ onChange={(value) => onChange({ rel: value })}
153
+ />
154
+ </ToolsPanelItem>
155
+ )}
156
+ </>
157
+ );
158
+ }
159
+
160
+ /**
161
+ * Link controls in their own tools panel.
162
+ *
163
+ * Takes the same props as `LinkToolsPanelItems`, plus:
164
+ *
165
+ * @param {Object} props
166
+ * @param {string} [props.label] Panel title. Default "Link".
167
+ * @param {string} [props.panelId] Unique id for the panel.
168
+ * @param {string} [props.className] Extra class for the panel.
169
+ * @param {Function} props.onChange Called with the changed values.
170
+ */
171
+ export function LinkToolsPanel({
172
+ label = __("Link", "wp-component-library"),
173
+ panelId = "link-tools-panel",
174
+ className,
175
+ onChange,
176
+ ...itemProps
177
+ }) {
178
+ return (
179
+ <ToolsPanel
180
+ label={label}
181
+ panelId={panelId}
182
+ resetAll={() => {
183
+ // rel only for blocks that offer it (they have the attribute).
184
+ const { rel, ...defaults } = LINK_DEFAULTS;
185
+ onChange(itemProps.showRel ? { ...defaults, rel } : defaults);
186
+ }}
187
+ className={className}
188
+ >
189
+ <LinkToolsPanelItems
190
+ {...itemProps}
191
+ onChange={onChange}
192
+ panelId={panelId}
193
+ />
194
+ </ToolsPanel>
195
+ );
196
+ }
197
+
198
+ export default LinkToolsPanel;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Emotion styled components for the Link Tools Panel.
3
+ */
4
+ import styled from "@emotion/styled";
5
+
6
+ /**
7
+ * Wraps WordPress's LinkControl inside a tools panel.
8
+ *
9
+ * LinkControl is laid out for popovers: a 350px minimum width and 16px
10
+ * gutters around each of its parts. In a tools panel the panel provides the
11
+ * gutters, so the field sits flush and fills the panel's width.
12
+ */
13
+ export const LinkField = styled.div`
14
+ .block-editor-link-control {
15
+ min-width: 0;
16
+ width: 100%;
17
+ }
18
+
19
+ .block-editor-link-control__search-input-wrapper {
20
+ margin-bottom: 0;
21
+ }
22
+
23
+ .block-editor-link-control__field {
24
+ margin: 0;
25
+ }
26
+
27
+ .block-editor-url-input {
28
+ min-width: 0;
29
+ width: 100%;
30
+ }
31
+
32
+ /* A chosen link: its preview row. */
33
+ .block-editor-link-control__preview {
34
+ padding: 0;
35
+ }
36
+
37
+ .block-editor-link-control__search-actions {
38
+ padding: 8px 0 0;
39
+ }
40
+
41
+ /* Search results: a bordered list under the field, as wide as the panel. */
42
+ .block-editor-link-control__search-results-wrapper {
43
+ margin-top: 4px;
44
+
45
+ /* Core's scroll fades are positioned for the popover's gutters. */
46
+ &::before,
47
+ &::after {
48
+ display: none;
49
+ }
50
+ }
51
+
52
+ .block-editor-link-control__search-results {
53
+ margin: 0;
54
+ padding: 4px;
55
+ max-height: 240px;
56
+ overflow-x: hidden;
57
+ background: var(--wp-components-color-background, #fff);
58
+ border: 1px solid var(--wp-components-color-gray-300, #ddd);
59
+ border-radius: 2px;
60
+ }
61
+
62
+ .block-editor-link-control__search-item.components-button {
63
+ width: 100%;
64
+ min-width: 0;
65
+ height: auto;
66
+ padding: 6px 8px;
67
+ }
68
+
69
+ .block-editor-link-control__search-item .components-menu-item__item,
70
+ .block-editor-link-control__search-item .components-menu-item__info-wrapper {
71
+ min-width: 0;
72
+ }
73
+
74
+ /* One line each for the title and URL, truncated to the panel's width. */
75
+ .block-editor-link-control__search-item .components-menu-item__info-wrapper > * {
76
+ display: block;
77
+ overflow: hidden;
78
+ text-overflow: ellipsis;
79
+ white-space: nowrap;
80
+ }
81
+
82
+ /* The type label ("Page", "Attachment") doesn't fit; the icon shows the type. */
83
+ .block-editor-link-control__search-item .components-menu-item__shortcut {
84
+ display: none;
85
+ }
86
+
87
+ .block-editor-link-control__help {
88
+ padding: 0;
89
+ }
90
+ `;