@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,30 @@
1
+ # SegmentedBar Component
2
+
3
+ A row of equal segments, one per item, each in a status color. Use it for "3 of 4 on" summaries where each part matters, not just the total.
4
+
5
+ ## Usage
6
+
7
+ ```jsx
8
+ import { SegmentedBar } from '@siratik/wp-component-library';
9
+
10
+ <SegmentedBar
11
+ label="Firewall: 3 of 4 on"
12
+ segments={ [
13
+ { key: 'waf', intent: 'success' },
14
+ { key: 'exploits', intent: 'success' },
15
+ { key: 'xmlrpc', intent: 'warning' },
16
+ { key: 'bots', intent: 'success' },
17
+ ] }
18
+ />
19
+ ```
20
+
21
+ ## Props
22
+
23
+ | Prop | Type | Default | Description |
24
+ |------|------|---------|-------------|
25
+ | `segments` | `Array<{key: string, intent: string}>` | - | One segment each, in order. `intent` is `'success'`, `'warning'`, `'error'`, `'info'` or `'default'` (neutral gray) |
26
+ | `label` | `string` | - | Accessible summary. The bar is announced as an image with this label |
27
+ | `height` | `number` | `6` | Segment height in px |
28
+ | `className` | `string` | `''` | Additional CSS classes |
29
+
30
+ Colors come from the shared status palette (`statusColor`), so they match `Badge` and the score charts.
@@ -0,0 +1,68 @@
1
+ /**
2
+ * SegmentedBar Component
3
+ *
4
+ * A row of equal segments, one per item, each in a status color — for
5
+ * "3 of 4 on" style summaries where every part matters, not just the total.
6
+ *
7
+ * @package WPComponentLibrary
8
+ */
9
+
10
+ import styled from "@emotion/styled";
11
+ import { statusColor } from "../../constants/statusColors";
12
+
13
+ const Track = styled.div`
14
+ display: flex;
15
+ gap: 6px;
16
+ width: 100%;
17
+ `;
18
+
19
+ const Segment = styled.span`
20
+ flex: 1;
21
+ height: ${({ $height }) => $height}px;
22
+ border-radius: ${({ $height }) => $height / 2}px;
23
+ background: ${({ $color }) => $color};
24
+ `;
25
+
26
+ const NEUTRAL = "var(--wpds-color-background-surface-neutral-weak, #f0f0f0)";
27
+
28
+ /**
29
+ * Color for a segment intent.
30
+ *
31
+ * @param {string} intent 'success', 'warning', 'error', 'info' or 'default'.
32
+ * @return {string} CSS color.
33
+ */
34
+ function segmentColor(intent) {
35
+ return ["success", "warning", "error", "info"].includes(intent)
36
+ ? statusColor(intent, "fill")
37
+ : NEUTRAL;
38
+ }
39
+
40
+ /**
41
+ * SegmentedBar Component
42
+ *
43
+ * @param {Object} props
44
+ * @param {Array<{key: string, intent: string}>} props.segments One segment each, in order.
45
+ * @param {string} props.label Accessible summary, e.g. "Firewall: 3 of 4 on".
46
+ * @param {number} [props.height=6] Segment height in px.
47
+ * @param {string} [props.className] Additional CSS classes.
48
+ * @return {JSX.Element} Segmented bar.
49
+ */
50
+ export function SegmentedBar({ segments, label, height = 6, className = "" }) {
51
+ return (
52
+ <Track
53
+ role="img"
54
+ aria-label={label}
55
+ className={`siratik-segmented-bar ${className}`.trim()}
56
+ >
57
+ {segments.map((segment) => (
58
+ <Segment
59
+ key={segment.key}
60
+ $height={height}
61
+ $color={segmentColor(segment.intent)}
62
+ />
63
+ ))}
64
+ </Track>
65
+ );
66
+ }
67
+
68
+ export default SegmentedBar;
@@ -0,0 +1,153 @@
1
+ # SortableSelect Component
2
+
3
+ A flexible component that combines react-select with drag-and-drop sorting capabilities using dnd-kit. The selected tokens/pills within the react-select component itself are sortable via drag and drop. Perfect for creating searchable, sortable lists of posts, terms, users, or any custom data.
4
+
5
+ ## Installation
6
+
7
+ This component's dependencies are included with the component library. No additional installation is required.
8
+
9
+ ### Dependencies Included:
10
+ - react-select (for the select functionality)
11
+ - @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities, @dnd-kit/modifiers (for drag and drop)
12
+
13
+ **Note about @emotion warnings:** You may see console warnings about multiple instances of @emotion/react. These warnings are harmless and occur because react-select bundles @emotion. The component will function correctly despite these warnings.
14
+
15
+ ## Basic Usage
16
+
17
+ ```jsx
18
+ import { SortableSelect } from '@siratik/wp-component-library';
19
+ import { useState } from '@wordpress/element';
20
+
21
+ function MyComponent() {
22
+ const [selected, setSelected] = useState([]);
23
+
24
+ return (
25
+ <SortableSelect
26
+ value={selected}
27
+ onChange={setSelected}
28
+ options={[
29
+ { value: '1', label: 'Option 1' },
30
+ { value: '2', label: 'Option 2' },
31
+ { value: '3', label: 'Option 3' },
32
+ ]}
33
+ placeholder="Select options..."
34
+ />
35
+ );
36
+ }
37
+ ```
38
+
39
+ ## Props
40
+
41
+ | Prop | Type | Default | Description |
42
+ |------|------|---------|-------------|
43
+ | `value` | `Array` | `[]` | Currently selected items |
44
+ | `onChange` | `Function` | required | Callback when selection or order changes |
45
+ | `options` | `Array` | - | Static options for sync mode |
46
+ | `loadOptions` | `Function` | - | Async function to load options |
47
+ | `getOptionLabel` | `Function` | `(option) => option.label \|\| option.name \|\| option.title` | Extract display label |
48
+ | `getOptionValue` | `Function` | `(option) => option.value \|\| option.id` | Extract unique value |
49
+ | `renderOption` | `Function` | - | Custom option renderer |
50
+ | `placeholder` | `string` | `"Search and select..."` | Placeholder text |
51
+ | `isMulti` | `boolean` | `true` | Enable multi-select |
52
+ | `isClearable` | `boolean` | `true` | Show clear button |
53
+ | `isSearchable` | `boolean` | `true` | Enable search |
54
+ | `isDisabled` | `boolean` | `false` | Disable component |
55
+ | `className` | `string` | `""` | Additional CSS classes |
56
+ | `maxItems` | `number` | - | Maximum selectable items |
57
+ | `filterOption` | `Function` | - | Custom filter function |
58
+
59
+ ## Advanced Examples
60
+
61
+ ### Async Post Search
62
+
63
+ ```jsx
64
+ import { SortableSelect } from '@siratik/wp-component-library';
65
+ import apiFetch from '@wordpress/api-fetch';
66
+
67
+ function PostSelector() {
68
+ const [selectedPosts, setSelectedPosts] = useState([]);
69
+
70
+ const searchPosts = async (inputValue) => {
71
+ const response = await apiFetch({
72
+ path: `/wp/v2/posts?search=${inputValue}&per_page=20`,
73
+ });
74
+ return response;
75
+ };
76
+
77
+ return (
78
+ <SortableSelect
79
+ value={selectedPosts}
80
+ onChange={setSelectedPosts}
81
+ loadOptions={searchPosts}
82
+ getOptionLabel={(post) => post.title.rendered}
83
+ getOptionValue={(post) => post.id}
84
+ placeholder="Search posts..."
85
+ />
86
+ );
87
+ }
88
+ ```
89
+
90
+ ### Custom Rendering
91
+
92
+ ```jsx
93
+ <SortableSelect
94
+ value={selectedUsers}
95
+ onChange={setSelectedUsers}
96
+ loadOptions={searchUsers}
97
+ renderOption={(user) => (
98
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
99
+ <img
100
+ src={user.avatar_urls['48']}
101
+ alt={user.name}
102
+ style={{ width: '24px', height: '24px', borderRadius: '50%' }}
103
+ />
104
+ <div>
105
+ <div>{user.name}</div>
106
+ <small style={{ color: '#666' }}>{user.email}</small>
107
+ </div>
108
+ </div>
109
+ )}
110
+ />
111
+ ```
112
+
113
+ ### Variable Tags with Categories
114
+
115
+ ```jsx
116
+ const variableTags = [
117
+ { value: '{{site_name}}', label: 'Site Name', category: 'Site' },
118
+ { value: '{{post_title}}', label: 'Post Title', category: 'Post' },
119
+ { value: '{{author_name}}', label: 'Author Name', category: 'Author' },
120
+ ];
121
+
122
+ <SortableSelect
123
+ value={selectedTags}
124
+ onChange={setSelectedTags}
125
+ options={variableTags}
126
+ renderOption={(option) => (
127
+ <div>
128
+ <strong>{option.label}</strong>
129
+ <code style={{ marginLeft: '8px' }}>{option.value}</code>
130
+ </div>
131
+ )}
132
+ />
133
+ ```
134
+
135
+ ## Styling
136
+
137
+ The component includes default styles and supports dark mode. You can customize the appearance using the provided CSS classes:
138
+
139
+ - `.sortable-select` - Main container
140
+ - `.sortable-select__control` - React-select control
141
+ - `.sortable-select__multi-value` - Individual token/pill
142
+ - `.sortable-select__drag-handle` - Drag handle icon within tokens
143
+ - `.sortable-select__multi-value__label` - Token label text
144
+ - `.sortable-select__multi-value__remove` - Token remove button
145
+
146
+ ## Accessibility
147
+
148
+ The component includes proper ARIA labels and keyboard support:
149
+ - Arrow keys to navigate options
150
+ - Enter to select
151
+ - Tab to move between elements
152
+ - Drag tokens to reorder them within the select component
153
+ - The drag handle appears on hover for better UX
@@ -0,0 +1,127 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { Button } from "@wordpress/components";
5
+ import { closeSmall } from "@wordpress/icons";
6
+
7
+ /**
8
+ * External dependencies
9
+ */
10
+ import { useSortable } from "@dnd-kit/sortable";
11
+ import { CSS } from "@dnd-kit/utilities";
12
+ import styled from '@emotion/styled';
13
+
14
+ // Styled components
15
+ const StyledToken = styled.span`
16
+ display: inline-flex;
17
+ align-items: center;
18
+ gap: 2px;
19
+ padding: 0 2px 0 6px;
20
+ height: 24px;
21
+ background: #ddd;
22
+ border-radius: 2px;
23
+ font-size: 13px;
24
+ cursor: grab;
25
+ position: relative;
26
+
27
+ &.is-dragging {
28
+ opacity: 0.5;
29
+ cursor: grabbing;
30
+ z-index: 1000;
31
+ }
32
+
33
+ &.is-plain-text {
34
+ background: transparent;
35
+ border-radius: 0;
36
+ padding: 0;
37
+ cursor: move;
38
+
39
+ .sortable-select__token-text {
40
+ font-weight: normal;
41
+ }
42
+ }
43
+
44
+ &.is-variable {
45
+ background: #e0e0e0;
46
+ border: 1px solid #ccc;
47
+ font-family: monospace;
48
+ font-size: 12px;
49
+ }
50
+ `;
51
+
52
+ const StyledTokenText = styled.span`
53
+ max-width: 200px;
54
+ overflow: hidden;
55
+ text-overflow: ellipsis;
56
+ white-space: nowrap;
57
+ `;
58
+
59
+ const StyledTokenRemove = styled(Button)`
60
+ padding: 0;
61
+ height: 18px;
62
+ width: 18px;
63
+ min-width: 18px;
64
+ background: transparent;
65
+ border: none;
66
+ cursor: pointer;
67
+
68
+ // Override WordPress button styles
69
+ &.components-button.has-icon {
70
+ padding: 0;
71
+ width: 24px;
72
+ min-width: 24px;
73
+ }
74
+ `;
75
+
76
+ /**
77
+ * CustomSortableToken Component
78
+ *
79
+ * A draggable token for the custom sortable select implementation.
80
+ */
81
+ export default function CustomSortableToken({
82
+ id,
83
+ value,
84
+ onRemove,
85
+ disabled = false,
86
+ isPlainText = false,
87
+ isVariable = false,
88
+ }) {
89
+ const {
90
+ attributes,
91
+ listeners,
92
+ setNodeRef,
93
+ transform,
94
+ transition,
95
+ isDragging,
96
+ } = useSortable({
97
+ id,
98
+ disabled,
99
+ });
100
+
101
+ const style = {
102
+ transform: CSS.Translate.toString(transform),
103
+ transition,
104
+ };
105
+
106
+ return (
107
+ <StyledToken
108
+ ref={setNodeRef}
109
+ style={style}
110
+ className={`${isDragging ? "is-dragging" : ""} ${isPlainText ? "is-plain-text" : ""} ${isVariable ? "is-variable" : ""}`}
111
+ {...attributes}
112
+ {...listeners}
113
+ >
114
+ <StyledTokenText>{value}</StyledTokenText>
115
+ <StyledTokenRemove
116
+ icon={closeSmall}
117
+ label="Remove"
118
+ onClick={(e) => {
119
+ e.stopPropagation();
120
+ onRemove();
121
+ }}
122
+ disabled={disabled}
123
+ size="small"
124
+ />
125
+ </StyledToken>
126
+ );
127
+ }